musicality 0.9.0 → 0.10.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.
- checksums.yaml +4 -4
- data/ChangeLog.md +7 -1
- data/lib/musicality.rb +0 -1
- data/lib/musicality/composition/dsl/score_methods.rb +5 -6
- data/lib/musicality/notation/conversion/score_conversion.rb +3 -34
- data/lib/musicality/notation/conversion/score_converter.rb +6 -17
- data/lib/musicality/notation/model/mark.rb +0 -12
- data/lib/musicality/notation/model/marks.rb +0 -3
- data/lib/musicality/notation/model/note.rb +0 -8
- data/lib/musicality/notation/model/score.rb +14 -35
- data/lib/musicality/notation/model/symbols.rb +0 -2
- data/lib/musicality/notation/parsing/mark_parsing.rb +0 -58
- data/lib/musicality/notation/parsing/mark_parsing.treetop +0 -12
- data/lib/musicality/notation/parsing/note_node.rb +22 -27
- data/lib/musicality/notation/parsing/note_parsing.rb +59 -189
- data/lib/musicality/notation/parsing/note_parsing.treetop +2 -9
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +1 -20
- data/lib/musicality/performance/model/note_sequence.rb +1 -1
- data/lib/musicality/printing/lilypond/note_engraving.rb +3 -3
- data/lib/musicality/printing/lilypond/part_engraver.rb +16 -12
- data/lib/musicality/project/create_tasks.rb +1 -1
- data/lib/musicality/project/load_config.rb +16 -1
- data/lib/musicality/project/project.rb +2 -2
- data/lib/musicality/version.rb +1 -1
- data/musicality.gemspec +0 -1
- data/spec/composition/dsl/score_methods_spec.rb +73 -0
- data/spec/notation/conversion/score_conversion_spec.rb +0 -100
- data/spec/notation/conversion/score_converter_spec.rb +33 -33
- data/spec/notation/model/note_spec.rb +2 -2
- data/spec/notation/model/score_spec.rb +17 -87
- data/spec/notation/parsing/note_node_spec.rb +2 -2
- data/spec/notation/parsing/note_parsing_spec.rb +3 -3
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +23 -0
- data/spec/performance/model/note_sequence_spec.rb +50 -6
- metadata +4 -19
- data/lib/musicality/notation/conversion/measure_note_map.rb +0 -40
- data/spec/notation/conversion/measure_note_map_spec.rb +0 -73
@@ -88,9 +88,9 @@ describe Parsing::NoteNode do
|
|
88
88
|
end
|
89
89
|
|
90
90
|
context 'with marks' do
|
91
|
-
[[BEGIN_SLUR],[
|
91
|
+
[[BEGIN_SLUR],[]].each do |begin_marks|
|
92
92
|
begin_marks_str = begin_marks.map {|m| m.to_s}.join
|
93
|
-
[[END_SLUR],[
|
93
|
+
[[END_SLUR],[]].each do |end_marks|
|
94
94
|
end_marks_str = end_marks.map {|m| m.to_s}.join
|
95
95
|
describe '#to_note' do
|
96
96
|
it 'should produce a Note with marks set correctly' do
|
@@ -12,7 +12,7 @@ describe Parsing::NoteParser do
|
|
12
12
|
'with articulation' => ['/4C2.',"5/3Db3,Bb2,E5.",'/2D3,F4_'],
|
13
13
|
'with accent' => ['/4C2','3/2Db3,Bb4'],
|
14
14
|
'with links' => ['/2C2~','/2C2:D2','/4D4:E4,G4;A5.'],
|
15
|
-
'with marks' => ['(3/4Bb3
|
15
|
+
'with marks' => ['(3/4Bb3', '/2F3,G3)', '(2/4C3', '(1B2', '/3B2,C2)', '(2/3D4)'],
|
16
16
|
'with single pitch + articulation + link + accent' => [
|
17
17
|
'(3/4D2~','5/8F2;G2.','/8Db4:Db5','/3G4;B4_'],
|
18
18
|
'with multiple pitches + articulation + links + accent' => [
|
@@ -23,8 +23,8 @@ describe Parsing::NoteParser do
|
|
23
23
|
'duration + accent + link' => ['1/4;','/2:','2/3~'],
|
24
24
|
'single pith with bad letter' => ['5/3Hb3'],
|
25
25
|
'single pitch without octave' => ['/33E)'],
|
26
|
-
'begins marks at the end' => ['1Bb3('
|
27
|
-
'end marks at the beginning ' => ['
|
26
|
+
'begins marks at the end' => ['1Bb3('],
|
27
|
+
'end marks at the beginning ' => [')3C3']
|
28
28
|
}
|
29
29
|
|
30
30
|
valid_cases.each do |descr, strs|
|
@@ -221,5 +221,28 @@ describe NoteSequenceExtractor do
|
|
221
221
|
@seqs[0].duration.should be <= (@notes[0].duration + @notes[1].duration)
|
222
222
|
end
|
223
223
|
end
|
224
|
+
|
225
|
+
context 'three notes with single pitch, tie between first two, portamento between last two' do
|
226
|
+
before :all do
|
227
|
+
@notes = "/8Eb4~ /8Eb4:C5 3/4C5".to_notes
|
228
|
+
@seqs = NoteSequenceExtractor.new(@notes).extract_sequences
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'should produce a single sequence' do
|
232
|
+
expect(@seqs.size).to eq(1)
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'should have same full duration as the notes together' do
|
236
|
+
expected_dur = @notes.map {|n| n.duration }.inject(0,:+)
|
237
|
+
seq = @seqs.first
|
238
|
+
expect(seq.full_duration).to eq(expected_dur)
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'should have duration less than the notes together' do
|
242
|
+
max_dur = @notes.map {|n| n.duration }.inject(0,:+)
|
243
|
+
seq = @seqs.first
|
244
|
+
expect(seq.duration).to be < max_dur
|
245
|
+
end
|
246
|
+
end
|
224
247
|
end
|
225
248
|
end
|
@@ -15,11 +15,10 @@ describe NoteSequence do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
before :all do
|
18
|
-
@
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
NoteSequence::Element.new(0.5, B2, Attack::ACCENT) ],
|
18
|
+
@element_ary = [
|
19
|
+
NoteSequence::Element.new(0.5, A2, Attack::NORMAL),
|
20
|
+
NoteSequence::Element.new(0.5, B2, Attack::NONE),
|
21
|
+
NoteSequence::Element.new(0.5, B2, Attack::ACCENT)
|
23
22
|
]
|
24
23
|
@offsets = [ 0, -5, 7, 77 ]
|
25
24
|
end
|
@@ -37,7 +36,7 @@ describe NoteSequence do
|
|
37
36
|
context 'with at least one element' do
|
38
37
|
it 'should return offsets of each element' do
|
39
38
|
@offsets.each do |offset|
|
40
|
-
@
|
39
|
+
@element_ary.combination(@element_ary.size-1).each do |els|
|
41
40
|
seq = NoteSequence.new(offset, Separation::NORMAL, els)
|
42
41
|
offsets = seq.offsets
|
43
42
|
expect(offsets.size).to eq(els.size)
|
@@ -51,4 +50,49 @@ describe NoteSequence do
|
|
51
50
|
end
|
52
51
|
end
|
53
52
|
end
|
53
|
+
|
54
|
+
describe '#stop' do
|
55
|
+
context 'no elements' do
|
56
|
+
it 'should raise RuntimeError' do
|
57
|
+
ns = NoteSequence.new(1.2, Separation::NORMAL, [])
|
58
|
+
expect { ns.stop }.to raise_error(RuntimeError)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#duration' do
|
64
|
+
context 'no elements' do
|
65
|
+
it 'should raise RuntimeError' do
|
66
|
+
ns = NoteSequence.new(1.2, Separation::NORMAL, [])
|
67
|
+
expect { ns.duration }.to raise_error(RuntimeError)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#full_duration' do
|
73
|
+
context 'no elements' do
|
74
|
+
it 'should return 0' do
|
75
|
+
ns = NoteSequence.new(1.2, Separation::NORMAL, [])
|
76
|
+
expect(ns.full_duration).to eq(0)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'with one element' do
|
81
|
+
it 'should return element duration' do
|
82
|
+
@element_ary.each do |el|
|
83
|
+
ns = NoteSequence.new(1.2, Separation::NORMAL, [el])
|
84
|
+
expect(ns.full_duration).to eq(el.duration)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'with multiple elements' do
|
90
|
+
it 'should return the sum of element durations' do
|
91
|
+
els = [ NoteSequence::Element.new(0.5, D4, Attack::NORMAL),
|
92
|
+
NoteSequence::Element.new(0.25, F3, Attack::TENUTO) ]
|
93
|
+
ns = NoteSequence.new(1.2, Separation::NORMAL, els)
|
94
|
+
expect(ns.full_duration).to eq(0.75)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
54
98
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: musicality
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Tunnell
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,20 +108,6 @@ dependencies:
|
|
108
108
|
- - ~>
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0.5'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: ruby-osc
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ~>
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0.4'
|
118
|
-
type: :runtime
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ~>
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0.4'
|
125
111
|
description: "The library is based around an abstract representation for music notation.
|
126
112
|
\\\n From here, functions are built up to make composing
|
127
113
|
elaborate pieces in this notation representation more manageable. \\\n Finally,
|
@@ -175,7 +161,6 @@ files:
|
|
175
161
|
- lib/musicality/composition/util/repeating_sequence.rb
|
176
162
|
- lib/musicality/errors.rb
|
177
163
|
- lib/musicality/notation/conversion/change_conversion.rb
|
178
|
-
- lib/musicality/notation/conversion/measure_note_map.rb
|
179
164
|
- lib/musicality/notation/conversion/note_time_converter.rb
|
180
165
|
- lib/musicality/notation/conversion/score_conversion.rb
|
181
166
|
- lib/musicality/notation/conversion/score_converter.rb
|
@@ -288,6 +273,7 @@ files:
|
|
288
273
|
- lib/musicality/version.rb
|
289
274
|
- musicality.gemspec
|
290
275
|
- spec/composition/convenience_methods_spec.rb
|
276
|
+
- spec/composition/dsl/score_methods_spec.rb
|
291
277
|
- spec/composition/generation/random_rhythm_generator_spec.rb
|
292
278
|
- spec/composition/model/pitch_class_spec.rb
|
293
279
|
- spec/composition/model/pitch_classes_spec.rb
|
@@ -301,7 +287,6 @@ files:
|
|
301
287
|
- spec/composition/util/repeating_sequence_spec.rb
|
302
288
|
- spec/musicality_spec.rb
|
303
289
|
- spec/notation/conversion/change_conversion_spec.rb
|
304
|
-
- spec/notation/conversion/measure_note_map_spec.rb
|
305
290
|
- spec/notation/conversion/note_time_converter_spec.rb
|
306
291
|
- spec/notation/conversion/score_conversion_spec.rb
|
307
292
|
- spec/notation/conversion/score_converter_spec.rb
|
@@ -374,6 +359,7 @@ specification_version: 4
|
|
374
359
|
summary: Music notation, composition, and performance
|
375
360
|
test_files:
|
376
361
|
- spec/composition/convenience_methods_spec.rb
|
362
|
+
- spec/composition/dsl/score_methods_spec.rb
|
377
363
|
- spec/composition/generation/random_rhythm_generator_spec.rb
|
378
364
|
- spec/composition/model/pitch_class_spec.rb
|
379
365
|
- spec/composition/model/pitch_classes_spec.rb
|
@@ -387,7 +373,6 @@ test_files:
|
|
387
373
|
- spec/composition/util/repeating_sequence_spec.rb
|
388
374
|
- spec/musicality_spec.rb
|
389
375
|
- spec/notation/conversion/change_conversion_spec.rb
|
390
|
-
- spec/notation/conversion/measure_note_map_spec.rb
|
391
376
|
- spec/notation/conversion/note_time_converter_spec.rb
|
392
377
|
- spec/notation/conversion/score_conversion_spec.rb
|
393
378
|
- spec/notation/conversion/score_converter_spec.rb
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module Musicality
|
2
|
-
|
3
|
-
module Conversion
|
4
|
-
# Convert offsets from measure-based to note-based.
|
5
|
-
# @param [Array] measure_offsets Measure offsets to be converted
|
6
|
-
# @param [Hash] measure_durations Map measure durations to measure offsets where the duration takes effect.
|
7
|
-
# @raise [NonZeroError] if first measure duration is not mapped to offset 0
|
8
|
-
def self.measure_note_map measure_offsets, measure_durations
|
9
|
-
mnoff_map = {}
|
10
|
-
moffs = measure_offsets.uniq.sort
|
11
|
-
mdurs = measure_durations.sort
|
12
|
-
cur_noff = 0.to_r
|
13
|
-
j = 0 # next measure offset to be converted
|
14
|
-
|
15
|
-
if mdurs[0][0] != 0
|
16
|
-
raise NonZeroError, "measure offset of 1st measure duration must be 0, not #{mdurs[0][0]}"
|
17
|
-
end
|
18
|
-
|
19
|
-
(0...mdurs.size).each do |i|
|
20
|
-
cur_moff, cur_mdur = mdurs[i]
|
21
|
-
if i < (mdurs.size - 1)
|
22
|
-
next_moff = mdurs[i+1][0]
|
23
|
-
else
|
24
|
-
next_moff = Float::INFINITY
|
25
|
-
end
|
26
|
-
|
27
|
-
while(j < moffs.size && moffs[j] <= next_moff) do
|
28
|
-
moff = moffs[j]
|
29
|
-
mnoff_map[moff] = cur_noff + (moff - cur_moff)*cur_mdur
|
30
|
-
j += 1
|
31
|
-
end
|
32
|
-
|
33
|
-
cur_noff += (next_moff - cur_moff) * cur_mdur
|
34
|
-
end
|
35
|
-
|
36
|
-
return mnoff_map
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
-
|
3
|
-
describe 'Conversion.measure_note_map' do
|
4
|
-
before :all do
|
5
|
-
mdurs = Hash[ [[0, (3/4)], [1, (1/2)], [3, (3/4)]] ]
|
6
|
-
@moffs = [ 0, 1, 3, 4, 5, 6, 7, 8, 11, 14, 17, 20, (45/2)]
|
7
|
-
@mnoff_map = Conversion.measure_note_map(@moffs,mdurs)
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'should return a Hash' do
|
11
|
-
@mnoff_map.should be_a Hash
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'should have same size as array returned by #measure_offsets' do
|
15
|
-
@mnoff_map.size.should eq(@moffs.size)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should have a key for each offset in the array returned by #measure_offsets' do
|
19
|
-
@mnoff_map.keys.sort.should eq(@moffs)
|
20
|
-
end
|
21
|
-
|
22
|
-
context 'single measure duration at 0' do
|
23
|
-
it 'should mutiply all measure offsets by start measure duration' do
|
24
|
-
[TWO_FOUR,SIX_EIGHT,FOUR_FOUR,THREE_FOUR].each do |meter|
|
25
|
-
mdur = meter.measure_duration
|
26
|
-
mdurs = { 0 => mdur }
|
27
|
-
tgt = @moffs.map {|moff| moff * mdur}
|
28
|
-
Conversion.measure_note_map(@moffs,mdurs).values.sort.should eq(tgt)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context '1 meter change' do
|
34
|
-
before :all do
|
35
|
-
@first_mc_off = 3
|
36
|
-
@start_meter = THREE_FOUR
|
37
|
-
@new_meter = TWO_FOUR
|
38
|
-
@score = Score::Tempo.new(@start_meter, 120,
|
39
|
-
meter_changes: { @first_mc_off => Change::Immediate.new(@new_meter) },
|
40
|
-
tempo_changes: {
|
41
|
-
"1/2".to_r => Change::Gradual.linear(100,1),
|
42
|
-
2 => Change::Immediate.new(120),
|
43
|
-
3 => Change::Immediate.new(100),
|
44
|
-
3.1 => Change::Gradual.linear(100,1),
|
45
|
-
5 => Change::Immediate.new(120),
|
46
|
-
6 => Change::Immediate.new(100),
|
47
|
-
}
|
48
|
-
)
|
49
|
-
@moffs = @score.measure_offsets
|
50
|
-
@mdurs = @score.measure_durations
|
51
|
-
@mnoff_map = Conversion.measure_note_map(@moffs,@mdurs)
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'should mutiply all measure offsets that occur on or before 1st meter change offset by start measure duration' do
|
55
|
-
moffs = @moffs.select{ |x| x <= @first_mc_off }
|
56
|
-
tgt = moffs.map do |moff|
|
57
|
-
moff * @start_meter.measure_duration
|
58
|
-
end.sort
|
59
|
-
src = @mnoff_map.select {|k,v| k <= @first_mc_off }
|
60
|
-
src.values.sort.should eq(tgt)
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'should, for any measure offsets occurring after 1st meter change offset, add 1st_meter_change_offset * 1st_measure_duration to \
|
64
|
-
new_measure_duration * (offset - 1st_meter_change_offset)' do
|
65
|
-
moffs = @moffs.select{ |x| x > @first_mc_off }
|
66
|
-
tgt = moffs.map do |moff|
|
67
|
-
@first_mc_off * @start_meter.measure_duration + (moff - @first_mc_off) * @new_meter.measure_duration
|
68
|
-
end.sort
|
69
|
-
src = @mnoff_map.select {|k,v| k > @first_mc_off }
|
70
|
-
src.values.sort.should eq(tgt)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|