music-transcription 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/examples/hip.yml +516 -0
  3. data/examples/make_hip.rb +63 -0
  4. data/examples/make_missed_connection.rb +65 -0
  5. data/examples/make_song1.rb +71 -0
  6. data/examples/make_song2.rb +58 -0
  7. data/examples/missed_connection.yml +305 -0
  8. data/examples/song1.yml +367 -0
  9. data/examples/song2.yml +236 -0
  10. data/lib/music-transcription/accent.rb +4 -15
  11. data/lib/music-transcription/accents.rb +12 -0
  12. data/lib/music-transcription/dynamic.rb +6 -15
  13. data/lib/music-transcription/meter.rb +15 -0
  14. data/lib/music-transcription/note.rb +28 -91
  15. data/lib/music-transcription/part.rb +9 -65
  16. data/lib/music-transcription/score.rb +14 -43
  17. data/lib/music-transcription/version.rb +1 -1
  18. data/lib/music-transcription.rb +2 -0
  19. data/spec/meter_spec.rb +25 -0
  20. data/spec/note_spec.rb +20 -33
  21. data/spec/part_spec.rb +13 -82
  22. data/spec/score_spec.rb +28 -16
  23. data/spec/spec_helper.rb +7 -2
  24. metadata +14 -20
  25. data/samples/arrangements/glissando_test.yml +0 -71
  26. data/samples/arrangements/hip.yml +0 -952
  27. data/samples/arrangements/instrument_test.yml +0 -119
  28. data/samples/arrangements/legato_test.yml +0 -237
  29. data/samples/arrangements/make_glissando_test.rb +0 -27
  30. data/samples/arrangements/make_hip.rb +0 -75
  31. data/samples/arrangements/make_instrument_test.rb +0 -34
  32. data/samples/arrangements/make_legato_test.rb +0 -37
  33. data/samples/arrangements/make_missed_connection.rb +0 -72
  34. data/samples/arrangements/make_portamento_test.rb +0 -27
  35. data/samples/arrangements/make_slur_test.rb +0 -37
  36. data/samples/arrangements/make_song1.rb +0 -84
  37. data/samples/arrangements/make_song2.rb +0 -69
  38. data/samples/arrangements/missed_connection.yml +0 -481
  39. data/samples/arrangements/portamento_test.yml +0 -71
  40. data/samples/arrangements/slur_test.yml +0 -237
  41. data/samples/arrangements/song1.yml +0 -640
  42. data/samples/arrangements/song2.yml +0 -429
@@ -3,39 +3,17 @@ module Transcription
3
3
 
4
4
  require 'set'
5
5
 
6
- # Abstraction of a musical note. The note can contain zero or more pitches,
7
- # with links to a pitches in a following note. The note also has an accent,
8
- # which must be one of Note::ACCENTS.
9
- #
10
- # @author James Tunnell
11
- #
12
- # @!attribute [rw] duration
13
- # @return [Numeric] The duration (in, say note length or time), greater than 0.0.
14
- #
15
- # @!attribute [r] pitches
16
- # @return [Set] The pitches that are part of the note and can link to
17
- # pitches in a following note.
18
- #
19
- # @!attribute [r] links
20
- # @return [Hash] Maps pitches in the current note to pitches in the following
21
- # note, by some link class, like Link::Slur.
22
- #
23
- # @!attribute [rw] accent
24
- # @return [Accent] The accent type, which must be one of Note::ACCENTS.
25
- #
26
6
  class Note
27
7
  attr_reader :duration, :pitches, :links
28
8
  attr_accessor :accent
29
9
 
30
- # A new instance of Note.
31
- def initialize duration, pitches = [], links: {}, accent: nil
10
+ def initialize duration, pitches = [], links: {}, accent: Accents::NONE
32
11
  self.duration = duration
33
12
  @pitches = Set.new(pitches).sort
34
13
  @links = links
35
14
  self.accent = accent
36
15
  end
37
16
 
38
- # Compare the equality of another Note object.
39
17
  def == other
40
18
  return (@duration == other.duration) &&
41
19
  (self.pitches == other.pitches) &&
@@ -51,32 +29,15 @@ class Note
51
29
  @duration = duration
52
30
  end
53
31
 
54
- # Produce an identical Note object.
55
32
  def clone
56
33
  Marshal.load(Marshal.dump(self))
57
34
  end
58
35
 
59
- def transpose_pitches_only diff
60
- self.clone.transpose_pitches! pitch_diff, transpose_link
61
- end
62
-
63
- def transpose_pitches_only! diff
64
- self.transpose! diff, false
65
- end
66
-
67
- def transpose_pitches_and_links diff
68
- self.clone.transpose_pitches_and_links! diff
69
- end
70
-
71
- def transpose_pitches_and_links! diff
72
- self.transpose! diff, true
36
+ def transpose diff
37
+ self.clone.transpose! diff
73
38
  end
74
39
 
75
- def transpose diff, transpose_links = true
76
- self.clone.transpose! diff, transpose_links
77
- end
78
-
79
- def transpose! diff, transpose_link_targets = true
40
+ def transpose! diff
80
41
  unless diff.is_a?(Pitch)
81
42
  diff = Pitch.make_from_semitone(diff)
82
43
  end
@@ -84,9 +45,7 @@ class Note
84
45
  @pitches = @pitches.map {|pitch| pitch + diff}
85
46
  new_links = {}
86
47
  @links.each_pair do |k,v|
87
- if transpose_link_targets
88
- v.target_pitch += diff
89
- end
48
+ v.target_pitch += diff
90
49
  new_links[k + diff] = v
91
50
  end
92
51
  @links = new_links
@@ -102,79 +61,57 @@ class Note
102
61
  return self
103
62
  end
104
63
 
105
- def to_s
106
- output = @duration.to_s
107
- if @pitches.any?
108
- output += "@"
109
- @pitches[0...-1].each do |pitch|
110
- output += pitch.to_s
111
- if @links.has_key? pitch
112
- output += @links[pitch].to_s
113
- end
114
- output += ","
115
- end
116
-
117
- last_pitch = @pitches[-1]
118
- output += last_pitch.to_s
119
- if @links.has_key? last_pitch
120
- output += @links[last_pitch].to_s
121
- end
122
- end
123
-
124
- return output
125
- end
126
-
127
64
  class Sixteenth < Note
128
- def initialize pitches = [], links: {}, accent: nil
129
- super(Rational(1,16),pitches, links: links, accent: accent)
65
+ def initialize pitches = [], links: {}, accent: Accents::NONE
66
+ super(Rational(1,16),pitches,links:links,accent:accent)
130
67
  end
131
68
  end
132
-
69
+
133
70
  class DottedSixteenth < Note
134
- def initialize pitches = [], links: {}, accent: nil
135
- super(Rational(3,32),pitches, links: links, accent: accent)
71
+ def initialize pitches = [], links: {}, accent: Accents::NONE
72
+ super(Rational(3,32),pitches,links:links,accent:accent)
136
73
  end
137
74
  end
138
75
 
139
76
  class Eighth < Note
140
- def initialize pitches = [], links: {}, accent: nil
141
- super(Rational(1,8),pitches, links: links, accent: accent)
77
+ def initialize pitches = [], links: {}, accent: Accents::NONE
78
+ super(Rational(1,8),pitches,links:links,accent:accent)
142
79
  end
143
80
  end
144
-
81
+
145
82
  class DottedEighth < Note
146
- def initialize pitches = [], links: {}, accent: nil
147
- super(Rational(3,16),pitches, links: links, accent: accent)
83
+ def initialize pitches = [], links: {}, accent: Accents::NONE
84
+ super(Rational(3,16),pitches,links:links,accent:accent)
148
85
  end
149
86
  end
150
87
 
151
88
  class Quarter < Note
152
- def initialize pitches = [], links: {}, accent: nil
153
- super(Rational(1,4),pitches, links: links, accent: accent)
89
+ def initialize pitches = [], links: {}, accent: Accents::NONE
90
+ super(Rational(1,4),pitches,links:links,accent:accent)
154
91
  end
155
92
  end
156
93
 
157
94
  class DottedQuarter < Note
158
- def initialize pitches = [], links: {}, accent: nil
159
- super(Rational(3,8),pitches, links: links, accent: accent)
95
+ def initialize pitches = [], links: {}, accent: Accents::NONE
96
+ super(Rational(3,8),pitches,links:links,accent:accent)
160
97
  end
161
98
  end
162
-
99
+
163
100
  class Half < Note
164
- def initialize pitches = [], links: {}, accent: nil
165
- super(Rational(1,2),pitches, links: links, accent: accent)
101
+ def initialize pitches = [], links: {}, accent: Accents::NONE
102
+ super(Rational(1,2),pitches,links:links,accent:accent)
166
103
  end
167
104
  end
168
-
105
+
169
106
  class DottedHalf < Note
170
- def initialize pitches = [], links: {}, accent: nil
171
- super(Rational(3,4),pitches, links: links, accent: accent)
107
+ def initialize pitches = [], links: {}, accent: Accents::NONE
108
+ super(Rational(3,4),pitches,links:links,accent:accent)
172
109
  end
173
110
  end
174
-
111
+
175
112
  class Whole < Note
176
- def initialize pitches = [], links: {}, accent: nil
177
- super(Rational(1,1),pitches, links: links, accent: accent)
113
+ def initialize pitches = [], links: {}, accent: Accents::NONE
114
+ super(Rational(1,1),pitches,links:links,accent:accent)
178
115
  end
179
116
  end
180
117
  end
@@ -3,90 +3,34 @@ require 'yaml'
3
3
  module Music
4
4
  module Transcription
5
5
 
6
- # Abstraction of a musical part. Contains notes and loudness_profile settings.
7
- #
8
- # @author James Tunnell
9
- #
10
- # @!attribute [r] notes
11
- # @return [Array] The notes to be played.
12
- #
13
- # @!attribute [r] dynamic_profile
14
- # @return [Profile] Dynamic values profile
15
- #
16
6
  class Part
17
- attr_reader :notes, :dynamic_profile
7
+ attr_reader :start_dynamic, :dynamic_changes, :notes
18
8
 
19
- def initialize notes: [], dynamic_profile: Profile.new(Dynamics::MF)
9
+ def initialize start_dynamic, notes: [], dynamic_changes: {}
20
10
  @notes = notes
21
- @dynamic_profile = dynamic_profile
22
-
23
- if dynamic_profile.changes_before?(0)
24
- raise ArgumentError, "dynamic profile has changes with offset less than 0"
25
- end
11
+ @start_dynamic = start_dynamic
12
+ @dynamic_changes = dynamic_changes
26
13
 
27
14
  d = self.duration
28
- if dynamic_profile.changes_after?(d)
29
- raise ArgumentError, "dynamic profile has changes with offset greater than part duration #{d}"
15
+ badkeys = dynamic_changes.keys.select {|k| k < 0 || k > d }
16
+ if badkeys.any?
17
+ raise ArgumentError, "dynamic profile has changes outside 0..d"
30
18
  end
31
19
  end
32
20
 
33
- # Produce an exact copy of the current object
34
21
  def clone
35
22
  Marshal.load(Marshal.dump(self))
36
23
  end
37
24
 
38
- # Compare the equality of another Part object.
39
25
  def ==(other)
40
26
  return (@notes == other.notes) &&
41
- (@dynamic_profile == other.dynamic_profile)
27
+ (@start_dynamic == other.start_dynamic) &&
28
+ (@dynamic_changes == other.dynamic_changes)
42
29
  end
43
30
 
44
- # Duration of part notes.
45
31
  def duration
46
32
  return @notes.inject(0) { |sum, note| sum + note.duration }
47
33
  end
48
-
49
- def transpose diff
50
- self.clone.transpose! diff
51
- end
52
-
53
- def transpose! diff
54
- @notes[0...-1].each do |note|
55
- note.transpose_pitches_and_links! diff
56
- end
57
- @notes[-1].transpose_pitches_only! diff
58
- return self
59
- end
60
-
61
- # Add on notes and dynamic_profile from another part, producing a new
62
- # Part object. The offsets of value changes in the dynamic profile,
63
- # for the other part, will be considered relative from end of current part.
64
- def append other
65
- self.clone.append! other
66
- end
67
-
68
- # Add on notes and dynamic_profile from another part, producing a new
69
- # Part object. The offsets of value changes in the dynamic profile,
70
- # for the other part, will be considered relative from end of current part.
71
- def append! other
72
- @dynamic_profile.append!(other.dynamic_profile,self.duration)
73
- @notes += other.notes.map {|x| x.clone}
74
- return self
75
- end
76
-
77
- def stretch ratio
78
- self.clone.stretch! ratio
79
- end
80
-
81
- def stretch! ratio
82
- @notes.each_index do |i|
83
- n1 = @notes[i]
84
- @notes[i] = Note.new(n1.duration * ratio, n1.pitches, links: n1.links, accent: n1.accent)
85
- end
86
-
87
- @dynamic_profile.stretch! ratio
88
- return self
89
- end
90
34
  end
91
35
 
92
36
  end
@@ -1,26 +1,16 @@
1
1
  module Music
2
2
  module Transcription
3
3
 
4
- # Score, containing parts and a program.
5
- #
6
- # @author James Tunnell
7
- #
8
- # @!attribute [rw] parts
9
- # @return [Hash] Score parts, mapped to part names
10
- #
11
- # @!attribute [rw] program
12
- # @return [Program] Score program (which segments are played when)
13
- #
14
- # @!attribute [rw] tempo_profile
15
- # @return [Profile] Tempo values profile
16
- #
17
4
  class Score
18
- attr_reader :parts, :program, :tempo_profile
5
+ attr_reader :start_meter, :start_tempo, :parts, :program, :meter_changes, :tempo_changes
19
6
 
20
- def initialize parts: {}, program: Program.new, tempo_profile: Profile.new(Tempo.new(120))
7
+ def initialize start_meter, start_tempo, meter_changes: {}, tempo_changes: {}, parts: {}, program: Program.new
8
+ @start_meter = start_meter
9
+ @start_tempo = start_tempo
10
+ @meter_changes = meter_changes
11
+ @tempo_changes = tempo_changes
21
12
  @parts = parts
22
13
  @program = program
23
- @tempo_profile = tempo_profile
24
14
  end
25
15
 
26
16
  def clone
@@ -28,35 +18,16 @@ class Score
28
18
  end
29
19
 
30
20
  def ==(other)
31
- return (@tempo_profile == other.tempo_profile) &&
32
- (@program == other.program) &&
33
- (@parts == other.parts)
21
+ return @start_meter == other.start_meter &&
22
+ @start_tempo == other.start_tempo &&
23
+ @meter_changes == other.meter_changes &&
24
+ @tempo_changes == other.tempo_changes &&
25
+ @parts == other.parts &&
26
+ @program == other.program
34
27
  end
35
28
 
36
- # Find the start of a score. The start will be at then start of whichever part begins
37
- # first, or 0 if no parts have been added.
38
- def start
39
- sos = 0.0
40
-
41
- @parts.each do |id,part|
42
- sop = part.start
43
- sos = sop if sop > sos
44
- end
45
-
46
- return sos
47
- end
48
-
49
- # Find the end of a score. The end will be at then end of whichever part ends
50
- # last, or 0 if no parts have been added.
51
- def end
52
- eos = 0.0
53
-
54
- @parts.each do |id,part|
55
- eop = part.end
56
- eos = eop if eop > eos
57
- end
58
-
59
- return eos
29
+ def duration
30
+ @parts.map {|p| p.duration }.max
60
31
  end
61
32
  end
62
33
 
@@ -2,6 +2,6 @@
2
2
  module Music
3
3
  module Transcription
4
4
  # music-transcription version
5
- VERSION = "0.6.3"
5
+ VERSION = "0.7.0"
6
6
  end
7
7
  end
@@ -6,6 +6,7 @@ require 'music-transcription/pitch'
6
6
  require 'music-transcription/pitches'
7
7
  require 'music-transcription/link'
8
8
  require 'music-transcription/accent'
9
+ require 'music-transcription/accents'
9
10
  require 'music-transcription/change'
10
11
  require 'music-transcription/note'
11
12
  require 'music-transcription/profile'
@@ -14,4 +15,5 @@ require 'music-transcription/dynamics'
14
15
  require 'music-transcription/part'
15
16
  require 'music-transcription/program'
16
17
  require 'music-transcription/tempo'
18
+ require 'music-transcription/meter'
17
19
  require 'music-transcription/score'
@@ -0,0 +1,25 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Meter do
4
+ describe '#initialize' do
5
+ it 'should assign beats per measure and beat duration' do
6
+ [[4,"1/4".to_r],[3,"1/4".to_r],[6,"1/8".to_r]].each do |bpm,bd|
7
+ m = Meter.new(bpm,bd)
8
+ m.beats_per_measure.should eq bpm
9
+ m.beat_duration.should eq bd
10
+ end
11
+ end
12
+
13
+ it 'should derive measure duration' do
14
+ {
15
+ [4,"1/4".to_r] => "1/1".to_r,
16
+ [3,"1/4".to_r] => "3/4".to_r,
17
+ [6,"1/8".to_r] => "6/8".to_r,
18
+ [12,"1/8".to_r] => "12/8".to_r,
19
+ }.each do |bpm,bd|
20
+ m = Meter.new(bpm,bd)
21
+ m.measure_duration.should eq(bpm*bd)
22
+ end
23
+ end
24
+ end
25
+ end
data/spec/note_spec.rb CHANGED
@@ -37,46 +37,33 @@ describe Note do
37
37
  end
38
38
 
39
39
  describe '#transpose!' do
40
- context 'transpose_link_targets set false' do
41
- context 'given pitch diff' do
42
- before(:all) do
43
- @note = Note::Quarter.new([C2,F2], links:{C2=>Link::Slur.new(D2)})
44
- @diff = Pitch.new(semitone: 4)
45
- @note.transpose! @diff, false
46
- end
47
-
48
- it 'should modifiy pitches by adding pitch diff' do
49
- @note.pitches[0].should eq E2
50
- @note.pitches[1].should eq A2
51
- end
40
+ context 'given pitch diff' do
41
+ before(:all) do
42
+ @note = Note::Quarter.new([C2,F2], links:{C2=>Link::Slur.new(D2)})
43
+ @diff = Pitch.new(semitone: 4)
44
+ @note.transpose! @diff
45
+ end
52
46
 
53
- it 'should not affect link targets' do
54
- @note.links.should have_key(E2)
55
- @note.links[E2].target_pitch.should eq(D2)
56
- end
47
+ it 'should modifiy pitches by adding pitch diff' do
48
+ @note.pitches[0].should eq E2
49
+ @note.pitches[1].should eq A2
57
50
  end
58
-
59
- context 'given integer diff' do
60
- it 'should transpose the given number of semitones' do
61
- Note::Quarter.new([C2]).transpose!(4,false).pitches[0].should eq(E2)
62
- end
51
+
52
+ it 'should also affect link targets' do
53
+ @note.links.should have_key(E2)
54
+ @note.links[E2].target_pitch.should eq(Gb2)
63
55
  end
64
56
  end
65
-
66
- context 'transpose_link_targets set true' do
67
- it 'should also transpose link targets' do
68
- note = Note::Quarter.new([C2,F2], links:{C2=>Link::Slur.new(D2)})
69
- note.transpose!(2,true)
70
- note.links[D2].target_pitch.should eq(E2)
57
+
58
+ context 'given integer diff' do
59
+ it 'should transpose the given number of semitones' do
60
+ Note::Quarter.new([C2]).transpose!(4).pitches[0].should eq(E2)
71
61
  end
72
62
  end
73
63
 
74
- context 'transpose_link_targets not set' do
75
- it 'should default to true' do
76
- note = Note::Quarter.new([C2,F2], links: {C2=>Link::Slur.new(D2)})
77
- note.transpose!(2)
78
- note.links[D2].target_pitch.should eq E2
79
- end
64
+ it 'should return self' do
65
+ n = Note::Quarter.new
66
+ n.transpose!(0).should eq n
80
67
  end
81
68
  end
82
69
 
data/spec/part_spec.rb CHANGED
@@ -1,91 +1,22 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe Part do
4
- context '.new' do
5
- it 'should have no notes' do
6
- Part.new.notes.should be_empty
7
- end
8
-
9
- it "should assign dynamic profile given during construction" do
10
- profile = Profile.new(Dynamics::FFF, { 1.0 => Change::Immediate.new(Dynamics::PP) })
11
- part = Part.new notes:[Note.new(1.to_r)], dynamic_profile: profile
12
- part.dynamic_profile.should eq(profile)
13
- end
14
-
15
- it "should assign notes given during construction" do
16
- notes = [ Note::Quarter.new([C1,D1]) ]
17
- part = Part.new notes: notes
18
- part.notes.should eq(notes)
19
- end
20
- end
21
-
22
- describe '#stretch' do
23
- before :all do
24
- p = Part.new(
25
- notes: [ Note::Quarter.new, Note::Whole.new, Note::Eighth.new ],
26
- dynamic_profile: Profile.new(
27
- Dynamics::PP,
28
- "1/2".to_r => Change::Immediate.new(Dynamics::MP),
29
- "3/4".to_r => Change::Immediate.new(Dynamics::FF)
30
- )
31
- )
32
- @p1 = p.stretch(1)
33
- @p2 = p.stretch("5/3".to_r)
34
- @p3 = p.stretch("3/5".to_r)
35
- end
36
-
37
- it 'should multiply durations by ratio' do
38
- @p1.notes.map {|n| n.duration }.should eq(["1/4".to_r, "1/1".to_r, "1/8".to_r])
39
- @p2.notes.map {|n| n.duration }.should eq(["5/12".to_r, "5/3".to_r, "5/24".to_r])
40
- @p3.notes.map {|n| n.duration }.should eq(["3/20".to_r, "3/5".to_r, "3/40".to_r])
4
+ context '#initialize' do
5
+ it 'should use empty containers for parameters not given' do
6
+ p = Part.new(Dynamics::MP)
7
+ p.notes.should be_empty
8
+ p.dynamic_changes.should be_empty
41
9
  end
42
10
 
43
- it 'should multiply dynamic profile changes by ratio' do
44
- @p1.dynamic_profile.value_changes.should have_key("1/2".to_r)
45
- @p1.dynamic_profile.value_changes.should have_key("3/4".to_r)
46
-
47
- @p2.dynamic_profile.value_changes.should have_key("5/6".to_r)
48
- @p2.dynamic_profile.value_changes.should have_key("15/12".to_r)
11
+ it "should assign parameters given during construction" do
12
+ p = Part.new(Dynamics::PPP)
13
+ p.start_dynamic.should eq Dynamics::PPP
49
14
 
50
- @p3.dynamic_profile.value_changes.should have_key("3/10".to_r)
51
- @p3.dynamic_profile.value_changes.should have_key("9/20".to_r)
52
- end
53
- end
54
-
55
- describe '#append!' do
56
- it 'should add other notes to current array' do
57
- p1 = Part.new(notes: [Note::Eighth.new([C4])])
58
- p2 = Part.new(notes: [Note::Eighth.new([E4])])
59
- p1.append! p2
60
- p1.notes.size.should be 2
61
- p1.notes[0].pitches[0].should eq C4
62
- p1.notes[1].pitches[0].should eq E4
63
- end
64
-
65
- it 'should add start dynamic from given part as immediate dynamic change' do
66
- p1 = Part.new(notes: [Note::Eighth.new])
67
- p2 = Part.new(notes: [Note::Eighth.new], dynamic_profile: Profile.new(Dynamics::PPP))
68
- p1.append! p2
69
- p1.dynamic_profile.value_changes.size.should eq 1
70
- p1.dynamic_profile.value_changes[Rational(1,8)].should be_a Change::Immediate
71
- p1.dynamic_profile.value_changes[Rational(1,8)].value.should eq Dynamics::PPP
72
- end
73
-
74
- it 'should add shifted dynamic changes from given part' do
75
- p1 = Part.new(notes: [Note::Whole.new])
76
- p2 = Part.new(
77
- notes: [Note::Whole.new],
78
- dynamic_profile: Profile.new(
79
- Dynamics::PPP,
80
- Rational(1,8) => Change::Gradual.new(Dynamics::PP,Rational(1,8)),
81
- Rational(3,8) => Change::Immediate.new(Dynamics::P)
82
- )
83
- )
84
- p1.append! p2
85
- p1.dynamic_profile.value_changes.size.should eq 3
86
- p1.dynamic_profile.value_changes[Rational(1,1)].value.should eq Dynamics::PPP
87
- p1.dynamic_profile.value_changes[Rational(9,8)].value.should eq Dynamics::PP
88
- p1.dynamic_profile.value_changes[Rational(11,8)].value.should eq Dynamics::P
15
+ notes = [Note::Whole.new([A2]), Note::Half.new]
16
+ dcs = { "1/2".to_r => Change::Immediate.new(Dynamics::P), 1 => Change::Gradual.new(Dynamics::MF,1) }
17
+ p = Part.new(Dynamics::FF, notes: notes, dynamic_changes: dcs)
18
+ p.notes.should eq notes
19
+ p.dynamic_changes.should eq dcs
89
20
  end
90
21
  end
91
22
  end
data/spec/score_spec.rb CHANGED
@@ -1,22 +1,34 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe Score do
4
- before :each do
5
- @parts = { "piano (LH)" => Samples::SAMPLE_PART }
6
- @program = Program.new [0...0.75, 0...0.75]
7
- end
8
-
9
- describe '.new' do
10
- it "should assign part and program given during construction" do
11
- score = Score.new parts: @parts, program: @program
12
- score.parts.should eq(@parts)
13
- score.program.should eq(@program)
4
+ describe '#initialize' do
5
+ it 'should use empty containers for parameters not given' do
6
+ s = Score.new(Meter.new(4,4),120)
7
+ s.parts.should be_empty
8
+ s.program.segments.should be_empty
9
+ end
10
+
11
+ it 'should assign given parameters' do
12
+ m = Meter.new(4,"1/4".to_r)
13
+ s = Score.new(m,120)
14
+ s.start_meter.should eq m
15
+ s.start_tempo.should eq 120
16
+
17
+ parts = { "piano (LH)" => Samples::SAMPLE_PART }
18
+ program = Program.new [0...0.75, 0...0.75]
19
+ mcs = { 1 => Change::Immediate.new(Meter.new(3,"1/4".to_r)) }
20
+ tcs = { 1 => Change::Immediate.new(100) }
21
+
22
+ s = Score.new(m,120,
23
+ parts: parts,
24
+ program: program,
25
+ meter_changes: mcs,
26
+ tempo_changes: tcs
27
+ )
28
+ s.parts.should eq parts
29
+ s.program.should eq program
30
+ s.meter_changes.should eq mcs
31
+ s.tempo_changes.should eq tcs
14
32
  end
15
-
16
- it "should assign tempo profile given during construction" do
17
- profile = Profile.new(Tempo.new(200), 0.5 => Change::Gradual.new(Tempo.new(120),0.5) )
18
- score = Score.new tempo_profile: profile
19
- score.tempo_profile.should eq(profile)
20
- end
21
33
  end
22
34
  end
data/spec/spec_helper.rb CHANGED
@@ -6,7 +6,12 @@ include Music::Transcription::Pitches
6
6
 
7
7
  class Samples
8
8
  SAMPLE_PART = Part.new(
9
- notes: [ Note::Quarter.new([ C1, D1 ]), Note::Quarter.new([ C2, D2 ]), Note::Whole.new([ C3, D3 ]) ],
10
- dynamic_profile: Profile.new(Dynamics::P, {1.0 => Change::Immediate.new(Dynamics::MP)})
9
+ Dynamics::P,
10
+ notes: [
11
+ Note::Quarter.new([ C1, D1 ]),
12
+ Note::Quarter.new([ C2, D2 ]),
13
+ Note::Whole.new([ C3, D3 ])
14
+ ],
15
+ dynamic_changes: {1.0 => Change::Immediate.new(Dynamics::MP)}
11
16
  )
12
17
  end