//| Copyright: (C) 2019-2020 Kevin Larke //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. #include #include #include #include #include #include #include #include "Fl_CbLinker.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 "cmText.h" #include "cmThread.h" #include "cmPrefs.h" #include "cmSymTbl.h" #include "cmTime.h" #include "cmMidi.h" #include "cmMidiFile.h" #include "cmAudioFile.h" #include "cmAudioFileMgr.h" #include "cmTimeLine.h" #include "cmScore.h" #include "cmTakeSeqBldr.h" #include "cmGr.h" #include "cmGrDevCtx.h" #include "cmGrPlot.h" #include "cmGrPage.h" #include "cmGrFltk.h" #include "gvHashFunc.h" #include "cmGrTksrFltk.h" #include "cmGrPlotAudio.h" #include "cmdIf.h" cmGrTksrFltk::cmGrTksrFltk(cmCtx_t* ctx, cmdIf* cp, Fl_Menu_Bar* menu, int x, int y, int w, int h) : cmGrPlotFltk(ctx,x,y,w,h), //_cmdIf(cp), _tksbH(cmTakeSeqBldrNullHandle), _menuBar(menu), _samplesMetricId(cmInvalidId),_secondsMetricId(cmInvalidId), //_objSecs(0), _objId(0) //_togFl(true) { cmErrSetup(&_err,&ctx->rpt,"cmGrTksrFltk"); _createMenu(); if( cmGrPageIsValid(pageHandle()) == false ) return; initViews(1,1); unsigned vwIdx = 0; cmGrPgH_t pgH = pageHandle(); cmGrVwH_t vwH = cmGrPageViewHandle( pgH, vwIdx); cmGrH_t cvH = cmGrViewGrHandle( vwH ); cmGrAxH_t axH = cmGrAxNullHandle; cmGrVExt_t limExt; _samplesMetricId = cmGrPageLabelFuncRegister( pgH, gvRoundHashValueFunc, this, "Round" ); _secondsMetricId = cmGrPageLabelFuncRegister( pgH, gvMinSecMsHashValueFunc, this, "Min:Sec:Ms" ); unsigned pitchLabelFuncId = cmGrPageLabelFuncRegister( pgH, gvMidiSciPitchValueFunc, this, "Pitch" ); cmGrVExtSetD(&limExt,0,0,0,127); cmGrObjSetWorldExt( cvH, cmGrRootObjH(cvH), &limExt ); cmGrObjSetWorldLimitExt(cvH, cmGrRootObjH(cvH), &limExt, kTopGrFl | kBottomGrFl ); axH = cmGrViewAxisHandle(vwH, kTopGrIdx); cmGrAxisSetCfg( axH, cmClrFlag(cmGrAxisCfg( axH ), kHashMarkGrFl | kHashLabelGrFl )); axH = cmGrViewAxisHandle(vwH, kLeftGrIdx ); cmGrAxisSetLabelFunc( axH, pitchLabelFuncId ); cmGrViewSetLabelFunc( vwH, kLeftGrIdx, pitchLabelFuncId ); axH = cmGrViewAxisHandle(vwH, kRightGrIdx); cmGrAxisSetCfg( axH, cmClrFlag(cmGrAxisCfg( axH ), kHashLabelGrFl )); cmGrViewSetCfg( vwH, cmSetFlag(cmGrViewCfg(vwH),kSelectHorzGrFl) ); } cmGrTksrFltk::~cmGrTksrFltk() {} void cmGrTksrFltk::setTksbHandle( void* v ) { _tksbH.h = v; } void cmGrTksrFltk::refresh() { if( cmGrPlotClear( plotHandle() ) != kOkGrPlRC ) { cmErrMsg(&_err,kClearPlotFailRC,"Plot clear failed."); return; } if( cmTakeSeqBldrIsValid(_tksbH) == false ) return; // insert tksb events here cmTakeSeqBldrRendReset(_tksbH); cmTksbRend_t m; unsigned absSmpIdx = 0; double srate = cmTakeSeqBldrSampleRate(_tksbH); while( cmTakeSeqBldrRendNext(_tksbH,&m) ) { m.evt.smpIdx = absSmpIdx; _insertEvent(&m,srate); absSmpIdx += m.offsetSmp; } } double cmGrTksrFltk::sampleRate() const { if( cmTakeSeqBldrIsValid(_tksbH) ) return cmTakeSeqBldrSampleRate(_tksbH); return 0; } bool cmGrTksrFltk::on_plot_object( cmGrPlotCbArg_t* arg ) { /* if( arg->selId==kStateChangeGrPlId && cmIsFlag(arg->deltaFlags,kSelectGrPlFl) ) { scObj_t* sop = (scObj_t*)cmGrPlotObjUserPtr(arg->objH); unsigned state = cmGrPlotObjStateFlags(arg->objH); bool isSelectedFl = cmIsFlag( state, kSelectGrPlFl); if( sop != NULL ) { //printf("SELECT:%i %i 0x%x\n",cmGrPlotObjId(arg->objH),isSelectedFl,state); if( sop->id==kTakeTksrId && sop->u.tlMarkerUid!=cmInvalidId ) { if( isSelectedFl ) cmTakeSeqBldrLoadTake(_tksbH,sop->u.tlMarkerUid,true); else cmTakeSeqBldrUnloadTake(_tksbH,sop->u.tlMarkerUid); setStatusText(cmTsPrintfS("%s", cmStringNullGuard(cmTakeSeqBldrScTrkTakeText(_tksbH,sop->u.tlMarkerUid)))); } if( sop->id==kEventTksrId && sop->u.ep!=NULL && sop->u.ep->type==kBarEvtScId ) { _lastBarPlotObjH = arg->objH; // callback to: kcApp::_ctl_cb(ctl_t* cp) callback()(this,user_data()); } } } */ return true; } void cmGrTksrFltk::_insertEvent( const cmTksbRend_t* m, double srate ) { if( cmGrPageIsValid(pageHandle()) == false ) return; cmGrPlH_t plH = plotHandle(); cmGrPgH_t pgH = pageHandle(); unsigned vwIdx = 0; cmGrVwH_t vwH = cmGrPageViewHandle( pgH, vwIdx ); cmGrH_t cvH = cmGrViewGrHandle( vwH ); cmGrPlObjH_t parentObjH = cmGrPlObjNullHandle; cmGrPlObjH_t xAnchorObjH = cmGrPlObjNullHandle; cmGrPlObjH_t yAnchorObjH = cmGrPlObjNullHandle; cmGrPlObjH_t objH = cmGrPlObjNullHandle; cmGrPlObjTypeId_t objTypeId = kRectGrPlId; cmReal_t x = m->evt.smpIdx / srate; cmReal_t y = 0; cmReal_t h = 1; cmReal_t w = m->durSmp / srate; const cmChar_t* label = NULL; unsigned flags = kNoDragGrPlFl; tksrId_t tid = kInvalidTksrId; if( cmMidiIsNoteOn(m->evt.status) ) { tid = kNoteTksrId; y = m->evt.d0; label = cmMidiToSciPitch(m->evt.d0,NULL,0); } else { if( cmMidiIsPedalDown(m->evt.status,m->evt.d0,m->evt.d1) ) { tid = kPedalTksrId; y = 120; label = cmMidiPedalLabel(m->evt.d0); flags |= kNoFillGrPlFl; } } if( tid == kInvalidTksrId ) return; //printf("absSmpIdx:%f %f\n",x,w); // create the plot object to represent this event if( cmGrPlotObjCreate(plH, cvH, &objH, _objId++, parentObjH, xAnchorObjH, yAnchorObjH, objTypeId, flags, x, y, w, h, label, NULL ) != kOkGrPlRC ) { cmErrMsg(&_err,kInsertObjFailRC,"Insert failed on a score event.", cmStringNullGuard(label)); return; } // store the score event reference as custom data inside the plot object scObj_t scObj(tid,m->rid); cmGrPlotObjAllocUser(objH,&scObj,sizeof(scObj)); switch( tid ) { case kNoteTksrId: cmGrPlotObjSetLineColor( objH, kEnablePlGrId, cmGrPlotObjFillColor(objH,kEnablePlGrId) ); cmGrPlotObjSetFontSize(objH,8); break; case kPedalTksrId: cmGrPlotObjSetLineColor( objH, kEnablePlGrId, kDeepPinkGrId ); cmGrPlotObjSetFontSize(objH,8); break; default: break; } } #define cmMENU_TITLE "Rndr" void cmGrTksrFltk::_createMenu( ) { int idx = _menuBar->add(cmMENU_TITLE,0,NULL,0,FL_SUBMENU); const char* titleArray[] = { "Pitch", "ScEvtIdx", "Delete", "Sustain", "Sostenuto", "Write", "Read" }; bool onFl[] = { true, false, false, false, false, false, false }; bool checkFl[] = { true, true, false, false, false, false, false }; int i; for(i=0; iinsert(idx+1+i,titleArray[i],0,_s_menuCallback, _menuArray + i, checkFl[i] ? FL_MENU_TOGGLE : 0 ); if( onFl[i] ) { Fl_Menu_Item* mip = (Fl_Menu_Item*)_menuBar->menu() + idx + i + 1; mip->set(); } } _menuBar->redraw(); } bool cmGrTksrFltk::_isMenuChecked( int id ) { unsigned i; // locate the menu item assoc'd with id for(i=0; ifind_index(cmMENU_TITLE)) == -1 ) return false; // The menu items and _menuArray[] were initialized in the same order // therefore the offset from the base of both should be the same. Fl_Menu_Item* mip = (Fl_Menu_Item*)_menuBar->menu() + menuIdx + i + 1; assert( (item_t*)mip->user_data() == _menuArray + i ); return mip->value() != 0; } void cmGrTksrFltk::_setEventLabels() { enum { kPitchFl=0x01, kScEvtFl=0x02 }; if( cmTakeSeqBldrIsValid( _tksbH ) == false ) return; cmGrPlH_t plH = plotHandle(); unsigned flags = 0; flags |= _isMenuChecked(kPitchMId) ? kPitchFl : 0; flags |= _isMenuChecked(kScEvtMId) ? kScEvtFl : 0; unsigned n = cmGrPlotObjectCount(plH); unsigned i; for(i=0; iid==kNoteTksrId && sop->u.rid!=cmInvalidId ) { cmTksbRend_t r; if( cmTakeSeqBldrRendInfo( _tksbH, sop->u.rid, &r ) == kOkTsbRC ) { int bufN = 255; cmChar_t buf[ bufN+1 ]; buf[bufN] = 0; buf[0] = 0; if( cmIsFlag(flags,kPitchFl) && r.evt.status == kNoteOnMdId ) snprintf(buf+strlen(buf),bufN-strlen(buf),"%s ",cmMidiToSciPitch(r.evt.d0,NULL,0)); if( cmIsFlag(flags,kScEvtFl) && r.scEvtIdx != cmInvalidIdx ) snprintf(buf+strlen(buf),bufN-strlen(buf),"sei:%i ",r.scEvtIdx); cmGrPlotObjSetLabel(poH, buf ); } } } } } void cmGrTksrFltk::_s_deleteSelectedEle( void* arg, cmGrPlObjH_t oh ) { if( cmIsFlag(cmGrPlotObjStateFlags(oh), kSelectGrPlFl) ) { cmGrTksrFltk* p = (cmGrTksrFltk*)arg; scObj_t* sop = (scObj_t*)cmGrPlotObjUserPtr(oh); cmTakeSeqBldrRendDelete( p->_tksbH, sop->u.rid ); } } void cmGrTksrFltk::_write() { const cmChar_t* fn = "/home/kevin/temp/kr/tksb/tksb0.js"; if( cmTakeSeqBldrIsValid(_tksbH) == false ) return; if( cmTakeSeqBldrWrite( _tksbH, fn ) != kOkTsbRC ) cmErrMsg(&_err,kTksbFailRC,"Render write failed for '%s'.",cmStringNullGuard(fn)); } void cmGrTksrFltk::_read() { const cmChar_t* fn = "/home/kevin/temp/kr/tksb/tksb0.js"; if( cmTakeSeqBldrIsValid(_tksbH) == false ) return; if( cmTakeSeqBldrRead( _tksbH, fn ) != kOkTsbRC ) cmErrMsg(&_err,kTksbFailRC,"Render write failed for '%s'.",cmStringNullGuard(fn)); } void cmGrTksrFltk::_insertPedal( unsigned long pedalMId ) { if( cmTakeSeqBldrIsValid(_tksbH) == false ) return; unsigned vwIdx = 0; cmGrPgH_t pgH = pageHandle(); cmGrVwH_t vwH = cmGrPageViewHandle( pgH, vwIdx); cmGrH_t cvH = cmGrViewGrHandle( vwH ); double srate = cmTakeSeqBldrSampleRate(_tksbH); cmGrVPt_t pt0,pt1; unsigned rid; cmTksbEvent_t e; memset(&e,0,sizeof(e)); cmGrSelectPoints( cvH, &pt0, &pt1 ); unsigned durSmp = (pt1.x - pt0.x) * srate; e.status = kCtlMdId; switch( pedalMId ) { case kSustainMId: e.d0 = kSustainCtlMdId; break; case kSostenutoMId: e.d0 = kSostenutoCtlMdId; break; } //printf("x0:%f x1:%f %i\n",pt0.x,pt1.x,durSmp); e.smpIdx = pt0.x * srate; e.d1 = 127; cmTakeSeqBldrRendInsert( _tksbH, &e, durSmp, &rid ); e.smpIdx = pt1.x * srate; e.d1 = 0; cmTakeSeqBldrRendInsert( _tksbH, &e, 0, &rid ); refresh(); } void cmGrTksrFltk::_s_menuCallback(Fl_Widget* w, void* arg ) { item_t* ip = (item_t*)arg; cmGrTksrFltk* p = ip->p; unsigned long id = ip->id; switch( id ) { case kPitchMId: case kScEvtMId: p->_setEventLabels(); p->redraw(); break; case kDeleteMId: cmGrPlotObjCb(p->plotHandle(),_s_deleteSelectedEle,p); p->refresh(); p->redraw(); break; case kSustainMId: case kSostenutoMId: p->_insertPedal(id); p->refresh(); p->redraw(); break; case kWriteMId: p->_write(); break; case kReadMId: p->_read(); break; } }