Class: PM::DSL
- Inherits:
-
Object
show all
- Includes:
- PM
- Defined in:
- lib/patchmaster/dsl.rb
Overview
Implements a DSL for describing a PatchMaster setup.
Constant Summary
Constants included
from PM
ACTIVE_SENSE, CC_BALANCE, CC_BALANCE_LSB, CC_BANK_SELECT, CC_BANK_SELECT_LSB, CC_BREATH_CONTROLLER, CC_BREATH_CONTROLLER_LSB, CC_CHORUS_DEPTH, CC_DATA_DECREMENT, CC_DATA_ENTRY, CC_DATA_ENTRY_LSB, CC_DATA_INCREMENT, CC_DETUNE_DEPTH, CC_EXPRESSION_CONTROLLER, CC_EXPRESSION_CONTROLLER_LSB, CC_EXT_EFFECTS_DEPTH, CC_FOOT_CONTROLLER, CC_FOOT_CONTROLLER_LSB, CC_GEN_PURPOSE_1, CC_GEN_PURPOSE_1_LSB, CC_GEN_PURPOSE_2, CC_GEN_PURPOSE_2_LSB, CC_GEN_PURPOSE_3, CC_GEN_PURPOSE_3_LSB, CC_GEN_PURPOSE_4, CC_GEN_PURPOSE_4_LSB, CC_GEN_PURPOSE_5, CC_GEN_PURPOSE_6, CC_GEN_PURPOSE_7, CC_GEN_PURPOSE_8, CC_HOLD_2, CC_MOD_WHEEL, CC_MOD_WHEEL_LSB, CC_NREG_PARAM_LSB, CC_NREG_PARAM_MSB, CC_PAN, CC_PAN_LSB, CC_PHASER_DEPTH, CC_PORTAMENTO, CC_PORTAMENTO_TIME, CC_PORTAMENTO_TIME_LSB, CC_REG_PARAM_LSB, CC_REG_PARAM_MSB, CC_SOFT_PEDAL, CC_SUSTAIN, CC_SUSTENUTO, CC_TREMELO_DEPTH, CC_VOLUME, CC_VOLUME_LSB, CHANNEL_PRESSURE, CLOCK, CM_ALL_NOTES_OFF, CM_LOCAL_CONTROL, CM_MONO_MODE_ON, CM_OMNI_MODE_OFF, CM_OMNI_MODE_ON, CM_POLY_MODE_ON, CM_RESET_ALL_CONTROLLERS, CONTINUE, CONTROLLER, CONTROLLER_NAMES, EOX, GM_DRUM_NOTE_LOWEST, GM_DRUM_NOTE_NAMES, GM_PATCH_NAMES, META_COPYRIGHT, META_CUE, META_EVENT, META_INSTRUMENT, META_LYRIC, META_MARKER, META_MIDI_CHAN_PREFIX, META_PATCH_SIG, META_SEQ_NAME, META_SEQ_NUM, META_SEQ_SPECIF, META_SET_TEMPO, META_SMPTE, META_TEXT, META_TIME_SIG, META_TRACK_END, MIDI_CHANNELS, NOTES_PER_CHANNEL, NOTE_OFF, NOTE_ON, PITCH_BEND, POLY_PRESSURE, PROGRAM_CHANGE, SONG_POINTER, SONG_SELECT, START, STOP, SYSEX, SYSTEM_RESET, TUNE_REQUEST
Instance Method Summary
collapse
-
#alias_input(new_sym, old_sym) ⇒ Object
-
#alias_output(new_sym, old_sym) ⇒ Object
-
#code_key(key_or_sym, &block) ⇒ Object
-
#connection(in_sym, in_chan, out_sym, out_chan = nil) {|@conn| ... } ⇒ Object
(also: #conn, #c)
in_chan can be skipped, so “connection :foo, :bar, 1” is the same as “connection :foo, nil, :bar, 1”.
-
#filter(&block) ⇒ Object
(also: #f)
-
#init ⇒ Object
Initialize state used for reading.
-
#initialize ⇒ DSL
constructor
-
#input(port_num, sym, name = nil) ⇒ Object
(also: #inp)
-
#load(file) ⇒ Object
-
#message(name, bytes) ⇒ Object
-
#message_key(key_or_sym, name) ⇒ Object
-
#notes(txt) ⇒ Object
-
#output(port_num, sym, name = nil) ⇒ Object
(also: #out, #outp)
-
#patch(name) {|@patch| ... } ⇒ Object
-
#prog_chg(bank_or_prog, prog = nil) ⇒ Object
(also: #pc)
If only bank_or_prog
is specified, then it’s a program change.
-
#save(file) ⇒ Object
****************************************************************.
-
#save_code_keys(f) ⇒ Object
-
#save_connection(f, conn) ⇒ Object
-
#save_instruments(f) ⇒ Object
-
#save_message_keys(f) ⇒ Object
-
#save_messages(f) ⇒ Object
-
#save_patch(f, patch) ⇒ Object
-
#save_song_lists(f) ⇒ Object
-
#save_songs(f) ⇒ Object
-
#save_triggers(f) ⇒ Object
-
#song(name) {|@song| ... } ⇒ Object
-
#song_list(name, song_names) ⇒ Object
-
#start_bytes(bytes) ⇒ Object
-
#stop_bytes(bytes) ⇒ Object
-
#transpose(xpose) ⇒ Object
(also: #xpose, #x)
-
#trigger(instrument_sym, bytes, &block) ⇒ Object
-
#zone(start_or_range = nil, stop = nil) ⇒ Object
(also: #z)
If start_or_range
is a Range, use that.
Constructor Details
#initialize ⇒ DSL
Returns a new instance of DSL.
11
12
13
14
|
# File 'lib/patchmaster/dsl.rb', line 11
def initialize
@pm = PatchMaster.instance
init
end
|
Instance Method Details
187
188
189
|
# File 'lib/patchmaster/dsl.rb', line 187
def alias_input(new_sym, old_sym)
@inputs[new_sym] = @inputs[old_sym]
end
|
#alias_output(new_sym, old_sym) ⇒ Object
191
192
193
|
# File 'lib/patchmaster/dsl.rb', line 191
def alias_output(new_sym, old_sym)
@outputs[new_sym] = @outputs[old_sym]
end
|
#code_key(key_or_sym, &block) ⇒ Object
82
83
84
85
86
|
# File 'lib/patchmaster/dsl.rb', line 82
def code_key(key_or_sym, &block)
ck = CodeKey.new(to_binding_key(key_or_sym), CodeChunk.new(block))
@pm.bind_code(ck)
@code_keys << ck
end
|
#connection(in_sym, in_chan, out_sym, out_chan = nil) {|@conn| ... } ⇒ Object
Also known as:
conn, c
in_chan can be skipped, so “connection :foo, :bar, 1” is the same as “connection :foo, nil, :bar, 1”.
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
# File 'lib/patchmaster/dsl.rb', line 122
def connection(in_sym, in_chan, out_sym, out_chan=nil)
input = @inputs[in_sym]
if in_chan.kind_of? Symbol
out_chan = out_sym
out_sym = in_chan
in_chan = nil
end
raise "can't find input instrument #{in_sym}" unless input
output = @outputs[out_sym]
raise "can't find outputput instrument #{out_sym}" unless output
@conn = Connection.new(input, in_chan, output, out_chan)
@patch << @conn
yield @conn if block_given?
end
|
#filter(&block) ⇒ Object
Also known as:
f
171
172
173
174
|
# File 'lib/patchmaster/dsl.rb', line 171
def filter(&block)
@conn.filter = Filter.new(CodeChunk.new(block))
@filters << @conn.filter
end
|
#init ⇒ Object
Initialize state used for reading.
17
18
19
20
21
22
23
24
|
# File 'lib/patchmaster/dsl.rb', line 17
def init
@inputs = {}
@outputs = {}
@triggers = []
@filters = []
@code_keys = []
@songs = {} end
|
35
36
37
38
39
40
41
42
43
|
# File 'lib/patchmaster/dsl.rb', line 35
def input(port_num, sym, name=nil)
raise "input: two inputs can not have the same symbol (:#{sym})" if @inputs[sym]
input = InputInstrument.new(sym, name, port_num, @pm.use_midi?)
@inputs[sym] = input
@pm.inputs << input
rescue => ex
raise "input: error creating input instrument \"#{name || sym}\" on input port #{port_num}: #{ex}"
end
|
#load(file) ⇒ Object
26
27
28
29
30
31
32
33
|
# File 'lib/patchmaster/dsl.rb', line 26
def load(file)
contents = IO.read(file)
init
instance_eval(contents)
read_code_keys(contents)
read_triggers(contents)
read_filters(contents)
end
|
#message(name, bytes) ⇒ Object
58
59
60
|
# File 'lib/patchmaster/dsl.rb', line 58
def message(name, bytes)
@pm.messages[name.downcase] = [name, bytes]
end
|
#message_key(key_or_sym, name) ⇒ Object
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
# File 'lib/patchmaster/dsl.rb', line 62
def message_key(key_or_sym, name)
if name.is_a?(Symbol)
name, key_or_sym = key_or_sym, name
$stderr.puts "WARNING: the arguments to message_key are now key first, then name."
$stderr.puts "I will use #{name} as the name and #{key_or_sym} as the key for now."
$stderr.puts "Please swap them for future compatability."
end
if key_or_sym.is_a?(String) && name.is_a?(String)
if name.length == 1 && key_or_sym.length > 1
name, key_or_sym = key_or_sym, name
$stderr.puts "WARNING: the arguments to message_key are now key first, then name."
$stderr.puts "I will use #{name} as the name and #{key_or_sym} as the key for now."
$stderr.puts "Please swap them for future compatability."
elsif name.length == 1 && key_or_sym.length == 1
raise "message_key: since both name and key are one-character strings, I can't tell which is which. Please make the name longer."
end
end
@pm.bind_message(name, to_binding_key(key_or_sym))
end
|
#notes(txt) ⇒ Object
102
103
104
|
# File 'lib/patchmaster/dsl.rb', line 102
def notes(txt)
@song.notes = txt
end
|
#output(port_num, sym, name = nil) ⇒ Object
Also known as:
out, outp
46
47
48
49
50
51
52
53
54
|
# File 'lib/patchmaster/dsl.rb', line 46
def output(port_num, sym, name=nil)
raise "output: two outputs can not have the same symbol (:#{sym})" if @outputs[sym]
output = OutputInstrument.new(sym, name, port_num, @pm.use_midi?)
@outputs[sym] = output
@pm.outputs << output
rescue => ex
raise "output: error creating output instrument \"#{name || sym}\" on output port #{port_num}: #{ex}"
end
|
#patch(name) {|@patch| ... } ⇒ Object
106
107
108
109
110
|
# File 'lib/patchmaster/dsl.rb', line 106
def patch(name)
@patch = Patch.new(name)
@song << @patch
yield @patch if block_given?
end
|
#prog_chg(bank_or_prog, prog = nil) ⇒ Object
Also known as:
pc
If only bank_or_prog
is specified, then it’s a program change. If both, then it’s bank number.
142
143
144
145
146
147
148
149
|
# File 'lib/patchmaster/dsl.rb', line 142
def prog_chg(bank_or_prog, prog=nil)
if prog
@conn.bank = bank_or_prog
@conn.pc_prog = prog
else
@conn.pc_prog = bank_or_prog
end
end
|
#save(file) ⇒ Object
****************************************************************
197
198
199
200
201
202
203
204
205
206
207
|
# File 'lib/patchmaster/dsl.rb', line 197
def save(file)
File.open(file, 'w') { |f|
save_instruments(f)
save_messages(f)
save_message_keys(f)
save_code_keys(f)
save_triggers(f)
save_songs(f)
save_song_lists(f)
}
end
|
#save_code_keys(f) ⇒ Object
231
232
233
234
235
236
237
238
239
240
|
# File 'lib/patchmaster/dsl.rb', line 231
def save_code_keys(f)
@pm.code_bindings.values.each do |code_key|
str = if code_key.code_chunk.text[0] == '{'
"code_key(#{to_save_key(code_key.key).inspect}) #{code_key.code_chunk.text}"
else
"code_key #{to_save_key(code_key.key).inspect} #{code_key.code_chunk.text}"
end
f.puts str
end
end
|
#save_connection(f, conn) ⇒ Object
268
269
270
271
272
273
274
275
276
277
|
# File 'lib/patchmaster/dsl.rb', line 268
def save_connection(f, conn)
in_chan = conn.input_chan ? conn.input_chan + 1 : 'nil'
out_chan = conn.output_chan + 1
f.puts " conn :#{conn.input.sym}, #{in_chan}, :#{conn.output.sym}, #{out_chan} do"
f.puts " prog_chg #{conn.pc_prog}" if conn.pc?
f.puts " zone #{conn.note_num_to_name(conn.zone.begin)}, #{conn.note_num_to_name(conn.zone.end)}" if conn.zone
f.puts " xpose #{conn.xpose}" if conn.xpose
f.puts " filter #{conn.filter.code_chunk.text}" if conn.filter
f.puts " end"
end
|
#save_instruments(f) ⇒ Object
209
210
211
212
213
214
215
216
217
|
# File 'lib/patchmaster/dsl.rb', line 209
def save_instruments(f)
@pm.inputs.each do |instr|
f.puts "input #{instr.port_num}, :#{instr.sym}, #{instr.name.inspect}"
end
@pm.outputs.each do |instr|
f.puts "output #{instr.port_num}, :#{instr.sym}, #{instr.name.inspect}"
end
f.puts
end
|
#save_message_keys(f) ⇒ Object
225
226
227
228
229
|
# File 'lib/patchmaster/dsl.rb', line 225
def save_message_keys(f)
@pm.message_bindings.each do |key, message_name|
f.puts "message_key #{to_save_key(key).inspect}, #{message_name.inspect}"
end
end
|
#save_messages(f) ⇒ Object
219
220
221
222
223
|
# File 'lib/patchmaster/dsl.rb', line 219
def save_messages(f)
@pm.messages.each do |_, (correct_case_name, msg)|
f.puts "message #{correct_case_name.inspect}, #{msg.inspect}"
end
end
|
#save_patch(f, patch) ⇒ Object
261
262
263
264
265
266
|
# File 'lib/patchmaster/dsl.rb', line 261
def save_patch(f, patch)
f.puts " patch #{patch.name.inspect} do"
f.puts " start_bytes #{patch.start_bytes.inspect}" if patch.start_bytes
patch.connections.each { |conn| save_connection(f, conn) }
f.puts " end"
end
|
#save_song_lists(f) ⇒ Object
279
280
281
282
283
284
285
286
287
288
|
# File 'lib/patchmaster/dsl.rb', line 279
def save_song_lists(f)
@pm.song_lists.each do |sl|
next if sl == @pm.all_songs
f.puts "song_list #{sl.name.inspect}, ["
@pm.all_songs.songs.each do |song|
f.puts " #{song.name.inspect},"
end
f.puts "]"
end
end
|
#save_songs(f) ⇒ Object
252
253
254
255
256
257
258
259
|
# File 'lib/patchmaster/dsl.rb', line 252
def save_songs(f)
@pm.all_songs.songs.each do |song|
f.puts "song #{song.name.inspect} do"
song.patches.each { |patch| save_patch(f, patch) }
f.puts "end"
f.puts
end
end
|
#save_triggers(f) ⇒ Object
242
243
244
245
246
247
248
249
250
|
# File 'lib/patchmaster/dsl.rb', line 242
def save_triggers(f)
@pm.inputs.each do |instrument|
instrument.triggers.each do |trigger|
str = "trigger :#{instrument.sym}, #{trigger.bytes.inspect} #{trigger.code_chunk.text}"
f.puts str
end
end
f.puts
end
|
#song(name) {|@song| ... } ⇒ Object
96
97
98
99
100
|
# File 'lib/patchmaster/dsl.rb', line 96
def song(name)
@song = Song.new(name) @songs[name] = @song
yield @song if block_given?
end
|
#song_list(name, song_names) ⇒ Object
177
178
179
180
181
182
183
184
185
|
# File 'lib/patchmaster/dsl.rb', line 177
def song_list(name, song_names)
sl = SongList.new(name)
@pm.song_lists << sl
song_names.each do |sn|
song = @songs[sn]
raise "song \"#{sn}\" not found (song list \"#{name}\")" unless song
sl << song
end
end
|
#start_bytes(bytes) ⇒ Object
112
113
114
|
# File 'lib/patchmaster/dsl.rb', line 112
def start_bytes(bytes)
@patch.start_bytes = bytes
end
|
#stop_bytes(bytes) ⇒ Object
116
117
118
|
# File 'lib/patchmaster/dsl.rb', line 116
def stop_bytes(bytes)
@patch.stop_bytes = bytes
end
|
#transpose(xpose) ⇒ Object
Also known as:
xpose, x
165
166
167
|
# File 'lib/patchmaster/dsl.rb', line 165
def transpose(xpose)
@conn.xpose = xpose
end
|
#trigger(instrument_sym, bytes, &block) ⇒ Object
88
89
90
91
92
93
94
|
# File 'lib/patchmaster/dsl.rb', line 88
def trigger(instrument_sym, bytes, &block)
instrument = @inputs[instrument_sym]
raise "trigger: error finding instrument #{instrument_sym}" unless instrument
t = Trigger.new(bytes, CodeChunk.new(block))
instrument.triggers << t
@triggers << t
end
|
#zone(start_or_range = nil, stop = nil) ⇒ Object
Also known as:
z
If start_or_range
is a Range, use that. Else either or both params may be nil.
154
155
156
157
158
159
160
161
162
|
# File 'lib/patchmaster/dsl.rb', line 154
def zone(start_or_range=nil, stop=nil)
@conn.zone = if start_or_range.kind_of? Range
start_or_range
elsif start_or_range == nil && stop == nil
nil
else
((start_or_range || 0) .. (stop || 127))
end
end
|