musicality 0.8.0 → 0.9.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +27 -1
  3. data/README.md +153 -10
  4. data/bin/collidify +102 -0
  5. data/bin/lilify +57 -29
  6. data/bin/midify +64 -24
  7. data/bin/musicality +39 -0
  8. data/examples/composition/auto_counterpoint.rb +4 -5
  9. data/examples/composition/part_generator.rb +8 -2
  10. data/examples/composition/scale_exercise.rb +1 -1
  11. data/examples/notation/notes.rb +27 -0
  12. data/examples/notation/parts.rb +51 -0
  13. data/examples/notation/scores.rb +38 -0
  14. data/examples/notation/twinkle.rb +34 -0
  15. data/examples/notation/twinkle.score +33 -0
  16. data/lib/musicality.rb +46 -11
  17. data/lib/musicality/composition/dsl/score_dsl.rb +2 -2
  18. data/lib/musicality/composition/dsl/score_methods.rb +10 -7
  19. data/lib/musicality/notation/conversion/change_conversion.rb +1 -1
  20. data/lib/musicality/notation/conversion/note_time_converter.rb +6 -23
  21. data/lib/musicality/notation/conversion/score_conversion.rb +15 -15
  22. data/lib/musicality/notation/conversion/score_converter.rb +50 -67
  23. data/lib/musicality/notation/model/articulations.rb +3 -2
  24. data/lib/musicality/notation/model/change.rb +15 -6
  25. data/lib/musicality/notation/model/dynamics.rb +11 -8
  26. data/lib/musicality/notation/model/instrument.rb +61 -0
  27. data/lib/musicality/notation/model/instruments.rb +111 -0
  28. data/lib/musicality/notation/model/key.rb +137 -0
  29. data/lib/musicality/notation/model/keys.rb +37 -0
  30. data/lib/musicality/notation/model/link.rb +6 -19
  31. data/lib/musicality/notation/model/mark.rb +43 -0
  32. data/lib/musicality/notation/model/marks.rb +11 -0
  33. data/lib/musicality/notation/model/meter.rb +4 -0
  34. data/lib/musicality/notation/model/note.rb +42 -28
  35. data/lib/musicality/notation/model/part.rb +18 -5
  36. data/lib/musicality/notation/model/pitch.rb +13 -4
  37. data/lib/musicality/notation/model/score.rb +104 -66
  38. data/lib/musicality/notation/model/symbols.rb +16 -11
  39. data/lib/musicality/notation/parsing/articulation_parsing.rb +38 -38
  40. data/lib/musicality/notation/parsing/articulation_parsing.treetop +14 -14
  41. data/lib/musicality/notation/parsing/link_parsing.rb +6 -6
  42. data/lib/musicality/notation/parsing/link_parsing.treetop +3 -3
  43. data/lib/musicality/notation/parsing/mark_parsing.rb +138 -0
  44. data/lib/musicality/notation/parsing/mark_parsing.treetop +31 -0
  45. data/lib/musicality/notation/parsing/note_node.rb +19 -12
  46. data/lib/musicality/notation/parsing/note_parsing.rb +218 -87
  47. data/lib/musicality/notation/parsing/note_parsing.treetop +9 -5
  48. data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +7 -2
  49. data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.treetop +1 -1
  50. data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.rb +6 -4
  51. data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.treetop +1 -1
  52. data/lib/musicality/notation/util/function.rb +41 -18
  53. data/lib/musicality/packable.rb +156 -0
  54. data/lib/musicality/performance/conversion/glissando_converter.rb +2 -2
  55. data/lib/musicality/performance/conversion/note_sequence_extractor.rb +223 -70
  56. data/lib/musicality/performance/conversion/portamento_converter.rb +5 -2
  57. data/lib/musicality/performance/conversion/score_collator.rb +70 -64
  58. data/lib/musicality/performance/midi/midi_events.rb +3 -3
  59. data/lib/musicality/performance/midi/midi_settings.rb +127 -0
  60. data/lib/musicality/performance/midi/midi_util.rb +8 -2
  61. data/lib/musicality/performance/midi/part_sequencer.rb +19 -18
  62. data/lib/musicality/performance/midi/score_sequencer.rb +13 -9
  63. data/lib/musicality/performance/midi/score_sequencing.rb +5 -5
  64. data/lib/musicality/performance/model/attack.rb +8 -0
  65. data/lib/musicality/performance/model/duration_functions.rb +23 -0
  66. data/lib/musicality/performance/model/note_sequence.rb +52 -95
  67. data/lib/musicality/performance/model/separation.rb +10 -0
  68. data/lib/musicality/performance/supercollider/add_actions.rb +13 -0
  69. data/lib/musicality/performance/supercollider/bundle.rb +18 -0
  70. data/lib/musicality/performance/supercollider/conductor.rb +125 -0
  71. data/lib/musicality/performance/supercollider/group.rb +71 -0
  72. data/lib/musicality/performance/supercollider/message.rb +26 -0
  73. data/lib/musicality/performance/supercollider/node.rb +122 -0
  74. data/lib/musicality/performance/supercollider/performer.rb +123 -0
  75. data/lib/musicality/performance/supercollider/score_conducting.rb +17 -0
  76. data/lib/musicality/performance/supercollider/server.rb +8 -0
  77. data/lib/musicality/performance/supercollider/synth.rb +43 -0
  78. data/lib/musicality/performance/supercollider/synthdef.rb +57 -0
  79. data/lib/musicality/performance/supercollider/synthdef_settings.rb +23 -0
  80. data/lib/musicality/performance/supercollider/synthdefs.rb +1654 -0
  81. data/lib/musicality/{composition/model/pitch_class.rb → pitch_class.rb} +1 -1
  82. data/lib/musicality/{composition/model/pitch_classes.rb → pitch_classes.rb} +9 -9
  83. data/lib/musicality/printing/lilypond/clef.rb +12 -0
  84. data/lib/musicality/printing/lilypond/key_engraving.rb +9 -0
  85. data/lib/musicality/printing/lilypond/lilypond_settings.rb +105 -0
  86. data/lib/musicality/printing/lilypond/meter_engraving.rb +1 -1
  87. data/lib/musicality/printing/lilypond/note_engraving.rb +112 -30
  88. data/lib/musicality/printing/lilypond/part_engraver.rb +114 -3
  89. data/lib/musicality/printing/lilypond/pitch_class_engraving.rb +22 -0
  90. data/lib/musicality/printing/lilypond/pitch_engraving.rb +2 -15
  91. data/lib/musicality/printing/lilypond/score_engraver.rb +44 -73
  92. data/lib/musicality/printing/lilypond/score_engraving.rb +3 -3
  93. data/lib/musicality/project/create_tasks.rb +31 -0
  94. data/lib/musicality/project/file_cleaner.rb +19 -0
  95. data/lib/musicality/project/file_raker.rb +107 -0
  96. data/lib/musicality/project/load_config.rb +43 -0
  97. data/lib/musicality/project/project.rb +64 -0
  98. data/lib/musicality/version.rb +1 -1
  99. data/musicality.gemspec +3 -0
  100. data/spec/composition/util/random_sampler_spec.rb +1 -1
  101. data/spec/notation/conversion/measure_note_map_spec.rb +1 -1
  102. data/spec/notation/conversion/note_time_converter_spec.rb +5 -85
  103. data/spec/notation/conversion/score_conversion_spec.rb +6 -41
  104. data/spec/notation/conversion/score_converter_spec.rb +19 -137
  105. data/spec/notation/model/change_spec.rb +55 -0
  106. data/spec/notation/model/key_spec.rb +171 -0
  107. data/spec/notation/model/link_spec.rb +34 -5
  108. data/spec/notation/model/meter_spec.rb +15 -0
  109. data/spec/notation/model/note_spec.rb +33 -27
  110. data/spec/notation/model/part_spec.rb +53 -4
  111. data/spec/notation/model/pitch_spec.rb +15 -0
  112. data/spec/notation/model/score_spec.rb +64 -72
  113. data/spec/notation/parsing/link_nodes_spec.rb +3 -3
  114. data/spec/notation/parsing/link_parsing_spec.rb +6 -6
  115. data/spec/notation/parsing/note_node_spec.rb +34 -9
  116. data/spec/notation/parsing/note_parsing_spec.rb +11 -9
  117. data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +4 -0
  118. data/spec/notation/parsing/pitch_node_spec.rb +0 -1
  119. data/spec/notation/util/value_computer_spec.rb +2 -2
  120. data/spec/performance/conversion/glissando_converter_spec.rb +9 -9
  121. data/spec/performance/conversion/note_sequence_extractor_spec.rb +48 -53
  122. data/spec/performance/conversion/portamento_converter_spec.rb +11 -9
  123. data/spec/performance/conversion/score_collator_spec.rb +59 -63
  124. data/spec/performance/midi/midi_util_spec.rb +22 -8
  125. data/spec/performance/midi/part_sequencer_spec.rb +2 -2
  126. data/spec/performance/midi/score_sequencer_spec.rb +12 -10
  127. data/spec/performance/midi/score_sequencing_spec.rb +2 -2
  128. data/spec/performance/model/note_sequence_spec.rb +41 -134
  129. data/spec/printing/note_engraving_spec.rb +204 -0
  130. data/spec/printing/score_engraver_spec.rb +40 -0
  131. data/spec/spec_helper.rb +1 -0
  132. metadata +69 -23
  133. data/examples/notation/hip.rb +0 -32
  134. data/examples/notation/missed_connection.rb +0 -26
  135. data/examples/notation/song1.rb +0 -33
  136. data/examples/notation/song2.rb +0 -32
  137. data/lib/musicality/notation/model/links.rb +0 -11
  138. data/lib/musicality/notation/packing/change_packing.rb +0 -56
  139. data/lib/musicality/notation/packing/part_packing.rb +0 -31
  140. data/lib/musicality/notation/packing/score_packing.rb +0 -123
  141. data/lib/musicality/performance/model/note_attacks.rb +0 -19
  142. data/lib/musicality/performance/util/note_linker.rb +0 -28
  143. data/spec/notation/packing/change_packing_spec.rb +0 -304
  144. data/spec/notation/packing/part_packing_spec.rb +0 -66
  145. data/spec/notation/packing/score_packing_spec.rb +0 -255
  146. data/spec/performance/util/note_linker_spec.rb +0 -68
@@ -23,6 +23,22 @@ describe Change::Immediate do
23
23
  YAML.load(c.to_yaml).should eq c
24
24
  end
25
25
  end
26
+
27
+ describe '#pack' do
28
+ it 'should produce a Hash' do
29
+ h = Change::Immediate.new(2).pack
30
+ h.should be_a Hash
31
+ end
32
+ end
33
+
34
+ describe '.unpack' do
35
+ it 'should return a Change::Immediate equal to the original' do
36
+ c1 = Change::Immediate.new(2)
37
+ c2 = Change::Immediate.unpack(c1.pack)
38
+ c2.should be_a Change::Immediate
39
+ c2.should eq c1
40
+ end
41
+ end
26
42
  end
27
43
 
28
44
  describe Change::Gradual do
@@ -122,6 +138,22 @@ describe Change::Gradual do
122
138
  YAML.load(c.to_yaml).should eq c
123
139
  end
124
140
  end
141
+
142
+ describe '#pack' do
143
+ it 'should produce a Hash' do
144
+ h = Change::Gradual.linear(4,2).pack
145
+ h.should be_a Hash
146
+ end
147
+ end
148
+
149
+ describe '.unpack' do
150
+ it 'should return a Change::Gradual equal to the original' do
151
+ c1 = Change::Gradual.linear(4,2)
152
+ c2 = Change::Gradual.unpack(c1.pack)
153
+ c2.should be_a Change::Gradual
154
+ c2.should eq c1
155
+ end
156
+ end
125
157
  end
126
158
 
127
159
  describe Change::Gradual::Trimmed do
@@ -190,4 +222,27 @@ describe Change::Gradual::Trimmed do
190
222
  Change::Gradual.linear(41,19).trim(4,9).trailing.should eq(9)
191
223
  end
192
224
  end
225
+
226
+ describe '#to_yaml' do
227
+ it 'should produce YAML that can be loaded' do
228
+ c = Change::Gradual::Trimmed.linear(4,2, preceding: 1, remaining: 0.5)
229
+ YAML.load(c.to_yaml).should eq c
230
+ end
231
+ end
232
+
233
+ describe '#pack' do
234
+ it 'should produce a Hash' do
235
+ h = Change::Gradual::Trimmed.linear(4,2, preceding: 1, remaining: 0.5).pack
236
+ h.should be_a Hash
237
+ end
238
+ end
239
+
240
+ describe '.unpack' do
241
+ it 'should return a Change::Gradual::Trimmed equal to the original' do
242
+ c1 = Change::Gradual::Trimmed.linear(4,2, preceding: 1, remaining: 0.5)
243
+ c2 = Change::Gradual::Trimmed.unpack(c1.pack)
244
+ c2.should be_a Change::Gradual::Trimmed
245
+ c2.should eq c1
246
+ end
247
+ end
193
248
  end
@@ -0,0 +1,171 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe Key do
4
+ describe '.major_flat' do
5
+ it 'should set triad to MAJOR and accidental_pref to FLAT' do
6
+ k = Key.major_flat(0)
7
+ k.triad.should eq(Key::MAJOR)
8
+ k.accidental_pref.should eq(Key::FLAT)
9
+ end
10
+ end
11
+
12
+ describe '.minor_flat' do
13
+ it 'should set triad to MAJOR and accidental_pref to SHARP' do
14
+ k = Key.major_sharp(0)
15
+ k.triad.should eq(Key::MAJOR)
16
+ k.accidental_pref.should eq(Key::SHARP)
17
+ end
18
+ end
19
+
20
+ describe '.major_sharp' do
21
+ it 'should set triad to MINOR and accidental_pref to FLAT' do
22
+ k = Key.minor_flat(0)
23
+ k.triad.should eq(Key::MINOR)
24
+ k.accidental_pref.should eq(Key::FLAT)
25
+ end
26
+ end
27
+
28
+ describe '.minor_sharp' do
29
+ it 'should set triad to MINOR and accidental_pref to SHARP' do
30
+ k = Key.minor_sharp(0)
31
+ k.triad.should eq(Key::MINOR)
32
+ k.accidental_pref.should eq(Key::SHARP)
33
+ end
34
+ end
35
+
36
+ describe '.new' do
37
+ context 'given tonic_pc that is not in 0..11' do
38
+ it 'should apply mod 12 to bring it in range' do
39
+ { 12 => 0, 13 => 1, -1 => 11, 24 => 0, 18 => 6
40
+ }.each do |t1,t2|
41
+ Key.major_flat(t1).tonic_pc.should eq(t2)
42
+ end
43
+ end
44
+ end
45
+
46
+ context 'given tonic_pc in 0..11' do
47
+ it 'should not change' do
48
+ (0..11).each do |pc|
49
+ Key.major_flat(pc).tonic_pc.should eq(pc)
50
+ end
51
+ end
52
+ end
53
+
54
+ context 'given triad that is not MAJOR or MINOR' do
55
+ it 'should raise ArgumentError' do
56
+ expect { Key.new(0, triad: :flipping) }.to raise_error(ArgumentError)
57
+ end
58
+ end
59
+
60
+ context 'given accidental_pref that is not FLAT or SHARP' do
61
+ it 'should raise ArgumentError' do
62
+ expect { Key.new(0, accidental_pref: :squiggle) }.to raise_error(ArgumentError)
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#flat?' do
68
+ context 'given accidental_pref is FLAT' do
69
+ it 'should return true' do
70
+ Key.major_flat(0).flat?.should be true
71
+ end
72
+ end
73
+ context 'given accidental_pref is SHARP' do
74
+ it 'should return false' do
75
+ Key.major_sharp(0).flat?.should be false
76
+ end
77
+ end
78
+ end
79
+
80
+ describe '#sharp?' do
81
+ context 'given accidental_pref is FLAT' do
82
+ it 'should return false' do
83
+ Key.major_flat(0).sharp?.should be false
84
+ end
85
+ end
86
+ context 'given accidental_pref is SHARP' do
87
+ it 'should return true' do
88
+ Key.major_sharp(0).sharp?.should be true
89
+ end
90
+ end
91
+ end
92
+
93
+ describe '#major?' do
94
+ context 'given triad is MAJOR' do
95
+ it 'should return true' do
96
+ Key.major_flat(0).major?.should be true
97
+ end
98
+ end
99
+ context 'given triad is MINOR' do
100
+ it 'should return false' do
101
+ Key.minor_flat(0).major?.should be false
102
+ end
103
+ end
104
+ end
105
+
106
+ describe '#minor?' do
107
+ context 'given triad is MAJOR' do
108
+ it 'should return false' do
109
+ Key.major_flat(0).minor?.should be false
110
+ end
111
+ end
112
+ context 'given triad is MINOR' do
113
+ it 'should return true' do
114
+ Key.minor_flat(0).minor?.should be true
115
+ end
116
+ end
117
+ end
118
+
119
+ describe '#==' do
120
+ context 'objects with different tonic_pc' do
121
+ it 'should return false' do
122
+ Key.major_flat(0).should_not eq(Key.major_flat(1))
123
+ end
124
+ end
125
+
126
+ context 'objects with different triad' do
127
+ it 'should return false' do
128
+ Key.major_flat(0).should_not eq(Key.minor_flat(0))
129
+ end
130
+ end
131
+
132
+ context 'objects with different accidental_type' do
133
+ it 'should return false' do
134
+ Key.major_flat(0).should_not eq(Key.major_sharp(0))
135
+ end
136
+ end
137
+
138
+ context 'objects with same tonic_pc, triad, and accidental_type' do
139
+ it 'should return true' do
140
+ Key.major_flat(0).should eq(Key.major_flat(0))
141
+ end
142
+ end
143
+ end
144
+
145
+ describe '#clone' do
146
+ it 'should return a different, equal object' do
147
+ k1 = Key.major_flat(0)
148
+ k2 = k1.clone
149
+ k1.should_not be k2
150
+ k1.should eq k2
151
+ end
152
+ end
153
+
154
+ describe '#accidentals' do
155
+ end
156
+
157
+ describe '#pack' do
158
+ it 'should return a Hash' do
159
+ Key.major_sharp(1).pack.should be_a Hash
160
+ end
161
+ end
162
+
163
+ describe '.unpack' do
164
+ it 'should return a Key object equal to the original' do
165
+ k1 = Key.major_sharp(1)
166
+ k2 = Key.unpack k1.pack
167
+ k2.should be_a Key
168
+ k2.should eq(k1)
169
+ end
170
+ end
171
+ end
@@ -1,8 +1,9 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'yaml'
2
3
 
3
4
  [
4
- [Link::Glissando, Link::Portamento, LINK_SYMBOLS[Links::GLISSANDO]],
5
- [Link::Portamento, Link::Glissando, LINK_SYMBOLS[Links::PORTAMENTO]],
5
+ [Link::Glissando, Link::Portamento, LINK_SYMBOLS[Link::Glissando]],
6
+ [Link::Portamento, Link::Glissando, LINK_SYMBOLS[Link::Portamento]],
6
7
  ].each do |klass,klass2,link_symbol|
7
8
  describe klass do
8
9
  before :all do
@@ -41,6 +42,20 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
41
42
  YAML.load(@obj.to_yaml).should eq @obj
42
43
  end
43
44
  end
45
+
46
+ describe '#pack' do
47
+ it 'should produce a Hash' do
48
+ @obj.pack.should be_a Hash
49
+ end
50
+ end
51
+
52
+ describe 'unpack' do
53
+ it 'should produce a Link object equal the original' do
54
+ obj2 = @obj.class.unpack @obj.pack
55
+ obj2.should be_a @obj.class
56
+ obj2.should eq @obj
57
+ end
58
+ end
44
59
 
45
60
  describe '#to_s' do
46
61
  it 'should produce string that include link char and target pitch str' do
@@ -76,10 +91,24 @@ describe Link::Tie do
76
91
  YAML.load(@obj.to_yaml).should eq @obj
77
92
  end
78
93
  end
79
-
94
+
95
+ describe '#pack' do
96
+ it 'should produce a Hash' do
97
+ @obj.pack.should be_a Hash
98
+ end
99
+ end
100
+
101
+ describe 'unpack' do
102
+ it 'should produce a Link object equal the original' do
103
+ obj2 = @obj.class.unpack @obj.pack
104
+ obj2.should be_a @obj.class
105
+ obj2.should eq @obj
106
+ end
107
+ end
108
+
80
109
  describe '#to_s' do
81
- it "should return #{LINK_SYMBOLS[Links::TIE]}" do
82
- @obj.to_s.should eq(LINK_SYMBOLS[Links::TIE])
110
+ it "should return #{LINK_SYMBOLS[Link::Tie]}" do
111
+ @obj.to_s.should eq(LINK_SYMBOLS[Link::Tie])
83
112
  end
84
113
  end
85
114
  end
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'yaml'
2
3
 
3
4
  describe Meter do
4
5
  describe '#initialize' do
@@ -47,6 +48,20 @@ describe Meter do
47
48
  YAML.load(m.to_yaml).should eq m
48
49
  end
49
50
  end
51
+
52
+ describe '#pack' do
53
+ it 'should produce a Hash' do
54
+ FOUR_FOUR.pack.should be_a Hash
55
+ end
56
+ end
57
+
58
+ describe 'unpack' do
59
+ it 'should produce an object equal the original' do
60
+ m2 = Meter.unpack FOUR_FOUR.pack
61
+ m2.should be_a Meter
62
+ m2.should eq(FOUR_FOUR)
63
+ end
64
+ end
50
65
 
51
66
  describe '#to_s' do
52
67
  context 'beat duration with 1 in denominator' do
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'yaml'
2
3
 
3
4
  describe Note do
4
5
  before :all do
@@ -10,20 +11,24 @@ describe Note do
10
11
  Note.new(2).duration.should eq(2)
11
12
  end
12
13
 
13
- it "should assign :articulation to Note::DEFAULT_ARTICULATION if not given" do
14
- Note.new(2).articulation.should eq(Note::DEFAULT_ARTICULATION)
14
+ it "should assign :articulation to NORMAL if not given" do
15
+ Note.new(2).articulation.should eq(NORMAL)
15
16
  end
16
17
 
17
18
  it "should assign :articulation parameter if given during construction" do
18
19
  Note.new(2, articulation: STACCATO).articulation.should eq(STACCATO)
19
20
  end
20
21
 
21
- it 'should assign :accented to false if not given' do
22
- Note.new(2).accented.should be false
22
+ it 'should assign :marks to [] if not given' do
23
+ Note.new(2).marks.should eq([])
23
24
  end
24
25
 
25
- it 'should assign :accented if given' do
26
- Note.new(2, accented: true).accented.should be true
26
+ it 'should assign :marks if given' do
27
+ [
28
+ [], [BEGIN_SLUR, BEGIN_TRIPLET]
29
+ ].each do |marks|
30
+ Note.quarter(marks: marks).marks.should eq(marks)
31
+ end
27
32
  end
28
33
 
29
34
  it 'should have no pitches if not given' do
@@ -95,13 +100,10 @@ describe Note do
95
100
  end
96
101
  end
97
102
 
98
- describe '#stretch' do
99
- it 'should multiply note duration by ratio' do
100
- note = Note::quarter.stretch(2)
103
+ describe '#resize' do
104
+ it 'should return new note object with given duration' do
105
+ note = Note::quarter.resize("1/2".to_r)
101
106
  note.duration.should eq(Rational(1,2))
102
-
103
- note = Note::quarter.stretch(Rational(1,2))
104
- note.duration.should eq(Rational(1,8))
105
107
  end
106
108
  end
107
109
 
@@ -114,7 +116,7 @@ describe Note do
114
116
  it 'should produce string that when parsed produces an equal note' do
115
117
  durations = ["1/8".to_r,"1".to_r,"5/3".to_r]
116
118
  include Articulations
117
- articulations = [NORMAL, SLUR, LEGATO, TENUTO, PORTATO, STACCATO, STACCATISSIMO ]
119
+ articulations = [NORMAL, TENUTO, MARCATO, ACCENT, PORTATO, STACCATO, STACCATISSIMO ]
118
120
  pitches_links_sets = [
119
121
  [[],{}],
120
122
  [[C2],{}],
@@ -129,8 +131,8 @@ describe Note do
129
131
  pitches,links = pitches_links_set
130
132
  if pitches.any?
131
133
  articulations.each do |art|
132
- [true,false].each do |acc|
133
- notes.push Note.new(d, pitches, articulation: art, links: links, accented: acc)
134
+ [[],[BEGIN_SLUR],[END_SLUR, BEGIN_TRIPLET]].each do |marks|
135
+ notes.push Note.new(d, pitches, articulation: art, links: links, marks: marks)
134
136
  end
135
137
  end
136
138
  else
@@ -163,6 +165,22 @@ describe Note do
163
165
  YAML.load(n.to_yaml).should eq n
164
166
  end
165
167
  end
168
+
169
+ describe '#pack' do
170
+ it 'should produce a Hash' do
171
+ n = Note.quarter([E2,F2,A2], articulation: STACCATO, marks: [BEGIN_SLUR], links: {E2 => Link::Tie.new, F2 => Link::Glissando.new(C3)})
172
+ n.pack.should be_a Hash
173
+ end
174
+ end
175
+
176
+ describe 'unpack' do
177
+ it 'should produce an object equal the original' do
178
+ n = Note.quarter([E2,F2,A2], articulation: STACCATO, marks: [BEGIN_SLUR], links: {E2 => Link::Tie.new, F2 => Link::Glissando.new(C3)})
179
+ n2 = Note.unpack n.pack
180
+ n2.should be_a Note
181
+ n2.should eq n
182
+ end
183
+ end
166
184
 
167
185
  describe '#valid?' do
168
186
  context 'note with positive duration' do
@@ -170,17 +188,5 @@ describe Note do
170
188
  Note.new(1,[C2]).should be_valid
171
189
  end
172
190
  end
173
-
174
- context 'note with 0 duration' do
175
- it 'should return false' do
176
- Note.new(0,[C2]).should be_invalid
177
- end
178
- end
179
-
180
- context 'note with negative duration' do
181
- it 'should be invalid' do
182
- Note.new(-1,[C2]).should be_invalid
183
- end
184
- end
185
191
  end
186
192
  end
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'yaml'
2
3
 
3
4
  describe Part do
4
5
  describe '#initialize' do
@@ -17,16 +18,66 @@ describe Part do
17
18
  p = Part.new(Dynamics::FF, notes: notes, dynamic_changes: dcs)
18
19
  p.notes.should eq notes
19
20
  p.dynamic_changes.should eq dcs
21
+
22
+ p = Part.new(Dynamics::P, settings: [ "dummy" ])
23
+ p.settings.should eq [ "dummy" ]
24
+ end
25
+ end
26
+
27
+ describe '#find_settings' do
28
+ context 'settings is empty' do
29
+ it 'should return nil' do
30
+ Part.new(Dynamics::P).find_settings(Integer).should be_nil
31
+ end
32
+ end
33
+
34
+ context 'one or more objects in settings' do
35
+ before :all do
36
+ @part = Part.new(Dynamics::MF, settings: [ 5, "boy" ])
37
+ end
38
+
39
+ context 'given class of object in settings' do
40
+ it 'should return the object' do
41
+ @part.find_settings(Integer).should be_a Integer
42
+ @part.find_settings(String).should be_a String
43
+ end
44
+ end
45
+
46
+ context 'given class not of any object in settings' do
47
+ it 'should return nil' do
48
+ @part.find_settings(Float).should be_nil
49
+ end
50
+ end
20
51
  end
21
52
  end
22
-
53
+
23
54
  describe '#to_yaml' do
24
55
  it 'should produce YAML that can be loaded' do
25
56
  p = Samples::SAMPLE_PART
26
57
  YAML.load(p.to_yaml).should eq p
27
58
  end
28
59
  end
29
-
60
+
61
+ describe '#pack' do
62
+ it 'should produce a Hash' do
63
+ notes = [Note::whole([A2]), Note::half]
64
+ dcs = { "1/2".to_r => Change::Immediate.new(Dynamics::P), 1 => Change::Gradual.sigmoid(Dynamics::MF,1) }
65
+ p = Part.new(Dynamics::FF, notes: notes, dynamic_changes: dcs, settings: [ "dummy" ])
66
+ p.pack.should be_a Hash
67
+ end
68
+ end
69
+
70
+ describe 'unpack' do
71
+ it 'should produce an object equal the original' do
72
+ notes = [Note::whole([A2]), Note::half]
73
+ dcs = { "1/2".to_r => Change::Immediate.new(Dynamics::P), 1 => Change::Gradual.sigmoid(Dynamics::MF,1) }
74
+ p = Part.new(Dynamics::FF, notes: notes, dynamic_changes: dcs, settings: [ "dummy" ])
75
+ p2 = Part.unpack p.pack
76
+ p2.should be_a Part
77
+ p2.should eq p
78
+ end
79
+ end
80
+
30
81
  describe '#valid?' do
31
82
  { 'negative start dynamic' => [-0.01],
32
83
  'start dynamic > 1' => [1.01],
@@ -39,8 +90,6 @@ describe Part do
39
90
  'dynamic change values outside 0..1' => [
40
91
  0.5, :notes => [ Note::whole ],
41
92
  :dynamic_changes => { 0.2 => Change::Immediate.new(-0.01), 0.3 => Change::Gradual.linear(1.01,0.2) }],
42
- 'notes with 0 duration' => [ 0.5, :notes => [ Note.new(0) ]],
43
- 'notes with negative duration' => [ 0.5, :notes => [ Note.new(-1) ]],
44
93
  }.each do |context_str, args|
45
94
  context context_str do
46
95
  it 'should return false' do