/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
This file is part of the JUCE library .
Copyright ( c ) 2015 - ROLI Ltd .
Permission is granted to use this software under the terms of either :
a ) the GPL v2 ( or any later version )
b ) the Affero GPL v3
Details of these licenses can be found at : www . gnu . org / licenses
JUCE 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 General Public License for more details .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
To release a closed - source product which uses JUCE , commercial licenses are
available : visit www . juce . com for more information .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# ifndef JUCE_MIDIDATACONCATENATOR_H_INCLUDED
# define JUCE_MIDIDATACONCATENATOR_H_INCLUDED
//==============================================================================
/**
Helper class that takes chunks of incoming midi bytes , packages them into
messages , and dispatches them to a midi callback .
*/
class MidiDataConcatenator
{
public :
//==============================================================================
MidiDataConcatenator ( const int initialBufferSize )
: pendingData ( ( size_t ) initialBufferSize ) ,
pendingDataTime ( 0 ) , pendingBytes ( 0 ) , runningStatus ( 0 )
{
}
void reset ( )
{
pendingBytes = 0 ;
runningStatus = 0 ;
pendingDataTime = 0 ;
}
template < typename UserDataType , typename CallbackType >
void pushMidiData ( const void * inputData , int numBytes , double time ,
UserDataType * input , CallbackType & callback )
{
const uint8 * d = static_cast < const uint8 * > ( inputData ) ;
while ( numBytes > 0 )
{
if ( pendingBytes > 0 | | d [ 0 ] = = 0xf0 )
{
processSysex ( d , numBytes , time , input , callback ) ;
runningStatus = 0 ;
}
else
{
int len = 0 ;
uint8 data [ 3 ] ;
while ( numBytes > 0 )
{
// If there's a realtime message embedded in the middle of
// the normal message, handle it now..
if ( * d > = 0xf8 & & * d < = 0xfe )
{
const MidiMessage m ( * d + + , time ) ;
callback . handleIncomingMidiMessage ( input , m ) ;
- - numBytes ;
}
else
{
if ( len = = 0 & & * d < 0x80 & & runningStatus > = 0x80 )
data [ len + + ] = runningStatus ;
data [ len + + ] = * d + + ;
- - numBytes ;
if ( len > = MidiMessage : : getMessageLengthFromFirstByte ( data [ 0 ] ) )
break ;
}
}
if ( len > 0 )
{
int used = 0 ;
const MidiMessage m ( data , len , used , 0 , time ) ;
if ( used < = 0 )
break ; // malformed message..
jassert ( used = = len ) ;
callback . handleIncomingMidiMessage ( input , m ) ;
runningStatus = data [ 0 ] ;
}
}
}
}
private :
template < typename UserDataType , typename CallbackType >
void processSysex ( const uint8 * & d , int & numBytes , double time ,
UserDataType * input , CallbackType & callback )
{
if ( * d = = 0xf0 )
{
pendingBytes = 0 ;
pendingDataTime = time ;
}
pendingData . ensureSize ( ( size_t ) ( pendingBytes + numBytes ) , false ) ;
uint8 * totalMessage = static_cast < uint8 * > ( pendingData . getData ( ) ) ;
uint8 * dest = totalMessage + pendingBytes ;
do
{
if ( pendingBytes > 0 & & * d > = 0x80 )
{
if ( * d = = 0xf7 )
{
* dest + + = * d + + ;
+ + pendingBytes ;
- - numBytes ;
break ;
}
if ( * d > = 0xfa | | * d = = 0xf8 )
{
callback . handleIncomingMidiMessage ( input , MidiMessage ( * d , time ) ) ;
+ + d ;
- - numBytes ;
}
else
{
pendingBytes = 0 ;
int used = 0 ;
const MidiMessage m ( d , numBytes , used , 0 , time ) ;
if ( used > 0 )
{
callback . handleIncomingMidiMessage ( input , m ) ;
numBytes - = used ;
d + = used ;
}
break ;
}
}
else
{
* dest + + = * d + + ;
+ + pendingBytes ;
- - numBytes ;
}
}
while ( numBytes > 0 ) ;
if ( pendingBytes > 0 )
{
if ( totalMessage [ pendingBytes - 1 ] = = 0xf7 )
{
callback . handleIncomingMidiMessage ( input , MidiMessage ( totalMessage , pendingBytes , pendingDataTime ) ) ;
pendingBytes = 0 ;
}
else
{
callback . handlePartialSysexMessage ( input , totalMessage , pendingBytes , pendingDataTime ) ;
}
}
}
MemoryBlock pendingData ;
double pendingDataTime ;
int pendingBytes ;
uint8 runningStatus ;
JUCE_DECLARE_NON_COPYABLE ( MidiDataConcatenator )
} ;
# endif // JUCE_MIDIDATACONCATENATOR_H_INCLUDED