mtk 0.0.2 → 0.0.3

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