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.
- data/.yardopts +3 -2
- data/DEVELOPMENT_NOTES.md +114 -0
- data/INTRO.md +64 -8
- data/LICENSE.txt +1 -1
- data/README.md +31 -102
- data/Rakefile +56 -18
- data/bin/mtk +215 -0
- data/examples/crescendo.rb +5 -5
- data/examples/drum_pattern1.rb +23 -0
- data/examples/dynamic_pattern.rb +8 -11
- data/examples/gets_and_play.rb +26 -0
- data/examples/notation.rb +22 -0
- data/examples/play_midi.rb +8 -10
- data/examples/random_tone_row.rb +2 -2
- data/examples/syntax_to_midi.rb +28 -0
- data/examples/test_output.rb +8 -0
- data/examples/tone_row_melody.rb +6 -6
- data/lib/mtk.rb +52 -40
- data/lib/mtk/chord.rb +55 -0
- data/lib/mtk/constants/durations.rb +57 -0
- data/lib/mtk/constants/intensities.rb +61 -0
- data/lib/mtk/constants/intervals.rb +73 -0
- data/lib/mtk/constants/pitch_classes.rb +29 -0
- data/lib/mtk/constants/pitches.rb +52 -0
- data/lib/mtk/duration.rb +211 -0
- data/lib/mtk/events/event.rb +119 -0
- data/lib/mtk/events/note.rb +112 -0
- data/lib/mtk/events/parameter.rb +54 -0
- data/lib/mtk/helpers/collection.rb +164 -0
- data/lib/mtk/helpers/convert.rb +36 -0
- data/lib/mtk/helpers/lilypond.rb +162 -0
- data/lib/mtk/helpers/output_selector.rb +67 -0
- data/lib/mtk/helpers/pitch_collection.rb +23 -0
- data/lib/mtk/helpers/pseudo_constants.rb +26 -0
- data/lib/mtk/intensity.rb +156 -0
- data/lib/mtk/interval.rb +155 -0
- data/lib/mtk/lang/mtk_grammar.citrus +190 -13
- data/lib/mtk/lang/parser.rb +29 -0
- data/lib/mtk/melody.rb +94 -0
- data/lib/mtk/midi/dls_synth_device.rb +144 -0
- data/lib/mtk/midi/dls_synth_output.rb +62 -0
- data/lib/mtk/midi/file.rb +67 -32
- data/lib/mtk/midi/input.rb +97 -0
- data/lib/mtk/midi/jsound_input.rb +36 -17
- data/lib/mtk/midi/jsound_output.rb +48 -46
- data/lib/mtk/midi/output.rb +195 -0
- data/lib/mtk/midi/unimidi_input.rb +117 -0
- data/lib/mtk/midi/unimidi_output.rb +121 -0
- data/lib/mtk/{_numeric_extensions.rb → numeric_extensions.rb} +12 -0
- data/lib/mtk/patterns/chain.rb +49 -0
- data/lib/mtk/{pattern → patterns}/choice.rb +14 -8
- data/lib/mtk/patterns/cycle.rb +18 -0
- data/lib/mtk/patterns/for_each.rb +71 -0
- data/lib/mtk/patterns/function.rb +39 -0
- data/lib/mtk/{pattern → patterns}/lines.rb +11 -17
- data/lib/mtk/{pattern → patterns}/palindrome.rb +11 -8
- data/lib/mtk/patterns/pattern.rb +171 -0
- data/lib/mtk/patterns/sequence.rb +20 -0
- data/lib/mtk/pitch.rb +7 -6
- data/lib/mtk/pitch_class.rb +124 -46
- data/lib/mtk/pitch_class_set.rb +58 -35
- data/lib/mtk/sequencers/event_builder.rb +131 -0
- data/lib/mtk/sequencers/legato_sequencer.rb +24 -0
- data/lib/mtk/sequencers/rhythmic_sequencer.rb +28 -0
- data/lib/mtk/{sequencer/abstract_sequencer.rb → sequencers/sequencer.rb} +37 -11
- data/lib/mtk/{sequencer → sequencers}/step_sequencer.rb +4 -4
- data/lib/mtk/timeline.rb +39 -22
- data/lib/mtk/variable.rb +32 -0
- data/spec/mtk/chord_spec.rb +83 -0
- data/spec/mtk/{_constants → constants}/durations_spec.rb +12 -41
- data/spec/mtk/{_constants → constants}/intensities_spec.rb +13 -37
- data/spec/mtk/{_constants → constants}/intervals_spec.rb +14 -32
- data/spec/mtk/{_constants → constants}/pitch_classes_spec.rb +8 -4
- data/spec/mtk/{_constants → constants}/pitches_spec.rb +5 -1
- data/spec/mtk/duration_spec.rb +372 -0
- data/spec/mtk/events/event_spec.rb +234 -0
- data/spec/mtk/events/note_spec.rb +174 -0
- data/spec/mtk/events/parameter_spec.rb +220 -0
- data/spec/mtk/{helper → helpers}/collection_spec.rb +86 -3
- data/spec/mtk/{helper → helpers}/pseudo_constants_spec.rb +2 -2
- data/spec/mtk/intensity_spec.rb +289 -0
- data/spec/mtk/interval_spec.rb +265 -0
- data/spec/mtk/lang/parser_spec.rb +597 -0
- data/spec/mtk/melody_spec.rb +223 -0
- data/spec/mtk/midi/file_spec.rb +16 -16
- data/spec/mtk/midi/jsound_input_spec.rb +11 -0
- data/spec/mtk/midi/jsound_output_spec.rb +11 -0
- data/spec/mtk/midi/output_spec.rb +102 -0
- data/spec/mtk/midi/unimidi_input_spec.rb +11 -0
- data/spec/mtk/midi/unimidi_output_spec.rb +11 -0
- data/spec/mtk/{_numeric_extensions_spec.rb → numeric_extensions_spec.rb} +1 -0
- data/spec/mtk/patterns/chain_spec.rb +110 -0
- data/spec/mtk/{pattern → patterns}/choice_spec.rb +20 -30
- data/spec/mtk/{pattern → patterns}/cycle_spec.rb +25 -35
- data/spec/mtk/patterns/for_each_spec.rb +136 -0
- data/spec/mtk/{pattern → patterns}/function_spec.rb +17 -30
- data/spec/mtk/{pattern → patterns}/lines_spec.rb +11 -27
- data/spec/mtk/{pattern → patterns}/palindrome_spec.rb +13 -29
- data/spec/mtk/patterns/pattern_spec.rb +132 -0
- data/spec/mtk/patterns/sequence_spec.rb +203 -0
- data/spec/mtk/pitch_class_set_spec.rb +23 -21
- data/spec/mtk/pitch_class_spec.rb +151 -39
- data/spec/mtk/pitch_spec.rb +22 -1
- data/spec/mtk/sequencers/event_builder_spec.rb +245 -0
- data/spec/mtk/sequencers/legato_sequencer_spec.rb +45 -0
- data/spec/mtk/sequencers/rhythmic_sequencer_spec.rb +84 -0
- data/spec/mtk/sequencers/sequencer_spec.rb +215 -0
- data/spec/mtk/{sequencer → sequencers}/step_sequencer_spec.rb +35 -13
- data/spec/mtk/timeline_spec.rb +109 -16
- data/spec/mtk/variable_spec.rb +52 -0
- data/spec/spec_coverage.rb +2 -0
- data/spec/spec_helper.rb +3 -0
- metadata +188 -91
- data/lib/mtk/_constants/durations.rb +0 -80
- data/lib/mtk/_constants/intensities.rb +0 -81
- data/lib/mtk/_constants/intervals.rb +0 -85
- data/lib/mtk/_constants/pitch_classes.rb +0 -35
- data/lib/mtk/_constants/pitches.rb +0 -49
- data/lib/mtk/event.rb +0 -70
- data/lib/mtk/helper/collection.rb +0 -114
- data/lib/mtk/helper/event_builder.rb +0 -85
- data/lib/mtk/helper/pseudo_constants.rb +0 -26
- data/lib/mtk/lang/grammar.rb +0 -17
- data/lib/mtk/note.rb +0 -63
- data/lib/mtk/pattern/abstract_pattern.rb +0 -132
- data/lib/mtk/pattern/cycle.rb +0 -51
- data/lib/mtk/pattern/enumerator.rb +0 -26
- data/lib/mtk/pattern/function.rb +0 -46
- data/lib/mtk/pattern/sequence.rb +0 -30
- data/lib/mtk/pitch_set.rb +0 -84
- data/lib/mtk/sequencer/rhythmic_sequencer.rb +0 -29
- data/lib/mtk/transform/invertible.rb +0 -15
- data/lib/mtk/transform/mappable.rb +0 -18
- data/lib/mtk/transform/set_theory_operations.rb +0 -34
- data/lib/mtk/transform/transposable.rb +0 -14
- data/spec/mtk/event_spec.rb +0 -139
- data/spec/mtk/helper/event_builder_spec.rb +0 -92
- data/spec/mtk/lang/grammar_spec.rb +0 -100
- data/spec/mtk/note_spec.rb +0 -115
- data/spec/mtk/pattern/abstract_pattern_spec.rb +0 -45
- data/spec/mtk/pattern/note_cycle_spec.rb.bak +0 -116
- data/spec/mtk/pattern/pitch_cycle_spec.rb.bak +0 -47
- data/spec/mtk/pattern/pitch_sequence_spec.rb.bak +0 -37
- data/spec/mtk/pattern/sequence_spec.rb +0 -151
- data/spec/mtk/pitch_set_spec.rb +0 -198
- data/spec/mtk/sequencer/abstract_sequencer_spec.rb +0 -159
- 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
|
data/examples/crescendo.rb
CHANGED
@@ -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 =
|
14
|
-
crescendo =
|
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 =
|
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
|
data/examples/dynamic_pattern.rb
CHANGED
@@ -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
|
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 =
|
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 =
|
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
|
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
|
data/examples/play_midi.rb
CHANGED
@@ -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,
|
6
|
-
unless file
|
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/
|
14
|
-
include MTK
|
11
|
+
require 'mtk/helpers/output_selector'
|
15
12
|
|
16
|
-
|
17
|
-
player = MTK::MIDI::JSoundOutput.new output
|
13
|
+
output = MTK::Helpers::OutputSelector.ensure_output(output_name)
|
18
14
|
|
19
|
-
|
15
|
+
timeline = MTK.MIDI_File(file).to_timelines
|
16
|
+
|
17
|
+
output.play(timeline)
|
data/examples/random_tone_row.rb
CHANGED
@@ -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 =
|
12
|
+
sequence = Patterns.Sequence *row
|
13
13
|
|
14
|
-
sequencer =
|
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
|
+
|
data/examples/tone_row_melody.rb
CHANGED
@@ -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
|
14
|
-
pitch_pattern =
|
15
|
-
rhythm_pattern =
|
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 =
|
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
|