libcm/cmProc4.h

535 lines
20 KiB
C
Raw Normal View History

2012-11-15 04:01:05 +00:00
#ifndef cmProc4_h
#define cmProc4_h
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
unsigned smpIdx; // time tag sample index for val
cmMidiByte_t val; //
2012-12-13 16:46:48 +00:00
bool validFl; //
2012-11-19 06:41:27 +00:00
} cmScFolBufEle_t;
2012-11-15 04:01:05 +00:00
typedef struct
{
2012-12-13 16:46:48 +00:00
unsigned pitch;
unsigned scEvtIdx;
} cmScFolEvt_t;
typedef struct
{
unsigned evtCnt; //
cmScFolEvt_t* evtV; // pitchV[pitchCnt]
unsigned scIdx; // index of the score loc (into cmScoreEvt[]) at this location
int barNumb; // bar number of this location
2012-11-15 04:01:05 +00:00
} cmScFolLoc_t;
2012-11-19 06:41:27 +00:00
typedef struct
{
cmObj obj;
cmReal_t srate; //
cmScH_t scH; // score handle
unsigned bufN; // event buffer count
cmScFolBufEle_t* bufV; // event buffer bufV[bufN] - bufV[bufN-1] newest event, bufV[boi] oldest event
int locN; // count of score locations
cmScFolLoc_t* loc; // score loc[locN]
unsigned sbi; // oldest score window index
unsigned sei; // newest score window index
unsigned msln; // minimum score look ahead count
unsigned mswn; // maximum score window length
unsigned forwardCnt; // count of score loc's to look ahead for a match to the current pitch when the optimal edit-dist alignment does not produce a match for the current pitch
unsigned maxDist; // max. dist allowed to still consider matching
unsigned minVel; // notes < minVel are ignored
bool printFl; // true if pitch tracker reporting should be included
bool noBackFl; // prevent the tracker from going backwards in time
2012-11-19 06:41:27 +00:00
unsigned* edWndMtx;
unsigned missCnt; // current consecutive unmatched notes
unsigned matchCnt; // current consecutive matched notes
unsigned eventIdx; // events since reset
unsigned skipCnt; // notes skipped due to velocity
unsigned ret_idx; // last tracked location
2012-11-19 06:41:27 +00:00
2012-11-15 04:01:05 +00:00
} cmScFol;
cmScFol* cmScFolAlloc( cmCtx* ctx, cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel );
2012-11-15 04:01:05 +00:00
cmRC_t cmScFolFree( cmScFol** pp );
cmRC_t cmScFolInit( cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel );
2012-11-15 04:01:05 +00:00
cmRC_t cmScFolFinal( cmScFol* p );
// Jump to a score location and reset the internal state of the follower.
2012-11-15 04:01:05 +00:00
cmRC_t cmScFolReset( cmScFol* p, unsigned scoreIndex );
// Give the follower a MIDI performance event. Only MIDI note-on events are acted upon;
// all others are ignored.
2012-11-15 04:01:05 +00:00
unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
2012-12-13 16:46:48 +00:00
//=======================================================================================================================
typedef struct
{
unsigned pitch;
unsigned scEvtIdx;
bool matchFl;
} cmScTrkEvt_t;
typedef struct
{
unsigned evtCnt; //
cmScTrkEvt_t* evtV; // evtV[evtCnt]
unsigned scIdx; // index of the score event (into cmScoreEvt[]) at this location
int barNumb; // bar number of this location
} cmScTrkLoc_t;
typedef struct
{
cmObj obj;
cmScFol* sfp;
double srate;
cmScH_t scH;
unsigned locN;
cmScTrkLoc_t* loc;
unsigned minVel;
unsigned maxWndCnt;
unsigned minWndLookAhead;
bool printFl;
int curLocIdx;
unsigned evtIndex;
} cmScTrk;
cmScTrk* cmScTrkAlloc( cmCtx* ctx, cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel );
cmRC_t cmScTrkFree( cmScTrk** pp );
cmRC_t cmScTrkInit( cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel );
cmRC_t cmScTrkFinal( cmScTrk* p );
// Jump to a score location and reset the internal state of the follower.
cmRC_t cmScTrkReset( cmScTrk* p, unsigned scoreIndex );
// Give the follower a MIDI performance event. Only MIDI note-on events are acted upon;
// all others are ignored.
unsigned cmScTrkExec( cmScTrk* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
//=======================================================================================================================
//
// Simplified string alignment function based on Levenshtein edit distance.
//
enum { kEdMinIdx, kEdSubIdx, kEdDelIdx, kEdInsIdx, kEdCnt };
typedef struct
{
unsigned v[kEdCnt];
bool matchFl;
bool transFl;
} ed_val;
typedef struct ed_path_str
{
unsigned code;
unsigned ri;
unsigned ci;
bool matchFl;
bool transFl;
struct ed_path_str* next;
} ed_path;
/*
Backtracking:
m[rn,cn] is organized to indicate the mutation operations
on s0[0:rn-1] or s1[0:cn-1] during backtracking.
Backtracking begins at cell m[rn-1,cn-1] and proceeds
up and left toward m[0,0]. The action to perform during
backtracking is determined by examinging which values
int m[].v[1:3] match m[].v[0].
Match Next Cell
Index Operation Location
----- ------------------------ ------------------------
1 Substitute char s0[ri-1] move diagonally; up-left
2 Delete char s0[ri-1] move up.
3 Delete char s1[ci-1] move left.
(same as inserting blank
into after s[ri-1]
Note that more than one value in m[].v[1:3] may match
m[].v[0]. In this case the candidate solution branches
at this point in the candidate selection processes.
*/
typedef struct
{
const char* s0; // forms rows of m[] - mutate to match s1 - rn=strlen(s0)
const char* s1; // forms columns of m[] - target string - cn=strlen(s1)
unsigned rn; // length of s0 + 1
unsigned cn; // length of s1 + 1
ed_val* m; // m[rn,cn]
unsigned pn; // rn+cn
ed_path* p_mem; // pmem[ 2*pn ];
ed_path* p_avl; // available path record linked list
ed_path* p_cur; // current path linked list
ed_path* p_opt; // p_opt[pn] current best alignment
double s_opt; // score of the current best alignment
} ed_r;
// print the DP matrix ed_r.m[rn,cn].
void ed_print_mtx( ed_r* r );
// Initialize ed_r.
void ed_init( ed_r* r, const char* s0, const char* s1 );
// Fill in the DP matrix.
void ed_calc_mtx( ed_r* r );
// Traverse the possible alignments in the DP matrix and determine the optimal alignment.
void ed_align( ed_r* r );
// Print the optimal alignment p_opt[]
void ed_print_opt( ed_r* r );
// Free resource allocated by ed_init().
void ed_free(ed_r* r);
// Main test function.
void ed_main();
//=======================================================================================================================
enum
{
kSmMinIdx,
kSmSubIdx, // 'substitute' - may or may not match
kSmDelIdx, // 'delete' - delete a MIDI note
kSmInsIdx, // 'insert' - insert a space in the score
kSmCnt
};
enum
{
kSmMatchFl = 0x01,
kSmTransFl = 0x02
};
// Dynamic Programming (DP) matrix element
typedef struct
{
unsigned v[kSmCnt]; //
unsigned flags;
} cmScMatchVal_t;
// List record used to track a path through the DP matrix p->m[,]
typedef struct cmScMatchPath_str
{
unsigned code;
unsigned ri;
unsigned ci;
unsigned flags;
unsigned locIdx;
struct cmScMatchPath_str* next;
} cmScMatchPath_t;
typedef struct cmScMatchEvt_str
{
unsigned pitch;
} cmScMatchEvt_t;
// Score location record.
typedef struct
{
unsigned evtCnt; //
cmScMatchEvt_t* evtV; // evtV[evtCnt]
unsigned scLocIdx; // scH score location index
int barNumb; // bar number of this location
} cmScMatchLoc_t;
typedef struct
{
cmObj obj;
cmScH_t scH; //
unsigned locN; //
cmScMatchLoc_t* loc; // loc[locN]
unsigned mrn; // max row count (midi)
unsigned rn; // cur row count
unsigned mcn; // max column count (score)
unsigned cn; // cur column count
unsigned mmn; // max length of midiBuf[] (mrn-1)
unsigned msn; // max length of score window (mcn-1)
cmScMatchVal_t* m; // m[mrn,mcn] DP matrix
unsigned pn; // mrn+mcn
cmScMatchPath_t* p_mem; // pmem[ 2*pn ];
cmScMatchPath_t* p_avl; // available path record linked list
cmScMatchPath_t* p_cur; // current path linked list
cmScMatchPath_t* p_opt; // p_opt[pn] current best alignment
double opt_cost; // p_opt cost set by cmScMatchExec()
} cmScMatch;
cmScMatch* cmScMatchAlloc( cmCtx* c, cmScMatch* p, cmScH_t scH, unsigned maxScWndN, unsigned maxMidiWndN );
cmRC_t cmScMatchFree( cmScMatch** pp );
cmRC_t cmScMatchInit( cmScMatch* p, cmScH_t scH, unsigned maxScWndN, unsigned maxMidiWndN );
cmRC_t cmScMatchFinal( cmScMatch* p );
// Returns cmEofRC if scLocIdx + locN > p->locN - note that this is not necessarily an error.
// The optimal path p_opt[] will only be updated if the edit cost is less than min_cost.
// Set min_cost to DBL_MAX to force p_opt[] to be updated.
cmRC_t cmScMatchExec( cmScMatch* p, unsigned scLocIdx, unsigned locN, const unsigned* midiPitchV, unsigned midiPitchN, double min_cost );
//=======================================================================================================================
typedef struct
{
unsigned locIdx; // location assoc'd with this MIDI evt (cmInvalidIdx if not a positive-match)
unsigned cbCnt; // count of times this event has been sent via the callback
unsigned mni; // unique identifier for this event since previous call to cmScAlignReset().
unsigned smpIdx; // time stamp of this event
unsigned pitch; // MIDI note pitch
unsigned vel; // " " velocity
} cmScMatcherMidi_t;
typedef struct
{
unsigned locIdx;
unsigned mni;
unsigned pitch;
unsigned vel;
bool tpFl; // true positive
bool fpFl; // false positive
} cmScMatcherResult_t;
typedef struct
{
cmObj obj;
cmScMatch* mp;
unsigned mn;
cmScMatcherMidi_t* midiBuf; // midiBuf[mn]
cmScMatcherResult_t* res; // res[rn]
unsigned rn; // length of res[]
unsigned ri; // next avail res[] recd.
double s_opt; //
unsigned missCnt; // count of consecutive trailing non-matches
unsigned esi; // index into loc[] of the last positive match.
unsigned mni; // track the count of MIDI events since the last call to cmScMatcherReset()
unsigned mbi; // index of oldest MIDI event in midiBuf[]; 0 when the buffer is full.
unsigned begSyncLocIdx; // start of score window, in mp->loc[], of best match in previous scan
unsigned stepCnt; // count of forward/backward score loc's to examine for a match during cmScMatcherStep().
unsigned maxMissCnt; // max. number of consecutive non-matches during step prior to executing a scan.
unsigned scanCnt; // count of time scan was executed inside cmScMatcherStep()
} cmScMatcher;
cmScMatcher* cmScMatcherAlloc( cmCtx* c, cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN );
cmRC_t cmScMatcherFree( cmScMatcher** pp );
cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN );
cmRC_t cmScMatcherFinal( cmScMatcher* p );
void cmScMatcherReset( cmScMatcher* p );
bool cmScMatcherInputMidi( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
// Slide a score window scanCnt times, beginning at 'bsi',
// looking for the best match to p->midiBuf[]. The score window
// contain scWndN (p->mp->mcn-1) score locations.
// Returns the index into p->mp->loc[] of the start of the best
// match score window. The score associated
// with this match is stored in s_opt.
unsigned cmScMatcherScan( cmScMatcher* p, unsigned bsi, unsigned scanCnt );
// Step forward/back by p->stepCnt from p->esi.
// p->esi must therefore be valid prior to calling this function.
// If more than p->maxMissCnt consecutive MIDI events are
// missed then automatically run cmScAlignScan().
// Return cmEofRC if the end of the score is encountered.
// Return cmSubSysFailRC if an internal scan resync. failed.
cmRC_t cmScMatcherStep( cmScMatcher* p );
cmRC_t cmScMatcherExec( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
//=======================================================================================================================
enum
{
kSaMinIdx,
kSaSubIdx, // 'substitute' - may or may not match
kSaDelIdx, // 'delete' - delete a MIDI note
kSaInsIdx, // 'insert' - insert a space in the score
kSaCnt
};
// Dynamic Programming (DP) matrix element
typedef struct
{
unsigned v[kSaCnt]; //
bool matchFl; // if this is a substitute; is it also a match?
bool transFl; // if this is a substitute; is this the second element in a reversed pair?
} cmScAlignVal_t;
// List record used to track a path through the DP matrix p->m[,]
typedef struct cmScAlignPath_str
{
unsigned code;
unsigned ri;
unsigned ci;
bool matchFl;
bool transFl;
unsigned locIdx;
struct cmScAlignPath_str* next;
} cmScAlignPath_t;
// Score note event record
typedef struct
{
unsigned pitch;
} cmScAlignScEvt_t;
// Score location record.
typedef struct
{
unsigned evtCnt; //
cmScAlignScEvt_t* evtV; // evtV[evtCnt]
unsigned scLocIdx; // scH score location index
int barNumb; // bar number of this location
} cmScAlignLoc_t;
typedef struct
{
unsigned locIdx; // location assoc'd with this MIDI evt (cmInvalidIdx if not a positive-match)
unsigned cbCnt; // count of times this event has been sent via the callback
unsigned mni; // unique identifier for this event since previous call to cmScAlignReset().
unsigned smpIdx; // time stamp of this event
unsigned pitch; // MIDI note pitch
unsigned vel; // " " velocity
} cmScAlignMidiEvt_t;
typedef struct
{
unsigned locIdx; // loc[] sync. location
unsigned smpIdx; //
unsigned mni; // MIDI event unique index
unsigned pitch; // MIDI event pitch which may not match the score event pitch
unsigned vel; // " " velocity
bool matchFl;
bool transFl;
bool foundFl;
} cmScAlignResult_t;
//
typedef void (*cmScAlignCb_t)( void* cbArg, unsigned scLocIdx, unsigned mni, unsigned pitch, unsigned vel );
typedef struct
{
cmObj obj;
cmScAlignCb_t cbFunc; //
void* cbArg; //
cmScH_t scH; //
double srate; //
unsigned locN; // length of loc[]
cmScAlignLoc_t* loc; // loc[locN] score array
unsigned rn; // length of midiBuf[] (mn+1)
unsigned cn; // length of score window (scWndN+1)
unsigned mn; // length of midiBuf[] (rn-1)
cmScAlignMidiEvt_t* midiBuf; // midiBuf[ mn ]
unsigned mbi; // index of first element in midiBuf[] - this is required because the MIDI buf fills from the end to the beginning
unsigned mni; // index of event in midiBuf[p->mn] - increments on each note inserted into midiBuf[] - zeroed by cmScAlignReset().
cmScAlignVal_t* m; // m[rn,cn]
unsigned pn; // rn+cn
cmScAlignPath_t* p_mem; // pmem[ 2*pn ];
cmScAlignPath_t* p_avl; // available path record linked list
cmScAlignPath_t* p_cur; // current path linked list
cmScAlignPath_t* p_opt; // p_opt[pn] current best alignment
double s_opt; // score of the current best alignment
unsigned esi; // loc[] index of latest positive match
unsigned missCnt; // count of consecutive trailing MIDI events without positive matches
unsigned scanCnt;
bool printFl;
unsigned begScanLocIdx; // begin the search at this score locations scWnd[begScanLocIdx:begScanLocIdx+p->cn-1]
unsigned begSyncLocIdx; // initial sync location
unsigned resN; // count of records in res[] == 2*cmScoreEvtCount()
cmScAlignResult_t* res; // res[resN]
unsigned ri; //
int stepCnt; // count of loc[] locations to step ahead/back during a cmScAlignStep() operation.
int maxStepMissCnt; // max. consecutive trailing non-positive matches before a scan takes place.
} cmScAlign;
cmScAlign* cmScAlignAlloc( cmCtx* ctx, cmScAlign* p, cmScAlignCb_t cbFunc, void* cbArg, cmReal_t srate, cmScH_t scH, unsigned midiN, unsigned scWndN );
cmRC_t cmScAlignFree( cmScAlign** pp );
cmRC_t cmScAlignInit( cmScAlign* p, cmScAlignCb_t cbFunc, void* cbArg, cmReal_t srate, cmScH_t scH, unsigned midiN, unsigned scWndN );
cmRC_t cmScAlignFinal( cmScAlign* p );
void cmScAlignReset( cmScAlign* p, unsigned begScanLocIdx );
cmRC_t cmScAlignExec( cmScAlign* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
bool cmScAlignInputMidi( cmScAlign* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
// Scan from p->begScanLocIdx to the end of the score looking
// for the best match to p->midiBuf[].
// Returns the score location index which best matches the
// first note p->midiBuf[]. The score associated
// with this match is stored in s_opt.
unsigned cmScAlignScan( cmScAlign* p, unsigned scanCnt );
// Step forward/back by p->stepCnt from p->esi.
// If more than p->maxStepMissCnt consecutive MIDI events are
// missed then automatically run cmScAlignScan().
// Return cmEofRC if the end of the score is encountered.
// Return cmSubSysFailRC if an internal scan resync. failed.
cmRC_t cmScAlignStep( cmScAlign* p );
unsigned cmScAlignScanToTimeLineEvent( cmScMatcher* p, cmTlH_t tlH, cmTlObj_t* top, unsigned endSmpIdx );
// Given a score, a time-line, and a marker on the time line scan the
// entire score looking for the best match between the first 'midiN'
// notes in each marker region and the score.
void cmScAlignScanMarkers( cmRpt_t* rpt, cmTlH_t tlH, cmScH_t scH );
2012-11-15 04:01:05 +00:00
//=======================================================================================================================
typedef struct
{
unsigned mni;
unsigned locIdx;
unsigned pitch;
unsigned vel;
unsigned smpIdx;
} cmScMeasMidi_t;
typedef struct
{
cmScoreSet_t* set; // A pointer to defining score set
unsigned bli; // Begin index into sap->loc[].
unsigned eli; // End index into sap->loc[].
unsigned bmi; // Begin index into midi[].
unsigned emi; // End index into midi[].
double* val; // val[sap->eleCnt]
} cmScMeasSet_t;
typedef struct
{
cmObj obj;
cmScAlign* sap;
unsigned mn;
cmScMeasMidi_t* midi;
} cmScMeas;
cmScMeas* cmScMeasAlloc( cmCtx* c, cmScMeas* p, double srate, cmScH_t scH );
cmRC_t cmScMeasFree( cmScMeas** pp );
cmRC_t cmScMeasInit( cmScMeas* p, double srate, cmScH_t scH );
cmRC_t cmScMeasFinal( cmScMeas* p );
cmRC_t cmScMeasExec( cmScMeas* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1, unsigned scLocIdx );
2012-11-15 04:01:05 +00:00
#ifdef __cplusplus
}
#endif
#endif