cwIoMidiREcordPlay,cwIoPresetSelApp : Updated to include half-pedal experimentation procedure, and separate velocity tables for each MIDI device.
This commit is contained in:
parent
cb31b0882a
commit
20f631afc5
@ -41,28 +41,65 @@ namespace cw
|
|||||||
unsigned midiOutDevIdx;
|
unsigned midiOutDevIdx;
|
||||||
unsigned midiOutPortIdx;
|
unsigned midiOutPortIdx;
|
||||||
bool enableFl;
|
bool enableFl;
|
||||||
|
unsigned velTableN;
|
||||||
|
uint8_t* velTableArray;
|
||||||
|
bool pedalMapEnableFl;
|
||||||
|
unsigned pedalDownVelId;
|
||||||
|
unsigned pedalDownHalfVelId;
|
||||||
|
unsigned pedalDownVel;
|
||||||
|
unsigned pedalDownHalfVel;
|
||||||
} midi_device_t;
|
} midi_device_t;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kHalfPedalDone,
|
||||||
|
kWaitForBegin,
|
||||||
|
kWaitForNoteOn,
|
||||||
|
kWaitForNoteOff,
|
||||||
|
kWaitForPedalUp,
|
||||||
|
kWaitForPedalDown,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct midi_record_play_str
|
typedef struct midi_record_play_str
|
||||||
{
|
{
|
||||||
io::handle_t ioH;
|
io::handle_t ioH;
|
||||||
|
|
||||||
am_midi_msg_t* msgArray; // msgArray[ msgArrayN ]
|
am_midi_msg_t* msgArray; // msgArray[ msgArrayN ]
|
||||||
unsigned msgArrayN; // Count of messages allocated in msgArray.
|
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 msgArrayInIdx; // Next available space for loaded MIDI messages (also the current count of msgs in msgArray[])
|
||||||
unsigned msgArrayOutIdx; // Next message to transmit in msgArray[]
|
unsigned msgArrayOutIdx; // Next message to transmit in msgArray[]
|
||||||
unsigned midi_timer_period_micro_sec; // Timer period in microseconds
|
unsigned midi_timer_period_micro_sec; // Timer period in microseconds
|
||||||
|
|
||||||
|
am_midi_msg_t* iMsgArray; // msgArray[ msgArrayN ]
|
||||||
|
unsigned iMsgArrayN; // Count of messages allocated in msgArray.
|
||||||
|
unsigned iMsgArrayInIdx; // Next available space for incoming MIDI messages (also the current count of msgs in msgArray[])
|
||||||
|
|
||||||
|
|
||||||
midi_device_t* midiDevA;
|
midi_device_t* midiDevA;
|
||||||
unsigned midiDevN;
|
unsigned midiDevN;
|
||||||
|
|
||||||
bool startedFl;
|
bool startedFl;
|
||||||
bool recordFl;
|
bool recordFl;
|
||||||
bool thruFl;
|
bool thruFl;
|
||||||
|
bool logInFl; // log incoming message when not in 'record' mode.
|
||||||
|
bool logOutFl; // log outgoing messages
|
||||||
|
|
||||||
|
bool halfPedalFl;
|
||||||
|
unsigned halfPedalState;
|
||||||
|
unsigned halfPedalNextUs;
|
||||||
|
unsigned halfPedalNoteDelayUs;
|
||||||
|
unsigned halfPedalNoteDurUs;
|
||||||
|
unsigned halfPedalUpDelayUs;
|
||||||
|
unsigned halfPedalDownDelayUs;
|
||||||
|
uint8_t halfPedalMidiPitch;
|
||||||
|
uint8_t halfPedalMidiNoteVel;
|
||||||
|
uint8_t halfPedalMidiPedalVel;
|
||||||
|
|
||||||
time::spec_t play_time;
|
time::spec_t play_time;
|
||||||
time::spec_t start_time;
|
time::spec_t start_time;
|
||||||
time::spec_t end_play_event_timestamp;
|
time::spec_t end_play_event_timestamp;
|
||||||
|
time::spec_t store_time;
|
||||||
|
|
||||||
bool pedalFl;
|
bool pedalFl;
|
||||||
|
|
||||||
@ -91,10 +128,12 @@ namespace cw
|
|||||||
{
|
{
|
||||||
mem::release(p->midiDevA[i].midiOutDevLabel);
|
mem::release(p->midiDevA[i].midiOutDevLabel);
|
||||||
mem::release(p->midiDevA[i].midiOutPortLabel);
|
mem::release(p->midiDevA[i].midiOutPortLabel);
|
||||||
|
mem::release(p->midiDevA[i].velTableArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
mem::release(p->midiDevA);
|
mem::release(p->midiDevA);
|
||||||
mem::release(p->msgArray);
|
mem::release(p->msgArray);
|
||||||
|
mem::release(p->iMsgArray);
|
||||||
mem::release(p);
|
mem::release(p);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -107,12 +146,16 @@ namespace cw
|
|||||||
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_device_list", midiDevL)) != kOkRC )
|
"midi_device_list", midiDevL,
|
||||||
|
"log_in_flag", p->logInFl,
|
||||||
|
"log_out_flag", p->logOutFl,
|
||||||
|
"half_pedal_flag", p->halfPedalFl)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kSyntaxErrorRC,"MIDI record play configuration parse failed.");
|
rc = cwLogError(kSyntaxErrorRC,"MIDI record play configuration parse failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->iMsgArrayN = p->msgArrayN;
|
||||||
|
|
||||||
if( midiDevL->child_count() > 0 )
|
if( midiDevL->child_count() > 0 )
|
||||||
{
|
{
|
||||||
@ -126,6 +169,8 @@ namespace cw
|
|||||||
const object_t* ele = midiDevL->child_ele(i);
|
const object_t* ele = midiDevL->child_ele(i);
|
||||||
const char* midiOutDevLabel = nullptr;
|
const char* midiOutDevLabel = nullptr;
|
||||||
const char* midiOutPortLabel = nullptr;
|
const char* midiOutPortLabel = nullptr;
|
||||||
|
const object_t* velTable = nullptr;
|
||||||
|
const object_t* pedalRecd = nullptr;
|
||||||
bool enableFl = false;
|
bool enableFl = false;
|
||||||
|
|
||||||
if((rc = ele->getv( "midi_out_device", midiOutDevLabel,
|
if((rc = ele->getv( "midi_out_device", midiOutDevLabel,
|
||||||
@ -136,14 +181,57 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if((rc = ele->getv_opt( "vel_table", velTable,
|
||||||
|
"pedal", pedalRecd)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kSyntaxErrorRC,"MIDI record play device optional argument parsing failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
p->midiDevA[i].midiOutDevLabel = mem::duplStr( midiOutDevLabel);
|
p->midiDevA[i].midiOutDevLabel = mem::duplStr( midiOutDevLabel);
|
||||||
p->midiDevA[i].midiOutPortLabel = mem::duplStr( midiOutPortLabel);
|
p->midiDevA[i].midiOutPortLabel = mem::duplStr( midiOutPortLabel);
|
||||||
p->midiDevA[i].enableFl = enableFl;
|
p->midiDevA[i].enableFl = enableFl;
|
||||||
|
|
||||||
|
if( velTable != nullptr )
|
||||||
|
{
|
||||||
|
p->midiDevA[i].velTableN = velTable->child_count();
|
||||||
|
p->midiDevA[i].velTableArray = mem::allocZ<uint8_t>(p->midiDevA[i].velTableN);
|
||||||
|
|
||||||
|
|
||||||
|
for(unsigned j=0; j<p->midiDevA[i].velTableN; ++j)
|
||||||
|
{
|
||||||
|
if((rc = velTable->child_ele(j)->value( p->midiDevA[i].velTableArray[j] )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kSyntaxErrorRC,"An error occured while parsing the velocity table for MIDI device:'%s' port:'%s'.",midiOutDevLabel,midiOutPortLabel);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pedalRecd != nullptr )
|
||||||
|
{
|
||||||
|
if((rc = pedalRecd->getv( "down_id", p->midiDevA[i].pedalDownVelId,
|
||||||
|
"down_vel", p->midiDevA[i].pedalDownVel,
|
||||||
|
"half_id", p->midiDevA[i].pedalDownHalfVelId,
|
||||||
|
"half_vel", p->midiDevA[i].pedalDownHalfVel )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kSyntaxErrorRC,"An error occured while parsing the pedal record for MIDI device:'%s' port:'%s'.",midiOutDevLabel,midiOutPortLabel);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->midiDevA[i].pedalMapEnableFl = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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->iMsgArray = mem::allocZ<am_midi_msg_t>( p->iMsgArrayN );
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
@ -151,54 +239,181 @@ namespace cw
|
|||||||
|
|
||||||
rc_t _stop( midi_record_play_t* p );
|
rc_t _stop( midi_record_play_t* p );
|
||||||
|
|
||||||
rc_t _event_callback( midi_record_play_t* p, unsigned id, const time::spec_t timestamp, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
|
||||||
|
const am_midi_msg_t* _midi_store( midi_record_play_t* p, unsigned devIdx, unsigned portIdx, const time::spec_t& ts, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
||||||
|
{
|
||||||
|
am_midi_msg_t* am = nullptr;
|
||||||
|
|
||||||
|
// verify that space exists in the record buffer
|
||||||
|
if( p->iMsgArrayInIdx < p->iMsgArrayN )
|
||||||
|
{
|
||||||
|
// MAKE THIS ATOMIC
|
||||||
|
unsigned id = p->iMsgArrayInIdx;
|
||||||
|
++p->iMsgArrayInIdx;
|
||||||
|
|
||||||
|
am = p->iMsgArray + id;
|
||||||
|
|
||||||
|
am->id = id;
|
||||||
|
am->devIdx = devIdx;
|
||||||
|
am->portIdx = portIdx;
|
||||||
|
am->timestamp = ts;
|
||||||
|
am->ch = ch;
|
||||||
|
am->status = status;
|
||||||
|
am->d0 = d0;
|
||||||
|
am->d1 = d1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return am;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _event_callback( midi_record_play_t* p, unsigned id, const time::spec_t timestamp, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1, bool log_fl=true )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
if( !time::isZero(p->end_play_event_timestamp) && time::isGT(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);
|
||||||
|
printf("ZERO\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if( p->halfPedalFl )
|
||||||
|
{
|
||||||
|
if( status==midi::kCtlMdId && d0 == midi::kSustainCtlMdId && d1 != 0 )
|
||||||
|
d1 = p->halfPedalMidiPedalVel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
for(unsigned i=0; i<p->midiDevN; ++i)
|
for(unsigned i=0; i<p->midiDevN; ++i)
|
||||||
if(p->midiDevA[i].enableFl )
|
if(p->midiDevA[i].enableFl )
|
||||||
io::midiDeviceSend( p->ioH, p->midiDevA[i].midiOutDevIdx, p->midiDevA[i].midiOutPortIdx, status + ch, d0, d1 );
|
{
|
||||||
|
uint8_t out_d1 = d1;
|
||||||
|
|
||||||
|
if( !p->halfPedalFl )
|
||||||
|
{
|
||||||
|
// map the note on velocity
|
||||||
|
if( status==midi::kNoteOnMdId and d1 != 0 and p->midiDevA[i].velTableArray != nullptr )
|
||||||
|
{
|
||||||
|
if( d1 >= p->midiDevA[i].velTableN )
|
||||||
|
cwLogError(kInvalidIdRC,"A MIDI note-on velocity (%i) outside the velocity table range was encountered.",d1);
|
||||||
|
else
|
||||||
|
out_d1 = p->midiDevA[i].velTableArray[ d1 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
// map the pedal down velocity
|
||||||
|
if( status==midi::kCtlMdId && d0 == midi::kSustainCtlMdId && p->midiDevA[i].pedalMapEnableFl )
|
||||||
|
{
|
||||||
|
if( d1 == p->midiDevA[i].pedalDownVelId )
|
||||||
|
out_d1 = p->midiDevA[i].pedalDownVel;
|
||||||
|
else
|
||||||
|
if( d1 == p->midiDevA[i].pedalDownHalfVelId )
|
||||||
|
out_d1 = p->midiDevA[i].pedalDownHalfVel;
|
||||||
|
else
|
||||||
|
cwLogError(kInvalidIdRC,"Unexpected pedal down velocity (%i) during pedal velocity mapping.",d1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
io::midiDeviceSend( p->ioH, p->midiDevA[i].midiOutDevIdx, p->midiDevA[i].midiOutPortIdx, status + ch, d0, out_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 );
|
||||||
|
|
||||||
|
if( log_fl && p->logOutFl )
|
||||||
|
{
|
||||||
|
// Note: The device of outgoing messages is set to p->midiDevN + 1 to distinguish it from
|
||||||
|
// incoming messages.
|
||||||
|
_midi_store( p, p->midiDevN, 0, timestamp, ch, status, d0, d1 );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _transmit_msg( midi_record_play_t* p, const am_midi_msg_t* am )
|
rc_t _transmit_msg( midi_record_play_t* p, const am_midi_msg_t* am, bool log_fl=true )
|
||||||
{
|
{
|
||||||
return _event_callback( p, am->id, am->timestamp, am->ch, am->status, am->d0, am->d1 );
|
return _event_callback( p, am->id, am->timestamp, am->ch, am->status, am->d0, am->d1, log_fl );
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _transmit_ctl( midi_record_play_t* p, unsigned ch, unsigned ctlId, unsigned ctlVal )
|
rc_t _transmit_note( midi_record_play_t* p, unsigned ch, unsigned pitch, unsigned vel, unsigned microsecs )
|
||||||
{
|
{
|
||||||
time::spec_t ts = {0};
|
time::spec_t ts = {0};
|
||||||
|
time::microsecondsToSpec( ts, microsecs );
|
||||||
|
return _event_callback( p, kInvalidId, ts, ch, midi::kNoteOnMdId, pitch, vel );
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _transmit_ctl( midi_record_play_t* p, unsigned ch, unsigned ctlId, unsigned ctlVal, unsigned microsecs )
|
||||||
|
{
|
||||||
|
time::spec_t ts = {0};
|
||||||
|
time::microsecondsToSpec( ts, microsecs );
|
||||||
return _event_callback( p, kInvalidId, ts, ch, midi::kCtlMdId, ctlId, ctlVal );
|
return _event_callback( p, kInvalidId, ts, ch, midi::kCtlMdId, ctlId, ctlVal );
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _transmit_pedal( midi_record_play_t* p, unsigned ch, unsigned pedalCtlId, bool pedalDownFl )
|
rc_t _transmit_pedal( midi_record_play_t* p, unsigned ch, unsigned pedalCtlId, bool pedalDownFl, unsigned microsecs )
|
||||||
{
|
{
|
||||||
return _transmit_ctl( p, ch, pedalCtlId, pedalDownFl ? 127 : 0);
|
return _transmit_ctl( p, ch, pedalCtlId, pedalDownFl ? 127 : 0, microsecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _half_pedal_update( midi_record_play_t* p, unsigned cur_time_us )
|
||||||
|
{
|
||||||
|
if( cur_time_us >= p->halfPedalNextUs )
|
||||||
|
{
|
||||||
|
unsigned midi_ch = 0;
|
||||||
|
switch( p->halfPedalState )
|
||||||
|
{
|
||||||
|
|
||||||
|
case kWaitForBegin:
|
||||||
|
printf("down: %i %i\n",cur_time_us/1000,p->halfPedalMidiPedalVel);
|
||||||
|
_transmit_ctl( p, midi_ch, midi::kSustainCtlMdId, p->halfPedalMidiPedalVel, cur_time_us);
|
||||||
|
p->halfPedalState = kWaitForNoteOn;
|
||||||
|
p->halfPedalNextUs += p->halfPedalNoteDelayUs;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kWaitForNoteOn:
|
||||||
|
printf("note: %i\n",cur_time_us/1000);
|
||||||
|
_transmit_note( p, midi_ch, p->halfPedalMidiPitch, p->halfPedalMidiNoteVel, cur_time_us );
|
||||||
|
p->halfPedalNextUs += p->halfPedalNoteDurUs;
|
||||||
|
p->halfPedalState = kWaitForNoteOff;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kWaitForNoteOff:
|
||||||
|
printf("off: %i\n",cur_time_us/1000);
|
||||||
|
_transmit_note( p, midi_ch, p->halfPedalMidiPitch, 0, cur_time_us );
|
||||||
|
p->halfPedalNextUs += p->halfPedalUpDelayUs;
|
||||||
|
p->halfPedalState = kWaitForPedalUp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kWaitForPedalUp:
|
||||||
|
printf("up: %i\n",cur_time_us/1000);
|
||||||
|
_transmit_ctl( p, midi_ch, midi::kSustainCtlMdId, 0, cur_time_us);
|
||||||
|
p->halfPedalNextUs += p->halfPedalDownDelayUs;
|
||||||
|
p->halfPedalState = kWaitForPedalDown;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kWaitForPedalDown:
|
||||||
|
//printf("down: %i\n",cur_time_us/1000);
|
||||||
|
//_transmit_ctl( p, midi_ch, midi::kSustainCtlMdId, p->halfPedalMidiPedalVel, cur_time_us);
|
||||||
|
//_stop(p);
|
||||||
|
p->halfPedalState = kHalfPedalDone;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case kHalfPedalDone:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the next location to store an incoming MIDI message
|
||||||
void _set_midi_msg_next_index( midi_record_play_t* p, unsigned next_idx )
|
void _set_midi_msg_next_index( midi_record_play_t* p, unsigned next_idx )
|
||||||
{
|
{
|
||||||
p->msgArrayInIdx = next_idx;
|
p->iMsgArrayInIdx = next_idx;
|
||||||
|
|
||||||
//io::uiSendValue( p->ioH, kInvalidId, uiFindElementUuId(p->ioH,kMsgCntId), p->midiMsgArrayInIdx );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the next index of the next MIDI message to transmit
|
||||||
void _set_midi_msg_next_play_index(midi_record_play_t* p, unsigned next_idx)
|
void _set_midi_msg_next_play_index(midi_record_play_t* p, unsigned next_idx)
|
||||||
{
|
{
|
||||||
p->msgArrayOutIdx = next_idx;
|
p->msgArrayOutIdx = next_idx;
|
||||||
@ -255,6 +470,7 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fill the play buffer from a previously store AM file.
|
||||||
rc_t _midi_read( midi_record_play_t* p, const char* fn )
|
rc_t _midi_read( midi_record_play_t* p, const char* fn )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -285,21 +501,24 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
_set_midi_msg_next_index(p, n );
|
p->msgArrayInIdx = n;
|
||||||
|
|
||||||
cwLogInfo("Read %i from '%s'.",n,fn);
|
cwLogInfo("Read %i from '%s'.",n,fn);
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
|
|
||||||
|
file::close(fH);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write the record buffer to an AM file
|
||||||
rc_t _midi_write( midi_record_play_t* p, const char* fn )
|
rc_t _midi_write( midi_record_play_t* p, const char* fn )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
file::handle_t fH;
|
file::handle_t fH;
|
||||||
|
|
||||||
if( p->msgArrayInIdx == 0 )
|
if( p->iMsgArrayInIdx == 0 )
|
||||||
{
|
{
|
||||||
cwLogWarning("Nothing to write.");
|
cwLogWarning("Nothing to write.");
|
||||||
return rc;
|
return rc;
|
||||||
@ -313,28 +532,75 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write the file header
|
// write the file header
|
||||||
if((rc = write(fH,p->msgArrayInIdx)) != kOkRC )
|
if((rc = write(fH,p->iMsgArrayInIdx)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kWriteFailRC,"Header write to '%s' failed.",cwStringNullGuard(fn));
|
rc = cwLogError(kWriteFailRC,"Header write to '%s' failed.",cwStringNullGuard(fn));
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the file data
|
// write the file data
|
||||||
if((rc = write(fH,p->msgArray,sizeof(am_midi_msg_t)*p->msgArrayInIdx)) != kOkRC )
|
if((rc = write(fH,p->iMsgArray,sizeof(am_midi_msg_t)*p->iMsgArrayInIdx)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kWriteFailRC,"Data write to '%s' failed.",cwStringNullGuard(fn));
|
rc = cwLogError(kWriteFailRC,"Data write to '%s' failed.",cwStringNullGuard(fn));
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update UI msg count
|
errLabel:
|
||||||
//io::uiSendValue( p->ioH, kInvalidId, uiFindElementUuId(p->ioH,kMsgCntId), p->msgArrayInIdx );
|
|
||||||
|
|
||||||
file::close(fH);
|
file::close(fH);
|
||||||
|
|
||||||
cwLogInfo("Saved %i events to '%s'.", p->msgArrayInIdx, fn );
|
cwLogInfo("Saved %i events to '%s'.", p->iMsgArrayInIdx, fn );
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _write_csv( midi_record_play_t* p, const char* fn )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
file::handle_t fH;
|
||||||
|
|
||||||
|
if( p->iMsgArrayInIdx == 0 )
|
||||||
|
{
|
||||||
|
cwLogWarning("Nothing to write.");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the file
|
||||||
|
if((rc = file::open(fH,fn,file::kWriteFl)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpenFailRC,"Unable to create the file '%s'.",cwStringNullGuard(fn));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
file::printf(fH,"dev,port,microsec,id,sec,ch,status,d0,d1\n");
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->iMsgArrayInIdx; ++i)
|
||||||
|
{
|
||||||
|
const am_midi_msg_t* m = p->iMsgArray + i;
|
||||||
|
|
||||||
|
double secs = time::elapsedSecs( p->iMsgArray[0].timestamp, p->iMsgArray[i].timestamp );
|
||||||
|
|
||||||
|
char sciPitch[ midi::kMidiSciPitchCharCnt + 1 ];
|
||||||
|
if( m->status == midi::kNoteOnMdId )
|
||||||
|
midi::midiToSciPitch( m->d0, sciPitch, midi::kMidiSciPitchCharCnt );
|
||||||
|
else
|
||||||
|
strcpy(sciPitch,"");
|
||||||
|
|
||||||
|
if((rc = file::printf(fH, "%3i,%3i,%8i,%3i,%8.4f,%2i,0x%2x,%5s,%3i,%3i\n",
|
||||||
|
m->devIdx, m->portIdx, m->microsec, m->id, secs,
|
||||||
|
m->ch, m->status, sciPitch, m->d0, m->d1 )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Write failed on line:%i", i+1 );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
|
file::close(fH);
|
||||||
|
|
||||||
|
cwLogInfo("Saved %i events to '%s'.", p->iMsgArrayInIdx, fn );
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _midi_file_write( const char* fn, const am_midi_msg_t* msgArray, unsigned msgArrayCnt )
|
rc_t _midi_file_write( const char* fn, const am_midi_msg_t* msgArray, unsigned msgArrayCnt )
|
||||||
@ -424,13 +690,14 @@ namespace cw
|
|||||||
time::spec_t t1;
|
time::spec_t t1;
|
||||||
time::get(t1);
|
time::get(t1);
|
||||||
|
|
||||||
|
// if we were recording
|
||||||
if( p->recordFl )
|
if( p->recordFl )
|
||||||
{
|
{
|
||||||
|
|
||||||
// set the 'microsec' value for each MIDI msg
|
// set the 'microsec' value for each MIDI msg as an offset from the first message[]
|
||||||
for(unsigned i=0; i<p->msgArrayInIdx; ++i)
|
for(unsigned i=0; i<p->iMsgArrayInIdx; ++i)
|
||||||
{
|
{
|
||||||
p->msgArray[i].microsec = time::elapsedMicros(p->msgArray[0].timestamp,p->msgArray[i].timestamp);
|
p->msgArray[i].microsec = time::elapsedMicros(p->iMsgArray[0].timestamp,p->iMsgArray[i].timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
cwLogInfo("MIDI messages recorded: %i",p->msgArrayInIdx );
|
cwLogInfo("MIDI messages recorded: %i",p->msgArrayInIdx );
|
||||||
@ -440,27 +707,16 @@ namespace cw
|
|||||||
{
|
{
|
||||||
io::timerStop( p->ioH, io::timerIdToIndex(p->ioH, kMidiRecordPlayTimerId) );
|
io::timerStop( p->ioH, io::timerIdToIndex(p->ioH, kMidiRecordPlayTimerId) );
|
||||||
|
|
||||||
// TODO: should work for all channels
|
// TODO:
|
||||||
|
// BUG BUG BUG: should work for all channels
|
||||||
|
|
||||||
// all notes off
|
// all notes off
|
||||||
_transmit_ctl( p, 0, 121, 0 ); // reset all controllers
|
_transmit_ctl( p, 0, 121, 0, 0 ); // reset all controllers
|
||||||
_transmit_ctl( p, 0, 123, 0 ); // all notes off
|
_transmit_ctl( p, 0, 123, 0, 0 ); // all notes off
|
||||||
_transmit_ctl( p, 0, 0, 0 ); // switch to bank 0
|
_transmit_ctl( p, 0, 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
|
|
||||||
//time::spec_t ts = {0};
|
|
||||||
//_event_callback( p, kInvalidId, ts, 0, midi::kPgmMdId, 0, 0 );
|
|
||||||
|
|
||||||
p->pedalFl = false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//cwLogInfo("Runtime: %5.2f seconds.", time::elapsedMs(p->start_time,t1)/1000.0 );
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,65 +736,42 @@ namespace cw
|
|||||||
{
|
{
|
||||||
|
|
||||||
//if( !midi::isPedal(pkt->msgArray[j].status,pkt->msgArray[j].d0) )
|
//if( !midi::isPedal(pkt->msgArray[j].status,pkt->msgArray[j].d0) )
|
||||||
// printf("0x%x 0x%x 0x%x\n", pkt->msgArray[j].status, pkt->msgArray[j].d0, pkt->msgArray[j].d1 );
|
//printf("IN: 0x%x 0x%x 0x%x\n", pkt->msgArray[j].status, pkt->msgArray[j].d0, pkt->msgArray[j].d1 );
|
||||||
|
|
||||||
if( p->recordFl && p->startedFl )
|
if( (p->recordFl || p->logInFl) && p->startedFl )
|
||||||
{
|
{
|
||||||
|
|
||||||
// verify that space exists in the record buffer
|
// verify that space exists in the record buffer
|
||||||
if( p->msgArrayInIdx >= p->msgArrayN )
|
if( p->iMsgArrayInIdx >= p->iMsgArrayN )
|
||||||
{
|
{
|
||||||
_stop(p);
|
_stop(p);
|
||||||
rc = cwLogError(kBufTooSmallRC,"MIDI message record buffer is full. % messages.",p->msgArrayN);
|
rc = cwLogError(kBufTooSmallRC,"MIDI message record buffer is full. % messages.",p->iMsgArrayN);
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// copy the msg into the record buffer
|
// copy the msg into the record buffer
|
||||||
am_midi_msg_t* am = p->msgArray + p->msgArrayInIdx;
|
|
||||||
midi::msg_t* mm = pkt->msgArray + j;
|
midi::msg_t* mm = pkt->msgArray + j;
|
||||||
|
|
||||||
if( midi::isChStatus(mm->status) )
|
if( midi::isChStatus(mm->status) )
|
||||||
{
|
{
|
||||||
|
const am_midi_msg_t* am = _midi_store( p, pkt->devIdx, pkt->portIdx, mm->timeStamp, mm->status & 0x0f, mm->status & 0xf0, mm->d0, mm->d1 );
|
||||||
|
|
||||||
am->id = p->msgArrayInIdx;
|
if( p->thruFl && am != nullptr )
|
||||||
am->devIdx = pkt->devIdx;
|
_transmit_msg( p, am, false );
|
||||||
am->portIdx = pkt->portIdx;
|
|
||||||
am->timestamp = mm->timeStamp;
|
|
||||||
am->ch = mm->status & 0x0f;
|
|
||||||
am->status = mm->status & 0xf0;
|
|
||||||
am->d0 = mm->d0;
|
|
||||||
am->d1 = mm->d1;
|
|
||||||
|
|
||||||
//printf("st:0x%x ch:%i d0:0x%x d1:0x%x\n",am->status,am->ch,am->d0,am->d1);
|
|
||||||
|
|
||||||
p->msgArrayInIdx += 1;
|
|
||||||
|
|
||||||
if( p->thruFl )
|
|
||||||
_transmit_msg( p, am );
|
|
||||||
|
|
||||||
// send msg count
|
|
||||||
//io::uiSendValue( p->ioH, kInvalidId, uiFindElementUuId(p->ioH,kMsgCntId), p->msgArrayInIdx );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if( pkt->msgArray == NULL )
|
|
||||||
printf("io midi cb: 0x%x ",pkt->sysExMsg[j]);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( !_midi_filter(pkt->msgArray + j) )
|
|
||||||
printf("io midi cb: %ld %ld 0x%x %i %i\n", pkt->msgArray[j].timeStamp.tv_sec, pkt->msgArray[j].timeStamp.tv_nsec, pkt->msgArray[j].status, pkt->msgArray[j].d0, pkt->msgArray[j].d1);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rc_t _timer_callback(midi_record_play_t* p, io::timer_msg_t& m)
|
rc_t _timer_callback(midi_record_play_t* p, io::timer_msg_t& m)
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -551,6 +784,9 @@ namespace cw
|
|||||||
|
|
||||||
unsigned cur_time_us = time::elapsedMicros(p->play_time,t);
|
unsigned cur_time_us = time::elapsedMicros(p->play_time,t);
|
||||||
|
|
||||||
|
if( p->halfPedalFl )
|
||||||
|
_half_pedal_update( p, cur_time_us );
|
||||||
|
else
|
||||||
while( p->msgArray[ p->msgArrayOutIdx ].microsec <= cur_time_us )
|
while( p->msgArray[ p->msgArrayOutIdx ].microsec <= cur_time_us )
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -558,30 +794,8 @@ namespace cw
|
|||||||
|
|
||||||
//_print_midi_msg(mm);
|
//_print_midi_msg(mm);
|
||||||
|
|
||||||
bool skipFl = false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
// if this is a pedal message
|
|
||||||
if( mm->status == midi::kCtlMdId && (mm->d0 == midi::kSustainCtlMdId || mm->d0 == midi::kSostenutoCtlMdId || mm->d0 == midi::kSoftPedalCtlMdId ) )
|
|
||||||
{
|
|
||||||
// if the pedal is down
|
|
||||||
if( p->pedalFl )
|
|
||||||
{
|
|
||||||
skipFl = mm->d1 > 64;
|
|
||||||
p->pedalFl = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
skipFl = mm->d1 <= 64;
|
|
||||||
p->pedalFl = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if( !skipFl )
|
|
||||||
{
|
|
||||||
_transmit_msg( p, mm );
|
_transmit_msg( p, mm );
|
||||||
}
|
|
||||||
_set_midi_msg_next_play_index(p, p->msgArrayOutIdx+1 );
|
_set_midi_msg_next_play_index(p, p->msgArrayOutIdx+1 );
|
||||||
|
|
||||||
// if all MIDI messages have been played
|
// if all MIDI messages have been played
|
||||||
@ -615,6 +829,16 @@ cw::rc_t cw::midi_record_play::create( handle_t& hRef, io::handle_t ioH, const o
|
|||||||
p->ioH = ioH;
|
p->ioH = ioH;
|
||||||
p->cb = cb;
|
p->cb = cb;
|
||||||
p->cb_arg = cb_arg;
|
p->cb_arg = cb_arg;
|
||||||
|
p->halfPedalState = kHalfPedalDone;
|
||||||
|
p->halfPedalNextUs = 0;
|
||||||
|
p->halfPedalNoteDelayUs = 100 * 1000;
|
||||||
|
p->halfPedalNoteDurUs = 1000 * 1000;
|
||||||
|
p->halfPedalUpDelayUs = 1000 * 1000;
|
||||||
|
p->halfPedalDownDelayUs = 1000 * 1000;
|
||||||
|
p->halfPedalMidiPitch = 64;
|
||||||
|
p->halfPedalMidiNoteVel = 64;
|
||||||
|
p->halfPedalMidiPedalVel = 127;
|
||||||
|
|
||||||
|
|
||||||
for( unsigned i=0; i<
|
for( unsigned i=0; i<
|
||||||
p->midiDevN; ++i)
|
p->midiDevN; ++i)
|
||||||
@ -673,7 +897,6 @@ cw::rc_t cw::midi_record_play::start( handle_t h, bool rewindFl, const time::spe
|
|||||||
{
|
{
|
||||||
midi_record_play_t* p = _handleToPtr(h);
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
p->startedFl = true;
|
p->startedFl = true;
|
||||||
p->pedalFl = false;
|
|
||||||
|
|
||||||
// set the end play time
|
// set the end play time
|
||||||
if( end_play_event_timestamp == nullptr or time::isZero(*end_play_event_timestamp) )
|
if( end_play_event_timestamp == nullptr or time::isZero(*end_play_event_timestamp) )
|
||||||
@ -683,11 +906,12 @@ cw::rc_t cw::midi_record_play::start( handle_t h, bool rewindFl, const time::spe
|
|||||||
|
|
||||||
time::get(p->start_time);
|
time::get(p->start_time);
|
||||||
|
|
||||||
if( p->recordFl )
|
if( p->recordFl || p->logInFl or p->logOutFl )
|
||||||
{
|
{
|
||||||
_set_midi_msg_next_index(p, 0 );
|
_set_midi_msg_next_index(p, 0 );
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if( !p->recordFl )
|
||||||
{
|
{
|
||||||
time::get(p->play_time);
|
time::get(p->play_time);
|
||||||
|
|
||||||
@ -700,6 +924,12 @@ cw::rc_t cw::midi_record_play::start( handle_t h, bool rewindFl, const time::spe
|
|||||||
time::subtractMicros(p->play_time, p->msgArray[ p->msgArrayOutIdx ].microsec );
|
time::subtractMicros(p->play_time, p->msgArray[ p->msgArrayOutIdx ].microsec );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( p->halfPedalFl )
|
||||||
|
{
|
||||||
|
p->halfPedalNextUs = 0;
|
||||||
|
p->halfPedalState = kWaitForBegin;
|
||||||
|
}
|
||||||
|
|
||||||
io::timerStart( p->ioH, io::timerIdToIndex(p->ioH, kMidiRecordPlayTimerId) );
|
io::timerStart( p->ioH, io::timerIdToIndex(p->ioH, kMidiRecordPlayTimerId) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -761,6 +991,12 @@ cw::rc_t cw::midi_record_play::save( handle_t h, const char* fn )
|
|||||||
return _midi_write(p,fn);
|
return _midi_write(p,fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::midi_record_play::save_csv( handle_t h, const char* fn )
|
||||||
|
{
|
||||||
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
|
return _write_csv(p,fn);
|
||||||
|
}
|
||||||
|
|
||||||
cw::rc_t cw::midi_record_play::open( handle_t h, const char* fn )
|
cw::rc_t cw::midi_record_play::open( handle_t h, const char* fn )
|
||||||
{
|
{
|
||||||
midi_record_play_t* p = _handleToPtr(h);
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
@ -790,6 +1026,7 @@ cw::rc_t cw::midi_record_play::load( handle_t h, const midi_msg_t* msg, unsigned
|
|||||||
p->msgArray[i].devIdx = kInvalidIdx;
|
p->msgArray[i].devIdx = kInvalidIdx;
|
||||||
p->msgArray[i].portIdx = kInvalidIdx;
|
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p->msgArrayInIdx = msg_count;
|
p->msgArrayInIdx = msg_count;
|
||||||
@ -815,13 +1052,12 @@ cw::rc_t cw::midi_record_play::seek( handle_t h, time::spec_t seek_timestamp )
|
|||||||
{
|
{
|
||||||
p->msgArrayOutIdx = i;
|
p->msgArrayOutIdx = i;
|
||||||
|
|
||||||
_transmit_pedal( p, mm->ch, midi::kSustainCtlMdId, damp_down_fl );
|
_transmit_pedal( p, mm->ch, midi::kSustainCtlMdId, damp_down_fl, 0 );
|
||||||
_transmit_pedal( p, mm->ch, midi::kSostenutoCtlMdId, sost_down_fl );
|
_transmit_pedal( p, mm->ch, midi::kSostenutoCtlMdId, sost_down_fl, 0 );
|
||||||
_transmit_pedal( p, mm->ch, midi::kSoftPedalCtlMdId, soft_down_fl );
|
_transmit_pedal( p, mm->ch, midi::kSoftPedalCtlMdId, soft_down_fl, 0 );
|
||||||
|
|
||||||
|
printf("PEDAL: %s.\n", damp_down_fl ? "Down" : "Up");
|
||||||
|
|
||||||
//io::midiDeviceSend( p->ioH, p->midiOutDevIdx, p->midiOutPortIdx, mm->status + mm->ch, midi::kSustainCtlMdId, damp_down_fl ? 127 : 0 );
|
|
||||||
//io::midiDeviceSend( p->ioH, p->midiOutDevIdx, p->midiOutPortIdx, mm->status + mm->ch, midi::kSostenutoCtlMdId, sost_down_fl ? 127 : 0 );
|
|
||||||
//io::midiDeviceSend( p->ioH, p->midiOutDevIdx, p->midiOutPortIdx, mm->status + mm->ch, midi::kSoftPedalCtlMdId, soft_down_fl ? 127 : 0 );
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,7 +1098,7 @@ unsigned cw::midi_record_play::event_count( handle_t h )
|
|||||||
unsigned cw::midi_record_play::event_index( handle_t h )
|
unsigned cw::midi_record_play::event_index( handle_t h )
|
||||||
{
|
{
|
||||||
midi_record_play_t* p = _handleToPtr(h);
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
return p->recordFl ? p->msgArrayInIdx : p->msgArrayOutIdx;
|
return p->recordFl ? p->iMsgArrayInIdx : p->msgArrayOutIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -923,6 +1159,18 @@ void cw::midi_record_play::enable_device( handle_t h, unsigned devIdx, bool enab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cw::midi_record_play::half_pedal_params( handle_t h, unsigned noteDelayMs, unsigned pitch, unsigned vel, unsigned pedal_vel, unsigned noteDurMs, unsigned downDelayMs )
|
||||||
|
{
|
||||||
|
midi_record_play_t* p = _handleToPtr(h);
|
||||||
|
p->halfPedalNoteDelayUs = noteDelayMs * 1000;
|
||||||
|
p->halfPedalNoteDurUs = noteDurMs * 1000;
|
||||||
|
p->halfPedalDownDelayUs = downDelayMs * 1000;
|
||||||
|
p->halfPedalMidiPitch = pitch;
|
||||||
|
p->halfPedalMidiNoteVel = vel;
|
||||||
|
p->halfPedalMidiPedalVel= pedal_vel;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
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 )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
@ -39,6 +39,8 @@ namespace cw
|
|||||||
bool thru_state( handle_t h );
|
bool thru_state( handle_t h );
|
||||||
|
|
||||||
rc_t save( handle_t h, const char* fn );
|
rc_t save( handle_t h, const char* fn );
|
||||||
|
rc_t save_csv( 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.
|
// Load the playback buffer with messages to output.
|
||||||
@ -54,6 +56,8 @@ namespace cw
|
|||||||
bool is_device_enabled( handle_t h, unsigned devIdx );
|
bool is_device_enabled( handle_t h, unsigned devIdx );
|
||||||
void enable_device( handle_t h, unsigned devIdx, bool enableFl );
|
void enable_device( handle_t h, unsigned devIdx, bool enableFl );
|
||||||
|
|
||||||
|
void half_pedal_params( handle_t h, unsigned noteDelayMs, unsigned pitch, unsigned vel, unsigned pedal_vel, unsigned noteDurMs, unsigned downDelayMs );
|
||||||
|
|
||||||
// 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 );
|
||||||
|
@ -69,6 +69,13 @@ namespace cw
|
|||||||
|
|
||||||
kStatusId,
|
kStatusId,
|
||||||
|
|
||||||
|
kHalfPedalPedalVel,
|
||||||
|
kHalfPedalDelayMs,
|
||||||
|
kHalfPedalPitch,
|
||||||
|
kHalfPedalVel,
|
||||||
|
kHalfPedalDurMs,
|
||||||
|
kHalfPedalDnDelayMs,
|
||||||
|
|
||||||
kLogId,
|
kLogId,
|
||||||
|
|
||||||
kFragListId,
|
kFragListId,
|
||||||
@ -140,6 +147,15 @@ namespace cw
|
|||||||
{ kPanelDivId, kInsertLocId, "insertLocId" },
|
{ kPanelDivId, kInsertLocId, "insertLocId" },
|
||||||
{ kPanelDivId, kInsertBtnId, "insertBtnId" },
|
{ kPanelDivId, kInsertBtnId, "insertBtnId" },
|
||||||
{ kPanelDivId, kDeleteBtnId, "deleteBtnId" },
|
{ kPanelDivId, kDeleteBtnId, "deleteBtnId" },
|
||||||
|
|
||||||
|
{ kPanelDivId, kHalfPedalPedalVel, "halfPedalPedalVelId" },
|
||||||
|
{ kPanelDivId, kHalfPedalDelayMs, "halfPedalDelayMsId" },
|
||||||
|
{ kPanelDivId, kHalfPedalPitch, "halfPedalPitchId" },
|
||||||
|
{ kPanelDivId, kHalfPedalVel, "halfPedalVelId" },
|
||||||
|
{ kPanelDivId, kHalfPedalDurMs, "halfPedalDurMsId" },
|
||||||
|
{ kPanelDivId, kHalfPedalDnDelayMs, "halfPedalDnDelayMsId" },
|
||||||
|
|
||||||
|
|
||||||
{ kPanelDivId, kStatusId, "statusId" },
|
{ kPanelDivId, kStatusId, "statusId" },
|
||||||
{ kPanelDivId, kLogId, "logId" },
|
{ kPanelDivId, kLogId, "logId" },
|
||||||
|
|
||||||
@ -214,6 +230,15 @@ namespace cw
|
|||||||
|
|
||||||
bool printMidiFl;
|
bool printMidiFl;
|
||||||
|
|
||||||
|
unsigned hpDelayMs;
|
||||||
|
unsigned hpPedalVel;
|
||||||
|
unsigned hpPitch;
|
||||||
|
unsigned hpVel;
|
||||||
|
unsigned hpDurMs;
|
||||||
|
unsigned hpDnDelayMs;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} app_t;
|
} app_t;
|
||||||
|
|
||||||
rc_t _parseCfg(app_t* app, const object_t* cfg, const object_t*& params_cfgRef )
|
rc_t _parseCfg(app_t* app, const object_t* cfg, const object_t*& params_cfgRef )
|
||||||
@ -362,13 +387,20 @@ namespace cw
|
|||||||
void _midi_play_callback( void* arg, unsigned id, const time::spec_t timestamp, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
void _midi_play_callback( void* arg, unsigned id, const time::spec_t timestamp, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 )
|
||||||
{
|
{
|
||||||
app_t* app = (app_t*)arg;
|
app_t* app = (app_t*)arg;
|
||||||
if( id != kInvalidId )
|
|
||||||
{
|
|
||||||
if( app->printMidiFl )
|
if( app->printMidiFl )
|
||||||
{
|
{
|
||||||
const unsigned buf_byte_cnt = 256;
|
const unsigned buf_byte_cnt = 256;
|
||||||
char buf[ buf_byte_cnt ];
|
char buf[ buf_byte_cnt ];
|
||||||
event_to_string( app->scoreH, id, buf, buf_byte_cnt );
|
|
||||||
|
// if this event is not in the score
|
||||||
|
if( id == kInvalidId )
|
||||||
|
{
|
||||||
|
// TODO: print this out in the same format as event_to_string()
|
||||||
|
snprintf(buf,buf_byte_cnt,"ch:%i status:0x%02x d0:%i d1:%i",ch,status,d0,d1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
score::event_to_string( app->scoreH, id, buf, buf_byte_cnt );
|
||||||
printf("%s\n",buf);
|
printf("%s\n",buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,9 +413,6 @@ namespace cw
|
|||||||
if( f != nullptr )
|
if( f != nullptr )
|
||||||
_do_select_frag( app, f->guiUuId );
|
_do_select_frag( app, f->guiUuId );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loc_map_t* _find_loc( app_t* app, unsigned loc )
|
loc_map_t* _find_loc( app_t* app, unsigned loc )
|
||||||
@ -424,6 +453,9 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
midi_record_play::half_pedal_params( app->mrpH, app->hpDelayMs, app->hpPitch, app->hpVel, app->hpPedalVel, app->hpDurMs, app->hpDnDelayMs );
|
||||||
|
|
||||||
|
|
||||||
if((begMap = _find_loc(app,begLoc)) == nullptr )
|
if((begMap = _find_loc(app,begLoc)) == nullptr )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kInvalidArgRC,"The begin play location is not valid.");
|
rc = cwLogError(kInvalidArgRC,"The begin play location is not valid.");
|
||||||
@ -971,6 +1003,7 @@ namespace cw
|
|||||||
m[i].d1 = e->d1;
|
m[i].d1 = e->d1;
|
||||||
m[i].id = e->uid;
|
m[i].id = e->uid;
|
||||||
|
|
||||||
|
|
||||||
app->locMap[i].loc = e->loc;
|
app->locMap[i].loc = e->loc;
|
||||||
app->locMap[i].timestamp = m[i].timestamp;
|
app->locMap[i].timestamp = m[i].timestamp;
|
||||||
|
|
||||||
@ -987,6 +1020,8 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cwLogInfo("%i MIDI events loaded.", midiEventN );
|
||||||
|
|
||||||
mem::free(m);
|
mem::free(m);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1031,7 +1066,6 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rc_t _on_ui_start( app_t* app )
|
rc_t _on_ui_start( app_t* app )
|
||||||
{
|
{
|
||||||
return _do_play(app, app->beg_play_loc, app->end_play_loc );
|
return _do_play(app, app->beg_play_loc, app->end_play_loc );
|
||||||
@ -1257,6 +1291,77 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _on_ui_half_pedal_value( app_t* app, unsigned appId, unsigned uuId, unsigned value )
|
||||||
|
{
|
||||||
|
switch( appId )
|
||||||
|
{
|
||||||
|
case kHalfPedalDelayMs:
|
||||||
|
app->hpDelayMs = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalPedalVel:
|
||||||
|
app->hpPedalVel = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalPitch:
|
||||||
|
app->hpPitch = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalVel:
|
||||||
|
app->hpVel = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalDurMs:
|
||||||
|
app->hpDurMs = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalDnDelayMs:
|
||||||
|
app->hpDnDelayMs = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{ assert(0); }
|
||||||
|
|
||||||
|
}
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _on_echo_half_pedal( app_t* app, unsigned appId, unsigned uuId )
|
||||||
|
{
|
||||||
|
switch( appId )
|
||||||
|
{
|
||||||
|
case kHalfPedalDelayMs:
|
||||||
|
io::uiSendValue( app->ioH, uuId, app->hpDelayMs );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalPedalVel:
|
||||||
|
io::uiSendValue( app->ioH, uuId, app->hpPedalVel );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalPitch:
|
||||||
|
io::uiSendValue( app->ioH, uuId, app->hpPitch );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalVel:
|
||||||
|
io::uiSendValue( app->ioH, uuId, app->hpVel );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalDurMs:
|
||||||
|
io::uiSendValue( app->ioH, uuId, app->hpDurMs );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalDnDelayMs:
|
||||||
|
io::uiSendValue( app->ioH, uuId, app->hpDnDelayMs );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{ assert(0); }
|
||||||
|
|
||||||
|
}
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
rc_t _onUiInit(app_t* app, const io::ui_msg_t& m )
|
rc_t _onUiInit(app_t* app, const io::ui_msg_t& m )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -1299,7 +1404,8 @@ namespace cw
|
|||||||
//preset_sel::report( app->psH );
|
//preset_sel::report( app->psH );
|
||||||
//io_flow::apply_preset( app->ioFlowH, 2000.0, app->tmp==0 ? "a" : "b");
|
//io_flow::apply_preset( app->ioFlowH, 2000.0, app->tmp==0 ? "a" : "b");
|
||||||
//app->tmp = !app->tmp;
|
//app->tmp = !app->tmp;
|
||||||
io_flow::print(app->ioFlowH);
|
//io_flow::print(app->ioFlowH);
|
||||||
|
midi_record_play::save_csv(app->mrpH,"/home/kevin/temp/mrp_1.csv");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kSaveBtnId:
|
case kSaveBtnId:
|
||||||
@ -1371,6 +1477,15 @@ namespace cw
|
|||||||
_on_ui_delete_btn(app);
|
_on_ui_delete_btn(app);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalPedalVel:
|
||||||
|
case kHalfPedalDelayMs:
|
||||||
|
case kHalfPedalPitch:
|
||||||
|
case kHalfPedalVel:
|
||||||
|
case kHalfPedalDurMs:
|
||||||
|
case kHalfPedalDnDelayMs:
|
||||||
|
_on_ui_half_pedal_value( app, m.appId, m.uuId, m.value->u.u );
|
||||||
|
break;
|
||||||
|
|
||||||
case kFragInGainId:
|
case kFragInGainId:
|
||||||
_on_ui_frag_value( app, m.uuId, m.value->u.d);
|
_on_ui_frag_value( app, m.uuId, m.value->u.d);
|
||||||
break;
|
break;
|
||||||
@ -1496,6 +1611,15 @@ namespace cw
|
|||||||
_on_echo_master_value( app, preset_sel::kMasterSyncDelayMsVarId, m.uuId );
|
_on_echo_master_value( app, preset_sel::kMasterSyncDelayMsVarId, m.uuId );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kHalfPedalPedalVel:
|
||||||
|
case kHalfPedalDelayMs:
|
||||||
|
case kHalfPedalPitch:
|
||||||
|
case kHalfPedalVel:
|
||||||
|
case kHalfPedalDurMs:
|
||||||
|
case kHalfPedalDnDelayMs:
|
||||||
|
_on_echo_half_pedal( app, m.appId, m.uuId );
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
@ -1614,8 +1738,9 @@ namespace cw
|
|||||||
|
|
||||||
cw::rc_t cw::preset_sel_app::main( const object_t* cfg, const object_t* flow_proc_dict )
|
cw::rc_t cw::preset_sel_app::main( const object_t* cfg, const object_t* flow_proc_dict )
|
||||||
{
|
{
|
||||||
|
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
app_t app = { };
|
app_t app = { .hpDelayMs=250, .hpPedalVel=127, .hpPitch=64, .hpVel=64, .hpDurMs=500, .hpDnDelayMs=1000 };
|
||||||
const object_t* params_cfg = nullptr;
|
const object_t* params_cfg = nullptr;
|
||||||
|
|
||||||
// Parse the configuration
|
// Parse the configuration
|
||||||
@ -1662,6 +1787,7 @@ cw::rc_t cw::preset_sel_app::main( const object_t* cfg, const object_t* flow_pro
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// execute the io framework
|
// execute the io framework
|
||||||
while( !isShuttingDown(app.ioH))
|
while( !isShuttingDown(app.ioH))
|
||||||
{
|
{
|
||||||
|
@ -49,6 +49,15 @@
|
|||||||
button:{ name: deleteBtnId, title:"Delete", enable: false },
|
button:{ name: deleteBtnId, title:"Delete", enable: false },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
row: {
|
||||||
|
number:{ name: halfPedalDelayMsId, title:"DelayMs:", min:0, max:5000, step:1, decpl:0 },
|
||||||
|
number:{ name: halfPedalPedalVelId, title:"PVel:", min:0, max:127, step:1, decpl:0 },
|
||||||
|
number:{ name: halfPedalPitchId, title:"Pitch:", min:0, max:127, step:1, decpl:0 },
|
||||||
|
number:{ name: halfPedalVelId, title:"Vel:", min:0, max:127, step:1, decpl:0 },
|
||||||
|
number:{ name: halfPedalDurMsId, title:"DurMs:", min:0, max:5000, step:1, decpl:0 },
|
||||||
|
number:{ name: halfPedalDnDelayMsId, title:"DownMs:", min:0, max:5000, step:1, decpl:0 },
|
||||||
|
},
|
||||||
|
|
||||||
row: {
|
row: {
|
||||||
str_disp:{ name: statusId, title:"Status:", value: "" },
|
str_disp:{ name: statusId, title:"Status:", value: "" },
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user