//| 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 "cmGrTksbFltk.h" #include "cmGrPlotAudio.h" #include "cmdIf.h" cmGrTksbFltk::cmGrTksbFltk(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), _lastBarPlotObjH(cmGrPlObjNullHandle), _nextTakeY(5), _curCbTId(kInvalidTId) { cmErrSetup(&_err,&ctx->rpt,"cmGrTksbFltk"); _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) ); } cmGrTksbFltk::~cmGrTksbFltk() { } void _cmGrTksbRecvScoreMsg( void* cbArg, const void* msg, unsigned msgByteCnt ) { cmGrTksbFltk* thisPtr = (cmGrTksbFltk*)cbArg; thisPtr->recvScoreMsg(msg,msgByteCnt); } void cmGrTksbFltk::setTksbHandle( void* v ) { _tksbH.h = v; if( cmTakeSeqBldrIsValid(_tksbH) == false ) return; // load the score plot objects cmScoreSeqNotifyCb(cmTakeSeqBldrScoreHandle(_tksbH),_cmGrTksbRecvScoreMsg, this ); // get the count of score-track takes unsigned n = cmTakeSeqBldrScTrkTakeCount(_tksbH); // for each score-track take for(unsigned i=0; iselId!=kStateChangeGrPlId || cmIsNotFlag(arg->deltaFlags,kSelectGrPlFl) ) return true; scObj_t* sop = (scObj_t*)cmGrPlotObjUserPtr(arg->objH); unsigned state = cmGrPlotObjStateFlags(arg->objH); bool isSelectedFl = cmIsFlag( state, kSelectGrPlFl); if( sop == NULL ) return true; //printf("SELECT:%i %i 0x%x\n",cmGrPlotObjId(arg->objH),isSelectedFl,state); if( sop->id==kTakeTksbId && 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)))); _curCbTId = kRefreshTId; // callback to: kcApp::_ctl_cb(ctl_t* cp) callback()(this,user_data()); } if( sop->id==kEventTksbId && sop->u.ep!=NULL && sop->u.ep->type==kBarEvtScId ) { _lastBarPlotObjH = arg->objH; _curCbTId = kSelectTId; // callback to: kcApp::_ctl_cb(ctl_t* cp) callback()(this,user_data()); } return true; } cmGrTksbFltk::cbTId_t cmGrTksbFltk::cbTypeId() const { return _curCbTId; } unsigned cmGrTksbFltk::scoreSelectedEleIndex() const { if( cmGrPlotObjIsValid(_lastBarPlotObjH) ) { scObj_t* sop = (scObj_t*)cmGrPlotObjUserPtr(_lastBarPlotObjH); if( sop!=NULL && sop->id==kEventTksbId && sop->u.ep != NULL && sop->u.ep->type == kBarEvtScId ) { return sop->u.ep->locIdx; } } return cmInvalidIdx; } void cmGrTksbFltk::setScoreLocation( unsigned locIdx, unsigned vel, unsigned smpIdx ) { } void cmGrTksbFltk::_insertSection( const cmScoreSection_t* m ) { // The argument is a serialzed copy of a cmScoreSection_t record. // Convert it to a pointer to an actual object in the local score mgr. if( cmGrPageIsValid(pageHandle()) == false ) return; m = cmScoreSection(cmTakeSeqBldrScoreHandle(_tksbH),m->index); assert(m!=NULL); const cmScoreEvt_t* ep = cmScoreEvt( cmTakeSeqBldrScoreHandle(_tksbH), m->begEvtIndex); assert( ep != NULL ); 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 = kLineGrPlId; cmReal_t x = ep->secs; cmReal_t y = 120; cmReal_t w = 0; cmReal_t h = 7; const cmChar_t* label = m->label; unsigned flags = kNoDragGrPlFl; cmGrVExt_t wext; scObj_t scObj(m); cmGrVExtSetNull(&wext); if( cmGrPlotObjCreate(plH, cvH, &objH, _objId++, parentObjH, xAnchorObjH, yAnchorObjH, objTypeId, flags, x, y, w, h, label, cmGrVExtIsNull(&wext)?NULL:&wext ) != kOkGrPlRC ) { cmErrMsg(&_err,kInsertObjFailRC,"Insert failed on a score section.", cmStringNullGuard(label)); return; } cmGrPlotObjAllocUser(objH,&scObj,sizeof(scObj)); unsigned f = 0 ? (kNorthJsGrFl | kTopJsGrFl) : (kSouthJsGrFl | kBottomJsGrFl); cmGrPlotObjSetLabelAttr( objH, f | kWestJsGrFl | kTopJsGrFl | kRightJsGrFl, 0, kBlackGrId ); cmGrPlotObjSetLineColor( objH, kEnablePlGrId, kGreenGrId ); //cmGrPlotObjSetPhysExt(objH, 1, 0, 1, 0 ); cmGrPlotObjSetFontSize(objH,8); } void cmGrTksbFltk::_insertEvent( const cmScoreEvt_t* m ) { // The argument is a serialzed copy of a cmScoreEvt record. // Convert it to a pointer to an actual object in the local score mgr. if( cmGrPageIsValid(pageHandle()) == false ) return; // Get a pointer to the score event m = cmScoreEvt( cmTakeSeqBldrScoreHandle(_tksbH), m->index ); assert(m!=NULL); 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 = kVLineGrPlId; cmReal_t x = m->secs; cmReal_t y = 0; cmReal_t w = 0; cmReal_t h = 127; const cmChar_t* label = NULL; unsigned flags = kNoDragGrPlFl; int bufN = 7; cmChar_t buf[bufN+1]; cmGrVExt_t wext; scObj_t scObj(m); cmGrVExtSetNull(&wext); switch( m->type ) { case kNonEvtScId: objTypeId = kRectGrPlId; y = m->pitch; h = 1; w = m->durSecs; label = cmMidiToSciPitch(m->pitch,NULL,0); break; case kPedalEvtScId: objTypeId = kRectGrPlId; y = 108; h = 2; w = m->durSecs; label = "pedal"; break; case kBarEvtScId: { buf[bufN] = 0; snprintf(buf,bufN,"%i",m->barNumb); objTypeId = kVLineGrPlId; label = buf; } break; default: return; } // create the plot object to represent this event if( cmGrPlotObjCreate(plH, cvH, &objH, _objId++, parentObjH, xAnchorObjH, yAnchorObjH, objTypeId, flags, x, y, w, h, label, cmGrVExtIsNull(&wext)?NULL:&wext ) != 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 cmGrPlotObjAllocUser(objH,&scObj,sizeof(scObj)); switch( m->type ) { case kBarEvtScId: { unsigned f = _togFl ? (kNorthJsGrFl | kTopJsGrFl) : (kSouthJsGrFl | kBottomJsGrFl); cmGrPlotObjSetLabelAttr( objH, f | kWestJsGrFl | kTopJsGrFl | kRightJsGrFl, 0, kBlueGrId ); cmGrPlotObjSetLineColor( objH, kEnablePlGrId, kYellowGrId ); cmGrPlotObjSetPhysExt(objH, 1, 0, 1, 0 ); _togFl = !_togFl; } break; case kNonEvtScId: cmGrPlotObjSetLineColor( objH, kEnablePlGrId, cmGrPlotObjFillColor(objH,kEnablePlGrId) ); cmGrPlotObjSetFontSize(objH,8); break; case kPedalEvtScId: cmGrPlotObjSetLineColor( objH, kEnablePlGrId, kDeepPinkGrId ); cmGrPlotObjSetFillColor(objH, kEnablePlGrId, kDeepPinkGrId ); cmGrPlotObjSetFontSize(objH,8); break; default: break; } if( cmIsFlag(m->flags,kInvalidScFl) ) { cmGrPlotObjSetFillColor(objH, kEnablePlGrId, kRedGrId ); } } void cmGrTksbFltk::_insertTake( const cmTksbScTrkTake_t* take ) { 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 = 0; cmReal_t y = 0; cmReal_t w = 0; cmReal_t h = 127; const cmChar_t* label = NULL; unsigned flags = kNoDragGrPlFl | kNoFillGrPlFl; int bufN = 7; cmChar_t buf[bufN+1]; cmGrVExt_t wext; cmGrVExt_t vext; scObj_t scObj(take->tlMarkerUid); cmGrVExtSetNull(&wext); if( cmGrPlotObjIsValid(objH = _scEvtIdxToPlotObj( take->minScEvtIdx ))==false ) return; cmGrPlotObjVExt( objH, &vext); x = cmGrVExtMinX(&vext); if( cmGrPlotObjIsValid(objH = _scEvtIdxToPlotObj( take->maxScEvtIdx )) == false ) return; cmGrPlotObjVExt( objH, &vext); w = cmGrVExtMaxX(&vext) - x; h = 1; y = _nextTakeY; buf[bufN] = 0; snprintf(buf,bufN,"%i",(_nextTakeY-5)/2); label = buf; _nextTakeY += 2; if( _nextTakeY > 120 ) _nextTakeY = 5; // create the plot object to represent this event if( cmGrPlotObjCreate(plH, cvH, &objH, _objId++, parentObjH, xAnchorObjH, yAnchorObjH, objTypeId, flags, x, y, w, h, label, cmGrVExtIsNull(&wext)?NULL:&wext ) != kOkGrPlRC ) { cmErrMsg(&_err,kInsertObjFailRC,"Insert failed on score-track take.", cmStringNullGuard(label)); return; } // store the score event reference as custom data inside the plot object cmGrPlotObjAllocUser(objH,&scObj,sizeof(scObj)); cmGrPlotObjSetLineColor( objH, kFocusPlGrId, kRedGrId ); cmGrPlotObjSetLineColor( objH, kSelectPlGrId, kDeepPinkGrId ); cmGrPlotObjSetFontSize(objH,8); } #define cmMENU_TITLE "Bldr" void cmGrTksbFltk::_createMenu( ) { int idx = _menuBar->add(cmMENU_TITLE,0,NULL,0,FL_SUBMENU); const char* titleArray[] = { "Pitch", "Attributes", "Dynamics", "Location", "Fraction", "Section Even", "Section Dyn", "Section Tempo" }; bool onFl[] = { true, false, false, false, false, false, false, false }; int i; for(i=0; iinsert(idx+1+i,titleArray[i],0,_s_menuCallback, _menuArray + i, FL_MENU_TOGGLE ); if( onFl[i] ) { Fl_Menu_Item* mip = (Fl_Menu_Item*)_menuBar->menu() + idx + i + 1; mip->set(); } } _menuBar->redraw(); } bool cmGrTksbFltk::_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 cmGrTksbFltk::_setEventLabels() { enum { kPitchFl=0x01, kAttrFl=0x02, kDynFl=0x04, kLocFl=0x08, kFracFl }; cmGrPlH_t plH = plotHandle(); unsigned flags = 0; flags |= _isMenuChecked(kPitchMId) ? kPitchFl : 0; flags |= _isMenuChecked(kAttrMId) ? kAttrFl : 0; flags |= _isMenuChecked(kDynMId) ? kDynFl : 0; flags |= _isMenuChecked(kLocIdxMId) ? kLocFl : 0; flags |= _isMenuChecked(kFracMId) ? kFracFl : 0; unsigned n = cmGrPlotObjectCount(plH); unsigned i; for(i=0; iid==kEventTksbId && sop->u.ep!=NULL && sop->u.ep->type==kNonEvtScId ) { const cmScoreEvt_t* ep = sop->u.ep; int bufN = 255; cmChar_t buf[ bufN+1 ]; buf[bufN] = 0; buf[0] = 0; if( cmIsFlag(flags,kPitchFl) ) snprintf(buf+strlen(buf),bufN-strlen(buf),"%s ",cmMidiToSciPitch(ep->pitch,NULL,0)); if( cmIsFlag(flags,kAttrFl) ) { cmChar_t s[4]; int j=0; if( cmIsFlag(ep->flags,kEvenScFl) ) s[j++] = 'e'; if( cmIsFlag(ep->flags,kDynScFl) ) s[j++] = 'd'; if( cmIsFlag(ep->flags,kTempoScFl) ) s[j++] = 't'; s[j] = 0; snprintf(buf+strlen(buf),bufN-strlen(buf),"%s ",s); } if( cmIsFlag(flags,kDynFl) && cmIsFlag(ep->flags,kDynScFl) ) { snprintf(buf+strlen(buf),bufN-strlen(buf),"d:%i",ep->dynVal); if( ep->perfDynLvl != 0 ) snprintf(buf+strlen(buf),bufN-strlen(buf),"|%i ",ep->perfDynLvl); else snprintf(buf+strlen(buf),bufN-strlen(buf)," "); } if( cmIsFlag(flags,kLocFl) ) snprintf(buf+strlen(buf),bufN-strlen(buf),"loc:%i ",ep->locIdx); if( cmIsFlag(flags,kFracFl) && ep->frac != 0) snprintf(buf+strlen(buf),bufN-strlen(buf),"%5.3f ",ep->frac); cmGrPlotObjSetLabel(poH, buf ); } } } } void cmGrTksbFltk::_setSectionLabels() { enum { kEvenFl=0x01, kDynFl=0x02, kTempoFl=0x04 }; cmGrPlH_t plH = plotHandle(); unsigned flags = 0; flags |= _isMenuChecked(kSectEvenMId) ? kEvenFl : 0; flags |= _isMenuChecked(kSectDynMId) ? kDynFl : 0; flags |= _isMenuChecked(kSectTempoMId) ? kTempoFl : 0; unsigned n = cmGrPlotObjectCount(plH); unsigned i; for(i=0; iid==kSectionTksbId && sop->u.sp!=NULL ) { const cmScoreSection_t* sp = sop->u.sp; int bufN = 255; cmChar_t buf[ bufN+1 ]; buf[bufN] = 0; buf[0] = 0; snprintf(buf,bufN,"%s ",sp->label); if( cmIsFlag(flags,kEvenFl) && sp->vars[kEvenVarScId] != DBL_MAX) snprintf(buf+strlen(buf),bufN-strlen(buf),"e:%f ",sp->vars[kEvenVarScId]); if( cmIsFlag(flags,kDynFl) && sp->vars[kDynVarScId] != DBL_MAX) snprintf(buf+strlen(buf),bufN-strlen(buf),"d:%f ",sp->vars[kDynVarScId]); if( cmIsFlag(flags,kTempoFl) && sp->vars[kTempoVarScId] != DBL_MAX) snprintf(buf+strlen(buf),bufN-strlen(buf),"t:%f ",sp->vars[kTempoVarScId]); cmGrPlotObjSetLabel(poH, buf ); } } } } void cmGrTksbFltk::_s_menuCallback(Fl_Widget* w, void* arg ) { item_t* ip = (item_t*)arg; cmGrTksbFltk* p = ip->p; unsigned long id = ip->id; switch( id ) { case kPitchMId: case kAttrMId: case kDynMId: case kLocIdxMId: case kFracMId: { p->_setEventLabels(); p->redraw(); } break; case kSectEvenMId: case kSectDynMId: case kSectTempoMId: { p->_setSectionLabels(); p->redraw(); } break; } } cmGrPlObjH_t cmGrTksbFltk::_scEvtIdxToPlotObj( unsigned scEvtIdx ) { cmGrPlH_t plH = plotHandle(); unsigned n = cmGrPlotObjectCount(plH); unsigned i; cmGrPlObjH_t poH; scObj_t* sop; for(i=0; iid == kEventTksbId && sop->u.ep->index == scEvtIdx ) { return poH; } return cmGrPlObjNullHandle; }