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
@@ -12,8 +12,8 @@ class ScoreDSL
|
|
12
12
|
@score = nil
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
@score = Score::
|
15
|
+
def tempo_score start_meter, start_tempo, &block
|
16
|
+
@score = Score::Tempo.new(start_meter,start_tempo)
|
17
17
|
@score.instance_eval(&block)
|
18
18
|
end
|
19
19
|
end
|
@@ -51,13 +51,14 @@ class Score
|
|
51
51
|
|
52
52
|
def dynamic_change new_dynamic, transition_dur: 0, offset: 0
|
53
53
|
if transition_dur == 0
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
change = (transition_dur == 0) ? Change::Immediate.new(new_tempo) : Change::Gradual.linear(new_tempo, transition_dur)
|
55
|
+
parts.values.each do |part|
|
56
|
+
part.tempo_changes[self.duration + offset] = change
|
57
|
+
end
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
60
|
-
class
|
61
|
+
class Tempo < Score
|
61
62
|
def tempo_change new_tempo, transition_dur: 0, offset: 0
|
62
63
|
if transition_dur == 0
|
63
64
|
tempo_changes[self.duration + offset] = Change::Immediate.new(new_tempo)
|
@@ -65,12 +66,14 @@ class Score
|
|
65
66
|
tempo_changes[self.duration + offset] = Change::Gradual.linear(new_tempo, transition_dur)
|
66
67
|
end
|
67
68
|
end
|
68
|
-
|
69
|
-
|
70
|
-
class Measured < Score::TempoBased
|
69
|
+
|
71
70
|
def meter_change new_meter, offset: 0
|
72
71
|
meter_changes[self.duration + offset] = Change::Immediate.new(new_meter)
|
73
72
|
end
|
73
|
+
|
74
|
+
def key_change new_key, offset: 0
|
75
|
+
key_changes[self.duration + offset] = Change::Immediate.new(new_key)
|
76
|
+
end
|
74
77
|
end
|
75
78
|
end
|
76
79
|
|
@@ -1,36 +1,19 @@
|
|
1
1
|
module Musicality
|
2
2
|
|
3
|
-
# Convert offsets in
|
3
|
+
# Convert offsets in measured note time to just plain time.
|
4
4
|
class NoteTimeConverter
|
5
5
|
# @param [ValueComputer] tempo_computer Given an offset, returns tempo
|
6
6
|
# value in quarter-notes-per-minute
|
7
7
|
# @param [Numeric] sample_rate Rate at which tempo values are sampled
|
8
8
|
# in the conversion (samples/sec).
|
9
|
-
def initialize sample_rate
|
9
|
+
def initialize tempo_computer, bdur_computer, sample_rate
|
10
|
+
@tempo_computer = tempo_computer
|
11
|
+
@bdur_computer = bdur_computer
|
10
12
|
@sample_period = Rational(1,sample_rate)
|
11
13
|
end
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
@tempo_computer = tempo_computer
|
16
|
-
super(sample_rate)
|
17
|
-
end
|
18
|
-
|
19
|
-
def notes_per_second_at offset
|
20
|
-
Tempo::QNPM.to_nps(@tempo_computer.at offset)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class Measured < NoteTimeConverter
|
25
|
-
def initialize tempo_computer, bdur_computer, sample_rate
|
26
|
-
@tempo_computer = tempo_computer
|
27
|
-
@bdur_computer = bdur_computer
|
28
|
-
super(sample_rate)
|
29
|
-
end
|
30
|
-
|
31
|
-
def notes_per_second_at offset
|
32
|
-
Tempo::BPM.to_nps(@tempo_computer.at(offset), @bdur_computer.at(offset))
|
33
|
-
end
|
15
|
+
def notes_per_second_at offset
|
16
|
+
Tempo::BPM.to_nps(@tempo_computer.at(offset), @bdur_computer.at(offset))
|
34
17
|
end
|
35
18
|
|
36
19
|
# Calculate the time elapsed between given start/end note offset. Using the
|
@@ -1,19 +1,11 @@
|
|
1
1
|
module Musicality
|
2
2
|
|
3
3
|
class Score
|
4
|
-
class
|
5
|
-
# Convert to timed score by converting measure-based offsets and note-based
|
6
|
-
# durations to time-based. This eliminates the use of tempos.
|
7
|
-
def to_timed tempo_sample_rate
|
8
|
-
ScoreConverter::Unmeasured.new(self, tempo_sample_rate).convert_score
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
class Measured < TempoBased
|
4
|
+
class Tempo < Score
|
13
5
|
# Convert to timed score by converting measure-based offsets and note-based
|
14
6
|
# durations to time-based. This eliminates the use of meters and tempos.
|
15
7
|
def to_timed tempo_sample_rate
|
16
|
-
ScoreConverter
|
8
|
+
ScoreConverter.new(self, tempo_sample_rate).convert_score
|
17
9
|
end
|
18
10
|
|
19
11
|
def measure_note_map
|
@@ -23,7 +15,7 @@ class Score
|
|
23
15
|
def measure_offsets
|
24
16
|
moffs = Set.new([0.to_r])
|
25
17
|
@tempo_changes.each {|moff,change| moffs += change.offsets(moff) }
|
26
|
-
@meter_changes.keys
|
18
|
+
moffs += @meter_changes.keys
|
27
19
|
@parts.values.each do |part|
|
28
20
|
part.dynamic_changes.each {|moff,change| moffs += change.offsets(moff) }
|
29
21
|
end
|
@@ -32,8 +24,12 @@ class Score
|
|
32
24
|
end
|
33
25
|
|
34
26
|
def beat_durations
|
35
|
-
bdurs = @meter_changes.map do |offset,
|
36
|
-
|
27
|
+
bdurs = @meter_changes.map do |offset,change_or_meter|
|
28
|
+
if change_or_meter.is_a? Meter
|
29
|
+
[ offset, change_or_meter.beat_duration ]
|
30
|
+
else
|
31
|
+
[ offset, change_or_meter.end_value.beat_duration ]
|
32
|
+
end
|
37
33
|
end.sort
|
38
34
|
|
39
35
|
if bdurs.empty? || bdurs[0][0] != 0
|
@@ -44,8 +40,12 @@ class Score
|
|
44
40
|
end
|
45
41
|
|
46
42
|
def measure_durations
|
47
|
-
mdurs = @meter_changes.map do |offset,
|
48
|
-
|
43
|
+
mdurs = @meter_changes.map do |offset,change_or_meter|
|
44
|
+
if change_or_meter.is_a? Meter
|
45
|
+
[ offset, change_or_meter.measure_duration ]
|
46
|
+
else
|
47
|
+
[ offset, change_or_meter.end_value.measure_duration ]
|
48
|
+
end
|
49
49
|
end.sort
|
50
50
|
|
51
51
|
if mdurs.empty? || mdurs[0][0] != 0
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Musicality
|
2
2
|
|
3
|
+
# Converts tempo-based score to timed score, by converting note-based offsets
|
4
|
+
# and durations to time-based, and eliminating the use of tempo and meters.
|
3
5
|
class ScoreConverter
|
4
6
|
def self.convert_changes changes, offset_map
|
5
7
|
Hash[ changes.map do |off,change|
|
@@ -14,13 +16,13 @@ class ScoreConverter
|
|
14
16
|
starttime = offset_map[offset]
|
15
17
|
endtime = offset_map[offset + note.duration]
|
16
18
|
offset += note.duration
|
17
|
-
|
18
|
-
newnote.duration = endtime - starttime
|
19
|
-
newnote
|
19
|
+
note.resize(endtime - starttime)
|
20
20
|
end
|
21
21
|
new_dcs = convert_changes(part.dynamic_changes, offset_map)
|
22
|
-
|
23
|
-
|
22
|
+
new_part = part.clone
|
23
|
+
new_part.notes = new_notes
|
24
|
+
new_part.dynamic_changes = new_dcs
|
25
|
+
[name, new_part]
|
24
26
|
end]
|
25
27
|
end
|
26
28
|
|
@@ -30,75 +32,56 @@ class ScoreConverter
|
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
@program = program
|
37
|
-
@note_time_map = note_time_converter.note_time_map(note_offsets)
|
38
|
-
end
|
39
|
-
|
40
|
-
def note_offsets
|
41
|
-
noffs = Set.new([0.to_r])
|
42
|
-
@parts.values.each do |part|
|
43
|
-
noff = 0.to_r
|
44
|
-
part.notes.each {|note| noffs.add(noff += note.duration) }
|
45
|
-
part.dynamic_changes.each {|noff2,change| noffs += change.offsets(noff2) }
|
46
|
-
end
|
47
|
-
noffs += @program.map {|seg| [seg.first, seg.last] }.flatten
|
48
|
-
return noffs.sort
|
35
|
+
def initialize score, tempo_sample_rate
|
36
|
+
if score.invalid?
|
37
|
+
raise NotValidError, "Errors detected given score: #{score.errors}"
|
49
38
|
end
|
39
|
+
mn_map = score.measure_note_map
|
40
|
+
new_parts = Hash[ score.parts.map do |name,part|
|
41
|
+
new_dcs = ScoreConverter.convert_changes(part.dynamic_changes, mn_map)
|
42
|
+
new_notes = part.notes.map {|n| n.clone } # note duration is already note-based
|
43
|
+
new_part = part.clone
|
44
|
+
new_part.notes = new_notes
|
45
|
+
new_part.dynamic_changes = new_dcs
|
46
|
+
[name, new_part]
|
47
|
+
end]
|
48
|
+
new_program = ScoreConverter.convert_program(score.program, mn_map)
|
49
|
+
new_tempo_changes = ScoreConverter.convert_changes(score.tempo_changes, mn_map)
|
50
|
+
new_beat_durations = Hash[ score.beat_durations.map do |moff,bdur|
|
51
|
+
[mn_map[moff], Change::Immediate.new(bdur) ]
|
52
|
+
end]
|
53
|
+
tempo_computer = ValueComputer.new(score.start_tempo, new_tempo_changes)
|
54
|
+
bdur_computer = ValueComputer.new(score.start_meter.beat_duration, new_beat_durations)
|
55
|
+
ntc = NoteTimeConverter.new(tempo_computer, bdur_computer, tempo_sample_rate)
|
50
56
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
# Convert note-based offsets & durations to time-based.
|
56
|
-
def convert_parts
|
57
|
-
ScoreConverter.convert_parts(@parts, @note_time_map)
|
58
|
-
end
|
59
|
-
|
60
|
-
# Convert note-based offsets & durations to time-based.
|
61
|
-
def convert_program
|
62
|
-
ScoreConverter.convert_program(@program, @note_time_map)
|
63
|
-
end
|
57
|
+
@parts = new_parts
|
58
|
+
@program = new_program
|
59
|
+
@note_time_map = ntc.note_time_map(note_offsets)
|
64
60
|
end
|
65
61
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
73
|
-
tempo_computer = ValueComputer.new(score.start_tempo, score.tempo_changes)
|
74
|
-
ntc = NoteTimeConverter::Unmeasured.new(tempo_computer, tempo_sample_rate)
|
75
|
-
super(score.parts, score.program, ntc)
|
62
|
+
def note_offsets
|
63
|
+
noffs = Set.new([0.to_r])
|
64
|
+
@parts.values.each do |part|
|
65
|
+
noff = 0.to_r
|
66
|
+
part.notes.each {|note| noffs.add(noff += note.duration) }
|
67
|
+
part.dynamic_changes.each {|noff2,change| noffs += change.offsets(noff2) }
|
76
68
|
end
|
69
|
+
noffs += @program.map {|seg| [seg.first, seg.last] }.flatten
|
70
|
+
return noffs.sort
|
71
|
+
end
|
72
|
+
|
73
|
+
def convert_score
|
74
|
+
Score::Timed.new(parts: convert_parts, program: convert_program)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Convert note-based offsets & durations to time-based.
|
78
|
+
def convert_parts
|
79
|
+
ScoreConverter.convert_parts(@parts, @note_time_map)
|
77
80
|
end
|
78
81
|
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
def initialize score, tempo_sample_rate
|
83
|
-
if score.invalid?
|
84
|
-
raise NotValidError, "Errors detected given score: #{score.errors}"
|
85
|
-
end
|
86
|
-
mn_map = score.measure_note_map
|
87
|
-
new_parts = Hash[ score.parts.map do |name,part|
|
88
|
-
new_dcs = ScoreConverter.convert_changes(part.dynamic_changes, mn_map)
|
89
|
-
new_notes = part.notes.map {|n| n.clone } # note duration is already note-based
|
90
|
-
[name, Part.new(part.start_dynamic, notes: new_notes, dynamic_changes: new_dcs)]
|
91
|
-
end]
|
92
|
-
new_program = ScoreConverter.convert_program(score.program, mn_map)
|
93
|
-
new_tempo_changes = ScoreConverter.convert_changes(score.tempo_changes, mn_map)
|
94
|
-
new_beat_durations = Hash[ score.beat_durations.map do |moff,bdur|
|
95
|
-
[mn_map[moff], Change::Immediate.new(bdur) ]
|
96
|
-
end]
|
97
|
-
tempo_computer = ValueComputer.new(score.start_tempo, new_tempo_changes)
|
98
|
-
bdur_computer = ValueComputer.new(score.start_meter.beat_duration, new_beat_durations)
|
99
|
-
ntc = NoteTimeConverter::Measured.new(tempo_computer, bdur_computer, tempo_sample_rate)
|
100
|
-
super(new_parts, new_program, ntc)
|
101
|
-
end
|
82
|
+
# Convert note-based offsets & durations to time-based.
|
83
|
+
def convert_program
|
84
|
+
ScoreConverter.convert_program(@program, @note_time_map)
|
102
85
|
end
|
103
86
|
end
|
104
87
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Musicality
|
2
2
|
|
3
3
|
class Change
|
4
|
+
include Packable
|
5
|
+
|
4
6
|
attr_reader :end_value
|
5
7
|
|
6
8
|
def initialize end_value
|
@@ -13,12 +15,12 @@ class Change
|
|
13
15
|
end
|
14
16
|
|
15
17
|
class Immediate < Change
|
16
|
-
def initialize
|
17
|
-
super(
|
18
|
+
def initialize end_value
|
19
|
+
super(end_value)
|
18
20
|
end
|
19
21
|
|
20
22
|
def clone
|
21
|
-
Immediate.new(@end_value)
|
23
|
+
Immediate.new(block_given? ? yield(@end_value) : @end_value)
|
22
24
|
end
|
23
25
|
|
24
26
|
def duration; 0; end
|
@@ -59,7 +61,12 @@ class Change
|
|
59
61
|
@start_value == other.start_value
|
60
62
|
end
|
61
63
|
|
62
|
-
def clone
|
64
|
+
def clone
|
65
|
+
ev = block_given? ? yield(@end_value) : @end_value
|
66
|
+
sv = (block_given? && !@start_value.nil?) ? yield(@start_value) : @start_value
|
67
|
+
Gradual.new(ev, @duration, @transition, start_value: sv)
|
68
|
+
end
|
69
|
+
|
63
70
|
def relative?; @start_value.nil?; end
|
64
71
|
def absolute?; !@start_value.nil?; end
|
65
72
|
|
@@ -102,8 +109,10 @@ class Change
|
|
102
109
|
end
|
103
110
|
|
104
111
|
def clone
|
105
|
-
|
106
|
-
|
112
|
+
ev = block_given? ? yield(@end_value) : @end_value
|
113
|
+
sv = (block_given? && !@start_value.nil?) ? yield(@start_value) : @start_value
|
114
|
+
Trimmed.new(ev, @duration, @transition, start_value: sv,
|
115
|
+
preceding: @preceding, remaining: @remaining)
|
107
116
|
end
|
108
117
|
end
|
109
118
|
|
@@ -1,12 +1,15 @@
|
|
1
1
|
module Musicality
|
2
2
|
module Dynamics
|
3
|
-
PPP = 0.
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
PPP = 0.05
|
4
|
+
FFF = 0.5
|
5
|
+
DYNAMIC_RATIO = (FFF/PPP)**(1.0/7.0) # 7 ratios between the 8 dynamic levels
|
6
|
+
|
7
|
+
PP = PPP*DYNAMIC_RATIO
|
8
|
+
P = PP*DYNAMIC_RATIO
|
9
|
+
MP = P*DYNAMIC_RATIO
|
10
|
+
MF = MP*DYNAMIC_RATIO
|
11
|
+
F = MF*DYNAMIC_RATIO
|
12
|
+
FF = F*DYNAMIC_RATIO
|
13
|
+
|
11
14
|
end
|
12
15
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Musicality
|
2
|
+
|
3
|
+
class Instrument
|
4
|
+
TREBLE = :treble
|
5
|
+
BASS = :bass
|
6
|
+
TENOR = :tenor
|
7
|
+
ALTO = :alto
|
8
|
+
CLEFS = [TREBLE, ALTO, BASS, TENOR]
|
9
|
+
|
10
|
+
DEFAULT_MIDI_OPT = :default
|
11
|
+
|
12
|
+
attr_accessor :name, :clefs, :midi_num, :transpose_interval
|
13
|
+
|
14
|
+
def initialize name, clefs, midi_num, transpose_interval = 0
|
15
|
+
@name = name
|
16
|
+
@clefs = clefs
|
17
|
+
@midi_num = midi_num
|
18
|
+
@transpose_interval = transpose_interval
|
19
|
+
end
|
20
|
+
|
21
|
+
def ==(other)
|
22
|
+
begin
|
23
|
+
return name == other.name &&
|
24
|
+
Set.new(clefs) == Set.new(other.clefs) &&
|
25
|
+
midi_num == other.midi_num &&
|
26
|
+
transpose_interval == other.transpose_interval
|
27
|
+
rescue # if other object doesn't have the right methods
|
28
|
+
return false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.treble name, midi_num, transpose_interval = 0
|
33
|
+
Instrument.new(name, [TREBLE], midi_num, transpose_interval)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.bass name, midi_num, transpose_interval = 0
|
37
|
+
Instrument.new(name, [BASS], midi_num, transpose_interval)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.treble_bass name, midi_num, transpose_interval = 0
|
41
|
+
Instrument.new(name, [TREBLE,BASS], midi_num, transpose_interval)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.treble_alto name, midi_num, transpose_interval = 0
|
45
|
+
Instrument.new(name, [TREBLE,ALTO], midi_num, transpose_interval)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.tenor_bass name, midi_num, transpose_interval = 0
|
49
|
+
Instrument.new(name, [TENOR, BASS], midi_num, transpose_interval)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.guitar name, midi_num
|
53
|
+
Instrument.new(name, [TENOR], midi_num, 12)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.bass_guitar name, midi_num
|
57
|
+
Instrument.new(name, [BASS], midi_num, 12)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|