#include "cwCommon.h" #include "cwLog.h" #include "cwCommonImpl.h" #include "cwMem.h" #include "cwObject.h" #include "cwText.h" #include "cwFileSys.h" #include "cwFile.h" #include "cwTime.h" #include "cwMidiDecls.h" #include "cwMidi.h" #include "cwUiDecls.h" #include "cwIo.h" #include "cwIoMidiRecordPlay.h" #include "cwIoPresetSelApp.h" #include "cwPianoScore.h" #include "cwIoFlow.h" #include "cwPresetSel.h" namespace cw { namespace preset_sel_app { // Application Id's for UI elements enum { // Resource Based elements kPanelDivId = 1000, kQuitBtnId, kIoReportBtnId, kReportBtnId, kStartBtnId, kStopBtnId, kMidiThruCheckId, kCurMidiEvtCntId, kTotalMidiEvtCntId, kCurAudioSecsId, kTotalAudioSecsId, kSaveBtnId, kLoadBtnId, kFnStringId, kBegPlayLocNumbId, kEndPlayLocNumbId, kInsertLocId, kInsertBtnId, kDeleteBtnId, kFragListId, kFragPanelId, kFragEndLocId, kFragPresetRowId, kFragPresetSelId, kFragPresetOrderId, kFragGainId, kFragWetDryGainId, kFragFadeOutMsId }; enum { kAmMidiTimerId }; // Application Id's for the resource based UI elements. ui::appIdMap_t mapA[] = { { ui::kRootAppId, kPanelDivId, "panelDivId" }, { kPanelDivId, kQuitBtnId, "quitBtnId" }, { kPanelDivId, kIoReportBtnId, "ioReportBtnId" }, { kPanelDivId, kReportBtnId, "reportBtnId" }, { kPanelDivId, kStartBtnId, "startBtnId" }, { kPanelDivId, kStopBtnId, "stopBtnId" }, { kPanelDivId, kMidiThruCheckId, "midiThruCheckId" }, { kPanelDivId, kCurMidiEvtCntId, "curMidiEvtCntId" }, { kPanelDivId, kTotalMidiEvtCntId, "totalMidiEvtCntId" }, { kPanelDivId, kCurAudioSecsId, "curAudioSecsId" }, { kPanelDivId, kTotalAudioSecsId, "totalAudioSecsId" }, { kPanelDivId, kSaveBtnId, "saveBtnId" }, { kPanelDivId, kLoadBtnId, "loadBtnId" }, { kPanelDivId, kFnStringId, "filenameId" }, { kPanelDivId, kBegPlayLocNumbId, "begLocNumbId" }, { kPanelDivId, kEndPlayLocNumbId, "endLocNumbId" }, { kPanelDivId, kInsertLocId, "insertLocId" }, { kPanelDivId, kInsertBtnId, "insertBtnId" }, { kPanelDivId, kDeleteBtnId, "deleteBtnId" }, { kPanelDivId, kFragListId, "fragListId" }, { kFragListId, kFragPanelId, "fragPanelId"}, { kFragPanelId, kFragEndLocId, "fragEndLocId" }, { kFragPanelId, kFragPresetRowId, "fragPresetRowId" }, { kFragPanelId, kFragGainId, "fragGainId" }, { kFragPanelId, kFragWetDryGainId, "fragWetDryGainId" }, { kFragPanelId, kFragFadeOutMsId, "fragFadeOutMsId" } }; unsigned mapN = sizeof(mapA)/sizeof(mapA[0]); typedef struct loc_map_str { unsigned loc; time::spec_t timestamp; } loc_map_t; typedef struct ui_blob_str { unsigned fragId; unsigned varId; unsigned presetId; } ui_blob_t; typedef struct app_str { io::handle_t ioH; const char* record_dir; const char* record_fn; const char* record_fn_ext; char* directory; const char* scoreFn; const object_t* frag_panel_cfg; const object_t* presets_cfg; const object_t* flow_cfg; midi_record_play::handle_t mrpH; score::handle_t scoreH; loc_map_t* locMap; unsigned locMapN; unsigned insertLoc; // last valid insert location id received from the GUI time::spec_t beg_play_timestamp; time::spec_t end_play_timestamp; preset_sel::handle_t psH; io_flow::handle_t ioFlowH; unsigned tmp; double crossFadeSrate; unsigned crossFadeCnt; } app_t; rc_t _parseCfg(app_t* app, const object_t* cfg, const object_t*& params_cfgRef ) { rc_t rc = kOkRC; if((rc = cfg->getv( "params", params_cfgRef, "flow", app->flow_cfg)) != kOkRC ) { rc = cwLogError(kSyntaxErrorRC,"Preset Select App 'params' cfg record not found."); goto errLabel; } if((rc = params_cfgRef->getv( "record_dir", app->record_dir, "record_fn", app->record_fn, "record_fn_ext", app->record_fn_ext, "score_fn", app->scoreFn, "frag_panel", app->frag_panel_cfg, "presets", app->presets_cfg, "crossFadeSrate",app->crossFadeSrate, "crossFadeCount",app->crossFadeCnt)) != kOkRC ) { rc = cwLogError(kSyntaxErrorRC,"Preset Select App configuration parse failed."); } // verify that the output directory exists if((rc = filesys::isDir(app->record_dir)) != kOkRC ) if((rc = filesys::makeDir(app->record_dir)) != kOkRC ) rc = cwLogError(rc,"Unable to create the base output directory:%s.",cwStringNullGuard(app->record_dir)); app->insertLoc = kInvalidId; // initialize 'insertLoc' to be invalid errLabel: return rc; } rc_t _free( app_t& app ) { preset_sel::destroy(app.psH); io_flow::destroy(app.ioFlowH); mem::release(app.locMap); mem::release(app.directory); return kOkRC; } rc_t _apply_preset( app_t* app, const time::spec_t& ts, const preset_sel::frag_t* frag=nullptr ) { if( frag == nullptr ) preset_sel::track_timestamp( app->psH, ts, frag); if( frag == nullptr ) cwLogInfo("No preset fragment was found for the requested timestamp."); else { unsigned preset_idx = fragment_play_preset_index(frag); const char* preset_label = preset_sel::preset_label(app->psH,preset_idx); printf("Apply preset: '%s'.\n", preset_idx==kInvalidIdx ? "" : preset_label); if( preset_label != nullptr ) io_flow::apply_preset( app->ioFlowH, frag->fadeOutMs, preset_label ); } return kOkRC; } 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; if( id != kInvalidId ) { const unsigned buf_byte_cnt = 256; char buf[ buf_byte_cnt ]; event_to_string( app->scoreH, id, buf, buf_byte_cnt ); printf("%s\n",buf); const preset_sel::frag_t* f = nullptr; if( preset_sel::track_timestamp( app->psH, timestamp, f ) ) { printf("NEW FRAG: id:%i loc:%i\n", f->fragId, f->endLoc ); _apply_preset( app, timestamp, f ); } } } void _update_event_ui( app_t* app ) { io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kCurMidiEvtCntId), midi_record_play::event_index(app->mrpH) ); io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kTotalMidiEvtCntId), midi_record_play::event_count(app->mrpH) ); } // Update the UI with the value from the the fragment data record. template< typename T > rc_t _update_frag_ui( app_t* app, unsigned fragId, unsigned psVarId, unsigned psPresetId, unsigned uiParentUuId, unsigned uiVarAppId, unsigned uiChanId, T& valRef ) { rc_t rc = kOkRC; unsigned uuid = kInvalidId; // Get the value from the data record if((rc = preset_sel::get_value( app->psH, fragId, psVarId, psPresetId, valRef )) != kOkRC ) { rc = cwLogError(rc,"Unable to locate the preset value for var:5i preset:%i.",psVarId,psPresetId); goto errLabel; } // Get the UI uuId if(( uuid = io::uiFindElementUuId( app->ioH, uiParentUuId, uiVarAppId, uiChanId )) == kInvalidId ) { rc = cwLogError(rc,"Unable to locate the UI uuid for appid:%i chanId:%i.", uiVarAppId, uiChanId ); goto errLabel; } // Send the value to the UI if((rc = io::uiSendValue( app->ioH, uuid, valRef )) != kOkRC ) { rc = cwLogError(rc,"Transmission of fragment value failed."); goto errLabel; } errLabel: return rc; } // Get the endLoc associated with this fragment id rc_t _frag_id_to_endloc( app_t* app, unsigned fragId, unsigned& endLocRef ) { rc_t rc = kOkRC; endLocRef = kInvalidId; if((rc = get_value( app->psH, fragId, preset_sel::kEndLocVarId, kInvalidId, endLocRef )) != kOkRC ) rc = cwLogError(rc,"Unable to get the 'end loc' value for fragment id:%i.",fragId); return rc; } // Update the preset select check boxes on a fragment panel rc_t _update_frag_select_flags( app_t* app, unsigned fragId, unsigned fragEndLoc=kInvalidId ) { rc_t rc = kOkRC; // if if( fragEndLoc == kInvalidId ) { // get the endLoc associated with this fragment rc = _frag_id_to_endloc(app, fragId, fragEndLoc ); } if( rc == kOkRC ) { bool bValue; unsigned uValue; // The uiChan is the fragment endLoc unsigned uiChanId = fragEndLoc; // The fragPanelUUid is the same as the fragId unsigned fragPanelUuId = fragId; // uuid of the frag preset row unsigned fragPresetRowUuId = io::uiFindElementUuId( app->ioH, fragPanelUuId, kFragPresetRowId, uiChanId ); // Update each fragment preset control UI by getting it's current value from the fragment data record for(unsigned preset_idx=0; preset_idxpsH); ++preset_idx) { _update_frag_ui( app, fragId, preset_sel::kPresetSelectVarId, preset_idx, fragPresetRowUuId, kFragPresetSelId, preset_idx, bValue ); _update_frag_ui( app, fragId, preset_sel::kPresetOrderVarId, preset_idx, fragPresetRowUuId, kFragPresetOrderId, preset_idx, uValue ); } } return rc; } // Update the fragment UI withh the fragment record associated with 'fragId' rc_t _update_frag_ui(app_t* app, unsigned fragId ) { // Notes: fragId == fragPanelUuId // uiChanId = endLoc for panel values // or uiChanId = preset_index for preset values rc_t rc = kOkRC; unsigned endLoc; // get the endLoc for this fragment if((rc = _frag_id_to_endloc(app, fragId, endLoc )) == kOkRC ) { unsigned uValue; double dValue; unsigned uiChanId = endLoc; unsigned fragPanelUuId = fragId; _update_frag_ui( app, fragId, preset_sel::kEndLocVarId, kInvalidId, fragPanelUuId, kFragEndLocId, uiChanId, uValue ); _update_frag_ui( app, fragId, preset_sel::kGainVarId, kInvalidId, fragPanelUuId, kFragGainId, uiChanId, dValue ); _update_frag_ui( app, fragId, preset_sel::kFadeOutMsVarId, kInvalidId, fragPanelUuId, kFragFadeOutMsId, uiChanId, dValue ); _update_frag_ui( app, fragId, preset_sel::kWetGainVarId, kInvalidId, fragPanelUuId, kFragWetDryGainId, uiChanId, dValue ); _update_frag_select_flags( app, fragId, endLoc ); } return rc; } // Called when a UI value is changed in a fragment panel (e.g. gain, fadeMs, ...) template< typename T> rc_t _on_ui_frag_value( app_t* app, unsigned uuId, const T& value ) { rc_t rc = kOkRC; unsigned blobByteN = 0; ui_blob_t* blob = nullptr; if(( blob = (ui_blob_t*)io::uiGetBlob( app->ioH, uuId, blobByteN )) == nullptr || blobByteN != sizeof(ui_blob_t) ) return cwLogError(kInvalidStateRC,"A fragment UI blob was missing or corrupt."); rc = preset_sel::set_value( app->psH, blob->fragId, blob->varId, blob->presetId, value ); if( rc != kOkRC ) { // TODO: Set the error indicator on the GUI } else { // TODO: Clear the error indicator on the GUI } // if( blob->varId == preset_sel::kPresetSelectVarId ) _update_frag_select_flags( app, blob->fragId); return rc; } rc_t _frag_set_ui_blob( app_t* app, unsigned uuId, unsigned fragId, unsigned varId, unsigned presetId ) { ui_blob_t blob = { .fragId=fragId, .varId=varId, .presetId=presetId }; return io::uiSetBlob( app->ioH, uuId, &blob, sizeof(blob) ); } rc_t _create_frag_preset_ctl( app_t* app, unsigned fragId, unsigned fragPresetRowUuId, unsigned presetN, unsigned preset_idx ) { rc_t rc = kOkRC; unsigned colUuId = kInvalidId; unsigned uuId = kInvalidId; const char* nullEleName = nullptr; const char* nullClass = nullptr; unsigned invalidAppId = kInvalidId; unsigned chanId = preset_idx; // chanId is the preset id const char* presetLabel = preset_sel::preset_label( app->psH, preset_idx ); assert( presetLabel != nullptr ); // preset control column container if((rc = io::uiCreateDiv( app->ioH, colUuId, fragPresetRowUuId, nullEleName, invalidAppId, chanId, "col fragPresetCtl", nullptr )) != kOkRC ) goto errLabel; // preset select check if((rc = io::uiCreateCheck( app->ioH, uuId, colUuId, nullEleName, kFragPresetSelId, chanId, nullClass, presetLabel )) != kOkRC ) goto errLabel; // store a connection for the select control back to the fragment record _frag_set_ui_blob(app, uuId, fragId, preset_sel::kPresetSelectVarId, preset_idx ); // preset order number if((rc = io::uiCreateNumb( app->ioH, uuId, colUuId, nullEleName, kFragPresetOrderId, chanId, nullClass, nullptr, 0, presetN, 1, 0 )) != kOkRC ) goto errLabel; // store a connection for the select control back to the fragment record _frag_set_ui_blob(app, uuId, fragId, preset_sel::kPresetOrderVarId, preset_idx ); errLabel: if(rc != kOkRC ) rc = cwLogError(rc,"Preset control index '%i' create failed."); return rc; } rc_t _create_frag_ui( app_t* app, unsigned endLoc, unsigned& fragIdRef ) { rc_t rc = kOkRC; unsigned fragListUuId = io::uiFindElementUuId( app->ioH, kFragListId ); unsigned fragChanId = endLoc; // use the frag. endLoc as the channel id unsigned fragPanelUuId = kInvalidId; unsigned fragEndLocUuId = kInvalidId; unsigned fragPresetRowUuId = kInvalidId; unsigned presetN = preset_sel::preset_count( app->psH ); // create the UI object if((rc = io::uiCreateFromObject( app->ioH, app->frag_panel_cfg, fragListUuId, fragChanId )) != kOkRC ) { rc = cwLogError(rc,"The fragments UI object creation failed."); goto errLabel; } // get the uuid's of the new fragment panel and the endloc number display fragPanelUuId = io::uiFindElementUuId( app->ioH, fragListUuId, kFragPanelId, fragChanId ); fragEndLocUuId = io::uiFindElementUuId( app->ioH, fragPanelUuId, kFragEndLocId, fragChanId ); fragPresetRowUuId = io::uiFindElementUuId( app->ioH, fragPanelUuId, kFragPresetRowId, fragChanId ); assert( fragPanelUuId != kInvalidId ); assert( fragEndLocUuId != kInvalidId ); assert( fragPresetRowUuId != kInvalidId ); // Make the fragment panel clickable io::uiSetClickable( app->ioH, fragPanelUuId); // Set the fragment panel order io::uiSetOrderKey( app->ioH, fragPanelUuId, endLoc ); // The fragment id is the same as the frag panel UUId fragIdRef = fragPanelUuId; // Attach blobs to the UI to allow convenient access back to the prese_sel data record _frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragGainId, fragChanId), fragIdRef, preset_sel::kGainVarId, kInvalidId ); _frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragWetDryGainId, fragChanId), fragIdRef, preset_sel::kWetGainVarId, kInvalidId ); _frag_set_ui_blob(app, io::uiFindElementUuId(app->ioH, fragPanelUuId, kFragFadeOutMsId, fragChanId), fragIdRef, preset_sel::kFadeOutMsVarId, kInvalidId ); // create each of the preset controls for(unsigned preset_idx=0; preset_idxrecord_dir, app->record_fn, app->record_fn_ext, NULL)) == nullptr ) { rc = cwLogError(kOpFailRC,"The preset select filename could not formed."); goto errLabel; } if( !filesys::isFile(fn) ) { cwLogInfo("The preset selection data file: '%s' does not exist.",cwStringNullGuard(fn)); goto errLabel; } // read the preset data file if((rc = preset_sel::read( app->psH, fn)) != kOkRC ) { rc = cwLogError(rc,"File write failed on preset select."); goto errLabel; } preset_sel::report( app->psH ); f = preset_sel::get_fragment_base(app->psH); for(; f!=nullptr; f=f->link) { unsigned fragId = kInvalidId; if((rc = _create_frag_ui(app, f->endLoc, fragId )) != kOkRC ) { cwLogError(rc,"Frag UI create failed."); goto errLabel; } // update the fragment id // TODO: // BUG BUG BUG: there is nothing to prevent the new fragment id from conflicting with the existing fragment id's // The correct way to handle this is to reset all the fragment id's in a single operation after the UI is created preset_sel::set_value(app->psH, f->fragId, preset_sel::kFragIdVarId, kInvalidId, fragId ); _update_frag_ui(app, fragId ); } errLabel: mem::release(fn); return rc; } rc_t _on_ui_save( app_t* app ) { rc_t rc = kOkRC; char* fn = nullptr; // form the output file name if((fn = filesys::makeFn(app->record_dir, app->record_fn, app->record_fn_ext, NULL)) == nullptr ) { rc = cwLogError(kOpFailRC,"The preset select filename could not formed."); goto errLabel; } // write the preset data file if((rc = preset_sel::write( app->psH, fn)) != kOkRC ) { rc = cwLogError(rc,"File write failed on preset select."); goto errLabel; } errLabel: mem::release(fn); return rc; } rc_t _on_ui_load( app_t* app ) { rc_t rc = kOkRC; const score::event_t* e = nullptr; unsigned midiEventN = 0; midi_record_play::midi_msg_t* m = nullptr; printf("Loading\n"); // create the score if((rc = score::create( app->scoreH, app->scoreFn )) != kOkRC ) { cwLogError(rc,"Score create failed on '%s'.",app->scoreFn); goto errLabel; } // get the count of MIDI events if((e = score::base_event( app->scoreH )) != nullptr ) for(; e!=nullptr; e=e->link) if( e->status != 0 ) midiEventN += 1; // copy the MIDI events if((e = score::base_event( app->scoreH )) != nullptr ) { // allocate the locMap[] mem::free(app->locMap); app->locMap = mem::allocZ( midiEventN ); app->locMapN = midiEventN; // allocate the the player msg array m = mem::allocZ( midiEventN ); // load the player msg array for(unsigned i=0; e!=nullptr && ilink) if( e->status != 0 ) { time::millisecondsToSpec(m[i].timestamp, (unsigned)(e->sec*1000) ); m[i].ch = e->status & 0x0f; m[i].status = e->status & 0xf0; m[i].d0 = e->d0; m[i].d1 = e->d1; m[i].id = e->uid; app->locMap[i].loc = e->loc; app->locMap[i].timestamp = m[i].timestamp; ++i; } // load the player with the msg list if((rc = midi_record_play::load( app->mrpH, m, midiEventN )) != kOkRC ) { cwLogError(rc,"MIDI player load failed."); goto errLabel; } mem::free(m); } // enable the 'End Loc' number box since the score is loaded io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kInsertLocId ), true ); // update the current event and event count _update_event_ui(app); // 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 ); // restore the fragment records if((rc = _restore( app )) != kOkRC ) { rc = cwLogError(rc,"Restore failed."); goto errLabel; } cwLogInfo("'%s' loaded.",app->scoreFn); errLabel: _update_event_ui( app ); return rc; } rc_t _on_ui_start( app_t* app ) { rc_t rc=kOkRC; bool rewindFl = true; if( !time::isZero(app->beg_play_timestamp) ) { // seek the player to the requested loc if((rc = midi_record_play::seek( app->mrpH, app->beg_play_timestamp )) != kOkRC ) { rc = cwLogError(rc,"MIDI seek failed."); goto errLabel; } rewindFl = false; } // apply the preset which is active at the start time if((rc = _apply_preset( app, app->beg_play_timestamp )) != kOkRC ) { rc = cwLogError(rc,"Preset application failed prior to MIDI start."); goto errLabel; } // start the MIDI playback if((rc = midi_record_play::start(app->mrpH,rewindFl,&app->end_play_timestamp)) != kOkRC ) { rc = cwLogError(rc,"MIDI start failed."); goto errLabel; } io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kCurMidiEvtCntId), midi_record_play::event_index(app->mrpH) ); //io::uiSendValue( app->ioH, kInvalidId, uiFindElementUuId(app->ioH,kCurAudioSecsId), audio_record_play::current_loc_seconds(app->arpH) ); errLabel: return rc; } rc_t _on_ui_stop( app_t* app ) { rc_t rc = kOkRC; if((rc = midi_record_play::stop(app->mrpH)) != kOkRC ) { rc = cwLogError(rc,"MIDI start failed."); goto errLabel; } //if((rc = audio_record_play::stop(app->arpH)) != kOkRC ) //{ // rc = cwLogError(rc,"Audio start failed."); // goto errLabel; //} errLabel: return rc; } rc_t _set_midi_thru_state( app_t* app, bool thru_fl ) { rc_t rc = kOkRC; if((rc = midi_record_play::set_thru_state(app->mrpH,thru_fl)) != kOkRC ) rc = cwLogError(rc,"%s MIDI thru state failed.",thru_fl ? "Enable" : "Disable" ); return rc; } loc_map_t* _find_loc( app_t* app, unsigned loc ) { unsigned i=0; for(; ilocMapN; ++i) if( app->locMap[i].loc == loc ) return app->locMap + i; return nullptr; } bool _is_valid_insert_loc( app_t* app, unsigned loc ) { bool fl0 = _find_loc(app,loc) != nullptr; bool fl1 = preset_sel::is_fragment_loc( app->psH, loc)==false; return fl0 && fl1; } rc_t _on_ui_play_loc(app_t* app, unsigned appId, unsigned loc) { rc_t rc = kOkRC; loc_map_t* map; // locate the map record if((map = _find_loc(app,loc)) == nullptr ) { rc = cwLogError(kOpFailRC,"The location '%i' could not be found.",loc); goto errLabel; } switch( appId ) { case kBegPlayLocNumbId: app->beg_play_timestamp = map->timestamp; break; case kEndPlayLocNumbId: app->end_play_timestamp = map->timestamp; break; } errLabel: return rc; } rc_t _on_ui_insert_loc( app_t* app, unsigned insertLoc ) { rc_t rc = kOkRC; bool enableFl = _is_valid_insert_loc(app,insertLoc); unsigned insertBtnUuId = io::uiFindElementUuId( app->ioH, kInsertBtnId ); io::uiSetEnable( app->ioH, insertBtnUuId, enableFl ); if( enableFl ) { app->insertLoc = insertLoc; // TODO: Clear GUI error indicator } else { app->insertLoc = kInvalidId; cwLogWarning("Location '%i' is not valid.",insertLoc); // TODO: Set GUI error indicator } return rc; } rc_t _on_ui_insert_btn( app_t* app ) { rc_t rc = kOkRC; unsigned fragId = kInvalidId; loc_map_t* loc_ts = nullptr; // verify that frag panel resource object is initiailized if( app->frag_panel_cfg == nullptr) { rc = cwLogError(kInvalidStateRC,"The fragment UI resource was not initialized."); goto errLabel; } // verify that the insertion location is valid if( app->insertLoc == kInvalidId ) { rc = cwLogError(kInvalidIdRC,"The new fragment's 'End Loc' is not valid."); goto errLabel; } // verify that the end-loc is not already in use - this shouldn't be possible because the 'insert' btn should be disabled if the 'insertLoc' is not valid if( preset_sel::is_fragment_loc( app->psH, app->insertLoc ) ) { rc = cwLogError(kInvalidIdRC,"The new fragment's 'End Loc' is already in use."); goto errLabel; } // get the timestamp assoc'd with the the 'end-loc' if((loc_ts = _find_loc( app, app->insertLoc )) == nullptr ) { rc = cwLogError(kOpFailRC,"The time stamp associated with the 'End Loc' '%i' could not be found.",app->insertLoc); goto errLabel; } // create the fragment UI panel if((rc = _create_frag_ui( app, app->insertLoc, fragId )) != kOkRC ) { rc = cwLogError(rc,"Fragment UI panel create failed."); goto errLabel; } // create the data record associated with the new fragment. if((rc = preset_sel::create_fragment( app->psH, fragId, app->insertLoc, loc_ts->timestamp)) != kOkRC ) { rc = cwLogError(rc,"Fragment data record create failed."); goto errLabel; } // update the fragment UI _update_frag_ui(app, fragId ); errLabel: return rc; } rc_t _on_ui_delete_btn( app_t* app ) { rc_t rc = kOkRC; unsigned fragId = kInvalidId; // get the fragment id (uuid) of the selected fragment if((fragId = preset_sel::ui_select_fragment_id(app->psH)) == kInvalidId ) { rc = cwLogError(kInvalidStateRC,"There is no selected fragment to delete."); goto errLabel; } // delete the fragment data record if((rc = preset_sel::delete_fragment(app->psH,fragId)) != kOkRC ) goto errLabel; // delete the fragment UI element if((rc = io::uiDestroyElement( app->ioH, fragId )) != kOkRC ) goto errLabel; errLabel: if( rc != kOkRC ) rc = cwLogError(rc,"Fragment delete failed."); return rc; } rc_t _onUiInit(app_t* app, const io::ui_msg_t& m ) { rc_t rc = kOkRC; _update_event_ui(app); // 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 ); const preset_sel::frag_t* f = preset_sel::get_fragment_base( app->psH ); for(; f!=nullptr; f=f->link) _update_frag_ui( app, f->fragId ); return rc; } rc_t _onUiValue(app_t* app, const io::ui_msg_t& m ) { rc_t rc = kOkRC; switch( m.appId ) { case kQuitBtnId: io::stop( app->ioH ); break; case kIoReportBtnId: io::report( app->ioH ); break; case kReportBtnId: //preset_sel::report( app->psH ); io_flow::apply_preset( app->ioFlowH, 2000.0, app->tmp==0 ? "a" : "b"); app->tmp = !app->tmp; break; case kSaveBtnId: _on_ui_save(app); break; case kLoadBtnId: _on_ui_load(app); break; case kMidiThruCheckId: cwLogInfo("MIDI thru:%i",m.value->u.b); _set_midi_thru_state(app, m.value->u.b); break; case kStartBtnId: _on_ui_start(app); break; case kStopBtnId: _on_ui_stop(app); break; case kFnStringId: mem::release(app->directory); app->directory = mem::duplStr(m.value->u.s); //rintf("filename:%s\n",app->directory); break; case kBegPlayLocNumbId: _on_ui_play_loc(app, m.appId, m.value->u.i); break; case kEndPlayLocNumbId: _on_ui_play_loc(app, m.appId, m.value->u.i); break; case kInsertLocId: _on_ui_insert_loc(app, m.value->u.u ); break; case kInsertBtnId: _on_ui_insert_btn(app); break; case kDeleteBtnId: _on_ui_delete_btn(app); break; case kFragGainId: _on_ui_frag_value( app, m.uuId, m.value->u.d ); break; case kFragWetDryGainId: _on_ui_frag_value( app, m.uuId, m.value->u.d ); break; case kFragFadeOutMsId: _on_ui_frag_value( app, m.uuId, m.value->u.u ); break; case kFragPresetOrderId: _on_ui_frag_value( app, m.uuId, m.value->u.u ); break; case kFragPresetSelId: _on_ui_frag_value( app, m.uuId, m.value->u.b ); break; } return rc; } rc_t _onUiClick( app_t* app, const io::ui_msg_t& m ) { rc_t rc = kOkRC; // get the last selected fragment unsigned uuId = preset_sel::ui_select_fragment_id(app->psH); // is the last selected fragment the same as the clicked fragment bool reclickFl = uuId == m.uuId; // if a different fragment was clicked then deselect the last fragment in the UI if( !reclickFl && uuId != kInvalidId ) uiSetSelect( app->ioH, uuId, false ); // select or deselect the clicked fragment uiSetSelect( app->ioH, m.uuId, !reclickFl ); // Note: calls to uiSetSelect() produce callbacks to _onUiSelect(). return rc; } rc_t _onUiSelect( app_t* app, const io::ui_msg_t& m ) { rc_t rc = kOkRC; bool selectFl = m.value->u.b; // True/False if the fragment is being selected/deselected // track the currently selected fragment. preset_sel::ui_select_fragment( app->psH, m.uuId, selectFl ); // enable/disable the delete fragment button io::uiSetEnable( app->ioH, io::uiFindElementUuId( app->ioH, kDeleteBtnId ), selectFl ); return rc; } rc_t _onUiEcho(app_t* app, const io::ui_msg_t& m ) { rc_t rc = kOkRC; return rc; } rc_t _ui_callback( app_t* app, const io::ui_msg_t& m ) { rc_t rc = kOkRC; switch( m.opId ) { case ui::kConnectOpId: cwLogInfo("UI Connected: wsSessId:%i.",m.wsSessId); break; case ui::kDisconnectOpId: cwLogInfo("UI Disconnected: wsSessId:%i.",m.wsSessId); break; case ui::kInitOpId: _onUiInit(app,m); break; case ui::kValueOpId: _onUiValue( app, m ); break; case ui::kClickOpId: _onUiClick( app, m ); break; case ui::kSelectOpId: _onUiSelect( app, m ); break; case ui::kEchoOpId: _onUiEcho( app, m ); break; case ui::kIdleOpId: break; case ui::kInvalidOpId: // fall through default: assert(0); break; } return rc; } // The main application callback rc_t _io_callback( void* arg, const io::msg_t* m ) { rc_t rc = kOkRC; app_t* app = reinterpret_cast(arg); if( app->mrpH.isValid() ) { midi_record_play::exec( app->mrpH, *m ); if( midi_record_play::is_started(app->mrpH) ) io::uiSendValue( app->ioH, uiFindElementUuId(app->ioH,kCurMidiEvtCntId), midi_record_play::event_index(app->mrpH) ); } if( app->ioFlowH.isValid() ) { io_flow::exec( app->ioFlowH, *m ); } /* if( app->arpH.isValid() ) { audio_record_play::exec( app->arpH, *m ); if( audio_record_play::is_started(app->arpH) ) io::uiSendValue( app->ioH, kInvalidId, uiFindElementUuId(app->ioH,kCurAudioSecsId), audio_record_play::current_loc_seconds(app->arpH) ); } */ switch( m->tid ) { case io::kTimerTId: break; case io::kSerialTId: break; case io::kMidiTId: break; case io::kAudioTId: break; case io::kAudioMeterTId: break; case io::kSockTId: break; case io::kWebSockTId: break; case io::kUiTId: rc = _ui_callback(app,m->u.ui); break; default: assert(0); } return rc; } } } cw::rc_t cw::preset_sel_app::main( const object_t* cfg, const object_t* flow_proc_dict ) { rc_t rc; app_t app = { }; const object_t* params_cfg = nullptr; // Parse the configuration if((rc = _parseCfg(&app,cfg,params_cfg)) != kOkRC ) goto errLabel; // create the io framework instance if((rc = io::create(app.ioH,cfg,_io_callback,&app,mapA,mapN)) != kOkRC ) { rc = cwLogError(kOpFailRC,"IO Framework create failed."); goto errLabel; } // create the preset selection state object if((rc = create(app.psH, app.presets_cfg )) != kOkRC ) { rc = cwLogError(kOpFailRC,"Preset state control object create failed."); goto errLabel; } // create the MIDI record-play object if((rc = midi_record_play::create(app.mrpH,app.ioH,*params_cfg,_midi_play_callback,&app)) != kOkRC ) { rc = cwLogError(rc,"MIDI record-play object create failed."); goto errLabel; } // 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 ) { rc = cwLogError(rc,"The IO Flow controller create failed."); goto errLabel; } /* // create the audio record-play object if((rc = audio_record_play::create(app.arpH,app.ioH,*cfg)) != kOkRC ) { rc = cwLogError(rc,"Audio record-play object create failed."); goto errLabel; } */ // start the io framework instance if((rc = io::start(app.ioH)) != kOkRC ) { rc = cwLogError(rc,"Preset-select app start failed."); goto errLabel; } // execute the io framework while( !isShuttingDown(app.ioH)) { exec(app.ioH); sleepMs(50); } if((rc = io::stop(app.ioH)) != kOkRC ) { rc = cwLogError(rc,"IO API stop failed."); goto errLabel; } errLabel: _free(app); io::destroy(app.ioH); printf("Preset-select Done.\n"); return rc; }