Skip to content
Browse files

[#20] I should be able to specify the time signature.

  • Loading branch information...
1 parent 7f29111 commit f2e512201233ffaa235222266bff4f1a9c078204 @gsmendoza committed May 29, 2012
View
1 .gitignore
@@ -3,6 +3,7 @@
git.bundle
.geanyprj
.rvmrc
+.switch_file
.yardoc
Gemfile.lock
doc/*
View
114 examples/tab-with-time-signature.ly
@@ -0,0 +1,114 @@
+\version "2.12.3"
+\include "english.ly"
+
+\paper {
+ indent = #0
+}
+
+\header {
+ title = ""
+ composer = ""
+ arranger = ""
+ instrument = ""
+}
+
+%-----------------------------------------------------------------------
+% Chord Sets
+%-----------------------------------------------------------------------
+% Bars
+
+vOneBarCChordBarOne = { c4 e4 }
+cBarCChordBarOne = { }
+sBarCChordBarOne = { r4^"C chord" r4 }
+
+vOneBarCChordBarTwo = { g2 }
+cBarCChordBarTwo = { }
+sBarCChordBarTwo = { r4 r4 }
+%-----------------------------------------------------------------------
+% Lines
+%-----------------------------------------------------------------------
+% Stanzas
+
+vOneStanzaCChord = { \vOneBarCChordBarOne \vOneBarCChordBarTwo }
+cStanzaCChord = { \cBarCChordBarOne \cBarCChordBarTwo }
+sStanzaCChord = { \sBarCChordBarOne \sBarCChordBarTwo }
+%-----------------------------------------------------------------------
+% Scores
+%-----------------------------------------------------------------------
+% Voices
+
+vOne = {
+ \vOneStanzaCChord
+}
+%-----------------------------------------------------------------------
+% Stanza Headings
+
+stanzaHeadings = { \sStanzaCChord }
+
+%-----------------------------------------------------------------------
+% Chord Headings
+
+chordHeadings = { \cStanzaCChord }
+
+%-----------------------------------------------------------------------
+
+\score {
+ \new StaffGroup <<
+ \new Staff <<
+ \time 2/4
+ \clef "treble_8"
+
+ \new Voice \with { \remove Rest_engraver } {
+ \stanzaHeadings
+ }
+
+ \new Voice {
+ \voiceOne
+ \vOne
+ }
+ >>
+
+ \new TabStaff <<
+ \new TabVoice {
+ \slurUp
+ \vOne
+ }
+ \new TabVoice {
+ \chordHeadings
+ }
+ >>
+ >>
+
+ \layout {
+ \context { \Staff
+ \override TimeSignature #'style = #'numbered
+ \override StringNumber #'transparent = ##t
+ }
+ \context { \TabStaff
+ \override TimeSignature #'style = #'numbered
+ }
+ \context { \Voice
+ \remove Slur_engraver
+ }
+ \context { \TabVoice
+ \remove Dots_engraver
+ \remove Stem_engraver
+ \remove Rest_engraver
+ }
+ }
+}
+
+% showLastLength = R1*4
+\score {
+ \new Staff \with {midiInstrument = #"acoustic guitar (nylon)"} <<
+ \clef "treble_8"
+
+ \new Voice {
+ \unfoldRepeats {
+ \vOne
+ }
+ }
+ >>
+
+ \midi {}
+}
View
13 examples/tab-with-time-signature.rb
@@ -0,0 +1,13 @@
+Gitara.define do
+ time '2/4'
+
+ stanza "C chord" do
+ bar do
+ notes "c4 e4"
+ end
+
+ bar do
+ notes "g2"
+ end
+ end
+end
View
1 lib/gitara.rb
@@ -26,6 +26,7 @@
require "gitara/node/score"
require "gitara/node/stanza"
require "gitara/node/tab"
+require "gitara/time_signature"
require "gitara/utilities"
require "gitara/version"
require "gitara/voice"
View
1 lib/gitara/dsl.rb
@@ -18,6 +18,7 @@ class Dsl < Valuable
can_add_property :midi_instrument
can_add_property :string_tunings
can_add_property :tempo
+ can_add_property :time
can_add_property :title
can_add_property :transposition
View
23 lib/gitara/node/bar.rb
@@ -5,10 +5,6 @@ class Bar < Base
# @attribute $1
has_value :specified_duration
- def duration
- specified_duration || 1
- end
-
def first_bar_of_stanza?
stanza && stanza.descendants(Node::Bar)[0] == self
end
@@ -26,7 +22,24 @@ def stanza
end
def stanza_heading
- first_bar_of_stanza? ? %Q|r#{duration}^"#{ancestor(Node::Stanza).name}"| : "r#{duration}"
+ first_bar_of_stanza? ? stanza_heading_for_first_bar : stanza_heading_for_succeeding_bars
+ end
+
+ def stanza_heading_for_first_bar
+ if specified_duration
+ %Q|r#{specified_duration}^"#{ancestor(Node::Stanza).name}"|
+ else
+ ts = ancestor(Node::Tab).time_signature
+ if ts.generates_whole_note_bars?
+ %Q|#{ts.rest_bar_value}^"#{ancestor(Node::Stanza).name}"|
+ else
+ %Q|r#{ts.beat_unit}^"#{ancestor(Node::Stanza).name}" | + ("r#{ts.beat_unit} " * (ts.beats_per_bar - 1)).strip
+ end
+ end
+ end
+
+ def stanza_heading_for_succeeding_bars
+ specified_duration ? "r#{specified_duration}" : ancestor(Node::Tab).time_signature.rest_bar_value
end
end
end
View
5 lib/gitara/node/tab.rb
@@ -10,6 +10,7 @@ class Tab < Base
has_value :midi_instrument, :default => "acoustic guitar (nylon)"
has_value :string_tunings
has_value :tempo
+ has_value :time
has_value :title
has_value :transposition
@@ -21,6 +22,10 @@ def playable_child
definition_children.last
end
+ def time_signature
+ @time_signature ||= TimeSignature.new(:value => time || '4/4')
+ end
+
def voices
@voices ||= Array.new(max_number_of_voices){|i| Voice.new(:id => i + 1, :parent => self)}
end
View
1 lib/gitara/template/tab.erb
@@ -69,6 +69,7 @@ chordHeadings = { <%= playable_child.chorded.call_name %> }
\score {
\new StaffGroup <<
\new Staff <<
+ <%= Gitara.render('tab_time', self) %>
<%= Gitara.render('tab_tempo', self) %>
\clef "treble_8"
View
3 lib/gitara/template/tab_time.erb
@@ -0,0 +1,3 @@
+<% if time %>
+\time <%= self.time %>
+<% end %>
View
21 lib/gitara/time_signature.rb
@@ -0,0 +1,21 @@
+module Gitara
+ class TimeSignature < Valuable
+ has_value :value
+
+ def beats_per_bar
+ value.split('/')[0].to_i
+ end
+
+ def beat_unit
+ value.split('/')[1].to_i
+ end
+
+ def generates_whole_note_bars?
+ beat_unit == beats_per_bar
+ end
+
+ def rest_bar_value
+ generates_whole_note_bars? ? "r1" : ("r#{beat_unit} " * beats_per_bar).strip
+ end
+ end
+end
View
3 spec/factories.rb
@@ -49,6 +49,9 @@
children [FactoryGirl.build(:score)]
end
+ factory :time_signature, :class => TimeSignature do
+ end
+
factory :voice, :class => Voice do
end
View
6 spec/lib/gitara/app_spec.rb
@@ -31,5 +31,11 @@
app_test.run
app_test.actual.should == app_test.expected
end
+
+ it "can convert a tab with a specified time to lilypond" do
+ app_test = AppTester.new(:name => 'tab-with-time-signature')
+ app_test.run
+ app_test.actual.should == app_test.expected
+ end
end
end
View
1 spec/lib/gitara/node/bar/stanza_version_spec.rb
@@ -5,6 +5,7 @@
it "should be the stanza heading of the bar" do
bar = FactoryGirl.build(:bar)
stanza = FactoryGirl.build(:stanza, :name => 'Intro', :children => [bar])
+ tab = FactoryGirl.build(:tab, :children => [stanza], :time => '4/4')
stanza_version_of_bar = FactoryGirl.build(:stanza_version_bar, :node => bar)
stanza_version_of_bar.value.should == 'r1^"Intro"'
View
38 spec/lib/gitara/node/bar_spec.rb
@@ -22,27 +22,37 @@
it "should be a whole rest with the stanza name if the bar is the first node of a stanza" do
bar = FactoryGirl.build(:bar)
stanza = FactoryGirl.build(:stanza, :name => 'Intro', :children => [bar])
+ tab = FactoryGirl.build(:tab, :children => [stanza], :time => '4/4')
bar.stanza_heading.should == 'r1^"Intro"'
end
it "should be a whole rest with no stanza name if the bar is not the first node of a stanza" do
- bar = FactoryGirl.build(:bar)
- bar.stanza_heading.should == 'r1'
+ first_bar = FactoryGirl.build(:bar)
+ second_bar = FactoryGirl.build(:bar)
+ stanza = FactoryGirl.build(:stanza, :name => 'Intro', :children => [first_bar, second_bar])
+ tab = FactoryGirl.build(:tab, :children => [stanza], :time => '4/4')
+
+ second_bar.stanza_heading.should == 'r1'
end
end
describe "#with a special_duration" do
- subject { FactoryGirl.build(:bar, :specified_duration => 8) }
-
it "should be a partial with the stanza name if the bar is the first node of a stanza" do
+ subject = FactoryGirl.build(:bar, :specified_duration => 8)
stanza = FactoryGirl.build(:stanza, :name => 'Intro', :children => [subject])
+ tab = FactoryGirl.build(:tab, :children => [stanza], :time => '4/4')
subject.stanza_heading.should == 'r8^"Intro"'
end
it "should be a partial with no stanza name if the subject is not the first node of a stanza" do
- subject.stanza_heading.should == 'r8'
+ first_bar = FactoryGirl.build(:bar)
+ second_bar = FactoryGirl.build(:bar, :specified_duration => 8)
+ stanza = FactoryGirl.build(:stanza, :name => 'Intro', :children => [first_bar, second_bar])
+ tab = FactoryGirl.build(:tab, :children => [stanza], :time => '4/4')
+
+ second_bar.stanza_heading.should == 'r8'
end
end
@@ -78,13 +88,21 @@
end
end
- describe "#duration" do
- it "should be 1 if there is no specified duration" do
- FactoryGirl.build(:bar, :specified_duration => nil).duration.should == 1
+ describe "#stanza_heading_for_first_bar" do
+ it "should be the time signature's rest bar value with the stanza name if the time signature will generate whole note bars" do
+ bar = FactoryGirl.build(:bar)
+ stanza = FactoryGirl.build(:stanza, :name => 'Intro', :children => [bar])
+ tab = FactoryGirl.build(:tab, :children => [stanza], :time => '4/4')
+
+ bar.stanza_heading_for_first_bar.should == 'r1^"Intro"'
end
- it "should be the specified duration if present" do
- FactoryGirl.build(:bar, :specified_duration => 8).duration.should == 8
+ it "should attach the stanza name to the first rest note if the time signature will not generate whole note bars" do
+ bar = FactoryGirl.build(:bar)
+ stanza = FactoryGirl.build(:stanza, :name => 'Intro', :children => [bar])
+ tab = FactoryGirl.build(:tab, :children => [stanza], :time => '3/4')
+
+ bar.stanza_heading_for_first_bar.should == 'r4^"Intro" r4 r4'
end
end
end
View
12 spec/lib/gitara/node/tab_spec.rb
@@ -50,4 +50,16 @@
tab.midi_instrument.should == 'acoustic guitar (nylon)'
end
end
+
+ describe "#time_signature" do
+ it "should be based on time if it exists" do
+ tab = FactoryGirl.build(:tab, :time => '3/4')
+ tab.time_signature.value.should == '3/4'
+ end
+
+ it "should be 4/4 if time is not set" do
+ tab = FactoryGirl.build(:tab, :time => nil)
+ tab.time_signature.value.should == '4/4'
+ end
+ end
end
View
35 spec/lib/gitara/time_signature_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+describe Gitara::TimeSignature do
+ describe "#rest_bar_value" do
+ it "should be r1 if the time signature generates whole note bars" do
+ FactoryGirl.build(:time_signature, :value => '4/4').rest_bar_value.should == "r1"
+ end
+
+ it "should be based on beat unit and beats per bar if the time signature does not generate whole note bars" do
+ FactoryGirl.build(:time_signature, :value => '3/4').rest_bar_value.should == "r4 r4 r4"
+ end
+ end
+
+ describe "#generates_whole_note_bars?" do
+ it "should be true if the beat unit is the same as the beats per bar" do
+ FactoryGirl.build(:time_signature, :value => '4/4').generates_whole_note_bars?.should be_true
+ end
+
+ it "should be false if the beat unit is not the same as the beats per bar" do
+ FactoryGirl.build(:time_signature, :value => '3/4').generates_whole_note_bars?.should be_false
+ end
+ end
+
+ describe "beat_unit" do
+ it "is the second part of the value" do
+ FactoryGirl.build(:time_signature, :value => '3/4').beat_unit.should == 4
+ end
+ end
+
+ describe "beats_per_bar" do
+ it "is the first part of the value" do
+ FactoryGirl.build(:time_signature, :value => '3/4').beats_per_bar.should == 3
+ end
+ end
+end

0 comments on commit f2e5122

Please sign in to comment.
Something went wrong with that request. Please try again.