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