mtk 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. data/.yardopts +3 -2
  2. data/DEVELOPMENT_NOTES.md +114 -0
  3. data/INTRO.md +64 -8
  4. data/LICENSE.txt +1 -1
  5. data/README.md +31 -102
  6. data/Rakefile +56 -18
  7. data/bin/mtk +215 -0
  8. data/examples/crescendo.rb +5 -5
  9. data/examples/drum_pattern1.rb +23 -0
  10. data/examples/dynamic_pattern.rb +8 -11
  11. data/examples/gets_and_play.rb +26 -0
  12. data/examples/notation.rb +22 -0
  13. data/examples/play_midi.rb +8 -10
  14. data/examples/random_tone_row.rb +2 -2
  15. data/examples/syntax_to_midi.rb +28 -0
  16. data/examples/test_output.rb +8 -0
  17. data/examples/tone_row_melody.rb +6 -6
  18. data/lib/mtk.rb +52 -40
  19. data/lib/mtk/chord.rb +55 -0
  20. data/lib/mtk/constants/durations.rb +57 -0
  21. data/lib/mtk/constants/intensities.rb +61 -0
  22. data/lib/mtk/constants/intervals.rb +73 -0
  23. data/lib/mtk/constants/pitch_classes.rb +29 -0
  24. data/lib/mtk/constants/pitches.rb +52 -0
  25. data/lib/mtk/duration.rb +211 -0
  26. data/lib/mtk/events/event.rb +119 -0
  27. data/lib/mtk/events/note.rb +112 -0
  28. data/lib/mtk/events/parameter.rb +54 -0
  29. data/lib/mtk/helpers/collection.rb +164 -0
  30. data/lib/mtk/helpers/convert.rb +36 -0
  31. data/lib/mtk/helpers/lilypond.rb +162 -0
  32. data/lib/mtk/helpers/output_selector.rb +67 -0
  33. data/lib/mtk/helpers/pitch_collection.rb +23 -0
  34. data/lib/mtk/helpers/pseudo_constants.rb +26 -0
  35. data/lib/mtk/intensity.rb +156 -0
  36. data/lib/mtk/interval.rb +155 -0
  37. data/lib/mtk/lang/mtk_grammar.citrus +190 -13
  38. data/lib/mtk/lang/parser.rb +29 -0
  39. data/lib/mtk/melody.rb +94 -0
  40. data/lib/mtk/midi/dls_synth_device.rb +144 -0
  41. data/lib/mtk/midi/dls_synth_output.rb +62 -0
  42. data/lib/mtk/midi/file.rb +67 -32
  43. data/lib/mtk/midi/input.rb +97 -0
  44. data/lib/mtk/midi/jsound_input.rb +36 -17
  45. data/lib/mtk/midi/jsound_output.rb +48 -46
  46. data/lib/mtk/midi/output.rb +195 -0
  47. data/lib/mtk/midi/unimidi_input.rb +117 -0
  48. data/lib/mtk/midi/unimidi_output.rb +121 -0
  49. data/lib/mtk/{_numeric_extensions.rb → numeric_extensions.rb} +12 -0
  50. data/lib/mtk/patterns/chain.rb +49 -0
  51. data/lib/mtk/{pattern → patterns}/choice.rb +14 -8
  52. data/lib/mtk/patterns/cycle.rb +18 -0
  53. data/lib/mtk/patterns/for_each.rb +71 -0
  54. data/lib/mtk/patterns/function.rb +39 -0
  55. data/lib/mtk/{pattern → patterns}/lines.rb +11 -17
  56. data/lib/mtk/{pattern → patterns}/palindrome.rb +11 -8
  57. data/lib/mtk/patterns/pattern.rb +171 -0
  58. data/lib/mtk/patterns/sequence.rb +20 -0
  59. data/lib/mtk/pitch.rb +7 -6
  60. data/lib/mtk/pitch_class.rb +124 -46
  61. data/lib/mtk/pitch_class_set.rb +58 -35
  62. data/lib/mtk/sequencers/event_builder.rb +131 -0
  63. data/lib/mtk/sequencers/legato_sequencer.rb +24 -0
  64. data/lib/mtk/sequencers/rhythmic_sequencer.rb +28 -0
  65. data/lib/mtk/{sequencer/abstract_sequencer.rb → sequencers/sequencer.rb} +37 -11
  66. data/lib/mtk/{sequencer → sequencers}/step_sequencer.rb +4 -4
  67. data/lib/mtk/timeline.rb +39 -22
  68. data/lib/mtk/variable.rb +32 -0
  69. data/spec/mtk/chord_spec.rb +83 -0
  70. data/spec/mtk/{_constants → constants}/durations_spec.rb +12 -41
  71. data/spec/mtk/{_constants → constants}/intensities_spec.rb +13 -37
  72. data/spec/mtk/{_constants → constants}/intervals_spec.rb +14 -32
  73. data/spec/mtk/{_constants → constants}/pitch_classes_spec.rb +8 -4
  74. data/spec/mtk/{_constants → constants}/pitches_spec.rb +5 -1
  75. data/spec/mtk/duration_spec.rb +372 -0
  76. data/spec/mtk/events/event_spec.rb +234 -0
  77. data/spec/mtk/events/note_spec.rb +174 -0
  78. data/spec/mtk/events/parameter_spec.rb +220 -0
  79. data/spec/mtk/{helper → helpers}/collection_spec.rb +86 -3
  80. data/spec/mtk/{helper → helpers}/pseudo_constants_spec.rb +2 -2
  81. data/spec/mtk/intensity_spec.rb +289 -0
  82. data/spec/mtk/interval_spec.rb +265 -0
  83. data/spec/mtk/lang/parser_spec.rb +597 -0
  84. data/spec/mtk/melody_spec.rb +223 -0
  85. data/spec/mtk/midi/file_spec.rb +16 -16
  86. data/spec/mtk/midi/jsound_input_spec.rb +11 -0
  87. data/spec/mtk/midi/jsound_output_spec.rb +11 -0
  88. data/spec/mtk/midi/output_spec.rb +102 -0
  89. data/spec/mtk/midi/unimidi_input_spec.rb +11 -0
  90. data/spec/mtk/midi/unimidi_output_spec.rb +11 -0
  91. data/spec/mtk/{_numeric_extensions_spec.rb → numeric_extensions_spec.rb} +1 -0
  92. data/spec/mtk/patterns/chain_spec.rb +110 -0
  93. data/spec/mtk/{pattern → patterns}/choice_spec.rb +20 -30
  94. data/spec/mtk/{pattern → patterns}/cycle_spec.rb +25 -35
  95. data/spec/mtk/patterns/for_each_spec.rb +136 -0
  96. data/spec/mtk/{pattern → patterns}/function_spec.rb +17 -30
  97. data/spec/mtk/{pattern → patterns}/lines_spec.rb +11 -27
  98. data/spec/mtk/{pattern → patterns}/palindrome_spec.rb +13 -29
  99. data/spec/mtk/patterns/pattern_spec.rb +132 -0
  100. data/spec/mtk/patterns/sequence_spec.rb +203 -0
  101. data/spec/mtk/pitch_class_set_spec.rb +23 -21
  102. data/spec/mtk/pitch_class_spec.rb +151 -39
  103. data/spec/mtk/pitch_spec.rb +22 -1
  104. data/spec/mtk/sequencers/event_builder_spec.rb +245 -0
  105. data/spec/mtk/sequencers/legato_sequencer_spec.rb +45 -0
  106. data/spec/mtk/sequencers/rhythmic_sequencer_spec.rb +84 -0
  107. data/spec/mtk/sequencers/sequencer_spec.rb +215 -0
  108. data/spec/mtk/{sequencer → sequencers}/step_sequencer_spec.rb +35 -13
  109. data/spec/mtk/timeline_spec.rb +109 -16
  110. data/spec/mtk/variable_spec.rb +52 -0
  111. data/spec/spec_coverage.rb +2 -0
  112. data/spec/spec_helper.rb +3 -0
  113. metadata +188 -91
  114. data/lib/mtk/_constants/durations.rb +0 -80
  115. data/lib/mtk/_constants/intensities.rb +0 -81
  116. data/lib/mtk/_constants/intervals.rb +0 -85
  117. data/lib/mtk/_constants/pitch_classes.rb +0 -35
  118. data/lib/mtk/_constants/pitches.rb +0 -49
  119. data/lib/mtk/event.rb +0 -70
  120. data/lib/mtk/helper/collection.rb +0 -114
  121. data/lib/mtk/helper/event_builder.rb +0 -85
  122. data/lib/mtk/helper/pseudo_constants.rb +0 -26
  123. data/lib/mtk/lang/grammar.rb +0 -17
  124. data/lib/mtk/note.rb +0 -63
  125. data/lib/mtk/pattern/abstract_pattern.rb +0 -132
  126. data/lib/mtk/pattern/cycle.rb +0 -51
  127. data/lib/mtk/pattern/enumerator.rb +0 -26
  128. data/lib/mtk/pattern/function.rb +0 -46
  129. data/lib/mtk/pattern/sequence.rb +0 -30
  130. data/lib/mtk/pitch_set.rb +0 -84
  131. data/lib/mtk/sequencer/rhythmic_sequencer.rb +0 -29
  132. data/lib/mtk/transform/invertible.rb +0 -15
  133. data/lib/mtk/transform/mappable.rb +0 -18
  134. data/lib/mtk/transform/set_theory_operations.rb +0 -34
  135. data/lib/mtk/transform/transposable.rb +0 -14
  136. data/spec/mtk/event_spec.rb +0 -139
  137. data/spec/mtk/helper/event_builder_spec.rb +0 -92
  138. data/spec/mtk/lang/grammar_spec.rb +0 -100
  139. data/spec/mtk/note_spec.rb +0 -115
  140. data/spec/mtk/pattern/abstract_pattern_spec.rb +0 -45
  141. data/spec/mtk/pattern/note_cycle_spec.rb.bak +0 -116
  142. data/spec/mtk/pattern/pitch_cycle_spec.rb.bak +0 -47
  143. data/spec/mtk/pattern/pitch_sequence_spec.rb.bak +0 -37
  144. data/spec/mtk/pattern/sequence_spec.rb +0 -151
  145. data/spec/mtk/pitch_set_spec.rb +0 -198
  146. data/spec/mtk/sequencer/abstract_sequencer_spec.rb +0 -159
  147. data/spec/mtk/sequencer/rhythmic_sequencer_spec.rb +0 -49
@@ -0,0 +1,26 @@
1
+ module MTK
2
+ module Helpers
3
+
4
+ # Extension for modules that want to define pseudo-constants (constant-like values with lower-case names)
5
+ module PseudoConstants
6
+
7
+ # Define a module method and module function (available both through the module namespace and as a mixin method),
8
+ # to provide a constant with a lower-case name.
9
+ #
10
+ # @param name [Symbol] the name of the pseudo-constant
11
+ # @param value [Object] the value of the pseudo-constant
12
+ # @return [nil]
13
+ def define_constant name, value
14
+ if name[0..0] =~ /[A-Z]/
15
+ const_set name, value # it's just a normal constant
16
+ else
17
+ # the pseudo-constant definition is the combination of a method and module_function:
18
+ define_method(name) { value }
19
+ module_function name
20
+ end
21
+ nil
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,156 @@
1
+ module MTK
2
+
3
+ # A measure of intensity, using an underlying value in the range 0.0-1.0
4
+ class Intensity
5
+
6
+ include Comparable
7
+
8
+ # The names of the base intensities. See {}MTK::Constants::Intensities} for more info.
9
+ NAMES = %w[ppp pp p mp mf o ff fff].freeze
10
+
11
+ VALUES_BY_NAME = {
12
+ 'ppp' => 0.125,
13
+ 'pp' => 0.25,
14
+ 'p' => 0.375,
15
+ 'mp' => 0.5,
16
+ 'mf' => 0.625,
17
+ 'o' => 0.75,
18
+ 'ff' => 0.875,
19
+ 'fff' => 1.0
20
+ }
21
+
22
+ @flyweight = {}
23
+
24
+ # The number of beats, typically representation as a Rational
25
+ attr_reader :value
26
+
27
+ def initialize(value)
28
+ @value = value
29
+ end
30
+
31
+ # Return an Intensity, only constructing a new instance when not already in the flyweight cache
32
+ def self.[](value)
33
+ value = value.to_f
34
+ @flyweight[value] ||= new(value)
35
+ end
36
+
37
+ class << self
38
+ alias :from_f :[]
39
+ alias :from_i :[]
40
+ end
41
+
42
+ # Lookup an intensity by name.
43
+ # This method supports appending '-' or '+' for more fine-grained values.
44
+ def self.from_s(s)
45
+ return self[1.0] if s == 'fff+' # special case because "fff" is already the maximum
46
+
47
+ name = nil
48
+ modifier = nil
49
+ if s =~ /^(\w+)([+-])?$/
50
+ name = $1
51
+ modifier = $2
52
+ end
53
+
54
+ value = VALUES_BY_NAME[name]
55
+ raise ArgumentError.new("Invalid Intensity string '#{s}'") unless value
56
+
57
+ value += 1.0/24 if modifier == '+'
58
+ value -= 1.0/24 if modifier == '-'
59
+
60
+ self[value]
61
+ end
62
+
63
+ class << self
64
+ alias :from_name :from_s
65
+ end
66
+
67
+ # The number of beats as a floating point number
68
+ def to_f
69
+ @value.to_f
70
+ end
71
+
72
+ # The numerical value for the nearest whole number of beats
73
+ def to_i
74
+ @value.round
75
+ end
76
+
77
+ def to_midi
78
+ (to_f * 127).round
79
+ end
80
+
81
+ def to_percent
82
+ (@value * 100).round
83
+ end
84
+
85
+ def to_s
86
+ "#{to_percent}% intensity"
87
+ end
88
+
89
+ def inspect
90
+ "#<#{self.class}:#{object_id} @value=#{@value}>"
91
+ end
92
+
93
+ def ==( other )
94
+ other.is_a? MTK::Intensity and other.value == @value
95
+ end
96
+
97
+ def <=> other
98
+ if other.respond_to? :value
99
+ @value <=> other.value
100
+ else
101
+ @value <=> other
102
+ end
103
+
104
+ end
105
+
106
+ def + intensity
107
+ if intensity.is_a? MTK::Intensity
108
+ MTK::Intensity[@value + intensity.value]
109
+ else
110
+ MTK::Intensity[@value + intensity]
111
+ end
112
+ end
113
+
114
+ def -intensity
115
+ if intensity.is_a? MTK::Intensity
116
+ MTK::Intensity[@value - intensity.value]
117
+ else
118
+ MTK::Intensity[@value - intensity]
119
+ end
120
+ end
121
+
122
+ def * intensity
123
+ if intensity.is_a? MTK::Intensity
124
+ MTK::Intensity[@value * intensity.value]
125
+ else
126
+ MTK::Intensity[@value * intensity]
127
+ end
128
+ end
129
+
130
+ def / intensity
131
+ if intensity.is_a? MTK::Intensity
132
+ MTK::Intensity[to_f / intensity.value]
133
+ else
134
+ MTK::Intensity[to_f / intensity]
135
+ end
136
+ end
137
+
138
+ def coerce(other)
139
+ return MTK::Intensity[other], self
140
+ end
141
+
142
+ end
143
+
144
+ # Construct a {Duration} from any supported type
145
+ def Intensity(*anything)
146
+ anything = anything.first if anything.length == 1
147
+ case anything
148
+ when Numeric then MTK::Intensity[anything]
149
+ when String, Symbol then MTK::Intensity.from_s(anything)
150
+ when Intensity then anything
151
+ else raise "Intensity doesn't understand #{anything.class}"
152
+ end
153
+ end
154
+ module_function :Intensity
155
+
156
+ end
@@ -0,0 +1,155 @@
1
+ module MTK
2
+
3
+ # A measure of intensity, using an underlying value in the range 0.0-1.0
4
+ class Interval
5
+
6
+ include Comparable
7
+
8
+ # The preferred names of all pre-defined intervals
9
+ NAMES = %w[P1 m2 M2 m3 M3 P4 TT P5 m6 M6 m7 M7 P8].freeze
10
+
11
+ # All valid names of pre-defined intervals, indexed by their value.
12
+ NAMES_BY_VALUE =
13
+ [ # names # value # description
14
+ %w( P1 p1 ), # 0 # unison
15
+ %w( m2 min2 ), # 1 # minor second
16
+ %w( M2 maj2 ), # 2 # major second
17
+ %w( m3 min3 ), # 3 # minor third
18
+ %w( M3 maj3 ), # 4 # major third
19
+ %w( P4 p4 ), # 5 # perfect fourth
20
+ %w( TT tt ), # 6 # tritone (AKA augmented fourth, diminished fifth)
21
+ %w( P5 p5 ), # 7 # perfect fifth
22
+ %w( m6 min6 ), # 8 # minor sixth
23
+ %w( M6 maj6 ), # 9 # major sixth
24
+ %w( m7 min7 ), # 10 # minor seventh
25
+ %w( M7 maj7 ), # 11 # major seventh
26
+ %w( P8 p8 ) # 12 # octave
27
+ ].freeze
28
+
29
+ # A mapping from intervals names to their value
30
+ VALUES_BY_NAME = Hash[ # a map from a list of name,value pairs
31
+ NAMES_BY_VALUE.map.with_index do |names,value|
32
+ names.map{|name| [name,value] }
33
+ end.flatten(1)
34
+ ].freeze
35
+
36
+ # All valid interval names
37
+ ALL_NAMES = NAMES_BY_VALUE.flatten.freeze
38
+
39
+
40
+ @flyweight = {}
41
+
42
+ # The number of semitones represented by this interval
43
+ attr_reader :value
44
+
45
+ def initialize(value)
46
+ @value = value
47
+ end
48
+
49
+ # Return an {Interval}, only constructing a new instance when not already in the flyweight cache
50
+ def self.[](value)
51
+ value = value.to_f unless value.is_a? Fixnum
52
+ @flyweight[value] ||= new(value)
53
+ end
54
+
55
+ class << self
56
+ alias :from_f :[]
57
+ alias :from_i :[]
58
+ end
59
+
60
+ # Lookup an interval duration by name.
61
+ def self.from_s(s)
62
+ value = VALUES_BY_NAME[s.to_s]
63
+ raise ArgumentError.new("Invalid Interval string '#{s}'") unless value
64
+ self[value]
65
+ end
66
+
67
+ class << self
68
+ alias :from_name :from_s
69
+ end
70
+
71
+ # The number of semitones as a floating point number
72
+ def to_f
73
+ @value.to_f
74
+ end
75
+
76
+ # The numerical value for the nearest whole number of semitones in this interval
77
+ def to_i
78
+ @value.round
79
+ end
80
+
81
+ def to_s
82
+ @value.to_s
83
+ end
84
+
85
+ def inspect
86
+ "#{self.class}<#{to_s} semitones>"
87
+ end
88
+
89
+ def ==( other )
90
+ other.is_a? MTK::Interval and other.value == @value
91
+ end
92
+
93
+ def <=> other
94
+ if other.respond_to? :value
95
+ @value <=> other.value
96
+ else
97
+ @value <=> other
98
+ end
99
+ end
100
+
101
+ def + interval
102
+ if interval.is_a? MTK::Interval
103
+ MTK::Interval[@value + interval.value]
104
+ else
105
+ MTK::Interval[@value + interval]
106
+ end
107
+ end
108
+
109
+ def -interval
110
+ if interval.is_a? MTK::Interval
111
+ MTK::Interval[@value - interval.value]
112
+ else
113
+ MTK::Interval[@value - interval]
114
+ end
115
+ end
116
+
117
+ def * interval
118
+ if interval.is_a? MTK::Interval
119
+ MTK::Interval[@value * interval.value]
120
+ else
121
+ MTK::Interval[@value * interval]
122
+ end
123
+ end
124
+
125
+ def / interval
126
+ if interval.is_a? MTK::Interval
127
+ MTK::Interval[to_f / interval.value]
128
+ else
129
+ MTK::Interval[to_f / interval]
130
+ end
131
+ end
132
+
133
+ def -@
134
+ MTK::Interval[@value * -1]
135
+ end
136
+
137
+ def coerce(other)
138
+ return MTK::Interval[other], self
139
+ end
140
+
141
+ end
142
+
143
+ # Construct a {Duration} from any supported type
144
+ def Interval(*anything)
145
+ anything = anything.first if anything.length == 1
146
+ case anything
147
+ when Numeric then MTK::Interval[anything]
148
+ when String, Symbol then MTK::Interval.from_s(anything)
149
+ when Interval then anything
150
+ else raise "Interval doesn't understand #{anything.class}"
151
+ end
152
+ end
153
+ module_function :Interval
154
+
155
+ end
@@ -1,44 +1,175 @@
1
1
  grammar MTK_Grammar
2
- include MTK
3
2
 
4
- rule pitch_sequence
5
- ( pitch (space pitch)* ) {
6
- Pattern.PitchSequence *captures[:pitch].map{|p| p.value }
3
+ rule root
4
+ ( space? root:(bare_sequencer | sequencer | timeline) space? ) {
5
+ root.value
7
6
  }
8
7
  end
9
8
 
9
+ rule bare_sequencer
10
+ ( pattern '' ) {
11
+ # it seems at least 2 elements are needed to access the pattern submatch,
12
+ # so using an empty string as a workaround
13
+ MTK::Sequencers.LegatoSequencer pattern.value
14
+ }
15
+ end
16
+
17
+ rule sequencer
18
+ ( left_curly bare_sequencer right_curly ) {
19
+ bare_sequencer.value
20
+ }
21
+ end
22
+
23
+ rule timeline
24
+ ( left_curly timepoint pattern (space timepoint pattern)* right_curly ) {
25
+ MTK::Timeline.from_a values_of(:timepoint).zip(values_of :pattern)
26
+ }
27
+ end
28
+
29
+ rule pattern
30
+ ( pattern:(bare_choice | choice) '' ) {
31
+ val = first.value
32
+ if val.is_a? MTK::Patterns::Pattern then val else MTK::Patterns::Pattern.new [val] end
33
+ }
34
+ end
35
+
36
+
37
+ rule bare_choice
38
+ (
39
+ seq:(bare_sequence | sequence) (pipe seq:(bare_sequence | sequence))*
40
+ )
41
+ {
42
+ vals = values_of :seq
43
+ if vals.length==1 then vals[0] else MTK::Patterns.Choice(*vals) end
44
+ }
45
+ end
46
+
47
+
48
+ rule choice
49
+ (
50
+ left_angle bare_choice right_angle
51
+ )
52
+ {
53
+ bare_choice.value
54
+ }
55
+ end
56
+
57
+
58
+ rule bare_sequence
59
+ (
60
+ chain (space chain)*
61
+ )
62
+ {
63
+ vals = values_of :chain
64
+ if vals.length==1 then vals[0] else MTK::Patterns.Sequence(*vals) end
65
+ }
66
+ end
67
+
68
+
69
+ rule sequence
70
+ (
71
+ left_paren chain (space chain)* right_paren ('*' max_cycles:int)? ('&' element_count:int)?
72
+ )
73
+ {
74
+ chains = values_of(:chain)
75
+ options = {}
76
+ if element_count
77
+ options[:min_elements] = options[:max_elements] = element_count.value
78
+ end
79
+ options[:max_cycles] = max_cycles.value if max_cycles
80
+ if chains.length == 1 and options.empty?
81
+ chains[0] # Don't form a chain unnecessarily
82
+ else
83
+ MTK::Patterns::Sequence.new chains, options
84
+ end
85
+ }
86
+ end
87
+
88
+
89
+ rule foreach
90
+ (
91
+ sequence ('@' sequence)+
92
+ )
93
+ {
94
+ MTK::Patterns::ForEach.new(values_of :sequence)
95
+ }
96
+ end
97
+
98
+
99
+ rule chain
100
+ ( chainable (':' chainable)* ) {
101
+ vals = values_of(:chainable)
102
+ vals.length == 1 ? vals[0] : MTK::Patterns.Chain(*vals)
103
+ }
104
+ end
105
+
106
+ rule chainable
107
+ ( foreach | choice | sequence | element )
108
+ end
109
+
110
+ rule element
111
+ (
112
+ elem:( intensity | duration | interval | pitch | pitch_class | variable ) ('*' max_cycles:int)?
113
+ )
114
+ {
115
+ if max_cycles
116
+ MTK::Patterns::Sequence.new( [elem.value], max_cycles: max_cycles.value )
117
+ else
118
+ elem.value
119
+ end
120
+ }
121
+ end
122
+
123
+ # rule chord
124
+ # ( left_bracket pitch (space pitch)* right_bracket ) {
125
+ # MTK::Chord *values_of(:pitch)
126
+ # }
127
+ # end
128
+
10
129
  rule pitch
11
130
  ( pitch_class int ) {
12
- Pitch[pitch_class.value, int.value]
131
+ MTK::Pitch[pitch_class.value, int.value]
13
132
  }
14
133
  end
15
134
 
16
135
  rule pitch_class
17
136
  ( [A-Ga-g] [#b]*2 ) {
18
- PitchClass[to_s]
137
+ MTK::PitchClass[to_s]
19
138
  }
20
139
  end
21
140
 
22
141
  rule interval
23
- ( 'P' [1458] | [Mm] [2367] | 'TT' ) {
24
- Intervals[to_s]
142
+ ( [Pp] [1458] | ('maj'|'min'|[Mm]) [2367] | 'TT' | 'tt' ) {
143
+ MTK::Interval.from_s(to_s)
25
144
  }
26
145
  end
27
146
 
28
147
  rule intensity
29
- ( ('p'1*3 | 'mp' | 'mf' | 'f'1*3) ('+'|'-')? ) {
30
- Intensities[to_s]
148
+ ( ('p'1*3 | 'mp' | 'mf' | 'o' | 'f'2*3) ('+'|'-')? ) {
149
+ MTK::Intensity.from_s(to_s)
31
150
  }
32
151
  end
33
152
 
34
153
  rule duration
35
- ( [whqesrx] ('.'|'t')* ) {
36
- Durations[to_s]
154
+ ( rest:'-'? multiplier:number? [whqisrx] ('.'|'t')* ) {
155
+ MTK::Duration.from_s(to_s)
156
+ }
157
+ end
158
+
159
+ rule variable
160
+ ( '$'+ ) {
161
+ MTK::Variable.new(to_s)
162
+ }
163
+ end
164
+
165
+ rule timepoint
166
+ ( number right_arrow ) {
167
+ number.value
37
168
  }
38
169
  end
39
170
 
40
171
  rule number
41
- float | int
172
+ float | rational | int
42
173
  end
43
174
 
44
175
  rule float
@@ -47,12 +178,58 @@ grammar MTK_Grammar
47
178
  }
48
179
  end
49
180
 
181
+ rule rational
182
+ ( numerator:int '/' denominator:[0-9]+ ) {
183
+ Rational(numerator.value, denominator.to_i)
184
+ }
185
+ end
186
+
50
187
  rule int
51
188
  ( '-'? [0-9]+ ) {
52
189
  to_i
53
190
  }
54
191
  end
55
192
 
193
+ rule left_paren
194
+ ( '(' space? ) { nil }
195
+ end
196
+
197
+ rule right_paren
198
+ ( space? ')' ) { nil }
199
+ end
200
+
201
+ rule left_bracket
202
+ ( '[' space? ) { nil }
203
+ end
204
+
205
+ rule right_bracket
206
+ ( space? ']' ) { nil }
207
+ end
208
+
209
+ rule left_curly
210
+ ( '{' space? ) { nil }
211
+ end
212
+
213
+ rule right_curly
214
+ ( space? '}' ) { nil }
215
+ end
216
+
217
+ rule left_angle
218
+ ( '<' space? ) { nil }
219
+ end
220
+
221
+ rule right_angle
222
+ ( space? '>' ) { nil }
223
+ end
224
+
225
+ rule pipe
226
+ ( space? '|' space? ) { nil }
227
+ end
228
+
229
+ rule right_arrow
230
+ ( space? '=>' space? ) { nil }
231
+ end
232
+
56
233
  rule space
57
234
  [\s]+ { nil }
58
235
  end