From b2dee6219fe9d9725dae8417a4b0e098e9a8a659 Mon Sep 17 00:00:00 2001 From: Kevin Larke Date: Sun, 22 Feb 2015 22:52:11 -0800 Subject: [PATCH] cmTakeSeqBldr.h/c : Initial commit. --- app/cmTakeSeqBldr.c | 283 ++++++++++++++++++++++++++++++++++++++++++++ app/cmTakeSeqBldr.h | 62 ++++++++++ 2 files changed, 345 insertions(+) create mode 100644 app/cmTakeSeqBldr.c create mode 100644 app/cmTakeSeqBldr.h diff --git a/app/cmTakeSeqBldr.c b/app/cmTakeSeqBldr.c new file mode 100644 index 0000000..9a5cd56 --- /dev/null +++ b/app/cmTakeSeqBldr.c @@ -0,0 +1,283 @@ +#include "cmPrefix.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 "cmJson.h" +#include "cmTime.h" +#include "cmMidi.h" +#include "cmMidiFile.h" +#include "cmAudioFile.h" +#include "cmTimeLine.h" +#include "cmSymTbl.h" +#include "cmScore.h" +#include "cmTakeSeqBldr.h" + + +typedef struct cmNoteTsb_str +{ + unsigned mni; // midi note index as an offset from the take marker + unsigned scEvtIdx; // score event index this not is assoc'd with or -1 if it did not match + unsigned flags; // flags from cmScMatcherResult_t +} cmNoteTsb_t; + +typedef struct cmTakeTsb_str +{ + unsigned markerUid; // marker time line uid assoc'd with this take + cmNoteTsb_t* noteV; // noteV[noteN] score to midi file map recd. array. + unsigned noteN; + bool failFl; +} cmTakeTsb_t; + +typedef struct +{ + cmCtx_t ctx; + cmErr_t err; + cmJsonH_t jsH; + const cmChar_t* tlFn; + const cmChar_t* scFn; + cmTakeTsb_t* takeV; + unsigned takeN; +} cmTsb_t; + +cmTakeSeqBldrH_t cmTakeSeqBldrNullHandle = cmSTATIC_NULL_HANDLE; + +cmTsb_t* _cmTsbHandleToPtr( cmTakeSeqBldrH_t h ) +{ + cmTsb_t* p = (cmTsb_t*)h.h; + return p; +} + +cmTsbRC_t _cmTsbFree( cmTsb_t* p ) +{ + cmTsbRC_t rc = kOkTsbRC; + + if( cmJsonFinalize(&p->jsH) != kOkJsRC ) + { + rc = cmErrMsg(&p->err,kJsonFailTsbRC,"JSON object finalize failed."); + goto errLabel; + } + + cmMemFree(p); + + errLabel: + return rc; +} + + +cmTsbRC_t cmTakeSeqBldrAlloc( cmCtx_t* ctx, cmTakeSeqBldrH_t* hp ) +{ + cmTsbRC_t rc; + if((rc = cmTakeSeqBldrFree(hp)) != kOkTsbRC ) + return kOkTsbRC; + + cmTsb_t* p = cmMemAllocZ(cmTsb_t,1); + + cmErrSetup(&p->err,&ctx->rpt,"TakeSeqBldr"); + + p->ctx = *ctx; + hp->h = p; + + + + return rc; +} + +cmTsbRC_t cmTakeSeqBldrAllocFn( cmCtx_t* ctx, cmTakeSeqBldrH_t* hp, const cmChar_t* tsbFn ) +{ + cmTsbRC_t rc; + if((rc = cmTakeSeqBldrAlloc(ctx,hp)) != kOkTsbRC ) + return rc; + + if((rc = cmTakeSeqBldrInitialize(*hp,tsbFn)) != kOkTsbRC ) + return rc; + + return rc; +} + +cmTsbRC_t cmTakeSeqBldrFree( cmTakeSeqBldrH_t* hp ) +{ + cmRC_t rc = kOkTsbRC; + + if( hp == NULL || cmTakeSeqBldrIsValid(*hp)==false ) + return kOkTsbRC; + + cmTsb_t* p = _cmTsbHandleToPtr(*hp); + + if((rc = _cmTsbFree(p)) != kOkTsbRC ) + return rc; + + hp->h = NULL; + + return rc; +} + +bool cmTakeSeqBldrIsValid( cmTakeSeqBldrH_t h ) +{ return h.h != NULL; } + + +cmTsbRC_t cmTakeSeqBldrInitialize( cmTakeSeqBldrH_t h, const cmChar_t* tsbFn ) +{ + cmTsbRC_t rc = kOkTsbRC; + cmTsb_t* p = _cmTsbHandleToPtr(h); + cmJsonNode_t* tkArrObj = NULL; + cmJsRC_t jsRC = kOkJsRC; + const cmChar_t* errMsg = NULL; + unsigned i; + + // initialize the TSB json object + if(( rc = cmJsonInitializeFromFile(&p->jsH,tsbFn,&p->ctx)) != kOkJsRC ) + { + rc = cmErrMsg(&p->err,kJsonFailTsbRC,"The Take Sequence Builder JSON file object could not be initialized from '%s'.",cmStringNullGuard(tsbFn)); + goto errLabel; + } + + // parse the header + if((jsRC = cmJsonMemberValues( cmJsonRoot(p->jsH), &errMsg, + "tlFn",kStringTId,&p->tlFn, + "scFn",kStringTId,&p->scFn, + "takeArray",kArrayTId | kOptArgJsFl,&tkArrObj, + 0 )) != kOkJsRC ) + { + if( jsRC == kNodeNotFoundJsRC && errMsg != NULL ) + rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file header parse failed missing required field:'%s'",errMsg); + else + rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file header parse failed."); + } + + // count of take records + unsigned tkArrN = cmJsonChildCount(tkArrObj); + + // array of take records + p->takeV = cmMemAllocZ(cmTakeTsb_t,tkArrN); + + // for each take record + for(i=0; ierr,kParseFailTsbRC,"Take record header at index %i access failed.",i); + goto errLabel; + } + + // parse the take record + if((jsRC = cmJsonMemberValues( takeObj, &errMsg, + "markerUid",kIntTId, &p->takeV[i].markerUid, + "failFl", kIntTId, &p->takeV[i].failFl, + "array", kArrayTId, ¬eArrObj, + 0)) != kOkJsRC ) + { + if( jsRC == kNodeNotFoundJsRC && errMsg != NULL ) + rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file take record parse failed missing required field:'%s'",errMsg); + else + rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file take record parse failed."); + } + + // get the count of note records + p->takeV[i].noteN = cmJsonChildCount(noteArrObj); + + // allocate a note record array for this take + p->takeV[i].noteV = cmMemAllocZ(cmNoteTsb_t, p->takeV[i].noteN); + + // for each note record + for(j=0; jtakeV[i].noteN; ++j) + { + cmJsonNode_t* noteObj = NULL; + + // get the note record JSON object + if((noteObj = cmJsonArrayElement(noteArrObj,j)) == NULL ) + { + rc = cmErrMsg(&p->err,kParseFailTsbRC,"Access failed for note record at index %i at take index %i.",j,i); + goto errLabel; + } + + // parse the note record + if((jsRC = cmJsonMemberValues( noteObj, &errMsg, + "mni", kIntTId, &p->takeV[i].noteV[j].mni, + "scEvtIdx", kIntTId, &p->takeV[i].noteV[j].scEvtIdx, + "flags", kIntTId, &p->takeV[i].noteV[j].flags, + 0)) != kOkJsRC ) + { + if( jsRC == kNodeNotFoundJsRC && errMsg != NULL ) + rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file note record parse failed missing required field:'%s'",errMsg); + else + rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file note record parse failed."); + } + } + } + + errLabel: + return rc; +} + +cmTsbRC_t cmTakeSeqBldrLoadSection( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool overwriteFL ) +{ + cmTsbRC_t rc = kOkTsbRC; + return rc; +} + +cmTsbRC_t cmTakeSeqBldrUnloadSection( cmTakeSeqBldrH_t h, unsigned tlMarkUid ) +{ + cmTsbRC_t rc = kOkTsbRC; + return rc; +} + +cmTsbRC_t cmTakeSeqBldrInsertScoreNotes( cmTakeSeqBldrH_t h, unsigned begScEvtIdx, unsigned endScEvtId ) +{ + cmTsbRC_t rc = kOkTsbRC; + return rc; +} + +cmTsbRC_t cmTakeSeqBldrRemoveScoreNotes( cmTakeSeqBldrH_t h, unsigned begScEvtIdx, unsigned endScEvtId ) +{ + cmTsbRC_t rc = kOkTsbRC; + return rc; +} + +cmTsbRC_t cmTakeSeqBldrSelectEnable( cmTakeSeqBldrH_t h, unsigned flags, unsigned id, bool selectFl ) +{ + cmTsbRC_t rc = kOkTsbRC; + return rc; +} + +cmTsbRC_t cmTakeSeqBldrEnableNote( cmTakeSeqBldrH_t h, unsigned ssqId, bool enableFl ) +{ + cmTsbRC_t rc = kOkTsbRC; + return rc; +} + +cmTsbRC_t cmTakeSeqBldrMoveNote( cmTakeSeqBldrH_t h, unsigned ssqId, int deltaSmpIdx ) +{ + cmTsbRC_t rc = kOkTsbRC; + return rc; +} + +cmTsbRC_t cmTakeSeqBldrWriteMidiFile( cmTakeSeqBldrH_t h, const char* fn ) +{ + cmTsbRC_t rc = kOkTsbRC; + return rc; +} + +cmTsbRC_t cmTakeSeqBldrTest( cmCtx_t* ctx ) +{ + const cmChar_t* tsbFn = "/home/kevin/src/cmkc/src/kc/data/assoc0.js"; + cmTakeSeqBldrH_t tsbH = cmTakeSeqBldrNullHandle; + cmTsbRC_t tsbRC = kOkTsbRC; + + if((tsbRC = cmTakeSeqBldrAllocFn(ctx, &tsbH, tsbFn )) != kOkTsbRC ) + return cmErrMsg(&ctx->err,tsbRC,"TSB Allocate and parse '%s' failed.",tsbFn); + + if((tsbRC = cmTakeSeqBldrFree(&tsbH)) != kOkTsbRC ) + return cmErrMsg(&ctx->err,tsbRC,"TSB Free failed."); + + return tsbRC; +} diff --git a/app/cmTakeSeqBldr.h b/app/cmTakeSeqBldr.h new file mode 100644 index 0000000..5f48881 --- /dev/null +++ b/app/cmTakeSeqBldr.h @@ -0,0 +1,62 @@ +#ifndef cmTakeSeqBldr_h +#define cmTakeSeqBldr_h + +#ifdef __cplusplus +extern "C" { +#endif + + + enum + { + kOkTsbRC = cmOkRC, + kJsonFailTsbRC, + kParseFailTsbRC + }; + + typedef cmRC_t cmTsbRC_t; + typedef cmHandle_t cmTakeSeqBldrH_t; + + extern cmTakeSeqBldrH_t cmTakeSeqBldrNullHandle; + + cmTsbRC_t cmTakeSeqBldrAlloc( cmCtx_t* ctx, cmTakeSeqBldrH_t* hp ); + cmTsbRC_t cmTakeSeqBldrAllocFn( cmCtx_t* ctx, cmTakeSeqBldrH_t* hp, const cmChar_t* tsbFn ); + + cmTsbRC_t cmTakeSeqBldrFree( cmTakeSeqBldrH_t* hp ); + + bool cmTakeSeqBldrIsValid( cmTakeSeqBldrH_t h ); + + cmTsbRC_t cmTakeSeqBldrInitialize( cmTakeSeqBldrH_t h, const cmChar_t* tsbFn ); + + // Load a group of notes delinated by a time-line marker into the sequence. + // If notes overlap with existing notes according to their 'scEvtIdx' attribute: + // a. If 'overWriteFl' is set then the incoming overlapped notes are enabled + // and the existing overlapped notes are disabled, otherwise the incoming + // overlapped notes are disabled and the existing notes remain enabled. + // b. The incoming section is time aligned with the first or last existing + // note depending on whether the new section aligns best with the beginning + // or ending of the existing notes. + // + // If no overlapping notes exist then the incoming section is aligned by estimating + // the alignment with existing notes using the score alone. + cmTsbRC_t cmTakeSeqBldrLoadSection( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool overwriteFL ); + cmTsbRC_t cmTakeSeqBldrUnloadSection( cmTakeSeqBldrH_t h, unsigned tlMarkUid ); + + // Fill in missing notes from the score. + cmTsbRC_t cmTakeSeqBldrInsertScoreNotes( cmTakeSeqBldrH_t h, unsigned begScEvtIdx, unsigned endScEvtId ); + cmTsbRC_t cmTakeSeqBldrRemoveScoreNotes( cmTakeSeqBldrH_t h, unsigned begScEvtIdx, unsigned endScEvtId ); + + enum { kMarkTsbFl = 0x01, kTlNoteTsbFl=0x02, kScoreNoteTsbFl = 0x04, kPedalTsbFl = 0x08 }; + cmTsbRC_t cmTakeSeqBldrSelectEnable( cmTakeSeqBldrH_t h, unsigned flags, unsigned id, bool selectFl ); + cmTsbRC_t cmTakeSeqBldrEnableNote( cmTakeSeqBldrH_t h, unsigned ssqId, bool enableFl ); + + cmTsbRC_t cmTakeSeqBldrMoveNote( cmTakeSeqBldrH_t h, unsigned ssqId, int deltaSmpIdx ); + + cmTsbRC_t cmTakeSeqBldrWriteMidiFile( cmTakeSeqBldrH_t h, const char* fn ); + + cmTsbRC_t cmTakeSeqBldrTest( cmCtx_t* ctx ); + +#ifdef __cplusplus +} +#endif + +#endif