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.
- 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
|