cwMidiDevice.h/cpp,cwMidiDecls.h : Added getBuffer(),clearBuffer(),maxBufferMsgCount() to cwMidiDevice.

Changed the MIDI device callback function to move the user arg outside of the 'packet_t'.
Added midi::ch_msg_t
This commit is contained in:
kevin 2024-04-06 15:44:43 -04:00
parent 7d3be5ebc6
commit a6f518ed54
3 changed files with 140 additions and 14 deletions

View File

@ -17,7 +17,7 @@ namespace cw
typedef struct packet_str typedef struct packet_str
{ {
void* cbArg; // Application supplied reference value //void* cbArg; // Application supplied reference value
unsigned devIdx; // The device the msg originated from unsigned devIdx; // The device the msg originated from
unsigned portIdx; // The port index on the source device unsigned portIdx; // The port index on the source device
msg_t* msgArray; // Pointer to an array of 'msgCnt' mdMsg records or NULL if sysExMsg is non-NULL msg_t* msgArray; // Pointer to an array of 'msgCnt' mdMsg records or NULL if sysExMsg is non-NULL
@ -25,8 +25,19 @@ namespace cw
unsigned msgCnt; // Count of mdMsg records or sys-ex bytes unsigned msgCnt; // Count of mdMsg records or sys-ex bytes
} packet_t; } packet_t;
typedef void (*cbFunc_t)( const packet_t* pktArray, unsigned pktCnt ); typedef void (*cbFunc_t)( void* cbArg, const packet_t* pktArray, unsigned pktCnt );
typedef struct ch_msg_str
{
time::spec_t timeStamp;
unsigned devIdx; // The device the msg originated from
unsigned portIdx; // The port index on the source device
unsigned uid; // application specified id
uint8_t ch; // midi channel
uint8_t status; // midi status byte (channel has been removed)
uint8_t d0; // midi data byte 0
uint8_t d1; // midi data byte 1
} ch_msg_t;
} }
} }
#endif #endif

View File

@ -55,6 +55,11 @@ namespace cw
unsigned long long last_posn_micros; unsigned long long last_posn_micros;
time::spec_t start_time; time::spec_t start_time;
ch_msg_t* buf;
unsigned bufN;
std::atomic<unsigned> buf_ii;
std::atomic<unsigned> buf_oi;
} device_t; } device_t;
device_t* _handleToPtr( handle_t h ) device_t* _handleToPtr( handle_t h )
@ -102,8 +107,11 @@ namespace cw
goto errLabel; goto errLabel;
} }
destroy(p->alsaDevH); destroy(p->alsaDevH);
destroy(p->fileDevH); destroy(p->fileDevH);
mem::release(p->buf);
mem::release(p); mem::release(p);
errLabel: errLabel:
@ -173,6 +181,45 @@ namespace cw
return true; return true;
} }
void _callback( void* cbArg, const packet_t* pktArray, unsigned pktCnt )
{
device_t* p = (device_t*)cbArg;
for(unsigned i=0; i<pktCnt; ++i)
{
const packet_t* pkt = pktArray + i;
if( pkt->msgArray != nullptr )
{
unsigned ii = p->buf_ii.load();
unsigned oi = p->buf_oi.load();
for(unsigned j=0; j<pkt->msgCnt; ++j)
{
ch_msg_t* m = p->buf + ii;
m->devIdx = pkt->devIdx;
m->portIdx = pkt->portIdx;
m->timeStamp = pkt->msgArray[j].timeStamp;
m->uid = pkt->msgArray[j].uid;
m->ch = pkt->msgArray[j].ch;
m->status = pkt->msgArray[j].status;
m->d0 = pkt->msgArray[j].d0;
m->d1 = pkt->msgArray[j].d1;
ii = (ii+1 == p->bufN ? 0 : ii+1);
if( ii == oi )
{
cwLogError(kBufTooSmallRC,"The MIDI device buffer is full %i.",p->bufN);
}
}
p->buf_ii.store(ii);
}
}
if( p->cbFunc != nullptr )
p->cbFunc(p->cbArg,pktArray,pktCnt);
}
} // device } // device
} // midi } // midi
@ -188,7 +235,9 @@ cw::rc_t cw::midi::device::create( handle_t& hRef,
const char* appNameStr, const char* appNameStr,
const char* fileDevName, const char* fileDevName,
unsigned fileDevReadAheadMicros, unsigned fileDevReadAheadMicros,
unsigned parserBufByteCnt ) unsigned parserBufByteCnt,
bool enableBufFl,
unsigned bufferMsgCnt )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
rc_t rc1 = kOkRC; rc_t rc1 = kOkRC;
@ -198,7 +247,11 @@ cw::rc_t cw::midi::device::create( handle_t& hRef,
device_t* p = mem::allocZ<device_t>(); device_t* p = mem::allocZ<device_t>();
if((rc = create( p->alsaDevH, cbFunc, cbArg, parserBufByteCnt, appNameStr )) != kOkRC ) if((rc = create( p->alsaDevH,
enableBufFl ? _callback : cbFunc,
enableBufFl ? p : cbArg,
parserBufByteCnt,
appNameStr )) != kOkRC )
{ {
rc = cwLogError(rc,"ALSA MIDI device create failed."); rc = cwLogError(rc,"ALSA MIDI device create failed.");
goto errLabel; goto errLabel;
@ -206,16 +259,29 @@ cw::rc_t cw::midi::device::create( handle_t& hRef,
p->alsa_dev_cnt = count(p->alsaDevH); p->alsa_dev_cnt = count(p->alsaDevH);
if((rc = create( p->fileDevH, cbFunc, cbArg, p->alsa_dev_cnt, filePortLabelA, max_file_cnt, fileDevName, fileDevReadAheadMicros )) != kOkRC ) if((rc = create( p->fileDevH,
enableBufFl ? _callback : cbFunc,
enableBufFl ? p : cbArg,
p->alsa_dev_cnt,
filePortLabelA,
max_file_cnt,
fileDevName,
fileDevReadAheadMicros )) != kOkRC )
{ {
rc = cwLogError(rc,"MIDI file device create failed."); rc = cwLogError(rc,"MIDI file device create failed.");
goto errLabel; goto errLabel;
} }
p->cbFunc = cbFunc;
p->cbArg = cbArg;
p->file_dev_cnt = count(p->fileDevH); p->file_dev_cnt = count(p->fileDevH);
p->total_dev_cnt = p->alsa_dev_cnt + p->file_dev_cnt; p->total_dev_cnt = p->alsa_dev_cnt + p->file_dev_cnt;
p->alsaPollfdA = pollFdArray(p->alsaDevH,p->alsaPollfdN); p->alsaPollfdA = pollFdArray(p->alsaDevH,p->alsaPollfdN);
p->fileDevStateId = kStoppedStateId; p->fileDevStateId = kStoppedStateId;
p->buf = mem::allocZ<ch_msg_t>( bufferMsgCnt );
p->bufN = bufferMsgCnt;
p->buf_ii.store(0);
p->buf_oi.store(0);
if((rc = thread::create(p->threadH, if((rc = thread::create(p->threadH,
_thread_func, _thread_func,
@ -257,6 +323,8 @@ cw::rc_t cw::midi::device::create( handle_t& h,
const char* fileDevName = "file_dev"; const char* fileDevName = "file_dev";
unsigned fileDevReadAheadMicros = 3000; unsigned fileDevReadAheadMicros = 3000;
unsigned parseBufByteCnt = 1024; unsigned parseBufByteCnt = 1024;
bool enableBufFl = false;
unsigned bufMsgCnt = 0;
const object_t* file_ports = nullptr; const object_t* file_ports = nullptr;
const object_t* port = nullptr; const object_t* port = nullptr;
@ -264,6 +332,8 @@ cw::rc_t cw::midi::device::create( handle_t& h,
"fileDevName",fileDevName, "fileDevName",fileDevName,
"fileDevReadAheadMicros",fileDevReadAheadMicros, "fileDevReadAheadMicros",fileDevReadAheadMicros,
"parseBufByteCnt",parseBufByteCnt, "parseBufByteCnt",parseBufByteCnt,
"enableBufFl",enableBufFl,
"bufferMsgCnt",bufMsgCnt,
"file_ports",file_ports)) != kOkRC ) "file_ports",file_ports)) != kOkRC )
{ {
rc = cwLogError(rc,"MIDI port parse args. failed."); rc = cwLogError(rc,"MIDI port parse args. failed.");
@ -290,7 +360,7 @@ cw::rc_t cw::midi::device::create( handle_t& h,
} }
} }
rc = create(h,cbFunc,cbArg,labelArray,fpi,appNameStr,fileDevName,fileDevReadAheadMicros,parseBufByteCnt); rc = create(h,cbFunc,cbArg,labelArray,fpi,appNameStr,fileDevName,fileDevReadAheadMicros,parseBufByteCnt,enableBufFl,bufMsgCnt);
} }
@ -445,7 +515,7 @@ const char* cw::midi::device::portName( handle_t h, unsigned devIdx, unsigned
cwLogError(kInvalidArgRC,"The device index %i is not valid."); cwLogError(kInvalidArgRC,"The device index %i is not valid.");
if( name == nullptr ) if( name == nullptr )
cwLogError(kOpFailRC,"The access to port name on device index %i port index %i failed.",devIdx,portIdx); cwLogError(kOpFailRC,"The access to %s port name on device index %i port index %i failed.",flags & kInMpFl ? "input" : "output", devIdx,portIdx);
return name; return name;
} }
@ -591,6 +661,43 @@ errLabel:
} }
unsigned cw::midi::device::maxBufferMsgCount( handle_t h )
{
device_t* p = _handleToPtr(h);
return p->bufN;
}
const cw::midi::ch_msg_t* cw::midi::device::getBuffer( handle_t h, unsigned& msgCntRef )
{
device_t* p = _handleToPtr(h);
unsigned ii = p->buf_ii.load();
unsigned oi = p->buf_oi.load();
ch_msg_t* m = nullptr;
msgCntRef = ii >= oi ? ii-oi : p->bufN - oi;
if( msgCntRef > 0 )
m = p->buf + oi;
return m;
}
cw::rc_t cw::midi::device::clearBuffer( handle_t h, unsigned msgCnt )
{
if( msgCnt > 0 )
{
device_t* p = _handleToPtr(h);
unsigned oi = p->buf_oi.load();
oi = (oi + msgCnt) % p->bufN;
p->buf_oi.store(oi);
}
return kOkRC;
}
cw::rc_t cw::midi::device::start( handle_t h ) cw::rc_t cw::midi::device::start( handle_t h )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
@ -669,6 +776,8 @@ cw::rc_t cw::midi::device::report( handle_t h )
report(h,tbH); report(h,tbH);
printf("%s\n",text(tbH));
errLabel: errLabel:
destroy(tbH); destroy(tbH);
return rc; return rc;

View File

@ -30,7 +30,9 @@ namespace cw
const char* appNameStr, const char* appNameStr,
const char* fileDevName = "file_dev", const char* fileDevName = "file_dev",
unsigned fileDevReadAheadMicros = 3000, unsigned fileDevReadAheadMicros = 3000,
unsigned parserBufByteCnt = 1024 ); unsigned parserBufByteCnt = 1024,
bool enableBufFl = false, // Enable buffer to hold all incoming msg's until RT thread can pick them up.
unsigned bufferMsgCnt = 4096); // Count of messages in input buffer.
rc_t create( handle_t& h, rc_t create( handle_t& h,
cbFunc_t cbFunc, cbFunc_t cbFunc,
@ -57,6 +59,10 @@ namespace cw
rc_t seekToMsg( handle_t h, unsigned devIdx, unsigned portIdx, unsigned msgIdx ); rc_t seekToMsg( handle_t h, unsigned devIdx, unsigned portIdx, unsigned msgIdx );
rc_t setEndMsg( handle_t h, unsigned devIdx, unsigned portidx, unsigned msgIdx ); rc_t setEndMsg( handle_t h, unsigned devIdx, unsigned portidx, unsigned msgIdx );
unsigned maxBufferMsgCount( handle_t h ); // max number of msg's which will ever be returned in a buffer
const ch_msg_t* getBuffer( handle_t h, unsigned& msgCntRef );
rc_t clearBuffer( handle_t h, unsigned msgCnt );
rc_t start( handle_t h ); rc_t start( handle_t h );
rc_t stop( handle_t h ); rc_t stop( handle_t h );
rc_t pause( handle_t h, bool pause_fl ); rc_t pause( handle_t h, bool pause_fl );