musicality 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +8 -1
  3. data/bin/midify +3 -4
  4. data/examples/composition/auto_counterpoint.rb +53 -0
  5. data/examples/composition/part_generator.rb +51 -0
  6. data/examples/composition/scale_exercise.rb +41 -0
  7. data/examples/{hip.rb → notation/hip.rb} +1 -1
  8. data/examples/{missed_connection.rb → notation/missed_connection.rb} +1 -1
  9. data/examples/{song1.rb → notation/song1.rb} +1 -1
  10. data/examples/{song2.rb → notation/song2.rb} +1 -1
  11. data/lib/musicality.rb +34 -4
  12. data/lib/musicality/composition/generation/counterpoint_generator.rb +153 -0
  13. data/lib/musicality/composition/generation/random_rhythm_generator.rb +39 -0
  14. data/lib/musicality/composition/model/pitch_class.rb +33 -0
  15. data/lib/musicality/composition/model/pitch_classes.rb +22 -0
  16. data/lib/musicality/composition/model/scale.rb +34 -0
  17. data/lib/musicality/composition/model/scale_class.rb +37 -0
  18. data/lib/musicality/composition/model/scale_classes.rb +91 -0
  19. data/lib/musicality/composition/note_generation.rb +31 -0
  20. data/lib/musicality/composition/transposition.rb +8 -0
  21. data/lib/musicality/composition/util/adding_sequence.rb +24 -0
  22. data/lib/musicality/composition/util/biinfinite_sequence.rb +130 -0
  23. data/lib/musicality/composition/util/compound_sequence.rb +44 -0
  24. data/lib/musicality/composition/util/probabilities.rb +20 -0
  25. data/lib/musicality/composition/util/random_sampler.rb +26 -0
  26. data/lib/musicality/composition/util/repeating_sequence.rb +24 -0
  27. data/lib/musicality/errors.rb +2 -0
  28. data/lib/musicality/notation/conversion/score_conversion.rb +1 -1
  29. data/lib/musicality/notation/conversion/score_converter.rb +3 -3
  30. data/lib/musicality/notation/model/link.rb +26 -24
  31. data/lib/musicality/notation/model/links.rb +11 -0
  32. data/lib/musicality/notation/model/note.rb +14 -15
  33. data/lib/musicality/notation/model/part.rb +3 -3
  34. data/lib/musicality/notation/model/pitch.rb +8 -0
  35. data/lib/musicality/notation/model/score.rb +70 -44
  36. data/lib/musicality/notation/model/symbols.rb +22 -0
  37. data/lib/musicality/notation/packing/score_packing.rb +2 -3
  38. data/lib/musicality/notation/parsing/articulation_parsing.rb +4 -4
  39. data/lib/musicality/notation/parsing/articulation_parsing.treetop +2 -2
  40. data/lib/musicality/notation/parsing/link_nodes.rb +2 -14
  41. data/lib/musicality/notation/parsing/link_parsing.rb +9 -107
  42. data/lib/musicality/notation/parsing/link_parsing.treetop +4 -12
  43. data/lib/musicality/notation/parsing/note_node.rb +23 -21
  44. data/lib/musicality/notation/parsing/note_parsing.rb +70 -70
  45. data/lib/musicality/notation/parsing/note_parsing.treetop +6 -3
  46. data/lib/musicality/notation/parsing/pitch_node.rb +4 -2
  47. data/lib/musicality/performance/conversion/score_collator.rb +3 -3
  48. data/lib/musicality/performance/midi/midi_util.rb +13 -6
  49. data/lib/musicality/performance/midi/score_sequencing.rb +17 -0
  50. data/lib/musicality/printing/lilypond/errors.rb +5 -0
  51. data/lib/musicality/printing/lilypond/meter_engraving.rb +11 -0
  52. data/lib/musicality/printing/lilypond/note_engraving.rb +53 -0
  53. data/lib/musicality/printing/lilypond/part_engraver.rb +12 -0
  54. data/lib/musicality/printing/lilypond/pitch_engraving.rb +30 -0
  55. data/lib/musicality/printing/lilypond/score_engraver.rb +78 -0
  56. data/lib/musicality/version.rb +1 -1
  57. data/spec/composition/generation/random_rhythm_generator_spec.rb +50 -0
  58. data/spec/composition/model/pitch_class_spec.rb +75 -0
  59. data/spec/composition/model/pitch_classes_spec.rb +24 -0
  60. data/spec/composition/model/scale_class_spec.rb +98 -0
  61. data/spec/composition/model/scale_spec.rb +110 -0
  62. data/spec/composition/note_generation_spec.rb +113 -0
  63. data/spec/composition/transposition_spec.rb +17 -0
  64. data/spec/composition/util/adding_sequence_spec.rb +176 -0
  65. data/spec/composition/util/compound_sequence_spec.rb +50 -0
  66. data/spec/composition/util/probabilities_spec.rb +39 -0
  67. data/spec/composition/util/random_sampler_spec.rb +47 -0
  68. data/spec/composition/util/repeating_sequence_spec.rb +151 -0
  69. data/spec/notation/conversion/score_conversion_spec.rb +3 -3
  70. data/spec/notation/conversion/score_converter_spec.rb +24 -24
  71. data/spec/notation/model/link_spec.rb +27 -25
  72. data/spec/notation/model/note_spec.rb +9 -6
  73. data/spec/notation/model/pitch_spec.rb +24 -1
  74. data/spec/notation/model/score_spec.rb +57 -16
  75. data/spec/notation/packing/score_packing_spec.rb +134 -206
  76. data/spec/notation/parsing/articulation_parsing_spec.rb +1 -8
  77. data/spec/notation/parsing/convenience_methods_spec.rb +1 -1
  78. data/spec/notation/parsing/link_nodes_spec.rb +3 -4
  79. data/spec/notation/parsing/link_parsing_spec.rb +10 -4
  80. data/spec/notation/parsing/note_node_spec.rb +8 -7
  81. data/spec/notation/parsing/note_parsing_spec.rb +9 -12
  82. data/spec/performance/conversion/score_collator_spec.rb +14 -14
  83. data/spec/performance/midi/midi_util_spec.rb +26 -0
  84. data/spec/performance/midi/score_sequencer_spec.rb +1 -1
  85. metadata +57 -12
  86. data/lib/musicality/notation/model/program.rb +0 -53
  87. data/lib/musicality/notation/packing/program_packing.rb +0 -16
  88. data/spec/notation/model/program_spec.rb +0 -50
  89. data/spec/notation/packing/program_packing_spec.rb +0 -33
@@ -120,18 +120,21 @@ describe Note do
120
120
  [[C2],{}],
121
121
  [[A5,D6],{ A5 => Link::Tie.new }],
122
122
  [[C5,E6,Gb2],{ C5 => Link::Glissando.new(D5) }],
123
- [[A5,D6],{ A5 => Link::Legato.new(B5), D6 => Link::Slur.new(E6) }],
124
123
  [[C5,E6,Gb2],{ C5 => Link::Portamento.new(D5), Gb2 => Link::Tie.new }],
125
124
  ]
126
125
 
127
126
  notes = []
128
127
  durations.each do |d|
129
- articulations.each do |art|
130
- pitches_links_sets.each do |pitches_links_set|
131
- pitches,links = pitches_links_set
132
- [true,false].each do |acc|
133
- notes.push Note.new(d, pitches, articulation: art, links: links, accented: acc)
128
+ pitches_links_sets.each do |pitches_links_set|
129
+ pitches,links = pitches_links_set
130
+ if pitches.any?
131
+ articulations.each do |art|
132
+ [true,false].each do |acc|
133
+ notes.push Note.new(d, pitches, articulation: art, links: links, accented: acc)
134
+ end
134
135
  end
136
+ else
137
+ notes.push Note.new(d)
135
138
  end
136
139
  end
137
140
  end
@@ -62,13 +62,36 @@ describe Pitch do
62
62
  end
63
63
 
64
64
  describe '#transpose' do
65
- it 'should add the given interval to total semitones' do
65
+ it 'should make a new pitch, adding the given interval to total semitones' do
66
66
  [0,1,2,5,12,13,-1,-2,-5,-12,-13].each do |interval|
67
67
  pitch = Eb3.transpose(interval)
68
+ pitch.should_not be Eb3
68
69
  pitch.diff(Eb3).should eq(interval)
69
70
  end
70
71
  end
71
72
  end
73
+
74
+ describe '#+' do
75
+ it 'should produce same result as #transpose' do
76
+ [0,1,2,5,12,13,-1,-2,-5,-12,-13].each do |interval|
77
+ pitch = Eb3 + interval
78
+ pitch.should_not be Eb3
79
+ pitch2 = Eb3.transpose(interval)
80
+ pitch.should eq(pitch2)
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '#-' do
86
+ it 'should produce same result as #transpose, with negative interval' do
87
+ [0,1,2,5,12,13,-1,-2,-5,-12,-13].each do |interval|
88
+ pitch = Eb3 - interval
89
+ pitch.should_not be Eb3
90
+ pitch2 = Eb3.transpose(-interval)
91
+ pitch.should eq(pitch2)
92
+ end
93
+ end
94
+ end
72
95
 
73
96
  describe '.total_semitones' do
74
97
  it 'should convert to whole/fractional total semitones value' do
@@ -4,14 +4,14 @@ describe Score do
4
4
  describe '#collated?' do
5
5
  context 'has program with more than one segment' do
6
6
  it 'should return false' do
7
- score = Score.new(program: Program.new([0..2,0..2]))
7
+ score = Score.new(program: [0..2,0..2])
8
8
  score.collated?.should be false
9
9
  end
10
10
  end
11
11
 
12
12
  context 'has program with 0 segments' do
13
13
  it 'should return false' do
14
- score = Score.new(program: Program.new([]))
14
+ score = Score.new(program: [])
15
15
  score.collated?.should be false
16
16
  end
17
17
  end
@@ -19,14 +19,14 @@ describe Score do
19
19
  context 'has program with 1 segment' do
20
20
  context 'program segment starts at 0' do
21
21
  it 'should return true' do
22
- score = Score.new(program: Program.new([0..2]))
22
+ score = Score.new(program: [0..2])
23
23
  score.collated?.should be true
24
24
  end
25
25
  end
26
26
 
27
27
  context 'program segment does not start at 0' do
28
28
  it 'should return false' do
29
- score = Score.new(program: Program.new([1..2]))
29
+ score = Score.new(program: [1..2])
30
30
  score.collated?.should be false
31
31
  end
32
32
  end
@@ -48,6 +48,32 @@ describe Score do
48
48
  end
49
49
  end
50
50
  end
51
+
52
+ describe '#valid?' do
53
+ context 'non-Range objects' do
54
+ it 'should return false' do
55
+ Score.new(program: [1,2,3]).should_not be_valid
56
+ end
57
+ end
58
+
59
+ context 'increasing, positive segments' do
60
+ it 'should return true' do
61
+ Score.new(program: [0..2,1..2,0..4]).should be_valid
62
+ end
63
+ end
64
+
65
+ context 'decreasing, positive segments' do
66
+ it 'should return false' do
67
+ Score.new(program: [2..0,2..1,04..0]).should be_invalid
68
+ end
69
+ end
70
+
71
+ context 'increasing, negative segments' do
72
+ it 'should return false' do
73
+ Score.new(program: [-1..2,-2..0,-2..2]).should be_invalid
74
+ end
75
+ end
76
+ end
51
77
  end
52
78
 
53
79
  describe Score::Measured do
@@ -55,7 +81,7 @@ describe Score::Measured do
55
81
  it 'should use empty containers for parameters not given' do
56
82
  s = Score::Measured.new(FOUR_FOUR,120)
57
83
  s.parts.should be_empty
58
- s.program.segments.should be_empty
84
+ s.program.should be_empty
59
85
  end
60
86
 
61
87
  it 'should assign given parameters' do
@@ -65,7 +91,7 @@ describe Score::Measured do
65
91
  s.start_tempo.should eq 120
66
92
 
67
93
  parts = { "piano (LH)" => Samples::SAMPLE_PART }
68
- program = Program.new [0...0.75, 0...0.75]
94
+ program = [0...0.75, 0...0.75]
69
95
  mcs = { 1 => Change::Immediate.new(THREE_FOUR) }
70
96
  tcs = { 1 => Change::Immediate.new(100) }
71
97
 
@@ -132,6 +158,21 @@ describe Score::Measured do
132
158
  ).measures_long.should eq(3.5)
133
159
  end
134
160
  end
161
+
162
+ context 'given specific note duration' do
163
+ it 'should change the given note duration to measures' do
164
+ score = Score::Measured.new(TWO_FOUR, 120,
165
+ meter_changes: {
166
+ 2 => Change::Immediate.new(FOUR_FOUR),
167
+ 4 => Change::Immediate.new(SIX_EIGHT)
168
+ })
169
+
170
+ { 1 => 2, 1.5 => 2.5, 2 => 3, 3 => 4, 3.75 => 5
171
+ }.each do |note_dur, meas_dur|
172
+ score.measures_long(note_dur).should eq(meas_dur)
173
+ end
174
+ end
175
+ end
135
176
  end
136
177
 
137
178
  describe '#valid?' do
@@ -142,7 +183,7 @@ describe Score::Measured do
142
183
  'valid meter changes' => [ FOUR_FOUR, 120,
143
184
  :meter_changes => { 1 => Change::Immediate.new(TWO_FOUR) } ],
144
185
  'valid part' => [ FOUR_FOUR, 120, :parts => { "piano" => Samples::SAMPLE_PART }],
145
- 'valid program' => [ FOUR_FOUR, 120, :program => Program.new([0..2,0..2]) ]
186
+ 'valid program' => [ FOUR_FOUR, 120, :program => [0..2,0..2] ]
146
187
  }.each do |context_str,args|
147
188
  context context_str do
148
189
  it 'should return true' do
@@ -165,7 +206,7 @@ describe Score::Measured do
165
206
  'non-integer meter change offset' => [ FOUR_FOUR, 120,
166
207
  :meter_changes => { 1.1 => Change::Immediate.new(TWO_FOUR) } ],
167
208
  'invalid part' => [ FOUR_FOUR, 120, :parts => { "piano" => Part.new(-0.1) }],
168
- 'invalid program' => [ FOUR_FOUR, 120, :program => Program.new([2..0]) ],
209
+ 'invalid program' => [ FOUR_FOUR, 120, :program => [2..0] ],
169
210
  }.each do |context_str,args|
170
211
  context context_str do
171
212
  it 'should return false' do
@@ -181,7 +222,7 @@ describe Score::Unmeasured do
181
222
  it 'should use empty containers for parameters not given' do
182
223
  s = Score::Unmeasured.new(30)
183
224
  s.parts.should be_empty
184
- s.program.segments.should be_empty
225
+ s.program.should be_empty
185
226
  end
186
227
 
187
228
  it 'should assign given parameters' do
@@ -189,7 +230,7 @@ describe Score::Unmeasured do
189
230
  s.start_tempo.should eq(30)
190
231
 
191
232
  parts = { "piano (LH)" => Samples::SAMPLE_PART }
192
- program = Program.new [0...0.75, 0...0.75]
233
+ program = [0...0.75, 0...0.75]
193
234
  tcs = { 1 => Change::Immediate.new(40) }
194
235
 
195
236
  s = Score::Unmeasured.new(30,
@@ -218,7 +259,7 @@ describe Score::Unmeasured do
218
259
  'valid tempo changes' => [ 30,
219
260
  :tempo_changes => { 1 => Change::Gradual.linear(40, 2), 2 => Change::Immediate.new(50) } ],
220
261
  'valid part' => [ 30, :parts => { "piano" => Samples::SAMPLE_PART }],
221
- 'valid program' => [ 30, :program => Program.new([0..2,0..2]) ]
262
+ 'valid program' => [ 30, :program => [0..2,0..2] ]
222
263
  }.each do |context_str,args|
223
264
  context context_str do
224
265
  it 'should return true' do
@@ -233,7 +274,7 @@ describe Score::Unmeasured do
233
274
  'tempo change value is not a valid value' => [ 30,
234
275
  :tempo_changes => { 1 => Change::Gradual.linear(-1,1) } ],
235
276
  'invalid part' => [ 30, :parts => { "piano" => Part.new(-0.1) }],
236
- 'invalid program' => [ 30, :program => Program.new([2..0]) ],
277
+ 'invalid program' => [ 30, :program => [2..0] ],
237
278
  }.each do |context_str,args|
238
279
  context context_str do
239
280
  it 'should return false' do
@@ -249,12 +290,12 @@ describe Score::Timed do
249
290
  it 'should use empty containers for parameters not given' do
250
291
  s = Score::Timed.new
251
292
  s.parts.should be_empty
252
- s.program.segments.should be_empty
293
+ s.program.should be_empty
253
294
  end
254
295
 
255
296
  it 'should assign given parameters' do
256
297
  parts = { "piano (LH)" => Samples::SAMPLE_PART }
257
- program = Program.new [0...0.75, 0...0.75]
298
+ program = [0...0.75, 0...0.75]
258
299
 
259
300
  s = Score::Timed.new(parts: parts, program: program)
260
301
  s.parts.should eq parts
@@ -274,7 +315,7 @@ describe Score::Timed do
274
315
  describe '#valid?' do
275
316
  {
276
317
  'valid part' => [ :parts => { "piano" => Samples::SAMPLE_PART }],
277
- 'valid program' => [ :program => Program.new([0..2,0..2]) ]
318
+ 'valid program' => [ :program => [0..2,0..2] ]
278
319
  }.each do |context_str,args|
279
320
  context context_str do
280
321
  it 'should return true' do
@@ -285,7 +326,7 @@ describe Score::Timed do
285
326
 
286
327
  {
287
328
  'invalid part' => [ :parts => { "piano" => Part.new(-0.1) }],
288
- 'invalid program' => [ :program => Program.new([2..0]) ],
329
+ 'invalid program' => [ :program => [2..0] ],
289
330
  }.each do |context_str,args|
290
331
  context context_str do
291
332
  it 'should return false' do
@@ -2,17 +2,26 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
2
 
3
3
  measured_score = Score::Measured.new(FOUR_FOUR,120) do |s|
4
4
  s.meter_changes[1] = Change::Immediate.new(THREE_FOUR)
5
- s.program = Program.new([0...2, 0...2,2...4,0...2])
5
+ s.meter_changes[7] = Change::Immediate.new(SIX_EIGHT)
6
+
7
+ s.tempo_changes[2] = Change::Immediate.new(100)
8
+ s.tempo_changes[4] = Change::Gradual.linear(70,2)
9
+ s.tempo_changes[9] = Change::Gradual.sigmoid(99,5).trim(2,2)
10
+
11
+ s.program += [0...2, 0...2,2...4,0...2]
6
12
  s.parts["lead"] = Part.new(Dynamics::MF) do |p|
7
13
  riff = "/6Bb3 /4 /12Db4= /6Db4= /36Db4 /36Eb4 /36Db4 /6Ab3 /12Db4 \
8
- /6Bb3 /4 /12Db4= /4Db4= /8=Db4 /8C4".to_notes
14
+ /6Bb3 /4 /12Db4= /4Db4= /8Db4= /8C4".to_notes
9
15
  p.notes = riff + riff.map {|n| n.transpose(2) }
16
+ p.dynamic_changes[1] = Change::Gradual.linear(Dynamics::F,2)
10
17
  end
11
18
 
12
19
  s.parts["bass"] = Part.new(Dynamics::MP) do |p|
13
20
  riff = "/6Bb2 /4 /3Ab2 /6F2 /12Ab2 \
14
21
  /6Bb2 /4 /3Ab2 /4Ab2".to_notes
15
22
  p.notes = riff + riff.map {|n| n.transpose(2) }
23
+ p.dynamic_changes[1] = Change::Immediate.new(Dynamics::F)
24
+ p.dynamic_changes[3] = Change::Gradual.sigmoid(Dynamics::PP,4).trim(1,1)
16
25
  end
17
26
  end
18
27
 
@@ -26,203 +35,162 @@ timed_score = Score::Timed.new do |s|
26
35
  s.parts = measured_score.parts
27
36
  end
28
37
 
29
- describe Score::Measured do
30
- before :all do
31
- @score = measured_score
32
- @h = @score.pack
33
- end
34
-
35
- describe '#pack' do
36
- it 'should return a hash' do
37
- @h.should be_a Hash
38
+ [ measured_score, unmeasured_score, timed_score ].each do |score|
39
+ describe score.class do
40
+ before :all do
41
+ @score = score
42
+ @h = @score.pack
38
43
  end
39
44
 
40
- it 'should return a hash with keys: "type","parts", "start_meter", ...' do
41
- ["type","parts","start_tempo","tempo_changes","program","start_meter","meter_changes"].each do |key|
42
- @h.should have_key(key)
45
+ describe '#pack' do
46
+ it 'should return a hash' do
47
+ @h.should be_a Hash
43
48
  end
44
- end
45
-
46
- it 'should set "type" key to "Measured"' do
47
- @h["type"].should eq("Measured")
48
- end
49
-
50
- it 'should pack start meter as a string' do
51
- @h['start_meter'].should be_a String
52
- end
53
-
54
- it 'should pack meter changes as whatver type Change#pack returns' do
55
- @h['meter_changes'].each do |offset,packed_v|
56
- change_v = @score.meter_changes[offset]
57
- t = change_v.pack.class
58
- packed_v.should be_a t
49
+
50
+ it 'should return a hash with keys: "type","parts", and "program"' do
51
+ ["type","parts","program"].each do |key|
52
+ @h.should have_key(key)
53
+ end
59
54
  end
60
- end
61
-
62
- it 'should pack meter change end values as strings' do
63
- @h['meter_changes'].each do |offset,packed_v|
64
- packed_v["end_value"].should be_a String
55
+
56
+ it 'should pack program as an array with same size' do
57
+ @h['program'].should be_a Array
58
+ @h['program'].size.should eq(@score.program.size)
65
59
  end
66
- end
67
-
68
- it 'should pack start tempo as numeric' do
69
- @h['start_tempo'].should be_a Numeric
70
- end
71
-
72
- it 'should pack tempo changes as whatver type Change#pack returns' do
73
- @h['tempo_changes'].each do |offset,packed_v|
74
- change_v = @score.tempo_changes[offset]
75
- t = change_v.pack.class
76
- packed_v.should be_a t
60
+
61
+ it 'should pack program segments as strings' do
62
+ @h['program'].each {|x| x.should be_a String }
77
63
  end
78
- end
79
-
80
- it 'should pack tempo change values as numerics' do
81
- @h['tempo_changes'].each do |offset,packed_v|
82
- packed_v[0].should be_a Numeric
64
+
65
+ it 'should pack parts as hash' do
66
+ @h['parts'].should be_a Hash
67
+ end
68
+
69
+ it 'should pack parts as whatever Part#pack returns' do
70
+ @score.parts.each do |name,part|
71
+ packing = part.pack
72
+ @h['parts'][name].should eq packing
73
+ end
83
74
  end
84
75
  end
85
76
 
86
- it 'should pack program as whatever type Program#pack returns' do
87
- t = @score.program.pack.class
88
- @h['program'].should be_a t
89
- end
90
-
91
- it 'should pack program segments as strings' do
92
- @h['program'].each {|x| x.should be_a String }
93
- end
94
-
95
- it 'should pack parts as hash' do
96
- @h['parts'].should be_a Hash
97
- end
98
-
99
- it 'should pack parts as whatever Part#pack returns' do
100
- @score.parts.each do |name,part|
101
- packing = part.pack
102
- @h['parts'][name].should eq packing
77
+ describe '.unpack' do
78
+ before :all do
79
+ @score2 = score.class.unpack @h
80
+ end
81
+
82
+ it "should return a #{score.class}" do
83
+ @score2.should be_a score.class
84
+ end
85
+
86
+ it 'should successfuly unpack the parts' do
87
+ @score2.parts.should eq @score.parts
88
+ end
89
+
90
+ it 'should successfuly unpack the program' do
91
+ @score2.program.should eq @score.program
103
92
  end
104
93
  end
105
94
  end
106
-
107
- describe '.unpack' do
95
+ end
96
+
97
+ [ measured_score, unmeasured_score ].each do |score|
98
+ describe score.class do
108
99
  before :all do
109
- @score2 = Score::Measured.unpack @h
110
- end
111
-
112
- it 'should return a Score::Measured' do
113
- @score2.should be_a Score::Measured
114
- end
115
-
116
- it 'should successfuly unpack the parts' do
117
- @score2.parts.should eq @score.parts
100
+ @score = score
101
+ @h = @score.pack
118
102
  end
119
103
 
120
- it 'should successfuly unpack the start meter' do
121
- @score2.start_meter.should eq @score.start_meter
122
- end
123
-
124
- it 'should successfuly unpack the start tempo' do
125
- @score2.start_tempo.should eq @score.start_tempo
126
- end
104
+ describe '#pack' do
105
+ it 'should return a hash with keys: "start_tempo" and "tempo_changes"' do
106
+ ["start_tempo","tempo_changes"].each {|key| @h.should have_key(key) }
107
+ end
127
108
 
128
- it 'should successfuly unpack the meter changes' do
129
- @score2.meter_changes.should eq @score.meter_changes
130
- end
109
+ it 'should pack start tempo as numeric' do
110
+ @h['start_tempo'].should be_a Numeric
111
+ end
131
112
 
132
- it 'should successfuly unpack the tempo changes' do
133
- @score2.tempo_changes.should eq @score.tempo_changes
113
+ it 'should pack tempo changes as a hash' do
114
+ @h['tempo_changes'].should be_a Hash
115
+ end
116
+
117
+ it 'should pack tempo changes values using Change#pack' do
118
+ @h['tempo_changes'].each do |offset,packed_v|
119
+ change = @score.tempo_changes[offset]
120
+ packed_v.should eq(change.pack)
121
+ end
122
+ end
134
123
  end
135
-
136
- it 'should successfuly unpack the program' do
137
- @score2.program.should eq @score.program
124
+
125
+ describe '.unpack' do
126
+ before :all do
127
+ @score2 = score.class.unpack @h
128
+ end
129
+
130
+ it 'should successfuly unpack the start tempo' do
131
+ @score2.start_tempo.should eq @score.start_tempo
132
+ end
133
+
134
+ it 'should successfuly unpack the tempo changes' do
135
+ @score2.tempo_changes.should eq @score.tempo_changes
136
+ end
138
137
  end
139
138
  end
140
139
  end
141
140
 
142
- describe Score::Unmeasured do
141
+ describe Score::Measured do
143
142
  before :all do
144
- @score = unmeasured_score
143
+ @score = measured_score
145
144
  @h = @score.pack
146
145
  end
147
146
 
148
- describe '#pack' do
149
- it 'should return a hash' do
150
- @h.should be_a Hash
151
- end
152
-
153
- it 'should return a hash with keys: "type","parts", "program", ...' do
154
- ["type","parts","start_tempo","tempo_changes","program"].each do |key|
155
- @h.should have_key(key)
156
- end
157
- end
158
-
159
- it 'should set "type" key to "Unmeasured"' do
160
- @h["type"].should eq("Unmeasured")
161
- end
162
-
163
- it 'should pack start tempo as numeric' do
164
- @h['start_tempo'].should be_a Numeric
147
+ describe '#pack' do
148
+ it 'should return a hash with keys: "start_meter" and "meter_changes"' do
149
+ ["start_meter","meter_changes"].each { |key| @h.should have_key(key) }
165
150
  end
166
151
 
167
- it 'should pack tempo changes as whatver type Change#pack returns' do
168
- @h['tempo_changes'].each do |offset,packed_v|
169
- change_v = @score.tempo_changes[offset]
170
- t = change_v.pack.class
171
- packed_v.should be_a t
172
- end
152
+ it 'should set "type" key to "Measured"' do
153
+ @h["type"].should eq("Measured")
173
154
  end
174
155
 
175
- it 'should pack tempo change values as numerics' do
176
- @h['tempo_changes'].each do |offset,packed_v|
177
- packed_v[0].should be_a Numeric
178
- end
156
+ it 'should pack start meter as a string' do
157
+ @h['start_meter'].should be_a String
179
158
  end
180
159
 
181
- it 'should pack program as whatever type Program#pack returns' do
182
- t = @score.program.pack.class
183
- @h['program'].should be_a t
184
- end
185
-
186
- it 'should pack program segments as strings' do
187
- @h['program'].each {|x| x.should be_a String }
160
+ it 'should pack meter changes values using Change#pack(:with => :to_s)' do
161
+ @h['meter_changes'].each do |offset,packed_v|
162
+ change = @score.meter_changes[offset]
163
+ packed_v.should eq(change.pack(:with => :to_s))
164
+ end
188
165
  end
189
166
 
190
- it 'should pack parts as hash' do
191
- @h['parts'].should be_a Hash
192
- end
193
-
194
- it 'should pack parts as whatever Part#pack returns' do
195
- @score.parts.each do |name,part|
196
- packing = part.pack
197
- @h['parts'][name].should eq packing
167
+ it 'should pack meter change end values as strings' do
168
+ @h['meter_changes'].each do |offset,packed_v|
169
+ packed_v["end_value"].should be_a String
198
170
  end
199
- end
171
+ end
200
172
  end
201
173
 
202
174
  describe '.unpack' do
203
175
  before :all do
204
- @score2 = Score::Unmeasured.unpack @h
205
- end
206
-
207
- it 'should return a Score::Unmeasured' do
208
- @score2.should be_a Score::Unmeasured
209
- end
210
-
211
- it 'should successfuly unpack the parts' do
212
- @score2.parts.should eq @score.parts
176
+ @score2 = Score::Measured.unpack @h
213
177
  end
214
178
 
215
- it 'should successfuly unpack the start tempo' do
216
- @score2.start_tempo.should eq @score.start_tempo
179
+ it 'should successfuly unpack the start meter' do
180
+ @score2.start_meter.should eq @score.start_meter
217
181
  end
218
182
 
219
- it 'should successfuly unpack the tempo changes' do
220
- @score2.tempo_changes.should eq @score.tempo_changes
183
+ it 'should successfuly unpack the meter changes' do
184
+ @score2.meter_changes.should eq @score.meter_changes
221
185
  end
186
+ end
187
+ end
222
188
 
223
- it 'should successfuly unpack the program' do
224
- @score2.program.should eq @score.program
225
- end
189
+ describe Score::Unmeasured do
190
+ describe '#pack' do
191
+ it 'should set "type" key to "Unmeasured"' do
192
+ unmeasured_score.pack["type"].should eq("Unmeasured")
193
+ end
226
194
  end
227
195
  end
228
196
 
@@ -233,57 +201,9 @@ describe Score::Timed do
233
201
  end
234
202
 
235
203
  describe '#pack' do
236
- it 'should return a hash' do
237
- @h.should be_a Hash
238
- end
239
-
240
- it 'should return a hash with keys: "type","parts", and "program"' do
241
- ["type","parts","program"].each do |key|
242
- @h.should have_key(key)
243
- end
244
- end
245
-
246
204
  it 'should set "type" key to "Timed"' do
247
205
  @h["type"].should eq("Timed")
248
- end
249
-
250
- it 'should pack program as whatever type Program#pack returns' do
251
- t = @score.program.pack.class
252
- @h['program'].should be_a t
253
- end
254
-
255
- it 'should pack program segments as strings' do
256
- @h['program'].each {|x| x.should be_a String }
257
- end
258
-
259
- it 'should pack parts as hash' do
260
- @h['parts'].should be_a Hash
261
- end
262
-
263
- it 'should pack parts as whatever Part#pack returns' do
264
- @score.parts.each do |name,part|
265
- packing = part.pack
266
- @h['parts'][name].should eq packing
267
- end
268
- end
269
- end
270
-
271
- describe '.unpack' do
272
- before :all do
273
- @score2 = Score::Timed.unpack @h
274
- end
275
-
276
- it 'should return a Score::Timed' do
277
- @score2.should be_a Score::Timed
278
- end
279
-
280
- it 'should successfuly unpack the parts' do
281
- @score2.parts.should eq @score.parts
282
- end
283
-
284
- it 'should successfuly unpack the program' do
285
- @score2.program.should eq @score.program
286
- end
206
+ end
287
207
  end
288
208
  end
289
209
 
@@ -291,10 +211,18 @@ describe Score do
291
211
  describe '.unpack' do
292
212
  [ timed_score, unmeasured_score, measured_score ].each do |score|
293
213
  context "given packing from a #{score.class} object" do
214
+ before :all do
215
+ @packing = score.pack
216
+ @score2 = Score.unpack(@packing)
217
+ end
218
+
294
219
  it "should return a #{score.class} object equal to original" do
295
- score2 = Score.unpack(score.pack)
296
- score2.should be_a score.class
297
- score2.should eq(score)
220
+ @score2.should be_a score.class
221
+ @score2.should eq(score)
222
+ end
223
+
224
+ it "should return a score equal to what #{score.class}.unpack returns" do
225
+ @score2.should eq(score.class.unpack(@packing))
298
226
  end
299
227
  end
300
228
  end