|
@@ -18,7 +18,7 @@
|
18
|
18
|
#include "cmTakeSeqBldr.h"
|
19
|
19
|
|
20
|
20
|
|
21
|
|
-// Map a score event to a MIDI event.
|
|
21
|
+// Score track record: Map a score event to a MIDI event.
|
22
|
22
|
typedef struct cmScTrkMidiTsb_str
|
23
|
23
|
{
|
24
|
24
|
unsigned mni; // midi note index as an offset from the take marker
|
|
@@ -91,6 +91,7 @@ typedef struct
|
91
|
91
|
cmTakeScEvtArrayTsb_t* takes; // list of scEvt arrays used by this sequence
|
92
|
92
|
cmTakeScEvtArrayTsb_t* manual; // list of manually inserted MIDI events
|
93
|
93
|
|
|
94
|
+ cmTakeScEvtArrayTsb_t* out; // render list
|
94
|
95
|
|
95
|
96
|
} cmTsb_t;
|
96
|
97
|
|
|
@@ -164,7 +165,7 @@ cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
|
164
|
165
|
"scoreFn", kStringTId, &p->scFn,
|
165
|
166
|
"tlPrefixPath", kStringTId, &p->tlPrefixPath,
|
166
|
167
|
"takeArray", kArrayTId | kOptArgJsFl, &tkArrObj,
|
167
|
|
- 0 )) != kOkJsRC )
|
|
168
|
+ NULL )) != kOkJsRC )
|
168
|
169
|
{
|
169
|
170
|
if( jsRC == kNodeNotFoundJsRC && errMsg != NULL )
|
170
|
171
|
rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file header parse failed missing required field:'%s'",errMsg);
|
|
@@ -199,7 +200,7 @@ cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
|
199
|
200
|
"markerUid",kIntTId, &p->scTrkTakeV[i].markerUid,
|
200
|
201
|
"failFl", kIntTId, &p->scTrkTakeV[i].failFl,
|
201
|
202
|
"array", kArrayTId, ¬eArrObj,
|
202
|
|
- 0)) != kOkJsRC )
|
|
203
|
+ NULL)) != kOkJsRC )
|
203
|
204
|
{
|
204
|
205
|
if( jsRC == kNodeNotFoundJsRC && errMsg != NULL )
|
205
|
206
|
rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file take record parse failed missing required field:'%s'",errMsg);
|
|
@@ -232,7 +233,7 @@ cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
|
232
|
233
|
"mni", kIntTId, &p->scTrkTakeV[i].midiV[j].mni,
|
233
|
234
|
"scEvtIdx", kIntTId, &p->scTrkTakeV[i].midiV[j].scEvtIdx,
|
234
|
235
|
"flags", kIntTId, &p->scTrkTakeV[i].midiV[j].flags,
|
235
|
|
- 0)) != kOkJsRC )
|
|
236
|
+ NULL)) != kOkJsRC )
|
236
|
237
|
{
|
237
|
238
|
if( jsRC == kNodeNotFoundJsRC && errMsg != NULL )
|
238
|
239
|
rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file note record parse failed missing required field:'%s'",errMsg);
|
|
@@ -260,13 +261,14 @@ unsigned _cmTsbScoreTrkMarkerEventCount( cmTsb_t* p, unsigned markUid )
|
260
|
261
|
|
261
|
262
|
for(i=0; i<p->scTrkTakeN; ++i)
|
262
|
263
|
for(j=0; j<p->scTrkTakeV[i].midiN; ++j)
|
263
|
|
- {
|
264
|
|
- if( p->scTrkTakeV[i].midiV[j].scEvtIdx < minScEvtIdx )
|
265
|
|
- minScEvtIdx = p->scTrkTakeV[i].midiV[j].scEvtIdx;
|
266
|
|
-
|
267
|
|
- if( p->scTrkTakeV[i].midiV[j].scEvtIdx > maxScEvtIdx )
|
268
|
|
- maxScEvtIdx = p->scTrkTakeV[i].midiV[j].scEvtIdx;
|
269
|
|
- }
|
|
264
|
+ if( p->scTrkTakeV[i].midiV[j].scEvtIdx != cmInvalidIdx )
|
|
265
|
+ {
|
|
266
|
+ if( p->scTrkTakeV[i].midiV[j].scEvtIdx < minScEvtIdx )
|
|
267
|
+ minScEvtIdx = p->scTrkTakeV[i].midiV[j].scEvtIdx;
|
|
268
|
+
|
|
269
|
+ if( p->scTrkTakeV[i].midiV[j].scEvtIdx > maxScEvtIdx )
|
|
270
|
+ maxScEvtIdx = p->scTrkTakeV[i].midiV[j].scEvtIdx;
|
|
271
|
+ }
|
270
|
272
|
|
271
|
273
|
if( maxScEvtIdx < minScEvtIdx )
|
272
|
274
|
return 0;
|
|
@@ -359,7 +361,9 @@ cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool ov
|
359
|
361
|
cmTlMarker_t* mark = NULL;
|
360
|
362
|
cmTlMidiFile_t* mf = NULL;
|
361
|
363
|
cmMidiFileH_t mfH = cmMidiFileNullHandle;
|
362
|
|
-
|
|
364
|
+ unsigned scEvtN = 0;
|
|
365
|
+ cmScEvtTsb_t* scEvtV = NULL;
|
|
366
|
+
|
363
|
367
|
// get a pointer to the time-line marker object
|
364
|
368
|
if((mark = cmTlMarkerObjPtr( p->tlH, cmTimeLineIdToObj( p->tlH, cmInvalidId, tlMarkUid))) == NULL )
|
365
|
369
|
{
|
|
@@ -367,6 +371,17 @@ cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool ov
|
367
|
371
|
goto errLabel;
|
368
|
372
|
}
|
369
|
373
|
|
|
374
|
+ // get the count of score events in the take marker
|
|
375
|
+ if((scEvtN = _cmTsbScoreTrkMarkerEventCount(p,tlMarkUid)) == 0 )
|
|
376
|
+ {
|
|
377
|
+ rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The selected take marker does not appear to contain any score events.");
|
|
378
|
+ goto errLabel;
|
|
379
|
+ }
|
|
380
|
+
|
|
381
|
+ // allocate a score event array
|
|
382
|
+ scEvtV = cmMemAllocZ(cmScEvtTsb_t,scEvtN);
|
|
383
|
+
|
|
384
|
+
|
370
|
385
|
// get the name of the MIDI file which contains the marker
|
371
|
386
|
if((mf = cmTimeLineMidiFileAtTime( p->tlH, mark->obj.seqId, mark->obj.seqSmpIdx )) == NULL )
|
372
|
387
|
{
|
|
@@ -394,11 +409,12 @@ cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool ov
|
394
|
409
|
unsigned n = cmMidiFileMsgCount(mfH);
|
395
|
410
|
const cmMidiTrackMsg_t** a = cmMidiFileMsgArray(mfH);
|
396
|
411
|
|
397
|
|
- // seek to the first MIDI msg after bsi
|
|
412
|
+ // seek to the first MIDI msg after sample index bsi in the MIDI file
|
398
|
413
|
for(i=0; i<n; ++i)
|
399
|
414
|
if( a[i]->dtick >= bsi )
|
400
|
415
|
break;
|
401
|
416
|
|
|
417
|
+ // if bsi is after the file then the MIDI file finished before the marker
|
402
|
418
|
if( i == n )
|
403
|
419
|
{
|
404
|
420
|
rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"No MIDI events were found in the marker.");
|
|
@@ -425,6 +441,11 @@ cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool ov
|
425
|
441
|
if( cmMidiFileClose(&mfH) != kOkMfRC )
|
426
|
442
|
rc = cmErrMsg(&p->err,kMidiFileFailTsbRC,"MIDI file close failed.");
|
427
|
443
|
|
|
444
|
+ if( rc != kOkTsbRC )
|
|
445
|
+ {
|
|
446
|
+ cmMemFree(scEvtV);
|
|
447
|
+ }
|
|
448
|
+
|
428
|
449
|
return rc;
|
429
|
450
|
}
|
430
|
451
|
|