comments please? midi parser code and SerialPort interface for infusionsystems usbmicrodig

View: New views
4 Messages — Rating Filter:   Alert me  

comments please? midi parser code and SerialPort interface for infusionsystems usbmicrodig

by loriend :: Rate this Message:

Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message

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;
                }
        }
                               
}

Re: comments please? midi parser code and SerialPort interface for infusionsystems usbmicrodig

by Fredrik Olofsson :: Rate this Message:

Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message

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.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/

Re: comments please? midi parser code and SerialPort interface for infusionsystems usbmicrodig

by loriend :: Rate this Message:

Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message

Hi Frederik,
    closing on cmdperiod is a neat idea and I was unaware of that
logical AND. It certainly does shave quite some time in the loops, will
see later what it does in situ.

thanks :)
Lorien

Fredrik Olofsson wrote:

> 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.shtml
> archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
> search: http://www.listarc.bham.ac.uk/lists/sc-users/search/
>


_______________________________________________
sc-users mailing list

info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/

Re: comments please? midi parser code and SerialPort interface for infusionsystems usbmicrodig

by loriend :: Rate this Message:

Reply (Restricted by the Administrator) | Reply to Author | View Threaded | Show Only this Message

Hi Fredrik,
    the and: thing made little difference, though it makes sense to me
that SC was always evaluating both conditions. It's not so bad so long
as I have a moving average filter on every sensor to make the icube
firmware data reduction really kick in, so I doubt it's worth writing as
a primitive. The CmdPeriod thing is really neat.

thanks,
Lorien
Fredrik Olofsson wrote:

> 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.shtml
> archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
> search: http://www.listarc.bham.ac.uk/lists/sc-users/search/
>


_______________________________________________
sc-users mailing list

info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/