Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. require 'dl/import' module Enumerable def rest return [] if empty? self[1..-1] end end class LiveMIDI ON = 0x90 OFF = 0x80 PC = 0xC0 attr_reader :interval @@singleton = nil def self.use(bpm=120) return @@singleton = self.new(bpm) if @@singleton.nil? @@singleton.bpm = bpm return @@singleton end def initialize(bpm=120) self.bpm = bpm @timer = Timer.get(@interval/10) open end def bpm=(bpm) @interval = 60.0 / bpm end def play(channel, note, duration, velocity=100, time=nil) on_time = time || Time.now.to_f @timer.at(on_time) { note_on(channel, note, velocity) } off_time = on_time + duration @timer.at(off_time) { note_off(channel, note, velocity) } end def note_on(channel, note, velocity=64) message(ON | channel, note, velocity) end def note_off(channel, note, velocity=64) message(OFF | channel, note, velocity) end def program_change(channel, preset) message(PC | channel, preset) end end class NoMIDIDestinations < Exception; end if RUBY_PLATFORM.include?('mswin') class LiveMIDI module C extend DL::Importable dlload 'winmm' extern "int midiOutOpen(HMIDIOUT*, int, int, int, int)" extern "int midiOutClose(int)" extern "int midiOutShortMsg(int, int)" end def open @device = DL.malloc(DL.sizeof('I')) C.midiOutOpen(@device, -1, 0, 0, 0) end def close C.midiOutClose(@device.ptr.to_i) end def message(one, two=0, three=0) message = one + (two << 8) + (three << 16) C.midiOutShortMsg(@device.ptr.to_i, message) end end elsif RUBY_PLATFORM.include?('darwin') class LiveMIDI module C extend DL::Importable dlload '/System/Library/Frameworks/CoreMIDI.framework/Versions/Current/CoreMIDI' extern "int MIDIClientCreate(void *, void *, void *, void *)" extern "int MIDIClientDispose(void *)" extern "int MIDIGetNumberOfDestinations()" extern "void * MIDIGetDestination(int)" extern "int MIDIOutputPortCreate(void *, void *, void *)" extern "void * MIDIPacketListInit(void *)" extern "void * MIDIPacketListAdd(void *, int, void *, int, int, int, void *)" extern "int MIDISend(void *, void *, void *)" end module CF extend DL::Importable dlload '/System/Library/Frameworks/CoreFoundation.framework/Versions/Current/CoreFoundation' extern "void * CFStringCreateWithCString (void *, char *, int)" end def open client_name = CF.cFStringCreateWithCString(nil, "RubyMIDI", 0) @client = DL::PtrData.new(nil) C.mIDIClientCreate(client_name, nil, nil, @client.ref); port_name = CF.cFStringCreateWithCString(nil, "Output", 0) @outport = DL::PtrData.new(nil) C.mIDIOutputPortCreate(@client, port_name, @outport.ref); num = C.mIDIGetNumberOfDestinations() raise NoMIDIDestinations if num < 1 @destination = C.mIDIGetDestination(0) end def close C.mIDIClientDispose(@client) end def message(*args) format = "C" * args.size bytes = args.pack(format).to_ptr packet_list = DL.malloc(256) packet_ptr = C.mIDIPacketListInit(packet_list) # Pass in two 32 bit 0s for the 64 bit time packet_ptr = C.mIDIPacketListAdd(packet_list, 256, packet_ptr, 0, 0, args.size, bytes) C.mIDISend(@outport, @destination, packet_list) end end elsif RUBY_PLATFORM.include?('linux') class LiveMIDI module C extend DL::Importable dlload 'libasound.so' extern "int snd_rawmidi_open(void*, void*, char*, int)" extern "int snd_rawmidi_close(void*)" extern "int snd_rawmidi_write(void*, void*, int)" extern "int snd_rawmidi_drain(void*)" end def open @output = DL::PtrData.new(nil) C.snd_rawmidi_open(nil, @output.ref, "virtual", 0) end def close C.snd_rawmidi_close(@output) end def message(*args) format = "C" * args.size bytes = args.pack(format).to_ptr C.snd_rawmidi_write(@output, bytes, args.size) C.snd_rawmidi_drain(@output) end end else raise "Couldn't find a LiveMIDI implementation for your platform" end class Timer def self.get(interval) @timers ||= {} return @timers[interval] if @timers[interval] return @timers[interval] = self.new(interval) end def initialize(resolution) @resolution = resolution @queue = [] Thread.new do while true dispatch sleep(@resolution) end end end end
This paste will be private.
From the Design Piracy series on my blog: