cwIoMidiRecordPlay.h/cpp : Add multiple MIDI devices.

This commit is contained in:
kevin 2022-01-22 09:42:21 -05:00
parent e4dcb5f83c
commit 586b71b93c
2 changed files with 122 additions and 37 deletions

View File

@ -34,20 +34,27 @@ namespace cw
} am_midi_msg_t; } am_midi_msg_t;
typedef struct midi_record_play_str typedef struct midi_device_str
{ {
io::handle_t ioH;
am_midi_msg_t* msgArray;
unsigned msgArrayN;
unsigned msgArrayInIdx;
unsigned msgArrayOutIdx;
unsigned midi_timer_period_micro_sec;
char* midiOutDevLabel; char* midiOutDevLabel;
char* midiOutPortLabel; char* midiOutPortLabel;
unsigned midiOutDevIdx; unsigned midiOutDevIdx;
unsigned midiOutPortIdx; unsigned midiOutPortIdx;
bool enableFl;
} midi_device_t;
typedef struct midi_record_play_str
{
io::handle_t ioH;
am_midi_msg_t* msgArray; // msgArray[ msgArrayN ]
unsigned msgArrayN; // Count of messages allocated in msgArray.
unsigned msgArrayInIdx; // Next available space for incoming MIDI messages (also the current count of msgs in msgArray[])
unsigned msgArrayOutIdx; // Next message to transmit in msgArray[]
unsigned midi_timer_period_micro_sec; // Timer period in microseconds
midi_device_t* midiDevA;
unsigned midiDevN;
bool startedFl; bool startedFl;
bool recordFl; bool recordFl;
@ -80,9 +87,14 @@ namespace cw
if((timerIdx = io::timerLabelToIndex( p->ioH, TIMER_LABEL )) != kInvalidIdx ) if((timerIdx = io::timerLabelToIndex( p->ioH, TIMER_LABEL )) != kInvalidIdx )
io::timerDestroy( p->ioH, timerIdx); io::timerDestroy( p->ioH, timerIdx);
for(unsigned i=0; i<p->midiDevN; ++i)
{
mem::release(p->midiDevA[i].midiOutDevLabel);
mem::release(p->midiDevA[i].midiOutPortLabel);
}
mem::release(p->midiDevA);
mem::release(p->msgArray); mem::release(p->msgArray);
mem::release(p->midiOutDevLabel);
mem::release(p->midiOutPortLabel);
mem::release(p); mem::release(p);
return rc; return rc;
@ -91,21 +103,47 @@ namespace cw
rc_t _parseCfg(midi_record_play_t* p, const object_t& cfg ) rc_t _parseCfg(midi_record_play_t* p, const object_t& cfg )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
const object_t* midiDevL = nullptr;
if((rc = cfg.getv( if((rc = cfg.getv(
"max_midi_msg_count", p->msgArrayN, "max_midi_msg_count", p->msgArrayN,
"midi_timer_period_micro_sec", p->midi_timer_period_micro_sec, "midi_timer_period_micro_sec", p->midi_timer_period_micro_sec,
"midi_out_device", p->midiOutDevLabel, "midi_device_list", midiDevL)) != kOkRC )
"midi_out_port", p->midiOutPortLabel)) != kOkRC )
{ {
rc = cwLogError(kSyntaxErrorRC,"MIDI record play configuration parse failed."); rc = cwLogError(kSyntaxErrorRC,"MIDI record play configuration parse failed.");
goto errLabel; goto errLabel;
} }
if( midiDevL->child_count() > 0 )
{
p->midiDevN = midiDevL->child_count();
p->midiDevA = mem::allocZ<midi_device_t>(p->midiDevN);
printf("Midi record play devices:%i\n",p->midiDevN);
for(unsigned i=0; i<p->midiDevN; ++i)
{
const object_t* ele = midiDevL->child_ele(i);
const char* midiOutDevLabel = nullptr;
const char* midiOutPortLabel = nullptr;
bool enableFl = false;
if((rc = ele->getv( "midi_out_device", midiOutDevLabel,
"midi_out_port", midiOutPortLabel,
"enableFl", enableFl)) != kOkRC )
{
rc = cwLogError(kSyntaxErrorRC,"MIDI record play device list configuration parse failed.");
goto errLabel;
}
p->midiDevA[i].midiOutDevLabel = mem::duplStr( midiOutDevLabel);
p->midiDevA[i].midiOutPortLabel = mem::duplStr( midiOutPortLabel);
p->midiDevA[i].enableFl = enableFl;
}
}
// allocate the MIDI msg buffer // allocate the MIDI msg buffer
p->msgArray = mem::allocZ<am_midi_msg_t>( p->msgArrayN ); p->msgArray = mem::allocZ<am_midi_msg_t>( p->msgArrayN );
p->midiOutDevLabel = mem::duplStr( p->midiOutDevLabel);
p->midiOutPortLabel = mem::duplStr( p->midiOutPortLabel);
errLabel: errLabel:
return rc; return rc;
@ -117,13 +155,15 @@ namespace cw
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
if( !time::isZero(p->end_play_event_timestamp) && time::isGTE(timestamp,p->end_play_event_timestamp)) if( !time::isZero(p->end_play_event_timestamp) && time::isGT(timestamp,p->end_play_event_timestamp))
{ {
rc = _stop(p); rc = _stop(p);
} }
else else
{ {
io::midiDeviceSend( p->ioH, p->midiOutDevIdx, p->midiOutPortIdx, status + ch, d0, d1 ); for(unsigned i=0; i<p->midiDevN; ++i)
if(p->midiDevA[i].enableFl )
io::midiDeviceSend( p->ioH, p->midiDevA[i].midiOutDevIdx, p->midiDevA[i].midiOutPortIdx, status + ch, d0, d1 );
if( p->cb ) if( p->cb )
p->cb( p->cb_arg, id, timestamp, ch, status, d0, d1 ); p->cb( p->cb_arg, id, timestamp, ch, status, d0, d1 );
@ -407,15 +447,19 @@ namespace cw
_transmit_ctl( p, 0, 123, 0 ); // all notes off _transmit_ctl( p, 0, 123, 0 ); // all notes off
_transmit_ctl( p, 0, 0, 0 ); // switch to bank 0 _transmit_ctl( p, 0, 0, 0 ); // switch to bank 0
//_transmit_pedal( p, 0, midi::kSustainCtlMdId, false );
//_transmit_pedal( p, 0, midi::kSostenutoCtlMdId, false );
//_transmit_pedal( p, 0, midi::kSoftPedalCtlMdId, false );
// send pgm change 0 // send pgm change 0
time::spec_t ts = {0}; //time::spec_t ts = {0};
_event_callback( p, kInvalidId, ts, 0, midi::kPgmMdId, 0, 0 ); //_event_callback( p, kInvalidId, ts, 0, midi::kPgmMdId, 0, 0 );
p->pedalFl = false; p->pedalFl = false;
} }
cwLogInfo("Runtime: %5.2f seconds.", time::elapsedMs(p->start_time,t1)/1000.0 ); //cwLogInfo("Runtime: %5.2f seconds.", time::elapsedMs(p->start_time,t1)/1000.0 );
return rc; return rc;
} }
@ -471,10 +515,7 @@ namespace cw
p->msgArrayInIdx += 1; p->msgArrayInIdx += 1;
if( p->thruFl ) if( p->thruFl )
{
_transmit_msg( p, am ); _transmit_msg( p, am );
//io::midiDeviceSend( p->ioH, p->midiOutDevIdx, p->midiOutPortIdx, am->status + am->ch, am->d0, am->d1 );
}
// send msg count // send msg count
//io::uiSendValue( p->ioH, kInvalidId, uiFindElementUuId(p->ioH,kMsgCntId), p->msgArrayInIdx ); //io::uiSendValue( p->ioH, kInvalidId, uiFindElementUuId(p->ioH,kMsgCntId), p->msgArrayInIdx );
@ -575,18 +616,26 @@ cw::rc_t cw::midi_record_play::create( handle_t& hRef, io::handle_t ioH, const o
p->cb = cb; p->cb = cb;
p->cb_arg = cb_arg; p->cb_arg = cb_arg;
if((p->midiOutDevIdx = io::midiDeviceIndex(p->ioH,p->midiOutDevLabel)) == kInvalidIdx ) for( unsigned i=0; i<
p->midiDevN; ++i)
{ {
rc = cwLogError(kInvalidArgRC,"The MIDI output device: '%s' was not found.", cwStringNullGuard(p->midiOutDevLabel) ); midi_device_t* dev = p->midiDevA + i;
if((dev->midiOutDevIdx = io::midiDeviceIndex(p->ioH,dev->midiOutDevLabel)) == kInvalidIdx )
{
rc = cwLogError(kInvalidArgRC,"The MIDI output device: '%s' was not found.", cwStringNullGuard(dev->midiOutDevLabel) );
goto errLabel; goto errLabel;
} }
if((p->midiOutPortIdx = io::midiDevicePortIndex(p->ioH,p->midiOutDevIdx,false,p->midiOutPortLabel)) == kInvalidIdx ) if((dev->midiOutPortIdx = io::midiDevicePortIndex(p->ioH,dev->midiOutDevIdx,false,dev->midiOutPortLabel)) == kInvalidIdx )
{ {
rc = cwLogError(kInvalidArgRC,"The MIDI output port: '%s' was not found.", cwStringNullGuard(p->midiOutPortLabel) ); rc = cwLogError(kInvalidArgRC,"The MIDI output port: '%s' was not found.", cwStringNullGuard(dev->midiOutPortLabel) );
goto errLabel; goto errLabel;
} }
printf("%s %s : %i %i\n",dev->midiOutDevLabel, dev->midiOutPortLabel, dev->midiOutDevIdx, dev->midiOutPortIdx );
}
// create the MIDI playback timer // create the MIDI playback timer
if((rc = timerCreate( p->ioH, TIMER_LABEL, kMidiRecordPlayTimerId, p->midi_timer_period_micro_sec)) != kOkRC ) if((rc = timerCreate( p->ioH, TIMER_LABEL, kMidiRecordPlayTimerId, p->midi_timer_period_micro_sec)) != kOkRC )
{ {
@ -738,8 +787,8 @@ cw::rc_t cw::midi_record_play::load( handle_t h, const midi_msg_t* msg, unsigned
p->msgArray[i].status = msg[i].status; p->msgArray[i].status = msg[i].status;
p->msgArray[i].d0 = msg[i].d0; p->msgArray[i].d0 = msg[i].d0;
p->msgArray[i].d1 = msg[i].d1; p->msgArray[i].d1 = msg[i].d1;
p->msgArray[i].devIdx = p->midiOutDevIdx; p->msgArray[i].devIdx = kInvalidIdx;
p->msgArray[i].portIdx = p->midiOutPortIdx; p->msgArray[i].portIdx = kInvalidIdx;
p->msgArray[i].microsec = time::elapsedMicros(p->msgArray[0].timestamp,p->msgArray[i].timestamp); p->msgArray[i].microsec = time::elapsedMicros(p->msgArray[0].timestamp,p->msgArray[i].timestamp);
} }
@ -842,7 +891,37 @@ cw::rc_t cw::midi_record_play::exec( handle_t h, const io::msg_t& m )
return rc; return rc;
} }
unsigned cw::midi_record_play::device_count( handle_t h )
{
midi_record_play_t* p = _handleToPtr(h);
return p->midiDevN;
}
bool cw::midi_record_play::is_device_enabled( handle_t h, unsigned devIdx )
{
midi_record_play_t* p = _handleToPtr(h);
bool fl = false;
if( devIdx >= p->midiDevN )
cwLogError(kInvalidArgRC,"The MIDI record-play device index '%i' is invalid.",devIdx );
else
fl = p->midiDevA[devIdx].enableFl;
return fl;
}
void cw::midi_record_play::enable_device( handle_t h, unsigned devIdx, bool enableFl )
{
midi_record_play_t* p = _handleToPtr(h);
if( devIdx >= p->midiDevN )
cwLogError(kInvalidArgRC,"The MIDI record-play device index '%i' is invalid.",devIdx );
else
{
p->midiDevA[devIdx].enableFl = enableFl;
printf("Enable: %i = %i\n",devIdx,enableFl);
}
}
cw::rc_t cw::midi_record_play::am_to_midi_file( const char* am_filename, const char* midi_filename ) cw::rc_t cw::midi_record_play::am_to_midi_file( const char* am_filename, const char* midi_filename )
{ {

View File

@ -40,6 +40,8 @@ namespace cw
rc_t save( handle_t h, const char* fn ); rc_t save( handle_t h, const char* fn );
rc_t open( handle_t h, const char* fn ); rc_t open( handle_t h, const char* fn );
// Load the playback buffer with messages to output.
rc_t load( handle_t h, const midi_msg_t* msg, unsigned msg_count ); rc_t load( handle_t h, const midi_msg_t* msg, unsigned msg_count );
rc_t seek( handle_t h, time::spec_t timestamp ); rc_t seek( handle_t h, time::spec_t timestamp );
@ -48,6 +50,10 @@ namespace cw
unsigned event_index( handle_t h ); unsigned event_index( handle_t h );
rc_t exec( handle_t h, const io::msg_t& msg ); rc_t exec( handle_t h, const io::msg_t& msg );
unsigned device_count( handle_t h );
bool is_device_enabled( handle_t h, unsigned devIdx );
void enable_device( handle_t h, unsigned devIdx, bool enableFl );
// Convert an audio-midi file to a MIDI file // Convert an audio-midi file to a MIDI file
rc_t am_to_midi_file( const char* am_filename, const char* midi_filename ); rc_t am_to_midi_file( const char* am_filename, const char* midi_filename );
rc_t am_to_midi_dir( const char* inDir ); rc_t am_to_midi_dir( const char* inDir );