|
@@ -9,8 +9,8 @@
|
9
|
9
|
#include "cmFile.h"
|
10
|
10
|
#include "cmAudioFile.h"
|
11
|
11
|
#include "cmSyncRecd.h"
|
12
|
|
-
|
13
|
|
-
|
|
12
|
+#include "cmVectOpsTemplateMain.h"
|
|
13
|
+#include "cmMidi.h"
|
14
|
14
|
typedef enum
|
15
|
15
|
{
|
16
|
16
|
kInvalidSrId,
|
|
@@ -53,16 +53,17 @@ enum
|
53
|
53
|
|
54
|
54
|
typedef struct cmSr_str
|
55
|
55
|
{
|
56
|
|
- cmErr_t err;
|
57
|
|
- cmFileH_t fH;
|
58
|
|
- cmAudioFileH_t afH;
|
59
|
|
- unsigned flags; // See kXXXSrFl
|
60
|
|
- cmSrRecd_t* cache; // cache[cn]
|
61
|
|
- cmSrAudio_t* map; //
|
62
|
|
- unsigned cn; // count of records in cache[].
|
63
|
|
- unsigned ci; // next cache recd index
|
64
|
|
- unsigned fn; // count of recds written to file
|
65
|
|
- long offs;
|
|
56
|
+ cmErr_t err;
|
|
57
|
+ cmFileH_t fH;
|
|
58
|
+ cmAudioFileH_t afH;
|
|
59
|
+ unsigned flags; // See kXXXSrFl
|
|
60
|
+ cmSrRecd_t* cache; // cache[cn]
|
|
61
|
+ cmSrAudio_t* map; //
|
|
62
|
+ unsigned cn; // count of records in cache[].
|
|
63
|
+ unsigned ci; // next cache recd index
|
|
64
|
+ unsigned fn; // count of recds written to file
|
|
65
|
+ long offs;
|
|
66
|
+ cmAudioFileInfo_t afInfo;
|
66
|
67
|
} cmSr_t;
|
67
|
68
|
|
68
|
69
|
|
|
@@ -207,7 +208,6 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
207
|
208
|
unsigned fileUUId = cmInvalidId;
|
208
|
209
|
unsigned audioFnCnt = 0;
|
209
|
210
|
cmChar_t* audioFn = NULL;
|
210
|
|
- cmAudioFileInfo_t afInfo;
|
211
|
211
|
unsigned i;
|
212
|
212
|
unsigned acnt = 0;
|
213
|
213
|
unsigned mcnt = 0;
|
|
@@ -283,6 +283,8 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
283
|
283
|
}
|
284
|
284
|
}
|
285
|
285
|
|
|
286
|
+ printf("%i %i = %i\n",mcnt,acnt,p->fn);
|
|
287
|
+
|
286
|
288
|
// rewind to the begining of the records
|
287
|
289
|
if( cmFileSeek(p->fH,kBeginFileFl,p->offs) != kOkFileRC )
|
288
|
290
|
{
|
|
@@ -342,19 +344,19 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
342
|
344
|
unsigned time_interval_micros = cmTimeAbsElapsedMicros(&r.u.a.timestamp,&p->cache[j].u.m.timestamp);
|
343
|
345
|
|
344
|
346
|
// if the audio recd is closer to this midi recd than prior audio records ...
|
345
|
|
- if( tiV[j] < time_interval_micros || i==0 )
|
|
347
|
+ if( time_interval_micros < tiV[j] || i==0 )
|
346
|
348
|
{
|
347
|
349
|
// ... then store the audio time stamp in the map
|
348
|
|
- tiV[j] = time_interval_micros;
|
349
|
|
- p->map->timestamp = r.u.a.timestamp;
|
350
|
|
- p->map->smpIdx = r.u.a.smpIdx;
|
|
350
|
+ tiV[j] = time_interval_micros;
|
|
351
|
+ p->map[j].timestamp = r.u.a.timestamp;
|
|
352
|
+ p->map[j].smpIdx = r.u.a.smpIdx;
|
351
|
353
|
}
|
352
|
354
|
}
|
353
|
355
|
}
|
354
|
356
|
}
|
355
|
357
|
|
356
|
358
|
// open the audio file
|
357
|
|
- if( cmAudioFileIsValid(p->afH = cmAudioFileNewOpen(audioFn,&afInfo,&afRC,&ctx->rpt ))==false)
|
|
359
|
+ if( cmAudioFileIsValid(p->afH = cmAudioFileNewOpen(audioFn,&p->afInfo,&afRC,&ctx->rpt ))==false)
|
358
|
360
|
{
|
359
|
361
|
rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Unable to open the sync-recd audio file '%s'.",cmStringNullGuard(audioFn));
|
360
|
362
|
goto errLabel;
|
|
@@ -440,16 +442,89 @@ cmSrRC_t cmSyncRecdAudioWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, u
|
440
|
442
|
cmSrRC_t cmSyncRecdPrint( cmSyncRecdH_t h )
|
441
|
443
|
{
|
442
|
444
|
cmSrRC_t rc = kOkSrRC;
|
443
|
|
- cmSr_t* p = _cmSrHtoP(h);
|
444
|
|
-
|
|
445
|
+ cmSr_t* p = _cmSrHtoP(h);
|
445
|
446
|
unsigned i;
|
|
447
|
+
|
|
448
|
+ if( cmIsFlag(p->flags,kReadSrFl)==false)
|
|
449
|
+ return cmErrMsg(&p->err,kInvalidOpSrRC,"The 'print' operation is only valid on sync-recd files opened for reading.");
|
446
|
450
|
|
447
|
451
|
for(i=0; i<p->cn; ++i)
|
448
|
452
|
{
|
449
|
453
|
cmSrRecd_t* r = p->cache + i;
|
450
|
|
- cmRptPrintf(p->err.rpt,"0x%x %3i %3i %ld %5.3f %ld %5.3f",r->u.m.status,r->u.m.d0,r->u.m.d1,r->u.m.timestamp.tv_sec,r->u.m.timestamp.tv_nsec/1000000000.0,p->map[i].timestamp.tv_sec,p->map[i].timestamp.tv_nsec/1000000000.0);
|
|
454
|
+ cmRptPrintf(p->err.rpt,"0x%x %3i %3i %ld %5.3f : %ld %5.3f %i",r->u.m.status,r->u.m.d0,r->u.m.d1,r->u.m.timestamp.tv_sec,r->u.m.timestamp.tv_nsec/1000000000.0,p->map[i].timestamp.tv_sec,p->map[i].timestamp.tv_nsec/1000000000.0,p->map[i].smpIdx);
|
|
455
|
+ }
|
|
456
|
+
|
|
457
|
+ return rc;
|
|
458
|
+}
|
|
459
|
+
|
|
460
|
+cmSrRC_t cmSyncRecdAudioFile( cmSyncRecdH_t h, const cmChar_t* fn )
|
|
461
|
+{
|
|
462
|
+ cmSrRC_t rc = kOkSrRC;
|
|
463
|
+ cmSr_t* p = _cmSrHtoP(h);
|
|
464
|
+ cmAudioFileH_t afH = cmNullAudioFileH;
|
|
465
|
+ unsigned chCnt = 2;
|
|
466
|
+ unsigned frmCnt = 1024;
|
|
467
|
+ unsigned chIdx = 0;
|
|
468
|
+ cmRC_t afRC = kOkAfRC;
|
|
469
|
+ unsigned actFrmCnt = 0;
|
|
470
|
+ unsigned smpIdx = 0;
|
|
471
|
+ cmSample_t* chs[chCnt];
|
|
472
|
+ cmSample_t buf[frmCnt*2];
|
|
473
|
+ chs[0] = buf;
|
|
474
|
+ chs[1] = buf+frmCnt;
|
|
475
|
+
|
|
476
|
+ if( cmIsFlag(p->flags,kReadSrFl)==false)
|
|
477
|
+ return cmErrMsg(&p->err,kInvalidOpSrRC,"The 'audio-file-output' operation is only valid on sync-recd files opened for reading.");
|
|
478
|
+
|
|
479
|
+ /// Open an audio file for writing
|
|
480
|
+ if(cmAudioFileIsValid(afH = cmAudioFileNewCreate(fn, p->afInfo.srate, p->afInfo.bits, chCnt, &afRC, p->err.rpt))==false)
|
|
481
|
+ {
|
|
482
|
+ rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Unable to create the synchronized audio file '%s'.",cmStringNullGuard(fn));
|
|
483
|
+ goto errLabel;
|
|
484
|
+ }
|
|
485
|
+
|
|
486
|
+ // rewind the input audio file
|
|
487
|
+ if( cmAudioFileSeek(p->afH,0) != kOkAfRC )
|
|
488
|
+ {
|
|
489
|
+ rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Seek failed during synchronized audio file output.");
|
|
490
|
+ goto errLabel;
|
451
|
491
|
}
|
452
|
492
|
|
|
493
|
+ actFrmCnt = frmCnt;
|
|
494
|
+
|
|
495
|
+ // for each buffer of audio
|
|
496
|
+ for(smpIdx=0; actFrmCnt==frmCnt; smpIdx+=actFrmCnt)
|
|
497
|
+ {
|
|
498
|
+ unsigned i;
|
|
499
|
+
|
|
500
|
+ // read frmCnt samples from the first channel of the input audio file
|
|
501
|
+ if( cmAudioFileReadSample(p->afH, frmCnt, chIdx, 1, chs, &actFrmCnt ) != kOkAfRC )
|
|
502
|
+ {
|
|
503
|
+ rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Audio file read failed.");
|
|
504
|
+ break;
|
|
505
|
+ }
|
|
506
|
+
|
|
507
|
+ // zero the output buffer for the second audio channel
|
|
508
|
+ cmVOS_Zero(chs[1],frmCnt);
|
|
509
|
+
|
|
510
|
+ // insert impulses at the location of the MIDI messages.
|
|
511
|
+ for(i=0; i<p->cn; ++i)
|
|
512
|
+ if( p->cache[i].u.m.status==kNoteOnMdId && smpIdx <= p->map[i].smpIdx && p->map[i].smpIdx < smpIdx+frmCnt )
|
|
513
|
+ chs[1][ p->map[i].smpIdx - smpIdx ] = 1.0;
|
|
514
|
+
|
|
515
|
+ // write the audio output samples
|
|
516
|
+ if( cmAudioFileWriteSample(afH, frmCnt, chCnt, chs ) != kOkAfRC )
|
|
517
|
+ {
|
|
518
|
+ rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Synchronized audio file write failed.");
|
|
519
|
+ break;
|
|
520
|
+ }
|
|
521
|
+
|
|
522
|
+ }
|
|
523
|
+
|
|
524
|
+ errLabel:
|
|
525
|
+ if( cmAudioFileDelete(&afH) != kOkAfRC )
|
|
526
|
+ rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Synchronized audio file close failed.");
|
|
527
|
+
|
453
|
528
|
return rc;
|
454
|
529
|
}
|
455
|
530
|
|
|
@@ -462,7 +537,8 @@ cmSrRC_t cmSyncRecdTest( cmCtx_t* ctx )
|
462
|
537
|
};
|
463
|
538
|
|
464
|
539
|
cmSrRC_t rc = kOkSrRC;
|
465
|
|
- const cmChar_t* srFn = "/home/kevin/temp/kr/sr/sr10.sr";
|
|
540
|
+ const cmChar_t* srFn = "/home/kevin/temp/kr/sr/sr0.sr";
|
|
541
|
+ const cmChar_t* aFn = "/home/kevin/temp/kr/sr/sync_af.aiff";
|
466
|
542
|
cmErr_t err;
|
467
|
543
|
cmSyncRecdH_t srH = cmSyncRecdNullHandle;
|
468
|
544
|
|
|
@@ -476,6 +552,7 @@ cmSrRC_t cmSyncRecdTest( cmCtx_t* ctx )
|
476
|
552
|
}
|
477
|
553
|
|
478
|
554
|
cmSyncRecdPrint(srH);
|
|
555
|
+ cmSyncRecdAudioFile(srH,aFn);
|
479
|
556
|
|
480
|
557
|
errLabel:
|
481
|
558
|
if((rc = cmSyncRecdFinal(&srH)) != kOkSrRC )
|