From ecdec5aa607417ee0c8af659ecb5dbd691ad71bd Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 20 Mar 2023 08:54:11 -0400 Subject: [PATCH] cwIoMidiRecordPlay.h/cpp: Load the velocity table from an external cfg file as provided by cwVelTableTuner.cpp --- cwIoMidiRecordPlay.cpp | 135 ++++++++++++++++++++++++++++++++++++++++- cwIoMidiRecordPlay.h | 13 ++-- 2 files changed, 141 insertions(+), 7 deletions(-) diff --git a/cwIoMidiRecordPlay.cpp b/cwIoMidiRecordPlay.cpp index bc6086f..5c74117 100644 --- a/cwIoMidiRecordPlay.cpp +++ b/cwIoMidiRecordPlay.cpp @@ -2,6 +2,7 @@ #include "cwLog.h" #include "cwCommonImpl.h" #include "cwMem.h" +#include "cwText.h" #include "cwObject.h" #include "cwFileSys.h" #include "cwFile.h" @@ -423,6 +424,7 @@ namespace cw p->midiDevA[i].midiOutPortLabel = mem::duplStr( midiOutPortLabel); p->midiDevA[i].enableFl = enableFl; + /* if( velTable != nullptr ) { p->midiDevA[i].velTableN = velTable->child_count(); @@ -438,7 +440,8 @@ namespace cw } } } - + */ + if( pedalRecd != nullptr ) { if((rc = pedalRecd->getv( "down_id", p->midiDevA[i].pedalDownVelId, @@ -1081,6 +1084,16 @@ namespace cw void _report_midi( midi_record_play_t* p ) { + + for(unsigned i=0; imidiDevN; ++i) + { + printf("vel table: %s:%s\n", cwStringNullGuard(p->midiDevA[i].midiOutDevLabel),cwStringNullGuard(p->midiDevA[i].midiOutPortLabel)); + for(unsigned j=0; jmidiDevA[i].velTableN; ++j) + printf("%i ",(unsigned)p->midiDevA[i].velTableArray[j]); + + printf("\n"); + } + printf("omsg cnt:%i\n",p->msgArrayInIdx); for(unsigned i=0; imsgArrayInIdx; ++i) { @@ -1284,15 +1297,112 @@ namespace cw return rc; } + + rc_t _loadVelTable( midi_record_play_t* p, const object_t* cfg, midi_device_t* dev, unsigned devIdx ) + { + rc_t rc = kOkRC; + const char* refDevLabel = nullptr; + const object_t* tables = nullptr; + unsigned i = 0; + + // get the textual name the device + switch( devIdx ) + { + case kSampler_MRP_DevIdx: refDevLabel="sampler"; break; + case kPiano_MRP_DevIdx: refDevLabel="piano"; break; + } + + // verify that the device has a label + if( refDevLabel == nullptr ) + { + rc = cwLogError(kInvalidStateRC,"The MIDI record-play unit device '%i' does not have a device label.",devIdx); + goto errLabel; + } + + // get the 'tables' node + if((rc = cfg->getv("tables",tables)) != kOkRC ) + { + rc = cwLogError(rc,"The 'tables' field could not be read from the vel. table cfg. object."); + goto errLabel; + } + + // for each table + for(i=0; ichild_count(); ++i) + { + const object_t* tbl = tables->child_ele(i); + const object_t* array = nullptr; + bool enableFl = false; + bool defaultFl = false; + const char* deviceLabel = nullptr; + + // read the table record + if((rc = tbl->getv("table",array, + "enableFl",enableFl, + "defaultFl",defaultFl, + "device",deviceLabel)) != kOkRC ) + { + rc = cwLogError(rc,"Parsing failed on the velocity table at index '%i'.",i); + goto errLabel; + } + + // if this table is enabled and the 'default' for this device + if( enableFl && defaultFl && textCompare(refDevLabel,deviceLabel) == 0 ) + { + // allocate the actual velocity table + dev->velTableN = array->child_count(); + dev->velTableArray = mem::allocZ(dev->velTableN); + + // for each velocity entry + for(unsigned j=0; jvelTableN; ++j) + { + // read the velocity value + unsigned v; + if((rc = array->child_ele(j)->value(v)) != kOkRC ) + { + rc = cwLogError(rc,"Parsing failed on the velocity at index '%i'.",j); + goto errLabel; + } + + // validate the velocity range + if( 0 <= v && v <= 127 ) + dev->velTableArray[j] = (uint8_t)v; + else + { + rc = cwLogError(kInvalidArgRC,"A velocity table entry outside the range 0-127 was encountered at index %i.",j); + goto errLabel; + } + } + + break; + } + } + + // if no enabled and default table was found for this device + if( i >= tables->child_count() ) + { + cwLogError(kInvalidStateRC,"A velocity table was not found for MIDI device index '%i'.",devIdx ); + goto errLabel; + } + + errLabel: + + return rc; + } } } -cw::rc_t cw::midi_record_play::create( handle_t& hRef, io::handle_t ioH, const object_t& cfg, event_callback_t cb, void* cb_arg ) +cw::rc_t cw::midi_record_play::create( handle_t& hRef, + io::handle_t ioH, + const object_t& cfg, + const char* velTableFname, + event_callback_t cb, + void* cb_arg ) { bool asyncFl = true; midi_record_play_t* p = nullptr; rc_t rc; + object_t* velTblCfg = nullptr; if((rc = destroy(hRef)) != kOkRC ) return rc; @@ -1300,10 +1410,19 @@ cw::rc_t cw::midi_record_play::create( handle_t& hRef, io::handle_t ioH, const o p = mem::allocZ(); p->ioH = ioH; // p->ioH is used in _destory() so initialize it here - + + // parse the cfg if((rc = _parseCfg(p,cfg)) != kOkRC ) goto errLabel; + // parse the vel table cfg + if(velTableFname != nullptr ) + if((rc = objectFromFile(velTableFname,velTblCfg)) != kOkRC ) + { + rc = cwLogError(rc,"Parsing the velocity table cfg. failed on '%s'.",cwStringNullGuard(velTableFname)); + goto errLabel; + } + p->cb = cb; p->cb_arg = cb_arg; p->halfPedalState = kHalfPedalDone; @@ -1336,6 +1455,13 @@ cw::rc_t cw::midi_record_play::create( handle_t& hRef, io::handle_t ioH, const o goto errLabel; } + if( velTblCfg != nullptr ) + if((rc = _loadVelTable( p, velTblCfg, dev, i )) != kOkRC ) + { + rc = cwLogError(rc,"MIDI record-play velocity table setup failed."); + goto errLabel; + } + printf("%s %s : %i %i\n",dev->midiOutDevLabel, dev->midiOutPortLabel, dev->midiOutDevIdx, dev->midiOutPortIdx ); } @@ -1353,6 +1479,9 @@ cw::rc_t cw::midi_record_play::create( handle_t& hRef, io::handle_t ioH, const o hRef.set(p); else _destroy(p); + + if(velTblCfg != nullptr ) + velTblCfg->free(); return rc; } diff --git a/cwIoMidiRecordPlay.h b/cwIoMidiRecordPlay.h index e2aa92f..868922a 100644 --- a/cwIoMidiRecordPlay.h +++ b/cwIoMidiRecordPlay.h @@ -24,18 +24,23 @@ namespace cw kPlayerStoppedActionId }; - typedef void (*event_callback_t)( void* arg, unsigned actionId, unsigned id, const time::spec_t timestamp, unsigned loc, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 ); enum { - kPiano_MRP_DevIdx = 1, - kSampler_MRP_DevIdx = 0 + kSampler_MRP_DevIdx = 0, + kPiano_MRP_DevIdx = 1 }; - rc_t create( handle_t& hRef, io::handle_t ioH, const object_t& cfg, event_callback_t cb=nullptr, void* cb_arg=nullptr ); + rc_t create( handle_t& hRef, + io::handle_t ioH, + const object_t& cfg, + const char* velTableFname=nullptr, + event_callback_t cb=nullptr, + void* cb_arg=nullptr ); + rc_t destroy( handle_t& hRef ); // Set rewindFl to play from start, otherwise play from current output location.