music-performance 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/music-performance/arrangement/midi/midi_events.rb +30 -3
- data/lib/music-performance/arrangement/midi/part_sequencer.rb +18 -14
- data/lib/music-performance/conversion/score_collator.rb +0 -2
- data/lib/music-performance/version.rb +1 -1
- data/spec/conversion/score_collator_spec.rb +18 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0aee433423e514dcf3e7c43cf3e41bedb419773
|
4
|
+
data.tar.gz: 935623cdf53a375dbbe7931f4bbc06857144a3eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 377e4df3573ca96e8b9307f87d8a4dc1cb5aef5bc709c841137649e7c973764b050ac3c2b0777188898c3d663305ec45cf31685a6839a0190f10ead2e9e495b4
|
7
|
+
data.tar.gz: 136086c85244cbcc75168c7de393ceec0df3d1ec6266aff023b8b21876d37c9f07dbacd2cb0f0735319eb1a232139fcc5bbbe020c0156d53d44de9b409971cf0
|
@@ -1,9 +1,36 @@
|
|
1
1
|
module Music
|
2
2
|
module Performance
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
class MidiEvent
|
5
|
+
def <=> other
|
6
|
+
ORDERING[self] <=> ORDERING[other]
|
7
|
+
end
|
8
|
+
|
9
|
+
class NoteOn < MidiEvent
|
10
|
+
attr_reader :notenum, :accented
|
11
|
+
def initialize notenum, accented
|
12
|
+
@notenum, @accented = notenum, accented
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class NoteOff < MidiEvent
|
17
|
+
attr_reader :notenum
|
18
|
+
def initialize notenum
|
19
|
+
@notenum = notenum
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Expression < MidiEvent
|
24
|
+
attr_reader :volume
|
25
|
+
def initialize volume
|
26
|
+
@volume = volume
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
ORDERING = {
|
31
|
+
NoteOff => 0, Expression => 1, NoteOn => 2
|
32
|
+
}
|
33
|
+
end
|
7
34
|
|
8
35
|
end
|
9
36
|
end
|
@@ -3,6 +3,8 @@ module Performance
|
|
3
3
|
|
4
4
|
class PartSequencer
|
5
5
|
def initialize part, dynamics_sample_rate: 50, cents_per_step: 10
|
6
|
+
replace_portamento_with_glissando(part.notes)
|
7
|
+
|
6
8
|
extractor = NoteSequenceExtractor.new(part.notes, cents_per_step)
|
7
9
|
note_sequences = extractor.extract_sequences
|
8
10
|
note_events = gather_note_events(note_sequences)
|
@@ -10,7 +12,7 @@ class PartSequencer
|
|
10
12
|
dynamic_events = gather_dynamic_events(part.start_dynamic,
|
11
13
|
part.dynamic_changes, dynamics_sample_rate)
|
12
14
|
|
13
|
-
@events = (note_events + dynamic_events).
|
15
|
+
@events = (note_events + dynamic_events).sort
|
14
16
|
end
|
15
17
|
|
16
18
|
def make_midi_track midi_sequence, part_name, channel, ppqn
|
@@ -25,12 +27,12 @@ class PartSequencer
|
|
25
27
|
end
|
26
28
|
|
27
29
|
track.events << case event
|
28
|
-
when
|
30
|
+
when MidiEvent::NoteOn
|
29
31
|
vel = MidiUtil.note_velocity(event.accented)
|
30
32
|
MIDI::NoteOn.new(channel, event.notenum, vel, delta)
|
31
|
-
when
|
33
|
+
when MidiEvent::NoteOff
|
32
34
|
MIDI::NoteOff.new(channel, event.notenum, 127, delta)
|
33
|
-
when
|
35
|
+
when MidiEvent::Expression
|
34
36
|
MIDI::Controller.new(channel, MIDI::CC_EXPRESSION_CONTROLLER, event.volume, delta)
|
35
37
|
end
|
36
38
|
|
@@ -41,13 +43,15 @@ class PartSequencer
|
|
41
43
|
|
42
44
|
private
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
def replace_portamento_with_glissando notes
|
47
|
+
notes.each do |note|
|
48
|
+
note.links.each do |pitch,link|
|
49
|
+
if link.is_a? Music::Transcription::Link::Portamento
|
50
|
+
note.links[pitch] = Music::Transcription::Link::Glissando.new(link.target_pitch)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
51
55
|
|
52
56
|
def gather_note_events note_sequences
|
53
57
|
note_events = []
|
@@ -65,8 +69,8 @@ class PartSequencer
|
|
65
69
|
on_at = offset
|
66
70
|
off_at = (i < (pitches.size - 1)) ? pitches[i+1][0] : note_seq.stop
|
67
71
|
|
68
|
-
note_events.push [on_at,
|
69
|
-
note_events.push [off_at,
|
72
|
+
note_events.push [on_at, MidiEvent::NoteOn.new(note_num, accented)]
|
73
|
+
note_events.push [off_at, MidiEvent::NoteOff.new(note_num)]
|
70
74
|
end
|
71
75
|
end
|
72
76
|
return note_events
|
@@ -91,7 +95,7 @@ class PartSequencer
|
|
91
95
|
unless sample == prev
|
92
96
|
offset = Rational(i,sample_rate)
|
93
97
|
volume = MidiUtil.dynamic_to_volume(sample)
|
94
|
-
dynamic_events.push [offset,
|
98
|
+
dynamic_events.push [offset, MidiEvent::Expression.new(volume)]
|
95
99
|
end
|
96
100
|
prev = sample
|
97
101
|
end
|
@@ -82,6 +82,24 @@ describe ScoreCollator do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
85
|
+
|
86
|
+
it 'should preserve links' do
|
87
|
+
notes = Parsing::notes("1Db4~Bb4")
|
88
|
+
score = Score.new(
|
89
|
+
FOUR_FOUR,120,
|
90
|
+
parts: { "lead" => Part.new(Dynamics::MP, notes: notes) },
|
91
|
+
program: Program.new([0..1,0..1]),
|
92
|
+
)
|
93
|
+
collator = ScoreCollator.new(score)
|
94
|
+
parts = collator.collate_parts
|
95
|
+
|
96
|
+
notes = parts["lead"].notes
|
97
|
+
notes.size.should eq 2
|
98
|
+
notes.each do |note|
|
99
|
+
note.links.should have_key(Db4)
|
100
|
+
note.links[Db4].should be_a Link::Glissando
|
101
|
+
end
|
102
|
+
end
|
85
103
|
end
|
86
104
|
|
87
105
|
describe '#collate_tempo_changes' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: music-performance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.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: 2014-10-
|
11
|
+
date: 2014-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|