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
data/bin/mtk ADDED
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mtk'
4
+ require 'optparse'
5
+
6
+ options = {}
7
+
8
+
9
+ #######################################################################
10
+
11
+ option_parser = OptionParser.new do |opts|
12
+
13
+ opts.banner = "Usage: #{$0} [options]"
14
+ opts.separator ''
15
+ opts.separator 'Options:'
16
+
17
+ opts.on('-c FILE', '--convert FILE', 'Convert a file containing MTK syntax to MIDI',
18
+ 'if a --file is given, write the MIDI to a file',
19
+ 'if an --output is given, play the MIDI',
20
+ 'otherwise print the MIDI') {|file| options[:convert] = file }
21
+
22
+ opts.separator ''
23
+
24
+ opts.on('-e [syntax]', '--eval [syntax]', 'Convert the given MTK syntax String to MIDI',
25
+ 'or start an interactive interpreter when [syntax] is omitted',
26
+ 'if a --file is given, write the MIDI to a file',
27
+ 'if an --output is given, play the MIDI',
28
+ 'otherwise print the MIDI') {|syntax| options[:eval] = syntax }
29
+
30
+ opts.separator ''
31
+
32
+ opts.on('-f FILE', '--file FILE', 'Write the output of --convert, --eval, or --input to a file') {|file| options[:file] = file }
33
+
34
+ opts.separator ''
35
+
36
+ opts.on('-h', '--help', 'Show this message') { puts opts; exit }
37
+
38
+ opts.separator ''
39
+
40
+ opts.on('-i INPUT', '--input INPUT', 'Set MIDI input for recording',
41
+ 'if no --file is specified, prints the recorded MIDI') {|input| options[:input] = input }
42
+
43
+ opts.separator ''
44
+
45
+ opts.on('-l', '--list', 'List available MIDI devices for --input and --output') { options[:list] = true }
46
+
47
+ opts.separator ''
48
+
49
+ opts.on('-m', '--monitor', 'Monitor MIDI input while recording') { options[:monitor] = true }
50
+
51
+ opts.separator ''
52
+
53
+ opts.on('-o OUTPUT', '--output OUTPUT', 'Set MIDI output for playing') {|output| options[:output] = output }
54
+
55
+ opts.separator ''
56
+
57
+ opts.on('-p FILE', '--play FILE', 'Play or print the contents of a MIDI file',
58
+ 'if no --output is specified, print the MIDI file') {|file| options[:play] = file }
59
+
60
+ opts.separator ''
61
+
62
+ #opts.on('-t', '--tutorial', 'Start an interactive tutorial for the MTK syntax') { options[:tutorial] = true }
63
+ #
64
+ #opts.separator ''
65
+
66
+ end
67
+
68
+
69
+ #######################################################################
70
+
71
+ puts option_parser and exit if ARGV.length == 0
72
+ #p ARGV
73
+ #p options
74
+
75
+ ERROR_INVALID_COMMAND = 1
76
+ ERROR_FILE_NOT_FOUND = 2
77
+ ERROR_OUTPUT_NOT_FOUND = 3
78
+ ERROR_INPUT_NOT_FOUND = 4
79
+
80
+ # Immediately trying to play output while Ruby is still "warming up" can cause timing issues with
81
+ # the first couple notes. So we play this "empty" Timeline containing a rest to address that issue.
82
+ WARMUP = MTK::Timeline.from_hash( {0 => MTK::Events::Note.new(MTK::Pitch(60), MTK::Duration(-1))} )
83
+
84
+ #######################################################################
85
+
86
+ begin
87
+ option_parser.parse!
88
+ rescue OptionParser::MissingArgument, OptionParser::InvalidOption
89
+ puts "Invalid command, #{$!}"
90
+ puts "For command line help: #{$0} --help"
91
+ exit ERROR_INVALID_COMMAND
92
+ end
93
+
94
+
95
+ def setup_io
96
+ require 'mtk/midi/input'
97
+ require 'mtk/midi/output'
98
+ end
99
+
100
+
101
+ def convert(mtk_syntax)
102
+ sequencer = MTK::Lang::Parser.parse(mtk_syntax)
103
+ timeline = sequencer.to_timeline
104
+ output(timeline)
105
+ end
106
+
107
+
108
+ def output(timelines, print_header='Timeline')
109
+ timelines = [timelines] unless timelines.is_a? Array
110
+ if @output
111
+ @output.play WARMUP
112
+ @output.play timelines.first # TODO: support multiple timelines
113
+ elsif @file
114
+ require 'mtk/midi/file'
115
+ MTK::MIDI_File(@file).write timelines
116
+ else
117
+ puts print_header, timelines
118
+ puts
119
+ end
120
+ end
121
+
122
+
123
+ def record
124
+ if @input
125
+ print "Press Enter to begin recording MIDI input..."
126
+ gets
127
+ puts "Recording input. Press control-C to stop."
128
+ @input.record monitor:@monitor
129
+ Signal.trap("INT") do # SIGINT = control-C
130
+ @input.stop
131
+ output @input.to_timeline, "\nRecorded MIDI data"
132
+ exit
133
+ end
134
+ loop{ sleep 0.01 }
135
+ end
136
+ end
137
+
138
+
139
+ #######################################################################
140
+
141
+ if options[:list]
142
+ setup_io
143
+ input_names = MTK::MIDI::Input.devices_by_name.keys
144
+ output_names = MTK::MIDI::Output.devices_by_name.keys
145
+ puts
146
+ puts (['INPUTS:'] + input_names).join("\n * ")
147
+ puts
148
+ puts (['OUTPUTS:']+output_names).join("\n * ")
149
+ puts
150
+ puts 'When specifying --input INPUT or --output OUTPUT, the first substring match will be used.'
151
+ puts "For example: --output IAC will use 'Apple Inc. IAC Driver' if it's the first OUTPUT containing 'IAC'"
152
+ puts
153
+ exit
154
+ end
155
+
156
+ @monitor = true if options[:monitor]
157
+
158
+ if options[:input]
159
+ setup_io
160
+ input_name = options[:input]
161
+ @input = MTK::MIDI::Input.find_by_name /#{input_name}/
162
+ if @input
163
+ puts "Using input '#{@input.name}'"
164
+ else
165
+ STDERR.puts "Input '#{input_name}' not found."
166
+ exit ERROR_INPUT_NOT_FOUND
167
+ end
168
+ end
169
+
170
+ if options[:output]
171
+ setup_io
172
+ output_name = options[:output]
173
+ @output = MTK::MIDI::Output.find_by_name /#{output_name}/
174
+ if @output
175
+ puts "Using output '#{@output.name}'"
176
+ else
177
+ STDERR.puts "Output '#{output_name}' not found."
178
+ exit ERROR_OUTPUT_NOT_FOUND
179
+ end
180
+ end
181
+
182
+ file = options[:file]
183
+ @file = file if file
184
+
185
+ if options[:play]
186
+ filename = options[:play]
187
+ require 'mtk/midi/file'
188
+ timelines = MTK::MIDI_File(filename).to_timelines
189
+ output(timelines, "Timeline for #{filename}")
190
+ end
191
+
192
+ if options.has_key? :eval
193
+ mtk_syntax = options[:eval]
194
+ if mtk_syntax.nil?
195
+ puts "Starting the interactive interpreter."
196
+ loop do
197
+ puts "Enter MTK syntax. Press Ctrl+C to exit."
198
+ convert(gets)
199
+ end
200
+ else
201
+ convert(mtk_syntax)
202
+ end
203
+ end
204
+
205
+ if options[:convert]
206
+ mtk_syntax_file = options[:convert]
207
+ mtk_syntax = IO.read(mtk_syntax_file)
208
+ convert(mtk_syntax)
209
+ end
210
+
211
+ #if options.has_key? :tutorial
212
+ # puts "TODO: tutorial"
213
+ #end
214
+
215
+ record if @input
@@ -5,15 +5,15 @@
5
5
  require 'mtk'
6
6
  require 'mtk/midi/file'
7
7
  include MTK
8
- include Pitches
9
- include Intensities
8
+ include Constants::Pitches
9
+ include Constants::Intensities
10
10
 
11
11
  file = ARGV[0] || 'MTK-crescendo.mid'
12
12
 
13
- scale = Pattern::PitchSequence C4,D4,E4,F4,G4,A4,B4,C5
14
- crescendo = Pattern::IntensityLines pp, [fff, scale.length-1] # step from pp to fff over the length of the scale
13
+ scale = Patterns.Sequence C4,D4,E4,F4,G4,A4,B4,C5
14
+ crescendo = Patterns.Lines pp, [fff, scale.length-1] # step from pp to fff over the length of the scale
15
15
 
16
- sequencer = Sequencer::StepSequencer.new [scale, crescendo]
16
+ sequencer = Sequencers.StepSequencer scale, crescendo
17
17
  timeline = sequencer.to_timeline
18
18
 
19
19
  MIDI_File(file).write timeline
@@ -0,0 +1,23 @@
1
+ require 'mtk'
2
+ require 'mtk/midi/file'
3
+ include MTK
4
+ include Constants::Pitches
5
+ include Constants::Intensities
6
+
7
+ file = ARGV[0] || "MTK-#{File.basename(__FILE__,'.rb')}.mid"
8
+
9
+ _ = nil # defines _ as a rest
10
+
11
+ pattern = {# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
12
+ C2 => [fff, _, _, _, mf, _, _, _, o, _, _, _, mp, _, _, _], # kick
13
+ Db2 => [ _, _, o, _, _, _, mp, _, _, _, o, _, _, _, mf, _], # snare
14
+ D2 => [ _, mp, _, mp, _, mp, _, mf, _, mp, _, mp, _, pp, _, mf] # hat
15
+ }
16
+
17
+ timeline = Timeline.new
18
+ for pitch,intensities in pattern
19
+ track = Sequencers::StepSequencer( Patterns.Sequence(intensities), default_pitch: pitch )
20
+ timeline.merge track.to_timeline
21
+ end
22
+
23
+ MIDI_File(file).write timeline
@@ -5,11 +5,11 @@
5
5
  require 'mtk'
6
6
  require 'mtk/midi/file'
7
7
  include MTK
8
- include Pitches
9
- include Intensities
10
- include Intervals
8
+ include MTK::Constants::Pitches
9
+ include MTK::Constants::Intensities
10
+ include MTK::Constants::Intervals
11
11
 
12
- file = ARGV[0] || "MTK-#{File.basename(__FILE__,'.rb')}.mid"
12
+ file = ARGV[0] || "MTK-#{File.basename __FILE__,'.rb'}.mid"
13
13
 
14
14
  interval_generator = lambda do
15
15
  # Randomly return intervals
@@ -26,14 +26,11 @@ interval_generator = lambda do
26
26
  end
27
27
  end
28
28
 
29
- pitches = Pattern::Function.new interval_generator, :type => :pitch, :max_elements => 24
29
+ pitches = Patterns.Function( interval_generator, max_elements: 24 )
30
30
 
31
31
  # we'll also use a weighted choice to generate the intensities
32
- intensities = Pattern::Choice.new [mp, mf, f, ff, fff], :type => :intensity, :weights => [1,2,3,2,1]
32
+ intensities = Patterns.Choice( mp,mf,o,ff,fff, weights: [1,2,3,2,1], max_cycles: 24 )
33
33
 
34
+ sequencer = Sequencers.StepSequencer( pitches,intensities, step_size: 0.5, max_interval: 17 )
34
35
 
35
- sequencer = Sequencer::StepSequencer.new [pitches, intensities], :step_size => 0.5
36
- timeline = sequencer.to_timeline
37
-
38
- MIDI_File(file).write timeline
39
-
36
+ MIDI_File(file).write( sequencer.to_timeline )
@@ -0,0 +1,26 @@
1
+ # Enter space-separated pitch classes (A,B,C,D,E,F,G) at the prompt and hear them play.
2
+
3
+ require 'mtk'
4
+ require 'mtk/helpers/output_selector'
5
+ include MTK
6
+
7
+ output = Helpers::OutputSelector.ensure_output ARGV[0]
8
+
9
+ def get_pitch_classes
10
+ puts "Enter pitch classes:"
11
+ input = STDIN.gets
12
+ input.strip.split(/\s+/).map{|name| PitchClass[name] } if input
13
+ rescue
14
+ puts "Invalid input."
15
+ end
16
+
17
+ while (pitch_classes = get_pitch_classes)
18
+ sequence = Patterns.Sequence pitch_classes
19
+ sequencer = Sequencers.StepSequencer sequence
20
+ timeline = sequencer.to_timeline
21
+
22
+ puts "Playing: #{pitch_classes}"
23
+ puts "Timeline:\n#{timeline}"
24
+ output.play timeline
25
+ end
26
+
@@ -0,0 +1,22 @@
1
+ require 'mtk'
2
+ require 'mtk/helpers/lilypond'
3
+ include MTK
4
+
5
+ def arg_error(error)
6
+ puts "Usage: ruby #$0 syntax output_file"
7
+ puts error
8
+ exit 1
9
+ end
10
+
11
+ syntax = ARGV[0]
12
+ arg_error "MTK syntax string not provided" unless syntax
13
+
14
+
15
+ file = ARGV[1]
16
+ arg_error "The output_file must end in '.png', '.pdf', or '.ps'" unless file
17
+
18
+
19
+ sequencer = MTK::Lang::Parser.parse(syntax)
20
+ timeline = sequencer.to_timeline
21
+ # Helpers::Lilypond.open(file).write(timeline)
22
+ Helpers::Lilypond.open(file, dpi:300).write(timeline) # higher resolution PNG
@@ -1,19 +1,17 @@
1
1
  # Play a given MIDI file with the given MIDI output
2
- #
3
- # NOTE: this example only runs under JRuby with the jsound and gamelan gems installed
4
2
 
5
- file, output = ARGV[0], ARGV[1]
6
- unless file and output
7
- puts "Usage: ruby #$0 midi_file output_device"
3
+ file, output_name = ARGV[0], ARGV[1]
4
+ unless file
5
+ puts "Usage: ruby #$0 midi_file [output_device]"
8
6
  exit 1
9
7
  end
10
8
 
11
9
  require 'mtk'
12
10
  require 'mtk/midi/file'
13
- require 'mtk/midi/jsound_output'
14
- include MTK
11
+ require 'mtk/helpers/output_selector'
15
12
 
16
- timeline = MIDI_File(file).to_timelines.first # for now this example just plays the first track (JSoundOutput needs to be enhanced to support multiple timelines)
17
- player = MTK::MIDI::JSoundOutput.new output
13
+ output = MTK::Helpers::OutputSelector.ensure_output(output_name)
18
14
 
19
- player.play timeline
15
+ timeline = MTK.MIDI_File(file).to_timelines
16
+
17
+ output.play(timeline)
@@ -9,9 +9,9 @@ include MTK
9
9
  file = ARGV[0] || 'MTK-random_tone_row.mid'
10
10
 
11
11
  row = PitchClassSet.random_row
12
- sequence = Pattern::PitchSequence *row.to_a
12
+ sequence = Patterns.Sequence *row
13
13
 
14
- sequencer = Sequencer::StepSequencer.new [sequence]
14
+ sequencer = Sequencers.StepSequencer sequence
15
15
  timeline = sequencer.to_timeline
16
16
 
17
17
  MIDI_File(file).write timeline
@@ -0,0 +1,28 @@
1
+ # Generate a MIDI file by reading in a file containing the MTK custom syntax (see mtk_grammar.citrus and grammar_spec.rb)
2
+ #
3
+ # NOTE: this blindly overwrites any existing MTK-syntax_to_midi.mid file, unless a second argument is provided
4
+
5
+ require 'mtk'
6
+ require 'mtk/midi/file'
7
+
8
+ input = ARGV[0]
9
+ if input.nil?
10
+ STDERR.puts "Input file is required."
11
+ STDERR.puts "Usage: #{$0} input [output]"
12
+ exit 1
13
+ end
14
+
15
+ unless File.exists? input
16
+ STDERR.puts "Cannot read file: #{input}"
17
+ exit 2
18
+ end
19
+
20
+ output = ARGV[1] || "MTK-#{File.basename(__FILE__,'.rb')}.mid"
21
+
22
+
23
+ syntax = IO.read(input)
24
+ sequencer = MTK::Lang::Parser.parse(syntax)
25
+ timeline = sequencer.to_timeline
26
+
27
+ MTK::MIDI_File(output).write timeline
28
+
@@ -0,0 +1,8 @@
1
+ require 'mtk'
2
+ require 'mtk/helpers/output_selector'
3
+ include MTK
4
+ include Constants::Pitches
5
+
6
+ output = Helpers::OutputSelector.ensure_output ARGV[0]
7
+
8
+ output.play Note(C4,1,2)
@@ -5,16 +5,16 @@
5
5
  require 'mtk'
6
6
  require 'mtk/midi/file'
7
7
  include MTK
8
- include PitchClasses
9
- include Durations
8
+ include MTK::Constants::PitchClasses
9
+ include MTK::Constants::Durations
10
10
 
11
11
  file = ARGV[0] || 'MTK-tone_row_melody.mid'
12
12
 
13
- row = PitchClassSet(Db, G, Ab, F, Eb, E, D, C, B, Gb, A, Bb)
14
- pitch_pattern = Pattern.PitchCycle *row
15
- rhythm_pattern = Pattern.RhythmCycle(Pattern.Choice s, e, e+s, q) # choose between sixteenth, eighth, dotted eighth, and quarter
13
+ row = PitchClassSet Db, G, Ab, F, Eb, E, D, C, B, Gb, A, Bb
14
+ pitch_pattern = Patterns.Cycle *row
15
+ rhythm_pattern = Patterns.Choice s, i, i+s, q # choose between sixteenth, eighth, dotted eighth, and quarter
16
16
 
17
- sequencer = Sequencer::RhythmicSequencer.new [pitch_pattern, rhythm_pattern], :max_steps => 36
17
+ sequencer = Sequencers.LegatoSequencer pitch_pattern, rhythm_pattern, max_steps: 36
18
18
  timeline = sequencer.to_timeline
19
19
 
20
20
  MIDI_File(file).write timeline