hello Lorien,
i don't know this device, but after a quick glance at your code, i
spot one possible optimisation...
{var byte= 0xFF; 1000000.do{if((byte>=0xF8).and(byte<=0xFF), {11},
{22})}}.bench;""
{var byte= 0xFF; 1000000.do{if((byte>=0xF8) and:{byte<=0xFF}, {11},
{22})}}.bench;""
ie replace all .and() with and:{} and it'll save a few cpu cycles.
also did you consider closing the serial port at command period?
something like CmdPeriod.doOnce{this.stop}. your task will be killed
anyway so there's no way - as it looks to me now - to recover a
cmdperiod without manually closing the port and reinstantiating. so
why not also stop+close at cmdperiod i mean. just a suggestion.
_f
15 apr 2009 kl. 10.02 skrev Lorien Dunn:
> Hi all,
> this code allows me to use my infusionsystems usbmicrodig in
> standalone mode without having the icubex editor running (the
> usbmicrodig is a usb serial device rather than usb midi device). It
> works very well indeed on my macbook, and should work on Linux (and
> Windows if SerialPort works). But I'm still a comparative newbie to
> supercollider and would appreciate some constructive criticism.
> Advice for optimisation would be nice too- under heavy sensor load
> with a 1ms sampling rate it's taken 20% of one core of a 2gHz core2,
> though under normal usage it's between 2 and 4%.
> the midi parser is loosely based on libmidi++ by Paul Davis.
>
> thanks,
> Lorien
>
> LowLevelMidiParser
> {
> classvar noteOffStat=0x80, noteOnStat=0x90, polytouchStat=0xA0,
> controlStat=0xB0;
> classvar programStat=0xC0, touchStat=0xD0, bendStat=0xE0; classvar
> sysexStat=0xF0, qFrameStat=0xF1, songPositionStat=0xF2,
> songSelectStat=0xF3;
> classvar tuneRequestStat=0xF6, eoxStat=0xF7;
> classvar bufferSize=16;
> var parserState, runnable, msgType, msgBuffer;
> var <noteOn, <noteOff;
> var <polytouch, <control;
> var <program, <touch;
> var <bend;
> var <>sysex;
>
> *new
> {
> var self = super.new;
> self.initLLMP;
> ^self;
> }
>
> initLLMP
> {
> noteOn = Array.fill(16,{|i| nil});
> noteOff = Array.fill(16,{|i| nil});
> polytouch = Array.fill(16,{|i| nil});
> control = Array.fill(16,{|i| Array.fill(128,{|j| nil})});
> program = Array.fill(16,{|i| nil});
> touch = Array.fill(16,{|i| nil});
> bend = Array.fill(16,{|i| nil});
> sysex = nil;
> parserState = \needStatus;
> runnable = true;
> msgType = noteOnStat;
> msgBuffer = Int16Array.new(bufferSize);
> msgBuffer.add(noteOnStat);
> }
>
> emit
> {
> var chan = msgBuffer[0] & 0xF;
> switch(msgType,
> controlStat, { //bandwidth hungry (i.e. lots of them) msgs first
> control[chan][msgBuffer[1]].value(msgBuffer[2]) },
> bendStat, {
> bend[chan].value(msgBuffer[2]<<7|msgBuffer[1]) },
> polytouchStat, {
> polytouch[chan].value(msgBuffer[1],msgBuffer[2]) },
> touchStat, {
> touch[chan].value(msgBuffer[1]) },
> noteOnStat, {
> noteOn[chan].value(msgBuffer[1],msgBuffer[2]) },
> noteOffStat, {
> noteOff[chan].value(msgBuffer[1],msgBuffer[2]) },
> programStat, {
> program[chan].value(msgBuffer[1]) }
> );
> }
>
> channelMessage
> { arg byte;
> switch((byte&0xF0),
> controlStat, {
> msgType = controlStat;
> parserState = \needTwoBytes },
> bendStat, {
> msgType = bendStat;
> parserState = \needTwoBytes },
> polytouchStat, {
> msgType = polytouchStat;
> parserState = \needTwoBytes },
> touchStat, {
> msgType = touchStat;
> parserState = \needOneByte },
> noteOnStat, {
> msgType = noteOnStat;
> parserState = \needTwoBytes },
> noteOffStat, {
> msgType = noteOffStat;
> parserState = \needTwoBytes },
> programStat, {
> msgType = programStat;
> parserState = \needOneByte }
>
> );
> }
>
> systemMessage
> { arg byte;
> msgType = byte;
> switch(byte,
> sysexStat, {
> parserState = \variableLength; },
> qFrameStat, {
> parserState = \needOneByte; },
> songPositionStat, {
> parserState = \needTwoBytes; },
> songSelectStat, {
> parserState = \needOneByte; },
> tuneRequestStat, {
> parserState = \needStatus; },
> eoxStat, {
> parserState = \needStatus; }
> );
> }
>
> parseByte
> { arg byte;
> var statusBit;
> var size;
> if((byte >= 0xF8).and(byte <= 0xFF)) {^nil}; //it's a realtime
> message, ignore it
> statusBit = byte & noteOffStat;
> if((statusBit != 0).and(parserState == \variableLength))
> {
> if(byte==eoxStat)
> {
> msgBuffer = msgBuffer.add(byte);
> sysex.value(msgBuffer);
> }
> {
> "Incorrectly terminated system exclusive message".postln;
> };
> };
> if(statusBit != 0)
> {
> msgBuffer = Int16Array.new(bufferSize);
> msgBuffer.add(byte);
> if((byte&sysexStat) == sysexStat)
> {
> runnable = false;
> this.systemMessage(byte);
> }
> {
> runnable = true;
> this.channelMessage(byte);
> };
> ^nil;
> };
> //it's a data byte
> msgBuffer = msgBuffer.add(byte);
> if(parserState == \needTwoBytes)
> {
> if(msgBuffer.size<3) {^nil};
> parserState = \needOneByte;
> };
> if(parserState == \needOneByte)
> {
> this.emit();
> if(runnable)
> {
> if(msgBuffer.size==3)
> {
> msgBuffer.pop();
> msgBuffer.pop();
> }
> {
> msgBuffer.pop();
> };
> }
> {
> parserState = \needStatus;
> };
> };
> }
> }
> UsbMicroDig : LowLevelMidiParser
> {
> var port;
> var device;
> var task;
>
> *new
> { arg dev="/dev/tty.SLAB_USBtoUART";
> var self = super.new;
> self.initUsbMD(dev);
> ^self;
> }
>
> initUsbMD
> { arg dev;
> device = dev;
> UI.registerForShutdown({this.stop()});
> }
>
> play
> {
> if(port.isNil)
> {
> port = SerialPort.new(
> port: device,
> baudrate: 115200,
> databits: 8,
> stopbit: true,
> parity: nil,
> crtscts: true,
> exclusive: true
> );
> task = fork { loop { this.parseByte(port.read()); } };
> };
> }
>
> stop
> {
> if(port.notNil)
> {
> task.stop;
> task = nil;
> port.close;
> port = nil;
> }
> }
>
> }
#|
fredrikolofsson.com klippav.org musicalfieldsforever.com
|#
_______________________________________________
sc-users mailing list
info (subscription, etc.):
http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtmlarchive:
http://www.listarc.bham.ac.uk/marchives/sc-users/search:
http://www.listarc.bham.ac.uk/lists/sc-users/search/