musicality 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +27 -1
- data/README.md +153 -10
- data/bin/collidify +102 -0
- data/bin/lilify +57 -29
- data/bin/midify +64 -24
- data/bin/musicality +39 -0
- data/examples/composition/auto_counterpoint.rb +4 -5
- data/examples/composition/part_generator.rb +8 -2
- data/examples/composition/scale_exercise.rb +1 -1
- data/examples/notation/notes.rb +27 -0
- data/examples/notation/parts.rb +51 -0
- data/examples/notation/scores.rb +38 -0
- data/examples/notation/twinkle.rb +34 -0
- data/examples/notation/twinkle.score +33 -0
- data/lib/musicality.rb +46 -11
- data/lib/musicality/composition/dsl/score_dsl.rb +2 -2
- data/lib/musicality/composition/dsl/score_methods.rb +10 -7
- data/lib/musicality/notation/conversion/change_conversion.rb +1 -1
- data/lib/musicality/notation/conversion/note_time_converter.rb +6 -23
- data/lib/musicality/notation/conversion/score_conversion.rb +15 -15
- data/lib/musicality/notation/conversion/score_converter.rb +50 -67
- data/lib/musicality/notation/model/articulations.rb +3 -2
- data/lib/musicality/notation/model/change.rb +15 -6
- data/lib/musicality/notation/model/dynamics.rb +11 -8
- data/lib/musicality/notation/model/instrument.rb +61 -0
- data/lib/musicality/notation/model/instruments.rb +111 -0
- data/lib/musicality/notation/model/key.rb +137 -0
- data/lib/musicality/notation/model/keys.rb +37 -0
- data/lib/musicality/notation/model/link.rb +6 -19
- data/lib/musicality/notation/model/mark.rb +43 -0
- data/lib/musicality/notation/model/marks.rb +11 -0
- data/lib/musicality/notation/model/meter.rb +4 -0
- data/lib/musicality/notation/model/note.rb +42 -28
- data/lib/musicality/notation/model/part.rb +18 -5
- data/lib/musicality/notation/model/pitch.rb +13 -4
- data/lib/musicality/notation/model/score.rb +104 -66
- data/lib/musicality/notation/model/symbols.rb +16 -11
- data/lib/musicality/notation/parsing/articulation_parsing.rb +38 -38
- data/lib/musicality/notation/parsing/articulation_parsing.treetop +14 -14
- data/lib/musicality/notation/parsing/link_parsing.rb +6 -6
- data/lib/musicality/notation/parsing/link_parsing.treetop +3 -3
- data/lib/musicality/notation/parsing/mark_parsing.rb +138 -0
- data/lib/musicality/notation/parsing/mark_parsing.treetop +31 -0
- data/lib/musicality/notation/parsing/note_node.rb +19 -12
- data/lib/musicality/notation/parsing/note_parsing.rb +218 -87
- data/lib/musicality/notation/parsing/note_parsing.treetop +9 -5
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +7 -2
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.treetop +1 -1
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.rb +6 -4
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.treetop +1 -1
- data/lib/musicality/notation/util/function.rb +41 -18
- data/lib/musicality/packable.rb +156 -0
- data/lib/musicality/performance/conversion/glissando_converter.rb +2 -2
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +223 -70
- data/lib/musicality/performance/conversion/portamento_converter.rb +5 -2
- data/lib/musicality/performance/conversion/score_collator.rb +70 -64
- data/lib/musicality/performance/midi/midi_events.rb +3 -3
- data/lib/musicality/performance/midi/midi_settings.rb +127 -0
- data/lib/musicality/performance/midi/midi_util.rb +8 -2
- data/lib/musicality/performance/midi/part_sequencer.rb +19 -18
- data/lib/musicality/performance/midi/score_sequencer.rb +13 -9
- data/lib/musicality/performance/midi/score_sequencing.rb +5 -5
- data/lib/musicality/performance/model/attack.rb +8 -0
- data/lib/musicality/performance/model/duration_functions.rb +23 -0
- data/lib/musicality/performance/model/note_sequence.rb +52 -95
- data/lib/musicality/performance/model/separation.rb +10 -0
- data/lib/musicality/performance/supercollider/add_actions.rb +13 -0
- data/lib/musicality/performance/supercollider/bundle.rb +18 -0
- data/lib/musicality/performance/supercollider/conductor.rb +125 -0
- data/lib/musicality/performance/supercollider/group.rb +71 -0
- data/lib/musicality/performance/supercollider/message.rb +26 -0
- data/lib/musicality/performance/supercollider/node.rb +122 -0
- data/lib/musicality/performance/supercollider/performer.rb +123 -0
- data/lib/musicality/performance/supercollider/score_conducting.rb +17 -0
- data/lib/musicality/performance/supercollider/server.rb +8 -0
- data/lib/musicality/performance/supercollider/synth.rb +43 -0
- data/lib/musicality/performance/supercollider/synthdef.rb +57 -0
- data/lib/musicality/performance/supercollider/synthdef_settings.rb +23 -0
- data/lib/musicality/performance/supercollider/synthdefs.rb +1654 -0
- data/lib/musicality/{composition/model/pitch_class.rb → pitch_class.rb} +1 -1
- data/lib/musicality/{composition/model/pitch_classes.rb → pitch_classes.rb} +9 -9
- data/lib/musicality/printing/lilypond/clef.rb +12 -0
- data/lib/musicality/printing/lilypond/key_engraving.rb +9 -0
- data/lib/musicality/printing/lilypond/lilypond_settings.rb +105 -0
- data/lib/musicality/printing/lilypond/meter_engraving.rb +1 -1
- data/lib/musicality/printing/lilypond/note_engraving.rb +112 -30
- data/lib/musicality/printing/lilypond/part_engraver.rb +114 -3
- data/lib/musicality/printing/lilypond/pitch_class_engraving.rb +22 -0
- data/lib/musicality/printing/lilypond/pitch_engraving.rb +2 -15
- data/lib/musicality/printing/lilypond/score_engraver.rb +44 -73
- data/lib/musicality/printing/lilypond/score_engraving.rb +3 -3
- data/lib/musicality/project/create_tasks.rb +31 -0
- data/lib/musicality/project/file_cleaner.rb +19 -0
- data/lib/musicality/project/file_raker.rb +107 -0
- data/lib/musicality/project/load_config.rb +43 -0
- data/lib/musicality/project/project.rb +64 -0
- data/lib/musicality/version.rb +1 -1
- data/musicality.gemspec +3 -0
- data/spec/composition/util/random_sampler_spec.rb +1 -1
- data/spec/notation/conversion/measure_note_map_spec.rb +1 -1
- data/spec/notation/conversion/note_time_converter_spec.rb +5 -85
- data/spec/notation/conversion/score_conversion_spec.rb +6 -41
- data/spec/notation/conversion/score_converter_spec.rb +19 -137
- data/spec/notation/model/change_spec.rb +55 -0
- data/spec/notation/model/key_spec.rb +171 -0
- data/spec/notation/model/link_spec.rb +34 -5
- data/spec/notation/model/meter_spec.rb +15 -0
- data/spec/notation/model/note_spec.rb +33 -27
- data/spec/notation/model/part_spec.rb +53 -4
- data/spec/notation/model/pitch_spec.rb +15 -0
- data/spec/notation/model/score_spec.rb +64 -72
- data/spec/notation/parsing/link_nodes_spec.rb +3 -3
- data/spec/notation/parsing/link_parsing_spec.rb +6 -6
- data/spec/notation/parsing/note_node_spec.rb +34 -9
- data/spec/notation/parsing/note_parsing_spec.rb +11 -9
- data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +4 -0
- data/spec/notation/parsing/pitch_node_spec.rb +0 -1
- data/spec/notation/util/value_computer_spec.rb +2 -2
- data/spec/performance/conversion/glissando_converter_spec.rb +9 -9
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +48 -53
- data/spec/performance/conversion/portamento_converter_spec.rb +11 -9
- data/spec/performance/conversion/score_collator_spec.rb +59 -63
- data/spec/performance/midi/midi_util_spec.rb +22 -8
- data/spec/performance/midi/part_sequencer_spec.rb +2 -2
- data/spec/performance/midi/score_sequencer_spec.rb +12 -10
- data/spec/performance/midi/score_sequencing_spec.rb +2 -2
- data/spec/performance/model/note_sequence_spec.rb +41 -134
- data/spec/printing/note_engraving_spec.rb +204 -0
- data/spec/printing/score_engraver_spec.rb +40 -0
- data/spec/spec_helper.rb +1 -0
- metadata +69 -23
- data/examples/notation/hip.rb +0 -32
- data/examples/notation/missed_connection.rb +0 -26
- data/examples/notation/song1.rb +0 -33
- data/examples/notation/song2.rb +0 -32
- data/lib/musicality/notation/model/links.rb +0 -11
- data/lib/musicality/notation/packing/change_packing.rb +0 -56
- data/lib/musicality/notation/packing/part_packing.rb +0 -31
- data/lib/musicality/notation/packing/score_packing.rb +0 -123
- data/lib/musicality/performance/model/note_attacks.rb +0 -19
- data/lib/musicality/performance/util/note_linker.rb +0 -28
- data/spec/notation/packing/change_packing_spec.rb +0 -304
- data/spec/notation/packing/part_packing_spec.rb +0 -66
- data/spec/notation/packing/score_packing_spec.rb +0 -255
- data/spec/performance/util/note_linker_spec.rb +0 -68
@@ -38,8 +38,8 @@ describe MidiUtil do
|
|
38
38
|
|
39
39
|
context 'given pitch outside C-1 to G9 range' do
|
40
40
|
it 'should raise error' do
|
41
|
-
expect { MidiUtil.pitch_to_notenum(Pitch.new(octave:-2)) }.to raise_error
|
42
|
-
expect { MidiUtil.pitch_to_notenum(Ab9) }.to raise_error
|
41
|
+
expect { MidiUtil.pitch_to_notenum(Pitch.new(octave:-2)) }.to raise_error(KeyError)
|
42
|
+
expect { MidiUtil.pitch_to_notenum(Ab9) }.to raise_error(KeyError)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -91,19 +91,33 @@ describe MidiUtil do
|
|
91
91
|
end
|
92
92
|
|
93
93
|
describe 'note_velocity' do
|
94
|
-
context 'given
|
95
|
-
it 'should return a
|
96
|
-
MidiUtil.note_velocity(
|
94
|
+
context 'given Attack::NORMAL' do
|
95
|
+
it 'should return a value at least that of when given Attack::NONE' do
|
96
|
+
MidiUtil.note_velocity(Attack::NORMAL).should be >= MidiUtil.note_velocity(Attack::NONE)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should return a value between 0 and 127' do
|
100
|
+
MidiUtil.note_velocity(Attack::NORMAL).should be_between(0,127)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'given Attack::TENUTO' do
|
105
|
+
it 'should return a higher value than when given Attack::NORMAL' do
|
106
|
+
MidiUtil.note_velocity(Attack::TENUTO).should be > MidiUtil.note_velocity(Attack::NORMAL)
|
97
107
|
end
|
98
108
|
|
99
109
|
it 'should return a value between 0 and 127' do
|
100
|
-
MidiUtil.note_velocity(
|
110
|
+
MidiUtil.note_velocity(Attack::TENUTO).should be_between(0,127)
|
101
111
|
end
|
102
112
|
end
|
103
113
|
|
104
|
-
context 'given
|
114
|
+
context 'given Attack::ACCENT' do
|
115
|
+
it 'should return a higher value than when given Attack::TENUTO' do
|
116
|
+
MidiUtil.note_velocity(Attack::ACCENT).should be > MidiUtil.note_velocity(Attack::TENUTO)
|
117
|
+
end
|
118
|
+
|
105
119
|
it 'should return a value between 0 and 127' do
|
106
|
-
MidiUtil.note_velocity(
|
120
|
+
MidiUtil.note_velocity(Attack::ACCENT).should be_between(0,127)
|
107
121
|
end
|
108
122
|
end
|
109
123
|
end
|
@@ -21,9 +21,9 @@ describe PartSequencer do
|
|
21
21
|
@track.name.should eq(@part_name)
|
22
22
|
end
|
23
23
|
|
24
|
-
it 'should assign program number via ProgramChange event' do
|
24
|
+
it 'should assign program number (less one) via ProgramChange event' do
|
25
25
|
event = @track.events.select { |x| x.is_a? MIDI::ProgramChange }.first
|
26
|
-
event.program.should eq(@program_num)
|
26
|
+
event.program.should eq(@program_num-1)
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'should assign the given channel number to all channel events' do
|
@@ -8,12 +8,13 @@ describe ScoreSequencer do
|
|
8
8
|
before :all do
|
9
9
|
@part1_name = "abc"
|
10
10
|
@part2_name = "def"
|
11
|
-
@part1 = Part.new(Dynamics::PP, notes: "/4C4 /4D4 /8 /8D4 /8E4 3/8C4".to_notes * 2
|
12
|
-
|
11
|
+
@part1 = Part.new(Dynamics::PP, notes: "/4C4 /4D4 /8 /8D4 /8E4 3/8C4".to_notes * 2,
|
12
|
+
settings: [ MidiSettings::ELECTRIC_BASS_PICK ])
|
13
|
+
@part2 = Part.new(Dynamics::FF, notes: "/4E4 3/4F4 /4E4".to_notes * 2,
|
14
|
+
settings: [ MidiSettings::ELECTRIC_GUITAR_JAZZ ])
|
13
15
|
@score = Score::Timed.new(program: [0..2.5],
|
14
|
-
parts: {@part1_name => @
|
15
|
-
@
|
16
|
-
@midi_seq = ScoreSequencer.new(@score).make_midi_seq(@instr_map)
|
16
|
+
parts: {@part1_name => @part1, @part2_name => @part2})
|
17
|
+
@midi_seq = ScoreSequencer.new(@score).make_midi_seq
|
17
18
|
end
|
18
19
|
|
19
20
|
it 'should return MIDI::Sequence' do
|
@@ -29,11 +30,12 @@ describe ScoreSequencer do
|
|
29
30
|
@midi_seq.tracks[2].name.should eq(@part2_name)
|
30
31
|
end
|
31
32
|
|
32
|
-
it 'should assign program number from
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
it 'should assign program number (starts at 0) from part midi program number (starts at 1)' do
|
34
|
+
prog_event = @midi_seq.tracks[1].events.select {|x| x.is_a? MIDI::ProgramChange }.first
|
35
|
+
prog_event.program.should eq(@part1.midi_settings.program - 1)
|
36
|
+
|
37
|
+
prog_event = @midi_seq.tracks[2].events.select {|x| x.is_a? MIDI::ProgramChange }.first
|
38
|
+
prog_event.program.should eq(@part2.midi_settings.program - 1)
|
37
39
|
end
|
38
40
|
|
39
41
|
it 'should assign different channel to each part track' do
|
@@ -21,9 +21,9 @@ describe Score::Timed do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
describe Score::
|
24
|
+
describe Score::Tempo do
|
25
25
|
before :all do
|
26
|
-
@score = Score::
|
26
|
+
@score = Score::Tempo.new(TWO_FOUR, 120) do |s|
|
27
27
|
s.parts["rhand"] = Part.new(Dynamics::MF) do |p|
|
28
28
|
p.notes += ("/4C4 "*2 + "/4G4 "*2 +
|
29
29
|
"/4A4 "*2 + "/2G4").to_notes
|
@@ -2,146 +2,53 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
2
|
|
3
3
|
describe NoteSequence do
|
4
4
|
describe '#initialize' do
|
5
|
-
it 'should assign given
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
seq = NoteSequence.new(start,stop,pitches,attacks)
|
10
|
-
seq.start.should eq(start)
|
11
|
-
seq.stop.should eq(stop)
|
12
|
-
seq.pitches.should eq(pitches)
|
13
|
-
seq.attacks.should eq(attacks)
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'should raise ArgumentError if start offset >= stop offset' do
|
17
|
-
expect do
|
18
|
-
NoteSequence.new(20,19, { 20 => C4 }, { 20 => UNACCENTED })
|
19
|
-
end.to raise_error(ArgumentError)
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'should raise ArgumentError if no pitches are given' do
|
23
|
-
expect do
|
24
|
-
NoteSequence.new(20,21, {}, { 20 => UNACCENTED })
|
25
|
-
end.to raise_error(ArgumentError)
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'should raise ArgumentError if no attacks are given' do
|
29
|
-
expect do
|
30
|
-
NoteSequence.new(20,21, { 20 => C4 }, {})
|
31
|
-
end.to raise_error(ArgumentError)
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'should raise ArgumentError if no start pitch is given' do
|
35
|
-
expect do
|
36
|
-
NoteSequence.new(20,21, { 20.1 => C4 }, { 20 => UNACCENTED })
|
37
|
-
end.to raise_error(ArgumentError)
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'should raise ArgumentError if no start attack is given' do
|
41
|
-
expect do
|
42
|
-
NoteSequence.new(20,21, { 20 => C4 }, { 20.1 => UNACCENTED })
|
43
|
-
end.to raise_error(ArgumentError)
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'should raise ArgumentError if any pitch offset is not between start..stop' do
|
47
|
-
expect do
|
48
|
-
NoteSequence.new(20,21, { 20 => C4, 21.01 => D4 }, { 20 => UNACCENTED })
|
49
|
-
end.to raise_error(ArgumentError)
|
50
|
-
|
51
|
-
expect do
|
52
|
-
NoteSequence.new(20,21, { 20 => C4, 19.99 => D4 }, { 20 => UNACCENTED })
|
53
|
-
end.to raise_error(ArgumentError)
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'should raise ArgumentError if any attack offset is not between start..stop' do
|
57
|
-
expect do
|
58
|
-
NoteSequence.new(20,21, { 20 => C4 }, { 20 => UNACCENTED, 21.01 => ACCENTED })
|
59
|
-
end.to raise_error(ArgumentError)
|
5
|
+
it 'should assign given offset, separation, and elements' do
|
6
|
+
offset = 12
|
7
|
+
separation = Separation::TENUTO
|
8
|
+
elements = [ NoteSequence::Element.new(2, G2, Attack::NORMAL) ]
|
60
9
|
|
61
|
-
|
62
|
-
|
63
|
-
|
10
|
+
seq = NoteSequence.new(offset, separation, elements)
|
11
|
+
expect(seq.offset).to eq(offset)
|
12
|
+
expect(seq.separation).to eq(separation)
|
13
|
+
expect(seq.elements).to eq(elements)
|
64
14
|
end
|
65
15
|
end
|
16
|
+
|
17
|
+
before :all do
|
18
|
+
@element_arys = [
|
19
|
+
[ NoteSequence::Element.new(0.5, B2, Attack::NONE) ],
|
20
|
+
[ NoteSequence::Element.new(0.5, A2, Attack::NORMAL),
|
21
|
+
NoteSequence::Element.new(0.5, B2, Attack::NONE),
|
22
|
+
NoteSequence::Element.new(0.5, B2, Attack::ACCENT) ],
|
23
|
+
]
|
24
|
+
@offsets = [ 0, -5, 7, 77 ]
|
25
|
+
end
|
66
26
|
|
67
|
-
describe '
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
(@seq.stop - @seq.start).should be <= @el.duration
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'should set start pitch according to element pitch' do
|
93
|
-
@seq.pitches[@seq.start].should eq(@el.pitch)
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'should set start attack according to element.accented' do
|
97
|
-
@seq.attacks[@seq.start].accented?.should eq(@el.accented)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
context 'multi-element' do
|
102
|
-
before :all do
|
103
|
-
@offset = 1.5
|
104
|
-
@els = [
|
105
|
-
SlurredElement.new(1.0, A2, false),
|
106
|
-
LegatoElement.new(1.1, B2, false),
|
107
|
-
SlurredElement.new(1.2, C2, false),
|
108
|
-
LegatoElement.new(1.3, B2, false),
|
109
|
-
FinalElement.new(1.4, A2, false, NORMAL)
|
110
|
-
]
|
111
|
-
@seq = NoteSequence.from_elements(@offset, @els)
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'should place pitches according to element duration' do
|
115
|
-
offset = @offset
|
116
|
-
@els.each do |el|
|
117
|
-
@seq.pitches.should have_key(offset)
|
118
|
-
@seq.pitches[offset].should eq(el.pitch)
|
119
|
-
offset += el.duration
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'should place attacks at beginning and following non-slur elements' do
|
124
|
-
@seq.attacks.should have_key(@offset)
|
125
|
-
|
126
|
-
offset = @offset + @els.first.duration
|
127
|
-
(1...@els.size).each do |i|
|
128
|
-
unless @els[i-1].slurred?
|
129
|
-
@seq.attacks.should have_key(offset)
|
27
|
+
describe '#offsets' do
|
28
|
+
context 'with no elements' do
|
29
|
+
it 'should raise RuntimeError' do
|
30
|
+
expect do
|
31
|
+
seq = NoteSequence.new(0, Separation::NORMAL, [])
|
32
|
+
seq.offsets
|
33
|
+
end.to raise_error(RuntimeError)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with at least one element' do
|
38
|
+
it 'should return offsets of each element' do
|
39
|
+
@offsets.each do |offset|
|
40
|
+
@element_arys.each do |els|
|
41
|
+
seq = NoteSequence.new(offset, Separation::NORMAL, els)
|
42
|
+
offsets = seq.offsets
|
43
|
+
expect(offsets.size).to eq(els.size)
|
44
|
+
expect(offsets[0]).to eq(seq.offset)
|
45
|
+
(1...offsets.size).each do |i|
|
46
|
+
dur = offsets[i] - offsets[i-1]
|
47
|
+
expect(dur).to eq(els[i-1].duration)
|
48
|
+
end
|
130
49
|
end
|
131
|
-
offset += @els[i].duration
|
132
50
|
end
|
133
51
|
end
|
134
52
|
end
|
135
|
-
|
136
|
-
context 'elements contain slur to same pitch' do
|
137
|
-
it 'should not add same pitch nor attack for second element' do
|
138
|
-
els = [ SlurredElement.new(1, C4, false), FinalElement.new(1, C4, false, NORMAL) ]
|
139
|
-
seq = NoteSequence.from_elements(0, els)
|
140
|
-
seq.pitches.should have_key(0)
|
141
|
-
seq.pitches.should_not have_key(1)
|
142
|
-
seq.attacks.should have_key(0)
|
143
|
-
seq.attacks.should_not have_key(1)
|
144
|
-
end
|
145
|
-
end
|
146
53
|
end
|
147
|
-
end
|
54
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Note do
|
4
|
+
describe '#fractional_subdurs' do
|
5
|
+
context 'duration that is entirely whole' do
|
6
|
+
it 'should return empty array' do
|
7
|
+
[1,2,3,4,7,11].each do |dur|
|
8
|
+
subdurs = Note.new(dur).fractional_subdurs(Rational(1,32))
|
9
|
+
subdurs.should be_empty
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'duration that is entirely fractional' do
|
15
|
+
context 'combination of multiples of power-of-two fractions' do
|
16
|
+
[
|
17
|
+
[Rational(3,8),Rational(7,32)],
|
18
|
+
[Rational(1,8),Rational(3,16),Rational(5,32)],
|
19
|
+
[Rational(1,2),Rational(3,32),Rational(5,64),Rational(17,128)],
|
20
|
+
].each do |subdurs|
|
21
|
+
dur = subdurs.inject(0.to_r,:+)
|
22
|
+
n = Note.new(dur)
|
23
|
+
subdurs2 = n.fractional_subdurs(Rational(1,512))
|
24
|
+
|
25
|
+
it 'should return descending power-of-two fractions' do
|
26
|
+
subdurs2.should eq subdurs2.sort.reverse
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return fractions that sum to note duration' do
|
30
|
+
subdurs2.inject(0.to_r,:+).should eq(dur)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'duration that has whole and fractional part' do
|
37
|
+
[
|
38
|
+
[6,Rational(3,8),Rational(11,16)],
|
39
|
+
[3,Rational(1,8),Rational(5,8),Rational(5,32)],
|
40
|
+
[1,Rational(3,32),Rational(1,2),Rational(5,4)],
|
41
|
+
].each do |subdurs|
|
42
|
+
dur = subdurs.inject(0.to_r,:+)
|
43
|
+
n = Note.new(dur)
|
44
|
+
subdurs2 = n.fractional_subdurs(Rational(1,1024))
|
45
|
+
|
46
|
+
it 'should return fractions that sum to fractional note duration' do
|
47
|
+
subdurs2.inject(0.to_r,:+).should eq(dur - dur.to_i)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#to_lilypond' do
|
54
|
+
context 'duration is entirely whole' do
|
55
|
+
context 'no pitches' do
|
56
|
+
it 'should return "r1"s' do
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# context 'no pitches' do
|
63
|
+
# it 'should represent note pieces with "r"' do
|
64
|
+
|
65
|
+
# end
|
66
|
+
# end
|
67
|
+
|
68
|
+
# it 'should '
|
69
|
+
# it 'should separate pieces with a "~" and a space' do
|
70
|
+
# [2,3+Rational(1,2)].each do |dur|
|
71
|
+
# [[],[Eb3],[C2,Gb4]].each do |pitches|
|
72
|
+
# n = Note.new(dur,pitches)
|
73
|
+
# s = n.to_lilypond
|
74
|
+
# pieces = s.split("~ ")
|
75
|
+
# pieces.
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
|
80
|
+
|
81
|
+
# and duration with deno'
|
82
|
+
# context 'simple power-of-two note duration' do
|
83
|
+
# it 'should return a string with "r" plus the duration denominator' do
|
84
|
+
# [1,0.5,0.25,0.125,0.0625].each do |dur|
|
85
|
+
# n = Note.new(dur.to_r)
|
86
|
+
# n.to_lilypond.should eq("r" + n.duration.denominator.to_s)
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
|
91
|
+
# context 'dotted power-of-two note duration less than 1 (e.g. 3/4 or 3/2)' do
|
92
|
+
# it 'should return a string with "r" plus half the duration denominator plus a "."' do
|
93
|
+
# [0.75,0.375].each do |dur|
|
94
|
+
# n = Note.new(dur.to_r)
|
95
|
+
# n.to_lilypond.should eq("r" + (n.duration.denominator/2).to_s + ".")
|
96
|
+
# end
|
97
|
+
# end
|
98
|
+
# end
|
99
|
+
|
100
|
+
# context 'compound duration reducible only to simple power-of-two durations (not dotted)' do
|
101
|
+
# it 'should return a string with r\'s plus the duration denominators' do
|
102
|
+
# [
|
103
|
+
# [1,0.25],
|
104
|
+
# [0.5,0.125],
|
105
|
+
# [0.25,0.0625],
|
106
|
+
# [0.5,0.125,0.03125]
|
107
|
+
# ].each do |subdurs|
|
108
|
+
# dur = subdurs.inject(0.to_r,:+)
|
109
|
+
# n = Note.new(dur)
|
110
|
+
# strs = n.to_lilypond.split
|
111
|
+
# strs.size.should eq subdurs.size
|
112
|
+
# strs.each_with_index do |str,i|
|
113
|
+
# str.should eq("r" + subdurs[i].to_r.denominator.to_s)
|
114
|
+
# end
|
115
|
+
# end
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
|
119
|
+
# context 'simple triplet duration' do
|
120
|
+
# it 'should return "r" + 3/2 duration enclosed inside \tuplet 3/2 {}' do
|
121
|
+
# [Rational(1,6),Rational(1,3),Rational(1,12)].each do |dur|
|
122
|
+
# n = Note.new(dur.to_r)
|
123
|
+
# n.to_lilypond.should eq("\\tuplet 3/2 {r#{(1.5.to_r*dur).denominator}}")
|
124
|
+
# end
|
125
|
+
# end
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
|
129
|
+
# context 'simple power-of-two note duration' do
|
130
|
+
# context 'one pitch' do
|
131
|
+
# it 'should return a string with Lilypond pitch plus the duration denominator' do
|
132
|
+
# [1,0.5,0.25,0.125,0.0625].each do |dur|
|
133
|
+
# [C3,Eb2,G4].each do |pitch|
|
134
|
+
# n = Note.new(dur.to_r, pitch)
|
135
|
+
# n.to_lilypond.should eq(pitch.to_lilypond + n.duration.denominator.to_s)
|
136
|
+
# end
|
137
|
+
# end
|
138
|
+
# end
|
139
|
+
# end
|
140
|
+
|
141
|
+
# context 'multiple pitch' do
|
142
|
+
# it 'should return a string with Lilypond pitches in angle brackets plus the duration denominator' do
|
143
|
+
# [1,0.25,0.0625].each do |dur|
|
144
|
+
# pitch_group = [Eb2,C3,G4]
|
145
|
+
# n = Note.new(dur.to_r, pitch_group)
|
146
|
+
# n.to_lilypond.should eq("<" + pitch_group.map {|p| p.to_lilypond}.join(" ") + ">" + n.duration.denominator.to_s)
|
147
|
+
# end
|
148
|
+
# end
|
149
|
+
# end
|
150
|
+
# end
|
151
|
+
|
152
|
+
# context 'dotted power-of-two note duration less than 1 (e.g. 3/4 or 3/2)' do
|
153
|
+
# context 'one pitch' do
|
154
|
+
# it 'should return a string with Lilypond pitch plus half the duration denominator plus a "."' do
|
155
|
+
# [0.75,0.375].each do |dur|
|
156
|
+
# [C3,Eb2,G4].each do |pitch|
|
157
|
+
# n = Note.new(dur.to_r, pitch)
|
158
|
+
# n.to_lilypond.should eq(pitch.to_lilypond + (n.duration.denominator/2).to_s + ".")
|
159
|
+
# end
|
160
|
+
# end
|
161
|
+
# end
|
162
|
+
# end
|
163
|
+
|
164
|
+
# context 'multiple pitch' do
|
165
|
+
# it 'should return a string with Lilypond pitches in angle brackets plus half the duration denominator plus a "."' do
|
166
|
+
# [0.75,0.375].each do |dur|
|
167
|
+
# pitch_group = [Eb2,C3,G4]
|
168
|
+
# n = Note.new(dur.to_r, pitch_group)
|
169
|
+
# n.to_lilypond.should eq("<" + pitch_group.map {|p| p.to_lilypond}.join(" ") + ">" + (n.duration.denominator/2).to_s + ".")
|
170
|
+
# end
|
171
|
+
# end
|
172
|
+
# end
|
173
|
+
# end
|
174
|
+
|
175
|
+
# context 'compound duration reducible only to simple power-of-two durations (not dotted)' do
|
176
|
+
# context 'one pitch' do
|
177
|
+
# it 'should return a string with Lilypond pitch plus the duration denominators, and a "~" if not the last piece' do
|
178
|
+
# [
|
179
|
+
# [1,0.25],
|
180
|
+
# [0.5,0.125],
|
181
|
+
# [0.25,0.0625],
|
182
|
+
# [0.5,0.125,0.03125]
|
183
|
+
# ].each do |subdurs|
|
184
|
+
# [Gb3,Bb3,C4].each do |pitch|
|
185
|
+
# dur = subdurs.inject(0.to_r,:+)
|
186
|
+
# n = Note.new(dur,pitch)
|
187
|
+
# str = n.to_lilypond
|
188
|
+
# strs = str.split
|
189
|
+
# strs.size.should eq subdurs.size
|
190
|
+
# strs.each_with_index do |str,i|
|
191
|
+
# if i != (strs.size-1)
|
192
|
+
# str.should eq(pitch.to_lilypond + subdurs[i].to_r.denominator.to_s + "~")
|
193
|
+
# else
|
194
|
+
# str.should eq(pitch.to_lilypond + subdurs[i].to_r.denominator.to_s)
|
195
|
+
# end
|
196
|
+
# end
|
197
|
+
# end
|
198
|
+
# end
|
199
|
+
# end
|
200
|
+
# end
|
201
|
+
|
202
|
+
# end
|
203
|
+
# end
|
204
|
+
end
|