musicality 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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