From d8e4109baf0f3e082c2deabeb7319d4095141cac Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 26 Oct 2022 08:47:54 -0400 Subject: [PATCH 1/7] cwIoMidiRecordPlay.h/cpp :Added send_midi_msg(). --- cwIoMidiRecordPlay.cpp | 15 +++++++++++++++ cwIoMidiRecordPlay.h | 1 + 2 files changed, 16 insertions(+) diff --git a/cwIoMidiRecordPlay.cpp b/cwIoMidiRecordPlay.cpp index 4816321..917ee23 100644 --- a/cwIoMidiRecordPlay.cpp +++ b/cwIoMidiRecordPlay.cpp @@ -382,6 +382,7 @@ namespace cw return rc; } + 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 ); @@ -1408,6 +1409,20 @@ void cw::midi_record_play::enable_device( handle_t h, unsigned devIdx, bool enab } } +cw::rc_t cw::midi_record_play::send_midi_msg( handle_t h, unsigned devIdx, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 ) +{ + midi_record_play_t* p = _handleToPtr(h); + + if( devIdx >= p->midiDevN ) + return cwLogError(kInvalidArgRC,"The MIDI record-play device index '%i' is invalid.",devIdx ); + + if( p->midiDevA[devIdx].enableFl ) + io::midiDeviceSend( p->ioH, p->midiDevA[devIdx].midiOutDevIdx, p->midiDevA[devIdx].midiOutPortIdx, status + ch, d0, d1 ); + + return kOkRC; +} + + 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); diff --git a/cwIoMidiRecordPlay.h b/cwIoMidiRecordPlay.h index d785384..a6f494d 100644 --- a/cwIoMidiRecordPlay.h +++ b/cwIoMidiRecordPlay.h @@ -63,6 +63,7 @@ namespace cw 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 ); + rc_t send_midi_msg( handle_t h, unsigned devIdx, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 ); void half_pedal_params( handle_t h, unsigned noteDelayMs, unsigned pitch, unsigned vel, unsigned pedal_vel, unsigned noteDurMs, unsigned downDelayMs ); From 714817bfb6a756b5fba589ea30950675c87a51b7 Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 26 Oct 2022 08:49:20 -0400 Subject: [PATCH 2/7] cwIoPresetSelApp.h/cpp : 'flow_proc_dict' is now read from an external file. Added 'live' option to select a preset while streaming live audio. --- cwIoPresetSelApp.cpp | 97 +++++++++++++++++++++++++++++++++++------- cwIoPresetSelApp.h | 2 +- html/preset_sel/ui.cfg | 1 + 3 files changed, 84 insertions(+), 16 deletions(-) diff --git a/cwIoPresetSelApp.cpp b/cwIoPresetSelApp.cpp index 75ccf48..4251eba 100644 --- a/cwIoPresetSelApp.cpp +++ b/cwIoPresetSelApp.cpp @@ -40,6 +40,7 @@ namespace cw kStartBtnId, kStopBtnId, + kLiveCheckId, kPrintMidiCheckId, kPianoMidiCheckId, @@ -105,8 +106,8 @@ namespace cw enum { - kPiano_MRP_DevIdx = 0, - kSampler_MRP_DevIdx = 1 + kPiano_MRP_DevIdx = 1, + kSampler_MRP_DevIdx = 0 }; enum @@ -126,6 +127,7 @@ namespace cw { kPanelDivId, kStartBtnId, "startBtnId" }, { kPanelDivId, kStopBtnId, "stopBtnId" }, + { kPanelDivId, kLiveCheckId, "liveCheckId" }, { kPanelDivId, kPrintMidiCheckId, "printMidiCheckId" }, { kPanelDivId, kPianoMidiCheckId, "pianoMidiCheckId" }, @@ -209,6 +211,7 @@ namespace cw const object_t* midi_play_record_cfg; const object_t* frag_panel_cfg; const object_t* presets_cfg; + object_t* flow_proc_dict; const object_t* flow_cfg; midi_record_play::handle_t mrpH; @@ -249,6 +252,8 @@ namespace cw unsigned seqStartedFl; // set by the first seq idle callback unsigned seqFragId; // unsigned seqPresetIdx; // + + bool useLiveMidiFl; } app_t; @@ -256,6 +261,7 @@ namespace cw rc_t _parseCfg(app_t* app, const object_t* cfg, const object_t*& params_cfgRef ) { rc_t rc = kOkRC; + const char* flow_proc_dict_fn = nullptr; if((rc = cfg->getv( "params", params_cfgRef, "flow", app->flow_cfg)) != kOkRC ) @@ -268,6 +274,7 @@ namespace cw "record_fn", app->record_fn, "record_fn_ext", app->record_fn_ext, "score_fn", app->scoreFn, + "flow_proc_dict_fn",flow_proc_dict_fn, "midi_play_record", app->midi_play_record_cfg, "frag_panel", app->frag_panel_cfg, "presets", app->presets_cfg, @@ -290,6 +297,12 @@ namespace cw rc = cwLogError(kInvalidArgRC,"The record directory path is invalid."); goto errLabel; } + + if((rc = objectFromFile( flow_proc_dict_fn, app->flow_proc_dict )) != kOkRC ) + { + rc = cwLogError(kInvalidArgRC,"The flow proc file '%s' parse failed.",app->flow_proc_dict); + goto errLabel; + } // verify that the output directory exists if((rc = filesys::isDir(app->record_dir)) != kOkRC ) @@ -338,6 +351,9 @@ namespace cw rc_t _free( app_t& app ) { + if( app.flow_proc_dict != nullptr ) + app.flow_proc_dict->free(); + mem::release((char*&)app.record_dir); mem::release((char*&)app.scoreFn); preset_sel::destroy(app.psH); @@ -475,6 +491,46 @@ namespace cw } } + rc_t _on_live_midi( app_t* app, const io::msg_t& msg ) + { + rc_t rc = kOkRC; + + if( msg.u.midi != nullptr ) + { + + const io::midi_msg_t& m = *msg.u.midi; + const midi::packet_t* pkt = m.pkt; + // for each midi msg + for(unsigned j=0; jmsgCnt; ++j) + { + // if this is a sys-ex msg + if( pkt->msgArray == NULL ) + { + cwLogError(kNotImplementedRC,"Sys-ex recording not implemented."); + } + else // this is a triple + { + midi::msg_t* mm = pkt->msgArray + j; + time::spec_t timestamp; + unsigned id = kInvalidId; + unsigned loc = app->beg_play_loc; + + time::get(timestamp); + + if( midi::isChStatus(mm->status) ) + { + if(midi_record_play::send_midi_msg( app->mrpH, kSampler_MRP_DevIdx, mm->status & 0x0f, mm->status & 0xf0, mm->d0, mm->d1 ) == kOkRC ) + _midi_play_callback( app, midi_record_play::kMidiEventActionId, id, timestamp, loc, mm->status & 0x0f, mm->status & 0xf0, mm->d0, mm->d1 ); + } + + } + } + } + + return rc; + } + + // Find the closest locMap equal to or after 'loc' loc_map_t* _find_loc( app_t* app, unsigned loc ) { @@ -542,7 +598,7 @@ namespace cw app->end_play_timestamp = endMap->timestamp; - if( !time::isZero(app->beg_play_timestamp) ) + if( !time::isZero(app->beg_play_timestamp) && !app->useLiveMidiFl ) { // seek the player to the requested loc if((rc = midi_record_play::seek( app->mrpH, app->beg_play_timestamp )) != kOkRC ) @@ -561,17 +617,20 @@ namespace cw } // start the MIDI playback - if((rc = midi_record_play::start(app->mrpH,rewindFl,&app->end_play_timestamp)) != kOkRC ) + if( !app->useLiveMidiFl ) { - rc = cwLogError(rc,"MIDI start failed."); - goto errLabel; - } + if((rc = midi_record_play::start(app->mrpH,rewindFl,&app->end_play_timestamp)) != kOkRC ) + { + rc = cwLogError(rc,"MIDI start failed."); + goto errLabel; + } - if((cur_loc = midi_record_play::event_loc(app->mrpH)) > 0 ) - { - io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kCurMidiEvtCntId), cur_loc ); + if((cur_loc = midi_record_play::event_loc(app->mrpH)) > 0 ) + { + io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kCurMidiEvtCntId), cur_loc ); + } } - + errLabel: return rc; } @@ -1236,6 +1295,7 @@ namespace cw // enable the start/stop buttons io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStartBtnId ), true ); io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStopBtnId ), true ); + io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kLiveCheckId ), true ); // restore the fragment records if( firstLoadFl ) @@ -1570,6 +1630,7 @@ namespace cw // disable start and stop buttons until a score is loaded io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStartBtnId ), false ); io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kStopBtnId ), false ); + io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kLiveCheckId ), false ); io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kSaveBtnId ), false ); const preset_sel::frag_t* f = preset_sel::get_fragment_base( app->psH ); @@ -1628,6 +1689,10 @@ namespace cw _do_stop_play(app); break; + case kLiveCheckId: + app->useLiveMidiFl = m.value->u.b; + break; + case kPrintMidiCheckId: app->printMidiFl = m.value->u.b; break; @@ -1792,7 +1857,7 @@ namespace cw errLabel: return rc; } - + rc_t _onUiEcho(app_t* app, const io::ui_msg_t& m ) { rc_t rc = kOkRC; @@ -1899,7 +1964,7 @@ namespace cw rc_t rc = kOkRC; app_t* app = reinterpret_cast(arg); - if( app->mrpH.isValid() ) + if( app->mrpH.isValid() && !app->useLiveMidiFl ) { midi_record_play::exec( app->mrpH, *m ); if( midi_record_play::is_started(app->mrpH) ) @@ -1928,6 +1993,8 @@ namespace cw break; case io::kMidiTId: + if( app->useLiveMidiFl && app->mrpH.isValid() ) + _on_live_midi( app, *m ); break; case io::kAudioTId: @@ -1959,7 +2026,7 @@ 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 ) { rc_t rc; @@ -1994,7 +2061,7 @@ cw::rc_t cw::preset_sel_app::main( const object_t* cfg, const object_t* flow_pro } // create the IO Flow controller - if(app.flow_cfg==nullptr || flow_proc_dict==nullptr || (rc = io_flow::create(app.ioFlowH,app.ioH,app.crossFadeSrate,app.crossFadeCnt,*flow_proc_dict,*app.flow_cfg)) != kOkRC ) + if(app.flow_cfg==nullptr || app.flow_proc_dict==nullptr || (rc = io_flow::create(app.ioFlowH,app.ioH,app.crossFadeSrate,app.crossFadeCnt,*app.flow_proc_dict,*app.flow_cfg)) != kOkRC ) { rc = cwLogError(rc,"The IO Flow controller create failed."); goto errLabel; diff --git a/cwIoPresetSelApp.h b/cwIoPresetSelApp.h index fac4c92..c0a9f6d 100644 --- a/cwIoPresetSelApp.h +++ b/cwIoPresetSelApp.h @@ -5,7 +5,7 @@ namespace cw { namespace preset_sel_app { - rc_t main( const object_t* cfg, const object_t* flow_proc_dict ); + rc_t main( const object_t* cfg ); } } diff --git a/html/preset_sel/ui.cfg b/html/preset_sel/ui.cfg index f6f588d..d021305 100644 --- a/html/preset_sel/ui.cfg +++ b/html/preset_sel/ui.cfg @@ -34,6 +34,7 @@ button:{ name: stopBtnId, title:"Stop" }, number:{ name: begLocNumbId, title:"Loc:", min:0, max:100000, step:1, decpl:0 }, number:{ name: endLocNumbId, title:"End:", min:0, max:100000, step:1, decpl:0 }, + check: { name: liveCheckId, title:"Live" }, }, row: { From 3b050ab640f7b9d3c84b5349f22f606a1590fd80 Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 11 Nov 2022 11:52:59 -0500 Subject: [PATCH 3/7] cwIoMidiRecordPlay.cpp : Fixed bug where sizeof file read was 0 in _am_file_read() --- cwIoMidiRecordPlay.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cwIoMidiRecordPlay.cpp b/cwIoMidiRecordPlay.cpp index 917ee23..5da0076 100644 --- a/cwIoMidiRecordPlay.cpp +++ b/cwIoMidiRecordPlay.cpp @@ -531,7 +531,7 @@ namespace cw unsigned fileByteN = 0; // count of bytes in the file int version = 0; // version id (always a negative number) bool alloc_fl = false; - bool print_fl = true; + bool print_fl = false; file::handle_t fH; if((rc = file::open(fH,fn,file::kReadFl)) != kOkRC ) @@ -586,6 +586,7 @@ namespace cw } else { + fileByteN = recordN * sizeof(am_midi_msg_t); if((rc = file::read(fH,msgArrayRef,fileByteN)) != kOkRC ) { rc = cwLogError(kReadFailRC,"Data read failed on Audio-MIDI file: '%s'.", fn ); From 79022916fe1b51a0d0969197f2d1e85670fd1a37 Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 11 Nov 2022 13:09:07 -0500 Subject: [PATCH 4/7] cwFlow,cwFlowProc,cwFlowTypes: Changes to support proc's taking a variable count of numbered inputs. --- cwFlow.cpp | 10 ++++-- cwFlowProc.cpp | 94 ++++++++++++++++++++++++++++++++++++++++--------- cwFlowTypes.cpp | 16 +++++++-- cwFlowTypes.h | 5 ++- 4 files changed, 103 insertions(+), 22 deletions(-) diff --git a/cwFlow.cpp b/cwFlow.cpp index fbb19e8..cc689e5 100644 --- a/cwFlow.cpp +++ b/cwFlow.cpp @@ -137,6 +137,7 @@ namespace cw const char* type_str = nullptr; unsigned type_flag = 0; bool srcVarFl = false; + bool srcOptFl = false; var_desc_t* vd = mem::allocZ(); vd->label = var_obj->pair_label(); @@ -158,7 +159,9 @@ namespace cw } // get the variable description - if((rc = vd->cfg->getv_opt("srcFl", srcVarFl,"value",vd->val_cfg)) != kOkRC ) + if((rc = vd->cfg->getv_opt("srcFl", srcVarFl, + "srcOptFl", srcOptFl, + "value",vd->val_cfg)) != kOkRC ) { rc = cwLogError(rc,"Parsing optional fields failed on class:%s variable: '%s'.", cd->label, vd->label ); goto errLabel; @@ -168,9 +171,10 @@ namespace cw vd->type |= type_flag; if( srcVarFl ) - { vd->flags |= kSrcVarFl; - } + + if( srcOptFl ) + vd->flags |= kSrcOptVarFl; vd->link = cd->varDescL; cd->varDescL = vd; diff --git a/cwFlowProc.cpp b/cwFlowProc.cpp index 11257e0..abe42f2 100644 --- a/cwFlowProc.cpp +++ b/cwFlowProc.cpp @@ -564,7 +564,7 @@ namespace cw // print a minutes counter inst->durSmpN += src_abuf->frameN; if( inst->durSmpN % ((unsigned)src_abuf->srate*60) == 0 ) - printf("%5.1f min\n", inst->durSmpN/(src_abuf->srate*60)); + printf("audio file out: %5.1f min\n", inst->durSmpN/(src_abuf->srate*60)); } @@ -982,35 +982,64 @@ namespace cw namespace audio_merge { enum { - kIn0PId, - kIn1PId, kGainPId, kOutPId, + kInBasePId, }; typedef struct { + unsigned srcN; } inst_t; rc_t create( instance_t* ctx ) { rc_t rc = kOkRC; - const abuf_t* abuf0 = nullptr; // - const abuf_t* abuf1 = nullptr; unsigned outChN = 0; - - // get the source audio buffer - if((rc = var_register_and_get(ctx, kAnyChIdx, - kIn0PId,"in0",abuf0, - kIn1PId,"in1",abuf1 )) != kOkRC ) + unsigned frameN = 0; + srate_t srate = 0; + + inst_t* inst = mem::allocZ(); + + ctx->userPtr = inst; + + for(unsigned i=0; 1; ++i) { - goto errLabel; + const abuf_t* abuf = nullptr; // + + char label[32]; + snprintf(label,31,"in%i",i); + label[31] = 0; + + // TODO: allow non-contiguous source labels + + // the source labels must be contiguous + if( !var_has_value( ctx, label, kAnyChIdx ) ) + break; + + // get the source audio buffer + if((rc = var_register_and_get(ctx, kAnyChIdx,kInBasePId+i,label,abuf )) != kOkRC ) + { + goto errLabel; + } + + if( i == 0 ) + { + frameN = abuf->frameN; + srate = abuf->srate; + } + else + { + // TODO: check srate and frameN are same as first src + } + + inst->srcN += 1; + outChN += abuf->chN; + } - assert( abuf0->frameN == abuf1->frameN ); - - outChN = abuf0->chN + abuf1->chN; + //outChN = abuf0->chN + abuf1->chN; // register the gain for(unsigned i=0; israte, outChN, abuf0->frameN ); + rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srate, outChN, frameN ); errLabel: return rc; } rc_t destroy( instance_t* ctx ) - { return kOkRC; } + { + inst_t* inst = (inst_t*)ctx->userPtr; + + mem::release(inst); + + return kOkRC; + } rc_t value( instance_t* ctx, variable_t* var ) { return kOkRC; } @@ -1052,6 +1087,7 @@ namespace cw return outChIdx; } + /* rc_t exec( instance_t* ctx ) { rc_t rc = kOkRC; @@ -1074,6 +1110,31 @@ namespace cw assert( oChIdx == obuf->chN ); + errLabel: + return rc; + } + */ + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + abuf_t* obuf = nullptr; + unsigned oChIdx = 0; + + if((rc = var_get(ctx,kOutPId, kAnyChIdx, obuf)) != kOkRC ) + goto errLabel; + + for(unsigned i=0; isrcN; ++i) + { + const abuf_t* ibuf = nullptr; + + if((rc = var_get(ctx,kInBasePId+i, kAnyChIdx, ibuf )) != kOkRC ) + goto errLabel; + + oChIdx = _exec( ctx, ibuf, obuf, oChIdx ); + } + errLabel: return rc; } @@ -1087,6 +1148,7 @@ namespace cw }; } + //------------------------------------------------------------------------------------------------------------------ // diff --git a/cwFlowTypes.cpp b/cwFlowTypes.cpp index 824b72b..75a6615 100644 --- a/cwFlowTypes.cpp +++ b/cwFlowTypes.cpp @@ -1013,9 +1013,10 @@ void cw::flow::class_dict_print( flow_t* p ) for(; vd!=nullptr; vd=vd->link) { - const char* srcFlStr = vd->flags&kSrcVarFl ? "src" : " "; + const char* srcFlStr = vd->flags & kSrcVarFl ? "src" : " "; + const char* srcOptFlStr = vd->flags & kSrcOptVarFl ? "srcOpt" : " "; - printf(" %10s 0x%08x %s %s\n", cwStringNullGuard(vd->label), vd->type, srcFlStr, cwStringNullGuard(vd->docText) ); + printf(" %10s 0x%08x %s %s %s\n", cwStringNullGuard(vd->label), vd->type, srcFlStr, srcOptFlStr, cwStringNullGuard(vd->docText) ); } } } @@ -1162,6 +1163,17 @@ cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, uns bool cw::flow::var_exists( instance_t* inst, const char* label, unsigned chIdx ) { return _var_find_on_label_and_ch(inst,label,chIdx) != nullptr; } +bool cw::flow::var_has_value( instance_t* inst, const char* label, unsigned chIdx ) +{ + variable_t* varPtr = nullptr; + rc_t rc; + + if((rc = var_find( inst, label, chIdx, varPtr )) != kOkRC ) + return false; + + return varPtr->value != nullptr; +} + cw::rc_t cw::flow::var_find( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef ) { diff --git a/cwFlowTypes.h b/cwFlowTypes.h index 3c98112..7d524b8 100644 --- a/cwFlowTypes.h +++ b/cwFlowTypes.h @@ -115,7 +115,9 @@ namespace cw typedef rc_t (*member_value_func_t)( struct instance_str* ctx, struct variable_str* var ); enum { - kSrcVarFl = 0x01 + kSrcVarFl = 0x01, + kSrcOptVarFl = 0x02 + }; typedef struct class_members_str @@ -397,6 +399,7 @@ namespace cw void _var_destroy( variable_t* var ); bool var_exists( instance_t* inst, const char* label, unsigned chIdx ); + bool var_has_value( instance_t* inst, const char* label, unsigned chIdx ); rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, const variable_t*& varRef ); rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, variable_t*& varRef ); From 39a7c1d5d8dec2b183d3997c4f88bd0c59231b1b Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 11 Nov 2022 13:11:44 -0500 Subject: [PATCH 5/7] cwIoPresetSelApp.cpp: Updates to support reading and applying beg/endPlayLoc from the .cfg file --- cwIoPresetSelApp.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/cwIoPresetSelApp.cpp b/cwIoPresetSelApp.cpp index 4251eba..37e47de 100644 --- a/cwIoPresetSelApp.cpp +++ b/cwIoPresetSelApp.cpp @@ -610,7 +610,7 @@ namespace cw } // apply the preset which is active at the start time - if((rc = _apply_preset( app, app->beg_play_timestamp, app->beg_play_loc )) != kOkRC ) + if((rc = _apply_preset( app, app->beg_play_timestamp, begMap->loc )) != kOkRC ) { rc = cwLogError(rc,"Preset application failed prior to MIDI start."); goto errLabel; @@ -1270,19 +1270,21 @@ namespace cw // set the range of the global play location controls if( firstLoadFl ) { - unsigned minLocUuId = io::uiFindElementUuId(app->ioH, kBegPlayLocNumbId); - unsigned maxLocUuId = io::uiFindElementUuId(app->ioH, kEndPlayLocNumbId); - //unsigned end_loc = app->end_play_loc==0 ? app->maxLoc : app->end_play_loc; - //unsigned beg_loc = app->minLoc <= app->beg_play_loc && app->beg_play_loc <= app->maxLoc ? app->beg_play_loc : app->minLoc; + unsigned begPlayLocUuId = io::uiFindElementUuId(app->ioH, kBegPlayLocNumbId); + unsigned endPlayLocUuId = io::uiFindElementUuId(app->ioH, kEndPlayLocNumbId); - io::uiSetNumbRange( app->ioH, minLocUuId, app->minLoc, app->maxLoc, 1, 0, app->minLoc ); - io::uiSetNumbRange( app->ioH, maxLocUuId, app->minLoc, app->maxLoc, 1, 0, app->maxLoc ); + unsigned end_play_loc = app->end_play_loc==0 ? app->maxLoc : app->end_play_loc; + unsigned beg_play_loc = app->minLoc <= app->beg_play_loc && app->beg_play_loc <= app->maxLoc ? app->beg_play_loc : app->minLoc; + + io::uiSetNumbRange( app->ioH, begPlayLocUuId, app->minLoc, app->maxLoc, 1, 0, app->minLoc ); + io::uiSetNumbRange( app->ioH, endPlayLocUuId, app->minLoc, app->maxLoc, 1, 0, app->maxLoc ); - //io::uiSendValue( app->ioH, minLocUuId, std::max(beg_loc,app->minLoc)); - //io::uiSendValue( app->ioH, maxLocUuId, std::min(end_loc,app->maxLoc)); + //io::uiSendValue( app->ioH, begPlayLocUuId, app->minLoc); + //io::uiSendValue( app->ioH, endPlayLocUuId, app->maxLoc); - io::uiSendValue( app->ioH, minLocUuId, app->minLoc); - io::uiSendValue( app->ioH, maxLocUuId, app->maxLoc); + + io::uiSendValue( app->ioH, begPlayLocUuId, beg_play_loc); + io::uiSendValue( app->ioH, endPlayLocUuId, end_play_loc); // enable the 'End Loc' number box since the score is loaded From c94556d4a1c3c16d8fc6e9ba4a59944ecb7bd442 Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 11 Nov 2022 13:13:35 -0500 Subject: [PATCH 6/7] cwCmInterface,cwScoreFollower : Initial commit. Not yet included in build. --- Makefile.am | 7 ++- cwCmInterface.cpp | 110 +++++++++++++++++++++++++++++++++++++ cwCmInterface.h | 19 +++++++ cwScoreFollower.cpp | 130 ++++++++++++++++++++++++++++++++++++++++++++ cwScoreFollower.h | 21 +++++++ 5 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 cwCmInterface.cpp create mode 100644 cwCmInterface.h create mode 100644 cwScoreFollower.cpp create mode 100644 cwScoreFollower.h diff --git a/Makefile.am b/Makefile.am index f801fad..169b209 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,8 +64,11 @@ libcwSRC += src/libcw/cwIo.cpp src/libcw/cwIoTest.cpp src/libcw/cwIoMinTest.cp libcwHDR += src/libcw/cwIoMidiRecordPlay.h src/libcw/cwIoAudioRecordPlay.h src/libcw/cwIoAudioMidiApp.h src/libcw/cwIoFlow.h libcwSRC += src/libcw/cwIoMidiRecordPlay.cpp src/libcw/cwIoAudioRecordPlay.cpp src/libcw/cwIoAudioMidiApp.cpp src/libcw/cwIoFlow.cpp -libcwHDR += src/libcw/cwIoPresetSelApp.h src/libcw/cwPianoScore.h src/libcw/cwPresetSel.h -libcwSRC += src/libcw/cwIoPresetSelApp.cpp src/libcw/cwPianoScore.cpp src/libcw/cwPresetSel.cpp +libcwHDR += src/libcw/cwIoPresetSelApp.h src/libcw/cwPianoScore.h src/libcw/cwPresetSel.h +libcwSRC += src/libcw/cwIoPresetSelApp.cpp src/libcw/cwPianoScore.cpp src/libcw/cwPresetSel.cpp + +# libcwHDR += src/libcw/cwCmInterface.h src/libcw/cwScoreFollower.h +# libcwSRC += src/libcw/cwCmInterface.cpp src/libcw/cwScoreFollower.cpp endif diff --git a/cwCmInterface.cpp b/cwCmInterface.cpp new file mode 100644 index 0000000..9830499 --- /dev/null +++ b/cwCmInterface.cpp @@ -0,0 +1,110 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwCmInterface.h" + +#include "cmGlobal.h" +#include "cmFloatTypes.h" +#include "cmRpt.h" +#include "cmErr.h" +#include "cmCtx.h" +#include "cmMem.h" +#include "cmMallocDebug.h" +#include "cmLinkedHeap.h" +#include "cmTime.h" +#include "cmMidi.h" +#include "cmSymTbl.h" +#include "cmScore.h" +#include "cmText.h" +#include "cmFileSys.h" + +extern "C" { + void _cm_print_info( void* arg, const char* text ) + { + cwLogInfo(text); + } + + void _cm_print_error( void* arg, const char* text ) + { + cwLogError(cw::kOpFailRC,text); + } +} + +namespace cw +{ + namespace cm + { + typedef struct cm_str + { + ::cmCtx_t ctx; + } cm_t; + + cm_t* _handleToPtr( handle_t h ) + { return handleToPtr(h); } + + rc_t _destroy( cm_t* p ) + { + if( p != nullptr ) + { + cmTsFinalize(); + cmFsFinalize(); + cmMdReport( kIgnoreNormalMmFl ); + cmMdFinalize(); + + mem::release(p); + } + return kOkRC; + } + } +} + +cw::rc_t cw::cm::create( handle_t& hRef ) +{ + rc_t rc = kOkRC; + cm_t* p = nullptr; + bool memDebugFl = 0; //cmDEBUG_FL; + unsigned memGuardByteCnt = memDebugFl ? 8 : 0; + unsigned memAlignByteCnt = 16; + unsigned memFlags = memDebugFl ? kTrackMmFl | kDeferFreeMmFl | kFillUninitMmFl : 0; + const cmChar_t* appTitle = "cwtest"; + + if((rc = destroy(hRef)) != kOkRC ) + return rc; + + p = mem::allocZ(); + + cmCtxSetup(&p->ctx,appTitle,_cm_print_info,_cm_print_error,NULL,memGuardByteCnt,memAlignByteCnt,memFlags); + + cmMdInitialize( memGuardByteCnt, memAlignByteCnt, memFlags, &p->ctx.rpt ); + + cmFsInitialize( &p->ctx, appTitle); + + cmTsInitialize( &p->ctx ); + + return rc; +} + +cw::rc_t cw::cm::destroy( handle_t& hRef ) +{ + rc_t rc = kOkRC; + cm_t* p = nullptr; + if( !hRef.isValid() ) + return rc; + + p = _handleToPtr(hRef); + + if((rc = _destroy(p)) != kOkRC ) + return rc; + + hRef.clear(); + return rc; + +} + +::cmCtx_t* cw::cm::context( handle_t h ) +{ + cm_t* p = _handleToPtr(h); + return &p->ctx; +} + diff --git a/cwCmInterface.h b/cwCmInterface.h new file mode 100644 index 0000000..557eac5 --- /dev/null +++ b/cwCmInterface.h @@ -0,0 +1,19 @@ +#ifndef cwCmInterface_h +#define cwCmInterface_h + +namespace cw +{ + namespace cm { + + extern "C" { struct cmCtx_str; } + + typedef handle< struct cm_str > handle_t; + + rc_t create( handle_t& hRef ); + rc_t destroy( handle_t& hRef ); + ::cmCtx_t* context( handle_t h ); + } +} + + +#endif diff --git a/cwScoreFollower.cpp b/cwScoreFollower.cpp new file mode 100644 index 0000000..92e4caa --- /dev/null +++ b/cwScoreFollower.cpp @@ -0,0 +1,130 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwText.h" +#include "cwObject.h" +#include "cwMidi.h" +#include "cwScoreFollower.h" + +#include "cmGlobal.h" +#include "cmFloatTypes.h" +#include "cmRpt.h" +#include "cmErr.h" +#include "cmCtx.h" +#include "cmTime.h" +#include "cmMidi.h" +#include "cmSymTbl.h" +#include "cmScore.h" + +namespace cw +{ + namespace score_follower + { + + typedef struct score_follower_str + { + unsigned search_area_locN; + unsigned key_wnd_locN; + char* score_csv_fname; + + + } score_follower_t; + + score_follower_t* _handleToPtr( handle_t h ) + { return handleToPtr(h); } + + + rc_t _parse_cfg( score_follower_t* p, const object_t* cfg ) + { + rc_t rc = kOkRC; + + const char* score_csv_fname; + + if((rc = cfg->getv("score_csv_fname", score_csv_fname, + "search_area_locN", p->search_area_locN, + "key_wnd_locN", p->key_wnd_locN )) != kOkRC ) + { + rc = cwLogError(kInvalidArgRC, "Score follower argument parsing failed."); + goto errLabel; + } + + if((app->score_csv_fname = filesys::expandPath( score_csv_fname )) == nullptr ) + { + rc = cwLogError(kOpFailRC,"Score follower score file expansion failed."); + goto errLabel; + } + + errLabel: + return rc; + } + + rc_t _destroy( score_follower_t* p) + { + mem::release(p->score_csv_fname); + mem::release(p); + return kOkRC; + } + } +} + +cw::rc_t cw::score_follower::create( handle_t& hRef, const object_t* cfg, double srate ) +{ + rc_t rc = kOkRC; + score_follower_t* p = nullptr; + + if((rc = destroy(hRef)) != kOkRC ) + return rc; + + p = mem::allocZ(); + + if((rc = _parse_cfg(p,cfg)) != kOkRC ) + goto errLabel; + + cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, double srate, const unsigned* dynRefArray, unsigned dynRefCnt, cmScCb_t cbFunc, void* cbArg, cmSymTblH_t stH ); + + //cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN, cmScMatcherCb_t cbFunc, void* cbArg ); + + + + hRef.set(p); + + errLabel: + if( rc != kOkRC ) + { + _destroy(p); + cwLogError(rc,"Score follower create failed."); + } + + return rc; +} + +cw::rc_t cw::score_follower::destroy( handle_t& hRef ) +{ + rc_t rc = kOkRC; + score_follower_t* p = nullptr; + + if( !hRef.isValid() ) + return rc; + + p = _handleToPtr(hRef); + + if((rc = _destroy(p)) != kOkRC ) + return rc; + + hRef.clear(); + return rc; +} + +cw::rc_t cw::score_follower::reset( handle_t h, unsigned loc ) +{ + rc_t rc = kOkRC; + return rc; +} + +cw::rc_t cw::score_follower::exec( handle_t h, unsigned smpIdx, unsigned muid, unsigned status, uint8_t d0, uint8_t d1, unsigned* scLocIdxPtr ) +{ + rc_t rc = kOkRC; + return rc; + +} diff --git a/cwScoreFollower.h b/cwScoreFollower.h new file mode 100644 index 0000000..a32d635 --- /dev/null +++ b/cwScoreFollower.h @@ -0,0 +1,21 @@ +#ifndef cwScoreFollower_h +#define cwScoreFollower_h + +namespace cw +{ + namespace score_follower + { + typedef handle< struct score_follower_str > handle_t; + + rc_t create( handle_t& hRef, const object_t* cfg, double srate ); + + rc_t destroy( handle_t& hRef ); + + rc_t reset( handle_t h, unsigned loc ); + + rc_t exec( handle_t h, unsigned smpIdx, unsigned muid, unsigned status, uint8_t d0, uint8_t d1, unsigned* scLocIdxPtr ); + } +} + + +#endif From c1a0e7708b0871f296c8e089a58ec0bd59a5c0ee Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 11 Nov 2022 13:15:35 -0500 Subject: [PATCH 7/7] cwMidiAlsa.cpp : Added TODO comments. --- cwMidiAlsa.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cwMidiAlsa.cpp b/cwMidiAlsa.cpp index 18e8ef7..3ed87e6 100644 --- a/cwMidiAlsa.cpp +++ b/cwMidiAlsa.cpp @@ -134,12 +134,18 @@ namespace cw // if no input if( rc == -EAGAIN ) + { + // TODO: report or at least count error break; - + } + // if input buffer overrun if( rc == -ENOSPC ) + { + // TODO: report or at least count error break; - + } + // get the device this event arrived from if( p->prvRcvDev==NULL || p->prvRcvDev->clientId != ev->source.client ) p->prvRcvDev = _cmMpClientIdToDev(p,ev->source.client); @@ -150,7 +156,7 @@ namespace cw if( p->prvRcvDev == NULL || p->prvRcvPort == NULL ) continue; - + //printf("%i %x\n",ev->type,ev->type); //printf("dev:%i port:%i ch:%i %i\n",ev->source.client,ev->source.port,ev->data.note.channel,ev->data.note.note);