class PM::PatchMaster
Global behavior: master list of songs, list of song lists, stuff like that.
Typical use:
PatchMaster.instance.load("my_pm_dsl_file") PatchMaster.instance.start # ...when you're done PatchMaster.instance.stop
Constants
- DEBUG_FILE
Attributes
A Cursor
to which we delegate incoming position methods (song_list, song, patch, next_song, prev_patch, etc.)
Public Class Methods
# File lib/patchmaster/patchmaster.rb, line 34 def initialize @running = false @cursor = Cursor.new(self) super(@cursor) @use_midi = true @gui = nil @message_bindings = {} @code_bindings = {} if $DEBUG @debug_file = File.open(DEBUG_FILE, 'a') end init_data end
Public Instance Methods
# File lib/patchmaster/patchmaster.rb, line 86 def bind_code(code_key) @code_bindings[code_key.key] = code_key end
# File lib/patchmaster/patchmaster.rb, line 82 def bind_message(name, key) @message_bindings[key] = name end
# File lib/patchmaster/patchmaster.rb, line 180 def close_debug_file @debug_file.close if @debug_file end
Output str
to @debug_file or $stderr.
# File lib/patchmaster/patchmaster.rb, line 173 def debug(str) return unless $DEBUG f = @debug_file || $stderr f.puts str f.flush end
Initializes the cursor and all data.
# File lib/patchmaster/patchmaster.rb, line 91 def init_data @cursor.clear @inputs = [] @outputs = [] @song_lists = [] @all_songs = SortedSongList.new('All Songs') @song_lists << @all_songs @messages = {} end
Loads file
. Does its best to restore the current song list, song, and patch after loading.
# File lib/patchmaster/patchmaster.rb, line 56 def load(file) restart = running? stop @cursor.mark init_data DSL.new.load(file) @loaded_file = file @cursor.restore if restart start(false) elsif @cursor.patch @cursor.patch.start end rescue => ex raise("error loading #{file}: #{ex}\n" + caller.join("\n")) end
# File lib/patchmaster/patchmaster.rb, line 50 def no_gui! @no_gui = true end
Sends the CM_ALL_NOTES_OFF
controller message to all output instruments on all 16 MIDI channels. If individual_notes
is true
send individual NOTE_OFF
messages to all notes as well.
# File lib/patchmaster/patchmaster.rb, line 158 def panic(individual_notes=false) debug("panic(#{individual_notes})") @outputs.each do |out| buf = [] MIDI_CHANNELS.times do |chan| buf += [CONTROLLER + chan, CM_ALL_NOTES_OFF, 0] if individual_notes buf += (0..127).collect { |note| [NOTE_OFF + chan, note, 0] }.flatten end end out.midi_out(buf) end end
Run PatchMaster
without the GUI. Don't use this when using PM::Main
. If there is a GUI then forward this request to it. Otherwise, call start
, wait for inputs' MIDIEye listener threads to finish, then call stop
. Note that normally nothing stops those threads, so this is used as a way to make sure the script doesn't quit until killed by something like SIGINT.
# File lib/patchmaster/patchmaster.rb, line 123 def run if @gui @gui.run else start(true) @inputs.each { |input| input.listener.join } stop end end
# File lib/patchmaster/patchmaster.rb, line 133 def running? @running end
# File lib/patchmaster/patchmaster.rb, line 75 def save(file) DSL.new.save(file) @loaded_file = file rescue => ex raise("error saving #{file}: #{ex}" + caller.join("\n")) end
Send the message with the given name
to all outputs. Names are matched case-insensitively.
# File lib/patchmaster/patchmaster.rb, line 139 def send_message(name) _correct_case_name, msg = @messages[name.downcase] if !msg message("Message \"#{name}\" not found") return end debug("Sending message \"#{name}\"") @outputs.each { |out| out.midi_out(msg) } # If the user accidentally calls send_message in a filter at the end, # then the filter will return whatever this method returns. Just in # case, return nil instead of whatever the preceding code would return. nil end
If init_cursor
is true
(the default), initializes current song list, song, and patch.
# File lib/patchmaster/patchmaster.rb, line 103 def start(init_cursor = true) @cursor.init if init_cursor @cursor.patch.start if @cursor.patch @running = true @inputs.map(&:start) end
Stop everything, including input instruments' MIDIEye listener threads.
# File lib/patchmaster/patchmaster.rb, line 111 def stop @cursor.patch.stop if @cursor.patch @inputs.map(&:stop) @running = false end