musicality 0.11.1 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.coveralls.yml +1 -0
- data/.ruby-version +1 -1
- data/.travis.yml +4 -0
- data/ChangeLog.md +11 -0
- data/README.md +3 -0
- data/Rakefile +11 -3
- data/lib/musicality/composition/model/rhythm.rb +33 -0
- data/lib/musicality/composition/model/rhythm_class.rb +30 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_kit.rb +18 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_machine.rb +59 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_parts.rb +21 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_pattern.rb +66 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_patterns/pop_drum_patterns.rb +146 -0
- data/lib/musicality/composition/sequencing/note_array.rb +33 -0
- data/lib/musicality/composition/sequencing/note_fifo.rb +73 -0
- data/lib/musicality/composition/sequencing/sequenceable.rb +9 -0
- data/lib/musicality/composition/sequencing/sequencer.rb +35 -0
- data/lib/musicality/errors.rb +2 -2
- data/lib/musicality/notation/model/dynamics.rb +2 -2
- data/lib/musicality/notation/model/key.rb +42 -91
- data/lib/musicality/notation/model/keys.rb +35 -34
- data/lib/musicality/notation/model/note.rb +31 -9
- data/lib/musicality/notation/model/pitch.rb +2 -2
- data/lib/musicality/notation/parsing/convenience_methods.rb +23 -12
- data/lib/musicality/notation/parsing/duration_parsing.rb +3 -3
- data/lib/musicality/notation/parsing/key_parsing.rb +150 -0
- data/lib/musicality/notation/parsing/key_parsing.treetop +37 -0
- data/lib/musicality/notation/parsing/meter_parsing.rb +3 -3
- data/lib/musicality/notation/parsing/numbers/nonnegative_float_parsing.rb +3 -1
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +1 -0
- data/lib/musicality/notation/parsing/numbers/nonnegative_rational_parsing.rb +1 -1
- data/lib/musicality/notation/parsing/numbers/positive_float_parsing.rb +4 -1
- data/lib/musicality/notation/parsing/numbers/positive_rational_parsing.rb +1 -1
- data/lib/musicality/notation/parsing/parseable.rb +13 -17
- data/lib/musicality/notation/parsing/pitch_parsing.rb +7 -0
- data/lib/musicality/notation/parsing/segment_parsing.rb +3 -0
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +82 -134
- data/lib/musicality/performance/model/note_sequence.rb +22 -3
- data/lib/musicality/performance/supercollider/performer.rb +2 -2
- data/lib/musicality/performance/supercollider/sc_drum_kits.rb +29 -0
- data/lib/musicality/performance/supercollider/synthdefs/bass.rb +211 -0
- data/lib/musicality/performance/supercollider/synthdefs/claps.rb +80 -0
- data/lib/musicality/performance/supercollider/synthdefs/cymbals.rb +57 -0
- data/lib/musicality/performance/supercollider/synthdefs/hihats.rb +67 -0
- data/lib/musicality/performance/supercollider/synthdefs/kicks.rb +158 -0
- data/lib/musicality/performance/supercollider/synthdefs/mario.rb +49 -0
- data/lib/musicality/performance/supercollider/{synthdefs.rb → synthdefs/other.rb} +0 -767
- data/lib/musicality/performance/supercollider/synthdefs/pianos.rb +46 -0
- data/lib/musicality/performance/supercollider/synthdefs/snares.rb +169 -0
- data/lib/musicality/performance/supercollider/synthdefs/toms.rb +25 -0
- data/lib/musicality/performance/supercollider/synthdefs/volume.rb +20 -0
- data/lib/musicality/pitch_class.rb +1 -1
- data/lib/musicality/pitch_classes.rb +3 -5
- data/lib/musicality/version.rb +1 -1
- data/lib/musicality.rb +25 -1
- data/musicality.gemspec +3 -2
- data/spec/composition/convenience_methods_spec.rb +8 -8
- data/spec/composition/generation/random_rhythm_generator_spec.rb +5 -5
- data/spec/composition/model/pitch_class_spec.rb +22 -16
- data/spec/composition/model/pitch_classes_spec.rb +5 -5
- data/spec/composition/model/rhythm_class_spec.rb +42 -0
- data/spec/composition/model/rhythm_spec.rb +43 -0
- data/spec/composition/model/scale_class_spec.rb +26 -26
- data/spec/composition/model/scale_spec.rb +38 -38
- data/spec/composition/sequencing/drum_machine/drum_machine_spec.rb +67 -0
- data/spec/composition/sequencing/drum_machine/drum_pattern_spec.rb +58 -0
- data/spec/composition/sequencing/note_array_spec.rb +94 -0
- data/spec/composition/sequencing/note_fifo_spec.rb +183 -0
- data/spec/composition/sequencing/sequencer_spec.rb +76 -0
- data/spec/composition/util/adding_sequence_spec.rb +33 -33
- data/spec/composition/util/compound_sequence_spec.rb +6 -6
- data/spec/composition/util/note_generation_spec.rb +34 -34
- data/spec/composition/util/probabilities_spec.rb +7 -7
- data/spec/composition/util/random_sampler_spec.rb +3 -3
- data/spec/composition/util/repeating_sequence_spec.rb +28 -28
- data/spec/musicality_spec.rb +1 -1
- data/spec/notation/conversion/change_conversion_spec.rb +87 -87
- data/spec/notation/conversion/note_time_converter_spec.rb +22 -22
- data/spec/notation/conversion/score_conversion_spec.rb +1 -1
- data/spec/notation/conversion/score_converter_spec.rb +31 -31
- data/spec/notation/conversion/tempo_conversion_spec.rb +11 -11
- data/spec/notation/model/change_spec.rb +80 -80
- data/spec/notation/model/key_spec.rb +135 -69
- data/spec/notation/model/link_spec.rb +27 -27
- data/spec/notation/model/meter_spec.rb +28 -28
- data/spec/notation/model/note_spec.rb +68 -47
- data/spec/notation/model/part_spec.rb +19 -19
- data/spec/notation/model/pitch_spec.rb +69 -68
- data/spec/notation/model/score_spec.rb +50 -47
- data/spec/notation/parsing/articulation_parsing_spec.rb +4 -4
- data/spec/notation/parsing/convenience_methods_spec.rb +49 -10
- data/spec/notation/parsing/duration_nodes_spec.rb +13 -13
- data/spec/notation/parsing/duration_parsing_spec.rb +10 -10
- data/spec/notation/parsing/key_parsing_spec.rb +19 -0
- data/spec/notation/parsing/link_nodes_spec.rb +7 -7
- data/spec/notation/parsing/link_parsing_spec.rb +4 -4
- data/spec/notation/parsing/meter_parsing_spec.rb +5 -5
- data/spec/notation/parsing/note_node_spec.rb +19 -19
- data/spec/notation/parsing/note_parsing_spec.rb +4 -4
- data/spec/notation/parsing/numbers/nonnegative_float_spec.rb +8 -8
- data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +2 -2
- data/spec/notation/parsing/numbers/nonnegative_rational_spec.rb +1 -1
- data/spec/notation/parsing/numbers/positive_float_spec.rb +8 -8
- data/spec/notation/parsing/numbers/positive_integer_spec.rb +6 -6
- data/spec/notation/parsing/numbers/positive_rational_spec.rb +6 -6
- data/spec/notation/parsing/pitch_node_spec.rb +7 -7
- data/spec/notation/parsing/pitch_parsing_spec.rb +2 -2
- data/spec/notation/parsing/segment_parsing_spec.rb +3 -3
- data/spec/notation/util/function_spec.rb +15 -15
- data/spec/notation/util/transition_spec.rb +12 -12
- data/spec/notation/util/value_computer_spec.rb +35 -36
- data/spec/performance/conversion/glissando_converter_spec.rb +24 -24
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +39 -39
- data/spec/performance/conversion/portamento_converter_spec.rb +23 -23
- data/spec/performance/midi/midi_util_spec.rb +41 -41
- data/spec/performance/midi/part_sequencer_spec.rb +10 -10
- data/spec/performance/midi/score_sequencer_spec.rb +15 -15
- data/spec/performance/midi/score_sequencing_spec.rb +2 -2
- data/spec/performance/util/optimization_spec.rb +9 -9
- data/spec/printing/note_engraving_spec.rb +16 -16
- data/spec/printing/score_engraver_spec.rb +5 -5
- data/spec/spec_helper.rb +5 -0
- metadata +85 -30
@@ -2,27 +2,28 @@ module Musicality
|
|
2
2
|
|
3
3
|
class Key
|
4
4
|
include Packable
|
5
|
-
|
5
|
+
|
6
6
|
FLAT = :flat
|
7
7
|
SHARP = :sharp
|
8
|
-
|
9
|
-
|
8
|
+
NONE = :none
|
9
|
+
ACCIDENTAL_TYPES = [FLAT, SHARP, NONE]
|
10
|
+
|
10
11
|
MAJOR = :major
|
11
12
|
MINOR = :minor
|
12
13
|
TRIAD_TYPES = [MAJOR, MINOR]
|
13
|
-
|
14
|
-
|
14
|
+
|
15
|
+
TONIC_PCS = {
|
15
16
|
MAJOR => {
|
16
17
|
FLAT => [PitchClasses::F, PitchClasses::Bb, PitchClasses::Eb,
|
17
|
-
PitchClasses::Ab, PitchClasses::Db, PitchClasses::Gb
|
18
|
+
PitchClasses::Ab, PitchClasses::Db, PitchClasses::Gb],
|
18
19
|
SHARP => [PitchClasses::G,PitchClasses::D,PitchClasses::A,
|
19
|
-
PitchClasses::E,PitchClasses::B
|
20
|
+
PitchClasses::E,PitchClasses::B]
|
20
21
|
},
|
21
22
|
MINOR => {
|
22
23
|
FLAT => [PitchClasses::D,PitchClasses::G,PitchClasses::C,
|
23
|
-
PitchClasses::F,PitchClasses::Bb,PitchClasses::Eb
|
24
|
+
PitchClasses::F,PitchClasses::Bb,PitchClasses::Eb],
|
24
25
|
SHARP => [PitchClasses::E,PitchClasses::B,PitchClasses::Fs,
|
25
|
-
PitchClasses::Cs,PitchClasses::Gs
|
26
|
+
PitchClasses::Cs,PitchClasses::Gs]
|
26
27
|
}
|
27
28
|
}
|
28
29
|
|
@@ -33,105 +34,55 @@ class Key
|
|
33
34
|
PitchClasses::Ds,PitchClasses::As,PitchClasses::Es,PitchClasses::Bs]
|
34
35
|
}
|
35
36
|
|
36
|
-
attr_reader :tonic_pc, :
|
37
|
-
|
38
|
-
def initialize tonic_pc, triad: MAJOR, accidental_pref: FLAT
|
39
|
-
self.tonic_pc = tonic_pc
|
40
|
-
self.triad = triad
|
41
|
-
self.accidental_pref = accidental_pref
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.major_flat tonic_pc
|
45
|
-
Key.new(tonic_pc, triad: MAJOR, accidental_pref: FLAT)
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.major_sharp tonic_pc
|
49
|
-
Key.new(tonic_pc, triad: MAJOR, accidental_pref: SHARP)
|
50
|
-
end
|
51
|
-
|
52
|
-
def self.minor_flat tonic_pc
|
53
|
-
Key.new(tonic_pc, triad: MINOR, accidental_pref: FLAT)
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.minor_sharp tonic_pc
|
57
|
-
Key.new(tonic_pc, triad: MINOR, accidental_pref: SHARP)
|
58
|
-
end
|
59
|
-
|
60
|
-
def major?; @triad == MAJOR; end
|
61
|
-
def minor?; @triad == MINOR; end
|
62
|
-
|
63
|
-
def flat?; accidental_type == FLAT; end
|
64
|
-
def sharp?; accidental_type == SHARP; end
|
65
|
-
|
66
|
-
def accidental_free?
|
67
|
-
(major? && @tonic_pc == PitchClasses::C) || (minor? && @tonic_pc == PitchClasses::A)
|
68
|
-
end
|
37
|
+
attr_reader :tonic_pc, :triad_type, :accidentals, :accidental_type
|
69
38
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
|
39
|
+
def initialize tonic_pc, triad_type: MAJOR
|
40
|
+
raise ArgumentError, "Unknown triad type #{triad_type}" unless TRIAD_TYPES.include?(triad_type)
|
41
|
+
@triad_type = triad_type
|
42
|
+
@tonic_pc = PitchClass.from_i(tonic_pc)
|
43
|
+
|
44
|
+
if (@triad_type == MAJOR && @tonic_pc == PitchClasses::C) ||
|
45
|
+
(@triad_type == MINOR && @tonic_pc == PitchClasses::A)
|
46
|
+
@accidentals = []
|
47
|
+
@accidental_type = NONE
|
48
|
+
else
|
49
|
+
if TONIC_PCS[@triad_type][FLAT].include?(@tonic_pc)
|
50
|
+
@accidental_type = FLAT
|
51
|
+
elsif TONIC_PCS[@triad_type][SHARP].include?(@tonic_pc)
|
52
|
+
@accidental_type = SHARP
|
53
|
+
else
|
54
|
+
raise ArgumentError, "unknown tonic PC #{@tonic_pc}"
|
74
55
|
end
|
75
|
-
|
76
|
-
|
56
|
+
i = TONIC_PCS[@triad_type][@accidental_type].index(@tonic_pc)
|
57
|
+
@accidentals = ACCIDENTALS[@accidental_type][0..i]
|
77
58
|
end
|
78
59
|
end
|
79
60
|
|
80
|
-
def
|
81
|
-
|
82
|
-
unless ACCIDENTAL_TYPES.include? accidental_pref
|
83
|
-
raise ArgumentError, "Accidental type #{accidental_pref} is not supported"
|
84
|
-
end
|
85
|
-
@accidental_pref = accidental_pref
|
86
|
-
reset_accidentals
|
87
|
-
end
|
61
|
+
def self.major tonic_pc
|
62
|
+
Key.new(tonic_pc, triad_type: MAJOR)
|
88
63
|
end
|
89
64
|
|
90
|
-
def
|
91
|
-
|
92
|
-
@tonic_pc = PitchClass.from_i(tonic_pc)
|
93
|
-
reset_accidentals
|
94
|
-
end
|
65
|
+
def self.minor tonic_pc
|
66
|
+
Key.new(tonic_pc, triad_type: MINOR)
|
95
67
|
end
|
96
|
-
|
68
|
+
|
69
|
+
def major?; @triad_type == MAJOR; end
|
70
|
+
def minor?; @triad_type == MINOR; end
|
71
|
+
|
72
|
+
def flat?; @accidental_type == FLAT; end
|
73
|
+
def sharp?; @accidental_type == SHARP; end
|
74
|
+
|
97
75
|
def ==(other)
|
98
|
-
return @tonic_pc == other.tonic_pc && @
|
99
|
-
@accidental_pref == other.accidental_pref
|
76
|
+
return @tonic_pc == other.tonic_pc && @triad_type == other.triad_type
|
100
77
|
end
|
101
78
|
|
102
79
|
def clone
|
103
80
|
Marshal.load(Marshal.dump(self))
|
104
81
|
end
|
105
|
-
|
106
|
-
def accidentals
|
107
|
-
unless @accidentals
|
108
|
-
@accidentals = []
|
109
|
-
unless accidental_free?
|
110
|
-
acc_type = accidental_type
|
111
|
-
idx = TONICS[@triad][acc_type].index(@tonic_pc)
|
112
|
-
@accidentals = ACCIDENTALS[acc_type].take(idx+1)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
return @accidentals
|
116
|
-
end
|
117
|
-
|
118
|
-
def accidental_type
|
119
|
-
if accidental_free? || TONICS[@triad][@accidental_pref].include?(@tonic_pc)
|
120
|
-
@accidental_pref
|
121
|
-
else
|
122
|
-
(@accidental_pref == FLAT) ? SHARP : FLAT
|
123
|
-
end
|
124
|
-
end
|
125
82
|
|
126
83
|
def transpose interval
|
127
|
-
|
128
|
-
new_key.tonic_pc += interval
|
129
|
-
return new_key
|
84
|
+
Key.new(PitchClass.from_i(@tonic_pc+interval), @triad_type)
|
130
85
|
end
|
131
|
-
|
132
|
-
private
|
133
|
-
|
134
|
-
def reset_accidentals; @accidentals = nil; end
|
135
86
|
end
|
136
87
|
|
137
88
|
end
|
@@ -1,37 +1,38 @@
|
|
1
1
|
module Musicality
|
2
2
|
module Keys
|
3
|
-
C_MAJOR = Key.
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
A_MINOR = Key.
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
3
|
+
C_MAJOR = Key.major(PitchClasses::C)
|
4
|
+
|
5
|
+
# Major keys with sharps
|
6
|
+
G_MAJOR = Key.major(PitchClasses::G)
|
7
|
+
D_MAJOR = Key.major(PitchClasses::D)
|
8
|
+
A_MAJOR = Key.major(PitchClasses::A)
|
9
|
+
E_MAJOR = Key.major(PitchClasses::E)
|
10
|
+
B_MAJOR = Key.major(PitchClasses::B)
|
11
|
+
|
12
|
+
# Major keys with flats
|
13
|
+
F_MAJOR = Key.major(PitchClasses::F)
|
14
|
+
Bb_MAJOR = Key.major(PitchClasses::Bb)
|
15
|
+
Eb_MAJOR = Key.major(PitchClasses::Eb)
|
16
|
+
Ab_MAJOR = Key.major(PitchClasses::Ab)
|
17
|
+
Db_MAJOR = Key.major(PitchClasses::Db)
|
18
|
+
Gb_MAJOR = Key.major(PitchClasses::Gb)
|
19
|
+
|
20
|
+
A_MINOR = Key.minor(PitchClasses::A)
|
21
|
+
|
22
|
+
# Minor keys with sharps
|
23
|
+
E_MINOR = Key.minor(PitchClasses::E)
|
24
|
+
B_MINOR = Key.minor(PitchClasses::B)
|
25
|
+
Fs_MINOR = Key.minor(PitchClasses::Fs)
|
26
|
+
Cs_MINOR = Key.minor(PitchClasses::Cs)
|
27
|
+
Gs_MINOR = Key.minor(PitchClasses::Gs)
|
28
|
+
|
29
|
+
# Minor keys with flats
|
30
|
+
D_MINOR = Key.minor(PitchClasses::D)
|
31
|
+
G_MINOR = Key.minor(PitchClasses::G)
|
32
|
+
C_MINOR = Key.minor(PitchClasses::C)
|
33
|
+
F_MINOR = Key.minor(PitchClasses::F)
|
34
|
+
Bb_MINOR = Key.minor(PitchClasses::Bb)
|
35
|
+
Eb_MINOR = Key.minor(PitchClasses::Eb)
|
36
|
+
end
|
37
|
+
|
36
38
|
end
|
37
|
-
end
|
@@ -5,10 +5,10 @@ require 'set'
|
|
5
5
|
class Note
|
6
6
|
include Packable
|
7
7
|
include Validatable
|
8
|
-
|
8
|
+
|
9
9
|
attr_reader :pitches, :links, :duration, :marks
|
10
10
|
attr_accessor :articulation
|
11
|
-
|
11
|
+
|
12
12
|
def initialize duration, pitches = [], links: {}, articulation: Articulations::NORMAL, marks: []
|
13
13
|
self.duration = duration
|
14
14
|
if !pitches.is_a? Enumerable
|
@@ -19,18 +19,24 @@ class Note
|
|
19
19
|
@articulation = articulation
|
20
20
|
@marks = marks
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def check_methods
|
24
|
-
[ :check_pitches ]
|
24
|
+
[ :check_duration, :check_pitches ]
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_duration
|
28
|
+
if duration <= 0
|
29
|
+
raise RangeError, "Duration is non-positive: #{duration}"
|
30
|
+
end
|
25
31
|
end
|
26
|
-
|
32
|
+
|
27
33
|
def check_pitches
|
28
34
|
non_pitches = @pitches.select {|p| !p.is_a?(Pitch) }
|
29
35
|
if non_pitches.any?
|
30
36
|
raise TypeError, "Found non-pitches: #{non_pitches}"
|
31
37
|
end
|
32
38
|
end
|
33
|
-
|
39
|
+
|
34
40
|
def == other
|
35
41
|
return (@duration == other.duration) &&
|
36
42
|
(self.pitches == other.pitches) &&
|
@@ -38,7 +44,7 @@ class Note
|
|
38
44
|
(@articulation == other.articulation) &&
|
39
45
|
(@marks == marks)
|
40
46
|
end
|
41
|
-
|
47
|
+
|
42
48
|
def clone
|
43
49
|
Marshal.load(Marshal.dump(self))
|
44
50
|
end
|
@@ -55,10 +61,26 @@ class Note
|
|
55
61
|
return new_note
|
56
62
|
end
|
57
63
|
|
64
|
+
def tie_to pitches
|
65
|
+
new_note = self.clone
|
66
|
+
if pitches.is_a? Pitch
|
67
|
+
pitches = [pitches]
|
68
|
+
end
|
69
|
+
|
70
|
+
pitches.each do |pitch|
|
71
|
+
new_note.links[pitch] = Link::Tie.new
|
72
|
+
end
|
73
|
+
return new_note
|
74
|
+
end
|
75
|
+
|
76
|
+
def mark_accented!
|
77
|
+
@articulation = Articulations::ACCENT
|
78
|
+
end
|
79
|
+
|
58
80
|
def transpose diff
|
59
81
|
self.clone.transpose! diff
|
60
82
|
end
|
61
|
-
|
83
|
+
|
62
84
|
def transpose! diff
|
63
85
|
@pitches = @pitches.map {|pitch| pitch.transpose(diff) }
|
64
86
|
@links = Hash[ @links.map do |k,v|
|
@@ -106,7 +128,7 @@ class Note
|
|
106
128
|
Note.new(dur, pitches, articulation: articulation, links: links, marks: marks)
|
107
129
|
end
|
108
130
|
end
|
109
|
-
|
131
|
+
|
110
132
|
{
|
111
133
|
:sixteenth => Rational(1,16),
|
112
134
|
:dotted_sixteenth => Rational(3,32),
|
@@ -13,9 +13,9 @@ module Musicality
|
|
13
13
|
# @author James Tunnell
|
14
14
|
#
|
15
15
|
# @!attribute [r] octave
|
16
|
-
# @return [
|
16
|
+
# @return [Integer] The pitch octave.
|
17
17
|
# @!attribute [r] semitone
|
18
|
-
# @return [
|
18
|
+
# @return [Integer] The pitch semitone.
|
19
19
|
#
|
20
20
|
class Pitch
|
21
21
|
include Comparable
|
@@ -5,13 +5,19 @@ module Musicality
|
|
5
5
|
CONVERSION_METHOD = :to_r
|
6
6
|
include Parseable
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
class Pitch
|
10
10
|
PARSER = Parsing::PitchParser.new
|
11
11
|
CONVERSION_METHOD = :to_pitch
|
12
12
|
include Parseable
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
|
+
class Key
|
16
|
+
PARSER = Parsing::KeyParser.new
|
17
|
+
CONVERSION_METHOD = :to_key
|
18
|
+
include Parseable
|
19
|
+
end
|
20
|
+
|
15
21
|
class Note
|
16
22
|
PARSER = Parsing::NoteParser.new
|
17
23
|
CONVERSION_METHOD = :to_note
|
@@ -23,7 +29,7 @@ module Musicality
|
|
23
29
|
CONVERSION_METHOD = :to_meter
|
24
30
|
include Parseable
|
25
31
|
end
|
26
|
-
|
32
|
+
|
27
33
|
class Segment
|
28
34
|
PARSER = Parsing::SegmentParser.new
|
29
35
|
CONVERSION_METHOD = :to_range
|
@@ -37,38 +43,43 @@ class String
|
|
37
43
|
end
|
38
44
|
alias :to_dur :to_duration
|
39
45
|
alias :to_d :to_duration
|
40
|
-
|
46
|
+
|
41
47
|
def to_durations pattern=" "
|
42
48
|
Musicality::Duration.split_parse(self, pattern)
|
43
49
|
end
|
44
50
|
alias :to_durs :to_durations
|
45
51
|
alias :to_ds :to_durations
|
46
|
-
|
47
|
-
def to_pitch
|
52
|
+
|
53
|
+
def to_pitch
|
48
54
|
Musicality::Pitch.parse(self)
|
49
55
|
end
|
50
56
|
alias :to_p :to_pitch
|
51
|
-
|
57
|
+
|
52
58
|
def to_pitches pattern=" "
|
53
59
|
Musicality::Pitch.split_parse(self, pattern)
|
54
60
|
end
|
55
61
|
alias :to_ps :to_pitches
|
56
|
-
|
62
|
+
|
63
|
+
def to_key
|
64
|
+
Musicality::Key.parse(self)
|
65
|
+
end
|
66
|
+
alias :to_k :to_key
|
67
|
+
|
57
68
|
def to_note
|
58
69
|
Musicality::Note.parse(self)
|
59
70
|
end
|
60
71
|
alias :to_n :to_note
|
61
|
-
|
72
|
+
|
62
73
|
def to_notes pattern=" "
|
63
74
|
Musicality::Note.split_parse(self, pattern)
|
64
75
|
end
|
65
76
|
alias :to_ns :to_notes
|
66
|
-
|
77
|
+
|
67
78
|
def to_meter
|
68
79
|
Musicality::Meter.parse(self)
|
69
80
|
end
|
70
|
-
|
81
|
+
|
71
82
|
def to_segment
|
72
83
|
Musicality::Segment.parse(self)
|
73
84
|
end
|
74
|
-
end
|
85
|
+
end
|
@@ -80,7 +80,7 @@ module Duration
|
|
80
80
|
r2 = true
|
81
81
|
@index += match_len
|
82
82
|
else
|
83
|
-
terminal_parse_failure("/")
|
83
|
+
terminal_parse_failure('"/"')
|
84
84
|
r2 = nil
|
85
85
|
end
|
86
86
|
s0 << r2
|
@@ -128,7 +128,7 @@ module Duration
|
|
128
128
|
r3 = true
|
129
129
|
@index += match_len
|
130
130
|
else
|
131
|
-
terminal_parse_failure("/")
|
131
|
+
terminal_parse_failure('"/"')
|
132
132
|
r3 = nil
|
133
133
|
end
|
134
134
|
if r3
|
@@ -173,7 +173,7 @@ module Duration
|
|
173
173
|
r1 = true
|
174
174
|
@index += match_len
|
175
175
|
else
|
176
|
-
terminal_parse_failure("/")
|
176
|
+
terminal_parse_failure('"/"')
|
177
177
|
r1 = nil
|
178
178
|
end
|
179
179
|
s0 << r1
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# Autogenerated from a Treetop grammar. Edits may be lost.
|
2
|
+
|
3
|
+
|
4
|
+
module Musicality
|
5
|
+
module Parsing
|
6
|
+
|
7
|
+
module Key
|
8
|
+
include Treetop::Runtime
|
9
|
+
|
10
|
+
def root
|
11
|
+
@root ||= :key
|
12
|
+
end
|
13
|
+
|
14
|
+
include Pitch
|
15
|
+
|
16
|
+
module Key0
|
17
|
+
def pitch_letter
|
18
|
+
elements[0]
|
19
|
+
end
|
20
|
+
|
21
|
+
def mod
|
22
|
+
elements[1]
|
23
|
+
end
|
24
|
+
|
25
|
+
def major_minor
|
26
|
+
elements[2]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Key1
|
31
|
+
def to_key
|
32
|
+
sem = pitch_letter.to_semitone
|
33
|
+
modval = 0
|
34
|
+
if !mod.empty?
|
35
|
+
modval = case mod.text_value
|
36
|
+
when "#" then 1
|
37
|
+
when "b" then -1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
triad_type = if major_minor.text_value.include?("maj")
|
42
|
+
Musicality::Key::MAJOR
|
43
|
+
else
|
44
|
+
Musicality::Key::MINOR
|
45
|
+
end
|
46
|
+
|
47
|
+
return Musicality::Key.new(sem + modval, triad_type: triad_type)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def _nt_key
|
52
|
+
start_index = index
|
53
|
+
if node_cache[:key].has_key?(index)
|
54
|
+
cached = node_cache[:key][index]
|
55
|
+
if cached
|
56
|
+
node_cache[:key][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
57
|
+
@index = cached.interval.end
|
58
|
+
end
|
59
|
+
return cached
|
60
|
+
end
|
61
|
+
|
62
|
+
i0, s0 = index, []
|
63
|
+
r1 = _nt_pitch_letter
|
64
|
+
s0 << r1
|
65
|
+
if r1
|
66
|
+
if has_terminal?(@regexps[gr = '\A[#b]'] ||= Regexp.new(gr), :regexp, index)
|
67
|
+
r3 = true
|
68
|
+
@index += 1
|
69
|
+
else
|
70
|
+
terminal_parse_failure('[#b]')
|
71
|
+
r3 = nil
|
72
|
+
end
|
73
|
+
if r3
|
74
|
+
r2 = r3
|
75
|
+
else
|
76
|
+
r2 = instantiate_node(SyntaxNode,input, index...index)
|
77
|
+
end
|
78
|
+
s0 << r2
|
79
|
+
if r2
|
80
|
+
r4 = _nt_major_minor
|
81
|
+
s0 << r4
|
82
|
+
end
|
83
|
+
end
|
84
|
+
if s0.last
|
85
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
86
|
+
r0.extend(Key0)
|
87
|
+
r0.extend(Key1)
|
88
|
+
else
|
89
|
+
@index = i0
|
90
|
+
r0 = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
node_cache[:key][start_index] = r0
|
94
|
+
|
95
|
+
r0
|
96
|
+
end
|
97
|
+
|
98
|
+
def _nt_major_minor
|
99
|
+
start_index = index
|
100
|
+
if node_cache[:major_minor].has_key?(index)
|
101
|
+
cached = node_cache[:major_minor][index]
|
102
|
+
if cached
|
103
|
+
node_cache[:major_minor][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
104
|
+
@index = cached.interval.end
|
105
|
+
end
|
106
|
+
return cached
|
107
|
+
end
|
108
|
+
|
109
|
+
i0 = index
|
110
|
+
if (match_len = has_terminal?("maj", false, index))
|
111
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + match_len))
|
112
|
+
@index += match_len
|
113
|
+
else
|
114
|
+
terminal_parse_failure('"maj"')
|
115
|
+
r1 = nil
|
116
|
+
end
|
117
|
+
if r1
|
118
|
+
r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
|
119
|
+
r0 = r1
|
120
|
+
else
|
121
|
+
if (match_len = has_terminal?("min", false, index))
|
122
|
+
r2 = instantiate_node(SyntaxNode,input, index...(index + match_len))
|
123
|
+
@index += match_len
|
124
|
+
else
|
125
|
+
terminal_parse_failure('"min"')
|
126
|
+
r2 = nil
|
127
|
+
end
|
128
|
+
if r2
|
129
|
+
r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
|
130
|
+
r0 = r2
|
131
|
+
else
|
132
|
+
@index = i0
|
133
|
+
r0 = nil
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
node_cache[:major_minor][start_index] = r0
|
138
|
+
|
139
|
+
r0
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
class KeyParser < Treetop::Runtime::CompiledParser
|
145
|
+
include Key
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Musicality
|
2
|
+
module Parsing
|
3
|
+
|
4
|
+
grammar Key
|
5
|
+
include Pitch
|
6
|
+
|
7
|
+
rule key
|
8
|
+
pitch_letter mod:[#b]? major_minor {
|
9
|
+
def to_key
|
10
|
+
sem = pitch_letter.to_semitone
|
11
|
+
modval = 0
|
12
|
+
if !mod.empty?
|
13
|
+
modval = case mod.text_value
|
14
|
+
when "#" then 1
|
15
|
+
when "b" then -1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
triad_type = if major_minor.text_value.include?("maj")
|
20
|
+
Musicality::Key::MAJOR
|
21
|
+
else
|
22
|
+
Musicality::Key::MINOR
|
23
|
+
end
|
24
|
+
|
25
|
+
return Musicality::Key.new(sem + modval, triad_type: triad_type)
|
26
|
+
end
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
rule major_minor
|
31
|
+
"maj" / "min"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -80,7 +80,7 @@ module Meter
|
|
80
80
|
r2 = true
|
81
81
|
@index += match_len
|
82
82
|
else
|
83
|
-
terminal_parse_failure("/")
|
83
|
+
terminal_parse_failure('"/"')
|
84
84
|
r2 = nil
|
85
85
|
end
|
86
86
|
s0 << r2
|
@@ -142,7 +142,7 @@ module Meter
|
|
142
142
|
r2 = true
|
143
143
|
@index += match_len
|
144
144
|
else
|
145
|
-
terminal_parse_failure("*")
|
145
|
+
terminal_parse_failure('"*"')
|
146
146
|
r2 = nil
|
147
147
|
end
|
148
148
|
s0 << r2
|
@@ -154,7 +154,7 @@ module Meter
|
|
154
154
|
r4 = true
|
155
155
|
@index += match_len
|
156
156
|
else
|
157
|
-
terminal_parse_failure("/")
|
157
|
+
terminal_parse_failure('"/"')
|
158
158
|
r4 = nil
|
159
159
|
end
|
160
160
|
s0 << r4
|
@@ -36,12 +36,14 @@ module NonnegativeFloat
|
|
36
36
|
r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
|
37
37
|
r0 = r1
|
38
38
|
r0.extend(NonnegativeFloat0)
|
39
|
+
r0.extend(NonnegativeFloat0)
|
39
40
|
else
|
40
41
|
r2 = _nt_float2
|
41
42
|
if r2
|
42
43
|
r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
|
43
44
|
r0 = r2
|
44
45
|
r0.extend(NonnegativeFloat0)
|
46
|
+
r0.extend(NonnegativeFloat0)
|
45
47
|
else
|
46
48
|
@index = i0
|
47
49
|
r0 = nil
|
@@ -222,7 +224,7 @@ module NonnegativeFloat
|
|
222
224
|
r1 = true
|
223
225
|
@index += match_len
|
224
226
|
else
|
225
|
-
terminal_parse_failure("e")
|
227
|
+
terminal_parse_failure('"e"')
|
226
228
|
r1 = nil
|
227
229
|
end
|
228
230
|
s0 << r1
|