cwIoMidiRecordPlay.cpp : Add chord based dynamics scaling.

This commit is contained in:
kevin 2022-12-22 15:52:49 -05:00
parent 21697d8e82
commit a2f459c5fb

View File

@ -33,6 +33,8 @@ namespace cw
uint8_t d0; uint8_t d0;
uint8_t d1; uint8_t d1;
unsigned chordNoteCnt; // count of notes in same chord as this note (only set on Note-on messages)
} am_midi_msg_t; } am_midi_msg_t;
typedef struct midi_device_str typedef struct midi_device_str
@ -65,6 +67,9 @@ namespace cw
unsigned damper_dead_band_min_value; unsigned damper_dead_band_min_value;
unsigned damper_dead_band_max_value; unsigned damper_dead_band_max_value;
bool scale_chord_notes_enable_fl;
double scale_chord_notes_factor;
} midi_device_t; } midi_device_t;
enum enum
@ -159,6 +164,41 @@ namespace cw
return rc; return rc;
} }
void _set_chord_note_count( am_midi_msg_t* m0, const am_midi_msg_t* m, unsigned chordNoteCnt )
{
for(; m0<m; ++m0)
if( midi::isNoteOn(m0->status,m0->d1) )
m0->chordNoteCnt = chordNoteCnt;
}
void _set_chord_note_count( midi_record_play_t* p )
{
unsigned chordNoteCnt = 1;
am_midi_msg_t* m0 = p->msgArray;
am_midi_msg_t* m = nullptr;
for(unsigned i=1; i<p->msgArrayN; ++i)
{
m = p->msgArray + i;
if( midi::isNoteOn(m->status,m->d1) )
{
if( time::isEqual(m0->timestamp, m->timestamp) )
++chordNoteCnt;
else
{
_set_chord_note_count(m0,m,chordNoteCnt);
chordNoteCnt=1;
m0 = m;
}
}
}
_set_chord_note_count(m0,m,chordNoteCnt);
}
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;
@ -211,7 +251,9 @@ namespace cw
"force_damper_down_velocity", p->midiDevA[i].force_damper_down_velocity, "force_damper_down_velocity", p->midiDevA[i].force_damper_down_velocity,
"damper_dead_band_enable_fl", p->midiDevA[i].damper_dead_band_enable_fl, "damper_dead_band_enable_fl", p->midiDevA[i].damper_dead_band_enable_fl,
"damper_dead_band_min_value", p->midiDevA[i].damper_dead_band_min_value, "damper_dead_band_min_value", p->midiDevA[i].damper_dead_band_min_value,
"damper_dead_band_max_value", p->midiDevA[i].damper_dead_band_max_value)) != kOkRC ) "damper_dead_band_max_value", p->midiDevA[i].damper_dead_band_max_value,
"scale_chord_notes_enable_fl",p->midiDevA[i].scale_chord_notes_enable_fl,
"scale_chord_notes_factor", p->midiDevA[i].scale_chord_notes_factor)) != kOkRC )
{ {
rc = cwLogError(kSyntaxErrorRC,"MIDI record play device optional argument parsing failed."); rc = cwLogError(kSyntaxErrorRC,"MIDI record play device optional argument parsing failed.");
goto errLabel; goto errLabel;
@ -309,7 +351,7 @@ namespace cw
return am; return am;
} }
rc_t _event_callback( midi_record_play_t* p, unsigned id, const time::spec_t timestamp, unsigned loc, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1, bool log_fl=true ) rc_t _event_callback( midi_record_play_t* p, unsigned id, const time::spec_t timestamp, unsigned loc, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1, unsigned chordNoteCnt, bool log_fl=true )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
// if we have arrived at the stop time // if we have arrived at the stop time
@ -350,6 +392,17 @@ namespace cw
cwLogError(kInvalidIdRC,"A MIDI note-on velocity (%i) outside the velocity table range was encountered.",d1); cwLogError(kInvalidIdRC,"A MIDI note-on velocity (%i) outside the velocity table range was encountered.",d1);
else else
out_d1 = p->midiDevA[i].velTableArray[ d1 ]; out_d1 = p->midiDevA[i].velTableArray[ d1 ];
if( p->midiDevA[i].scale_chord_notes_enable_fl && chordNoteCnt>1 )
{
uint8_t delta = (uint8_t)lround(out_d1 * p->midiDevA[i].scale_chord_notes_factor * (chordNoteCnt-1) );
if( delta < out_d1 )
{
//printf("%i %i %i %i\n",chordNoteCnt,delta,out_d1,out_d1-delta);
out_d1 -= delta;
}
}
} }
// store the note-on velocity histogram data // store the note-on velocity histogram data
@ -364,7 +417,6 @@ namespace cw
if( p->midiDevA[i].force_damper_down_fl && is_damper_fl && out_d1>p->midiDevA[i].force_damper_down_threshold ) if( p->midiDevA[i].force_damper_down_fl && is_damper_fl && out_d1>p->midiDevA[i].force_damper_down_threshold )
out_d1 = p->midiDevA[i].force_damper_down_velocity; out_d1 = p->midiDevA[i].force_damper_down_velocity;
// map the pedal down velocity // map the pedal down velocity
if( status==midi::kCtlMdId && d0 == midi::kSustainCtlMdId && p->midiDevA[i].pedalMapEnableFl ) if( status==midi::kCtlMdId && d0 == midi::kSustainCtlMdId && p->midiDevA[i].pedalMapEnableFl )
{ {
@ -407,21 +459,21 @@ namespace cw
rc_t _transmit_msg( midi_record_play_t* p, const am_midi_msg_t* am, bool log_fl=true ) 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->loc, am->ch, am->status, am->d0, am->d1, log_fl ); return _event_callback( p, am->id, am->timestamp, am->loc, am->ch, am->status, am->d0, am->d1, am->chordNoteCnt, log_fl );
} }
rc_t _transmit_note( midi_record_play_t* p, unsigned ch, unsigned pitch, unsigned vel, unsigned microsecs ) 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 ); time::microsecondsToSpec( ts, microsecs );
return _event_callback( p, kInvalidId, ts, kInvalidId, ch, midi::kNoteOnMdId, pitch, vel ); return _event_callback( p, kInvalidId, ts, kInvalidId, ch, midi::kNoteOnMdId, pitch, vel, 0 );
} }
rc_t _transmit_ctl( midi_record_play_t* p, unsigned ch, unsigned ctlId, unsigned ctlVal, unsigned microsecs ) rc_t _transmit_ctl( midi_record_play_t* p, unsigned ch, unsigned ctlId, unsigned ctlVal, unsigned microsecs )
{ {
time::spec_t ts = {0}; time::spec_t ts = {0};
time::microsecondsToSpec( ts, microsecs ); time::microsecondsToSpec( ts, microsecs );
return _event_callback( p, kInvalidId, ts, kInvalidId, ch, midi::kCtlMdId, ctlId, ctlVal ); return _event_callback( p, kInvalidId, ts, kInvalidId, ch, midi::kCtlMdId, ctlId, ctlVal, 0 );
} }
rc_t _transmit_pedal( midi_record_play_t* p, unsigned ch, unsigned pedalCtlId, bool pedalDownFl, unsigned microsecs ) rc_t _transmit_pedal( midi_record_play_t* p, unsigned ch, unsigned pedalCtlId, bool pedalDownFl, unsigned microsecs )
@ -856,7 +908,7 @@ namespace cw
void _print_midi_msg( const am_midi_msg_t* mm ) void _print_midi_msg( const am_midi_msg_t* mm )
{ {
printf("%i %i : %10i : %2i 0x%02x 0x%02x 0x%02x\n", mm->devIdx, mm->portIdx, mm->microsec, mm->ch, mm->status, mm->d0, mm->d1 ); printf("%i %i : %10i : %2i 0x%02x 0x%02x 0x%02x %i\n", mm->devIdx, mm->portIdx, mm->microsec, mm->ch, mm->status, mm->d0, mm->d1, mm->chordNoteCnt );
} }
void _report_midi( midi_record_play_t* p ) void _report_midi( midi_record_play_t* p )
@ -1089,7 +1141,7 @@ cw::rc_t cw::midi_record_play::create( handle_t& hRef, io::handle_t ioH, const o
p->halfPedalMidiPitch = 64; p->halfPedalMidiPitch = 64;
p->halfPedalMidiNoteVel = 64; p->halfPedalMidiNoteVel = 64;
p->halfPedalMidiPedalVel = 127; p->halfPedalMidiPedalVel = 127;
p->velHistogramEnableFl = true;
for( unsigned i=0; i<p->midiDevN; ++i) for( unsigned i=0; i<p->midiDevN; ++i)
{ {
@ -1311,6 +1363,8 @@ cw::rc_t cw::midi_record_play::load( handle_t h, const midi_msg_t* msg, unsigned
p->msgArrayInIdx = msg_count; p->msgArrayInIdx = msg_count;
p->msgArrayOutIdx = 0; p->msgArrayOutIdx = 0;
_set_chord_note_count(p);
return rc; return rc;
} }