Browse Source

Merge branch 'master' of klarke.webfactional.com:webapps/gitweb/repos/libcm

master
kevin larke 7 years ago
parent
commit
e426f5dbd1
15 changed files with 1210 additions and 371 deletions
  1. 2
    0
      .gitignore
  2. 38
    26
      app/cmMidiScoreFollow.c
  3. 9
    1
      app/cmMidiScoreFollow.h
  4. 63
    26
      app/cmScore.c
  5. 5
    1
      app/cmScore.h
  6. 2
    4
      app/cmScoreMatchGraphic.c
  7. 20
    14
      app/cmTimeLine.c
  8. 758
    257
      app/cmXScore.c
  9. 12
    19
      app/cmXScore.h
  10. 203
    4
      cmMidiFile.c
  11. 19
    2
      cmMidiFile.h
  12. 71
    14
      cmSvgWriter.c
  13. 6
    1
      cmSvgWriter.h
  14. 1
    1
      dsp/cmDspKr.c
  15. 1
    1
      dsp/cmDspPgmKrChain.c

+ 2
- 0
.gitignore View File

@@ -1 +1,3 @@
1 1
 Makefile.in
2
+.DS_Store
3
+

+ 38
- 26
app/cmMidiScoreFollow.c View File

@@ -112,6 +112,14 @@ void _cmMsf_ReportMidiErrors( const _cmMsf_ScoreFollow_t* f, cmScH_t scH, const
112 112
   }
113 113
 }
114 114
 
115
+void _cmMsf_WriteMatchFileHeader( cmFileH_t fH )
116
+{
117
+  cmFilePrintf(fH,"  Score Score Score MIDI  MIDI MIDI\n");
118
+  cmFilePrintf(fH,"  Bar   UUID  Pitch UUID  Ptch Vel.\n");
119
+  cmFilePrintf(fH,"- ----- ----- ----- ----- ---- ----\n");
120
+}
121
+
122
+
115 123
 // Write one scScoreMatcherResult_t record to the file fH.
116 124
 unsigned _cmMsf_WriteMatchFileLine( cmFileH_t fH, cmScH_t scH, const cmScMatcherResult_t* r )
117 125
 {
@@ -130,7 +138,7 @@ unsigned _cmMsf_WriteMatchFileLine( cmFileH_t fH, cmScH_t scH, const cmScMatcher
130 138
     cmMidiToSciPitch(e->pitch,buf,5);
131 139
   }
132 140
   
133
-  cmFilePrintf(fH,"m %3i %5i %4s %5i %4s %3i\n",
141
+  cmFilePrintf(fH,"m %5i %5i %5s %5i %4s %3i\n",
134 142
     loc==NULL ? 0 : loc->barNumb,              // score evt bar
135 143
     scUid,                                     // score event uuid
136 144
     buf,                                       // score event pitch
@@ -147,17 +155,17 @@ void _cmMsf_ScoreFollowCb( struct cmScMatcher_str* p, void* arg, cmScMatcherResu
147 155
   r->rV[r->rN++] = *rp;
148 156
 }
149 157
 
150
-cmMsfRC_t cmMidiScoreFollowMain( cmCtx_t* ctx )
158
+cmMsfRC_t cmMidiScoreFollowMain(
159
+  cmCtx_t* ctx,
160
+  const cmChar_t* scoreCsvFn,      // score CSV file as generated from cmXScoreTest().
161
+  const cmChar_t* midiFn,          // MIDI file to track
162
+  const cmChar_t* matchRptOutFn,   // Score follow status report 
163
+  const cmChar_t* matchSvgOutFn,   // Score follow graphic report
164
+  const cmChar_t* midiOutFn,       // (optional) midiFn with apply sostenuto and velocities from the score to the MIDI file
165
+  const cmChar_t* tlBarOutFn       // (optional) bar positions sutiable for use in a cmTimeLine description file.
166
+)
151 167
 {
152
-  cmMsfRC_t             rc          = kOkMsfRC;
153
-  //const cmChar_t* scoreFn         = cmFsMakeUserDirFn("src/kc/src/kc/data","mod2e.csv");
154
-  const cmChar_t*          scoreFn  = cmFsMakeUserDirFn("temp","a7.csv");
155
-  const cmChar_t*          midiFn   = cmFsMakeUserDirFn("media/projects/imag_themes/scores/gen","round1-utf8_11.mid");
156
-  const cmChar_t*          outFn    = cmFsMakeUserDirFn("temp","match.txt");
157
-  const cmChar_t*          svgFn    = cmFsMakeUserDirFn("temp","score0.html");
158
-  const cmChar_t*          newMidiFn= cmFsMakeUserDirFn("temp","a7.mid");
159
-  const cmChar_t*          tlBarFn  = cmFsMakeUserDirFn("temp","time_line_temp.txt");
160
-  
168
+  cmMsfRC_t                rc        = kOkMsfRC;  
161 169
   double                   srate    = 96000.0;
162 170
   cmScMatcher*             smp      = NULL;  
163 171
   cmScH_t                  scH      = cmScNullHandle;
@@ -179,16 +187,16 @@ cmMsfRC_t cmMidiScoreFollowMain( cmCtx_t* ctx )
179 187
   cmCtx* prCtx   = cmCtxAlloc(NULL, err.rpt, cmLHeapNullHandle, cmSymTblNullHandle );
180 188
   
181 189
   // initialize the score
182
-  if( cmScoreInitialize( ctx, &scH, scoreFn, srate, NULL, 0, NULL, NULL, cmSymTblNullHandle) != kOkScRC )
190
+  if( cmScoreInitialize( ctx, &scH, scoreCsvFn, srate, NULL, 0, NULL, NULL, cmSymTblNullHandle) != kOkScRC )
183 191
   {
184
-    rc = cmErrMsg(&err,kFailMsfRC,"cmScoreInitialize() failed on %s",cmStringNullGuard(scoreFn));
192
+    rc = cmErrMsg(&err,kFailMsfRC,"cmScoreInitialize() failed on %s",cmStringNullGuard(scoreCsvFn));
185 193
     goto errLabel;
186 194
   }
187 195
 
188 196
   // setup the callback record
189 197
   if((sfr.rAllocN  = cmScoreEvtCount( scH )*2) == 0)
190 198
   {
191
-    rc = cmErrMsg(&err,kFailMsfRC,"The score %s appears to be empty.",cmStringNullGuard(scoreFn));
199
+    rc = cmErrMsg(&err,kFailMsfRC,"The score %s appears to be empty.",cmStringNullGuard(scoreCsvFn));
192 200
     goto errLabel;
193 201
   }
194 202
 
@@ -229,19 +237,21 @@ cmMsfRC_t cmMidiScoreFollowMain( cmCtx_t* ctx )
229 237
   printf("MIDI notes:%i Score Events:%i\n",mN,cmScoreEvtCount(scH));
230 238
 
231 239
   // create the output file
232
-  if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
240
+  if( cmFileOpen(&fH,matchRptOutFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
233 241
   {
234
-    rc = cmErrMsg(&err,kFailMsfRC,"Unable to create the file '%s'.",cmStringNullGuard(outFn));
242
+    rc = cmErrMsg(&err,kFailMsfRC,"Unable to create the file '%s'.",cmStringNullGuard(matchRptOutFn));
235 243
     goto errLabel;    
236 244
   }
237 245
 
238 246
   // allocate the graphics object
239
-  if( cmScoreMatchGraphicAlloc( ctx, &smgH, scoreFn, midiFn ) != kOkSmgRC )
247
+  if( cmScoreMatchGraphicAlloc( ctx, &smgH, scoreCsvFn, midiFn ) != kOkSmgRC )
240 248
   {
241 249
     rc = cmErrMsg(&err,kFailMsfRC,"Score Match Graphics allocation failed..");
242 250
     goto errLabel;    
243 251
   }
244 252
 
253
+  // write the match report output file header
254
+  _cmMsf_WriteMatchFileHeader(fH);
245 255
 
246 256
   // for each score follower callback record 
247 257
   for(i=0; i<sfr.rN; ++i)
@@ -267,12 +277,14 @@ cmMsfRC_t cmMidiScoreFollowMain( cmCtx_t* ctx )
267 277
   //cmMidiFilePrintMsgs( mfH, &ctx->rpt );
268 278
 
269 279
   // write the tracking match file as an SVG file.
270
-  cmScoreMatchGraphicWrite( smgH, svgFn );
280
+  cmScoreMatchGraphicWrite( smgH, matchSvgOutFn );
271 281
 
272 282
   // write a cmTimeLine file which contains markers at each bar position
273
-  cmScoreMatchGraphicGenTimeLineBars(smgH, tlBarFn, srate );
283
+  if( tlBarOutFn != NULL )
284
+    cmScoreMatchGraphicGenTimeLineBars(smgH, tlBarOutFn, srate );
274 285
 
275
-  cmScoreMatchGraphicUpdateMidiFromScore( ctx, smgH, newMidiFn );
286
+  if( midiOutFn != NULL )
287
+    cmScoreMatchGraphicUpdateMidiFromScore( ctx, smgH, midiOutFn );
276 288
 
277 289
 
278 290
  errLabel:
@@ -286,12 +298,12 @@ cmMsfRC_t cmMidiScoreFollowMain( cmCtx_t* ctx )
286 298
 
287 299
   cmCtxFree(&prCtx);
288 300
 
289
-  cmFsFreeFn(scoreFn);
290
-  cmFsFreeFn(midiFn);
291
-  cmFsFreeFn(outFn);
292
-  cmFsFreeFn(svgFn);
293
-  cmFsFreeFn(newMidiFn);
294
-  cmFsFreeFn(tlBarFn);
301
+  //cmFsFreeFn(scoreCsvFn);
302
+  //cmFsFreeFn(midiFn);
303
+  //cmFsFreeFn(matchRptOutFn);
304
+  //cmFsFreeFn(matchSvgOutFn);
305
+  //cmFsFreeFn(outMidiFn);
306
+  //cmFsFreeFn(tlBarFn);
295 307
   
296 308
   return rc;
297 309
 }

+ 9
- 1
app/cmMidiScoreFollow.h View File

@@ -15,7 +15,15 @@ extern "C" {
15 15
   typedef cmRC_t cmMsfRC_t;
16 16
   
17 17
 
18
-  cmMsfRC_t cmMidiScoreFollowMain( cmCtx_t* ctx );
18
+  cmMsfRC_t cmMidiScoreFollowMain(
19
+    cmCtx_t* ctx,
20
+    const cmChar_t* scoreCsvFn,      // score CSV file as generated from cmXScoreTest().
21
+    const cmChar_t* midiFn,          // MIDI file to track
22
+    const cmChar_t* matchRptOutFn,   // Score follow status report 
23
+    const cmChar_t* matchSvgOutFn,   // Score follow graphic report
24
+    const cmChar_t* midiOutFn,       // (optional) midiFn with apply sostenuto and velocities from the score to the MIDI file
25
+    const cmChar_t* tlBarOutFn       // (optional) bar positions sutiable for use in a cmTimeLine description file.
26
+                                  );
19 27
   
20 28
 #ifdef __cplusplus
21 29
 }

+ 63
- 26
app/cmScore.c View File

@@ -154,15 +154,16 @@ cmScEvtRef_t _cmScEvtRefArray[] =
154 154
 
155 155
 cmScEvtRef_t _cmScDynRefArray[] = 
156 156
 {
157
-  { 1, 0, "pppp"},
158
-  { 2, 0, "ppp" },
159
-  { 3, 0, "pp"  },
160
-  { 4, 0, "p"   },
161
-  { 5, 0, "mp"  },
162
-  { 6, 0, "mf"  },
163
-  { 7, 0, "f"   },
164
-  { 8, 0, "ff"  },
165
-  { 9, 0, "fff" },
157
+  { 1, 0, "silent"},
158
+  { 2, 0, "pppp"},
159
+  { 3, 0, "ppp" },
160
+  { 4, 0, "pp"  },
161
+  { 5, 0, "p"   },
162
+  { 6, 0, "mp"  },
163
+  { 7, 0, "mf"  },
164
+  { 8, 0, "f"   },
165
+  { 9, 0, "ff"  },
166
+  { 10, 0, "fff" },
166 167
   { kInvalidDynScId,0, "***" },
167 168
 };
168 169
 
@@ -361,6 +362,22 @@ void _cmScFreeMarkList( cmScMark_t* markList )
361 362
   }
362 363
 }
363 364
 
365
+void _cmScFreeSectList( cmSc_t* p )
366
+{
367
+  
368
+  // release the section linked list
369
+  cmScSect_t* sp = p->sectList;
370
+  cmScSect_t* np = NULL;
371
+  while(sp!=NULL)
372
+  {
373
+    np = sp->link;
374
+    cmMemFree(sp);
375
+    sp = np;
376
+  }
377
+  
378
+  p->sectList = NULL;
379
+}
380
+
364 381
 void _cmScFreeSetList( cmScSet_t* setList )
365 382
 {
366 383
   cmScSet_t* tp = setList;
@@ -412,6 +429,8 @@ cmScRC_t _cmScFinalize( cmSc_t* p )
412 429
     cmMemFree(p->sets);
413 430
   }
414 431
 
432
+  _cmScFreeSectList( p );
433
+
415 434
   _cmScFreeSetList(p->setList);
416 435
 
417 436
   _cmScFreeMarkList(p->markList);
@@ -1124,9 +1143,10 @@ cmScRC_t _cmScProcSets( cmSc_t* p )
1124 1143
 
1125 1144
 
1126 1145
 
1127
-cmScRC_t _cmScProcSections( cmSc_t* p, cmScSect_t* sectList )
1146
+cmScRC_t _cmScProcSections( cmSc_t* p )
1128 1147
 {
1129 1148
   cmScRC_t rc = kOkScRC;
1149
+  cmScSect_t* sectList = p->sectList;
1130 1150
   unsigned i;
1131 1151
 
1132 1152
   // count the sections
@@ -1171,16 +1191,9 @@ cmScRC_t _cmScProcSections( cmSc_t* p, cmScSect_t* sectList )
1171 1191
     }
1172 1192
   }
1173 1193
 
1174
-  // release the section linked list
1175
-  sp = sectList;
1176
-  cmScSect_t* np = NULL;
1177
-  while(sp!=NULL)
1178
-  {
1179
-    np = sp->link;
1180
-    cmMemFree(sp);
1181
-    sp = np;
1182
-  }
1183 1194
 
1195
+  _cmScFreeSectList(p);
1196
+  
1184 1197
   //_cmScPrintSets("Sets",p->setList );
1185 1198
 
1186 1199
   _cmScProcSets(p);
@@ -1592,7 +1605,7 @@ cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, doubl
1592 1605
   if((rc = _cmScInitLocArray(p)) != kOkScRC )
1593 1606
     goto errLabel;
1594 1607
 
1595
-  if((rc = _cmScProcSections(p,p->sectList)) != kOkScRC )
1608
+  if((rc = _cmScProcSections(p)) != kOkScRC )
1596 1609
     goto errLabel;
1597 1610
 
1598 1611
   if((rc = _cmScProcMarkers(p)) != kOkScRC )
@@ -2409,6 +2422,16 @@ cmScRC_t      cmScoreDecode( const void* msg, unsigned msgByteCnt, cmScMsg_t* m)
2409 2422
   return kOkScRC;
2410 2423
 }
2411 2424
 
2425
+const cmChar_t* _cmScoreSectionLabel( cmSc_t* p, const cmScoreEvt_t* r )
2426
+{
2427
+  unsigned i;
2428
+  for(i=0; i<p->sectCnt; ++i)
2429
+    if( p->sect[i].locPtr != NULL && p->sect[i].locPtr->index == r->locIdx && p->sect[i].begEvtIndex == r->index )
2430
+      return p->sect[i].label;
2431
+
2432
+  return NULL;
2433
+}
2434
+
2412 2435
 void _cmScorePrintHdr( cmRpt_t* rpt )
2413 2436
 {
2414 2437
   cmRptPrintf(rpt,"evnt  CSV             bar\n");
@@ -2416,12 +2439,13 @@ void _cmScorePrintHdr( cmRpt_t* rpt )
2416 2439
   cmRptPrintf(rpt,"----- ----- ----- --- --- ----- ----- --- -------\n");  
2417 2440
 }
2418 2441
 
2419
-void _cmScorePrintEvent( const cmScoreEvt_t* r, unsigned i, cmRpt_t* rpt )
2442
+void _cmScorePrintEvent( cmSc_t* p, const cmScoreEvt_t* r, unsigned i, cmRpt_t* rpt )
2420 2443
 {
2444
+  bool eolFl = true;
2421 2445
   switch(r->type)
2422 2446
   {
2423 2447
     case kBarEvtScId:
2424
-      cmRptPrintf(rpt,"%5i %5i %3i bar\n",
2448
+      cmRptPrintf(rpt,"%5i %5i %3i bar ",
2425 2449
         i,
2426 2450
         r->line,
2427 2451
         r->barNumb );
@@ -2429,7 +2453,7 @@ void _cmScorePrintEvent( const cmScoreEvt_t* r, unsigned i, cmRpt_t* rpt )
2429 2453
 
2430 2454
     case kPedalEvtScId:
2431 2455
     case kNonEvtScId:
2432
-      cmRptPrintf(rpt,"%5i %5i %5i %3i %3i %s %5s %c%c%c %s\n",
2456
+      cmRptPrintf(rpt,"%5i %5i %5i %3i %3i %s %5s   %c%c%c %-7s ",
2433 2457
         i,
2434 2458
         r->line,
2435 2459
         r->locIdx,
@@ -2440,12 +2464,20 @@ void _cmScorePrintEvent( const cmScoreEvt_t* r, unsigned i, cmRpt_t* rpt )
2440 2464
         cmIsFlag(r->flags,kEvenScFl)  ? 'e' : ' ',
2441 2465
         cmIsFlag(r->flags,kTempoScFl) ? 't' : ' ',
2442 2466
         cmIsFlag(r->flags,kDynScFl)   ? 'd' : ' ',
2467
+        //cmIsFlag(r->flags,kDynScFl)   ? 7-strlen(cmScDynIdToLabel(r->dynVal)) : 7,
2443 2468
         cmIsFlag(r->flags,kDynScFl)   ? cmScDynIdToLabel(r->dynVal) : "");          
2444 2469
       break;
2445 2470
 
2446 2471
     default:
2472
+      eolFl = false;
2447 2473
       break;
2448 2474
   }
2475
+
2476
+  const cmChar_t* sectionLabel;
2477
+  if((sectionLabel = _cmScoreSectionLabel(p,r)) != NULL )
2478
+    cmRptPrintf(rpt,"section:%s ",sectionLabel);
2479
+
2480
+  cmRptPrintf(rpt,"\n");
2449 2481
   
2450 2482
 }
2451 2483
 
@@ -2458,7 +2490,7 @@ void cmScorePrint( cmScH_t h, cmRpt_t* rpt )
2458 2490
   _cmScorePrintHdr(rpt);
2459 2491
   
2460 2492
   for(i=0; i<p->cnt; ++i)
2461
-    _cmScorePrintEvent(p->array+i,i,rpt);
2493
+    _cmScorePrintEvent(p,p->array+i,i,rpt);
2462 2494
 }
2463 2495
 
2464 2496
 
@@ -2483,7 +2515,7 @@ void cmScorePrintSets( cmScH_t h, cmRpt_t* rpt )
2483 2515
         
2484 2516
       _cmScorePrintHdr(rpt);
2485 2517
       for(j=0; j<s->eleCnt; ++j)
2486
-        _cmScorePrintEvent(*s->eleArray+j,j,rpt);
2518
+        _cmScorePrintEvent(p,*s->eleArray+j,j,rpt);
2487 2519
 
2488 2520
       cmRptPrintf(rpt,"Targets Section: ");
2489 2521
       for(j=0; j<s->sectCnt; ++j)
@@ -2709,7 +2741,7 @@ cmScRC_t      cmScoreFileFromMidi( cmCtx_t* ctx, const cmChar_t* midiFn, const c
2709 2741
 }
2710 2742
 
2711 2743
 
2712
-void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn )
2744
+void cmScoreReport( cmCtx_t* ctx, const cmChar_t* fn )
2713 2745
 {
2714 2746
   cmScH_t h = cmScNullHandle;
2715 2747
   if( cmScoreInitialize(ctx,&h,fn,0,NULL,0,NULL,NULL, cmSymTblNullHandle ) != kOkScRC )
@@ -2720,6 +2752,11 @@ void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn )
2720 2752
   cmScoreFinalize(&h);
2721 2753
 }
2722 2754
 
2755
+void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn )
2756
+{
2757
+}
2758
+
2759
+
2723 2760
 // 1. Fix absolute message time which was incorrect on original score file.
2724 2761
 // 2. 
2725 2762
 void cmScoreFix( cmCtx_t* ctx )

+ 5
- 1
app/cmScore.h View File

@@ -280,8 +280,12 @@ extern "C" {
280 280
   // Generate a new score file from a MIDI file.
281 281
   cmScRC_t      cmScoreFileFromMidi( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* scoreFn );
282 282
 
283
-  void          cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn );
283
+  // Print open the score file 'fn' and report the contents.  This function
284
+  // simply wraps calls to cmScoreInitialize() and cmScorePrint().
285
+  void          cmScoreReport( cmCtx_t* ctx, const cmChar_t* fn );
284 286
 
287
+  void          cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn );
288
+    
285 289
   //)
286 290
   
287 291
 #ifdef __cplusplus

+ 2
- 4
app/cmScoreMatchGraphic.c View File

@@ -538,7 +538,7 @@ cmSmgRC_t cmScoreMatchGraphicWrite( cmSmgH_t h, const cmChar_t* fn )
538 538
   svgHeight += 10; // add a right and lower border
539 539
   svgWidth  += 10;
540 540
 
541
-  cmFilePrintf(fH,"<!DOCTYPE html>\n<html>\n<head><link rel=\"stylesheet\" type=\"text/css\" href=\"score0.css\"></head><body>\n<svg width=\"%i\" height=\"%i\">\n",svgWidth,svgHeight);
541
+  cmFilePrintf(fH,"<!DOCTYPE html>\n<html>\n<head><link rel=\"stylesheet\" type=\"text/css\" href=\"cmScoreMatchGraphic.css\"></head><body>\n<svg width=\"%i\" height=\"%i\">\n",svgWidth,svgHeight);
542 542
 
543 543
   for(i=0; i<p->locN; ++i)
544 544
   {
@@ -690,7 +690,7 @@ cmSmgRC_t _cmScoreMatchGraphicInsertMidiMsg( cmSmg_t* p, cmMidiFileH_t mfH, bool
690 690
   cmMidiByte_t midi_vel     = pedalDnFl ? 64 :   0;
691 691
   cmMidiByte_t midi_ch      = 0;
692 692
 
693
-  printf("pedal:%s\n",pedalDnFl?"down":"up");
693
+  //printf("pedal:%s\n",pedalDnFl?"down":"up");
694 694
   
695 695
   // insert a pedal msg relative to the reference event
696 696
   if( cmMidiFileInsertMsg(mfH, m->uid, dtick_offset, midi_ch, kCtlMdId, kSostenutoCtlMdId, midi_vel ) != kOkMfRC )
@@ -798,8 +798,6 @@ cmSmgRC_t cmScoreMatchGraphicUpdateMidiFromScore( cmCtx_t* ctx, cmSmgH_t h, cons
798 798
     goto errLabel;
799 799
   }
800 800
 
801
-  cmMidiFilePrintMsgs(mfH, p->err.rpt );
802
-
803 801
 
804 802
  errLabel:
805 803
   cmMidiFileClose(&mfH);

+ 20
- 14
app/cmTimeLine.c View File

@@ -134,7 +134,7 @@ cmTlMidiFile_t*  _cmTlMidiFileObjPtr(  _cmTl_t* p, cmTlObj_t* op, bool errFl )
134 134
   if( op==NULL || op->typeId != kMidiFileTlId )
135 135
   {
136 136
     if( errFl && p != NULL)
137
-      cmErrMsg(&p->err,kTypeCvtFailTlRC,"A time line object type promotion failed.");
137
+      cmErrMsg(&p->err,kTypeCvtFailTlRC,"A time line object type promotion to MIDI file failed.");
138 138
     return NULL;
139 139
   }
140 140
 
@@ -147,7 +147,7 @@ cmTlMidiEvt_t*   _cmTlMidiEvtObjPtr(   _cmTl_t* p, cmTlObj_t* op, bool errFl )
147 147
   if( op==NULL || op->typeId != kMidiEvtTlId )
148 148
   {
149 149
     if( errFl && p != NULL )
150
-      cmErrMsg(&p->err,kTypeCvtFailTlRC,"A time line object type promotion failed.");
150
+      cmErrMsg(&p->err,kTypeCvtFailTlRC,"A time line object type promotion to MIDI event failed.");
151 151
     return NULL;
152 152
   }
153 153
 
@@ -173,7 +173,7 @@ cmTlAudioEvt_t*  _cmTlAudioEvtObjPtr(  _cmTl_t* p, cmTlObj_t* op, bool errFl )
173 173
   if( op==NULL || op->typeId != kAudioEvtTlId )
174 174
   {
175 175
     if( errFl && p != NULL)
176
-      cmErrMsg(&p->err,kTypeCvtFailTlRC,"A time line object type promotion failed.");
176
+      cmErrMsg(&p->err,kTypeCvtFailTlRC,"A time line object type promotion to audio event failed.");
177 177
     return NULL;
178 178
   }
179 179
   return (cmTlAudioEvt_t*)op;
@@ -186,7 +186,7 @@ cmTlMarker_t*    _cmTlMarkerObjPtr(    _cmTl_t* p, cmTlObj_t* op, bool errFl )
186 186
   if( op==NULL || op->typeId != kMarkerTlId )
187 187
   {
188 188
     if( errFl && p != NULL)
189
-      cmErrMsg(&p->err,kTypeCvtFailTlRC,"A time line object type promotion failed.");
189
+      cmErrMsg(&p->err,kTypeCvtFailTlRC,"A time line object type promotion to marker object failed.");
190 190
     return NULL;
191 191
   }
192 192
   return (cmTlMarker_t*)op;
@@ -1227,31 +1227,37 @@ _cmTlObj_t* _cmTimeLineObjAtTime( _cmTl_t* p, unsigned seqId, unsigned seqSmpIdx
1227 1227
   _cmTlObj_t* op      = p->seq[seqId].first;
1228 1228
   _cmTlObj_t* min_op  = NULL;
1229 1229
   unsigned    minDist = UINT_MAX;
1230
-
1230
+  bool        inFl    = false;
1231
+  
1232
+  // for each object in the requested sequence
1231 1233
   for(; op!=NULL; op=op->next)
1232 1234
     if( typeId==cmInvalidId || op->obj->typeId == typeId )
1233 1235
     {
1234
-      // if seqSmpIdx is inside this object - then return it as the solution
1236
+      bool in0Fl = false;
1237
+      
1238
+      // if seqSmpIdx is inside this object - then the returned object must contain seqSmpIdx
1239
+      // (but the ideal point to return is the one which contains seqSmpIdx and also has
1240
+      //  a begin or end point very close to seqSmpIdx - so this defer selecting an object
1241
+      // until all objects which may contain seqSmpIdx have been examined 
1235 1242
       if((op->obj->seqSmpIdx <= seqSmpIdx && seqSmpIdx < (op->obj->seqSmpIdx + op->obj->durSmpCnt)))
1236
-        return op;
1237
-
1243
+      {
1244
+        inFl  = true;   // the returned object must contain seqSmpIdx
1245
+        in0Fl = true;   // this object contains seqSmpIdx
1246
+      }
1247
+      
1238 1248
       // measure the distance from seqSmpIdx to the begin and end of this object
1239 1249
       unsigned d0 =  op->obj->seqSmpIdx                    < seqSmpIdx ? seqSmpIdx - op->obj->seqSmpIdx                    : op->obj->seqSmpIdx - seqSmpIdx;
1240 1250
       unsigned d1 =  op->obj->seqSmpIdx+op->obj->durSmpCnt < seqSmpIdx ? seqSmpIdx - op->obj->seqSmpIdx+op->obj->durSmpCnt : op->obj->seqSmpIdx+op->obj->durSmpCnt - seqSmpIdx;
1241 1251
 
1242
-      // d0 and d1 should decrease as the cur object approaches seqSmpIdx
1243
-      // If they do not then the search is over - return the closest point.
1244
-      if( d0>minDist && d1>minDist)
1245
-        break;
1246 1252
 
1247 1253
       // track the min dist and the assoc'd obj
1248
-      if( d0 < minDist )
1254
+      if( d0 < minDist && (inFl==false || inFl==in0Fl))
1249 1255
       {
1250 1256
         minDist = d0;
1251 1257
         min_op  = op;
1252 1258
       }
1253 1259
 
1254
-      if( d1 < minDist )
1260
+      if( d1 < minDist && (inFl==false || inFl==in0Fl))
1255 1261
       {
1256 1262
         minDist = d1;
1257 1263
         min_op  = op;

+ 758
- 257
app/cmXScore.c
File diff suppressed because it is too large
View File


+ 12
- 19
app/cmXScore.h View File

@@ -18,7 +18,9 @@ extern "C" {
18 18
     kPedalStateErrorXsRc,
19 19
     kMidiFailXsRC,
20 20
     kFileFailXsRC,
21
-    kSvgFailXsRC
21
+    kSvgFailXsRC,
22
+    kOverlapWarnXsRC,
23
+    kZeroLengthEventXsRC
22 24
   };
23 25
 
24 26
   typedef cmRC_t     cmXsRC_t;
@@ -41,32 +43,23 @@ extern "C" {
41 43
   //
42 44
   // M-x load-file ~/src/emacs/proc_music_xml.el
43 45
   //
44
-  // 3) How to assigned dynamic markings (they are not attached to notes). (from MIDI file?)
45
-  // 4) Tempo syntax is inconsistent (only a problem in full part2 score)     
46
-  // 5) Heel is being parsed but not used. 
47
-  // 6) Sostenuto pedal events are not being parsed because they are not pedal events.
48
-  // 7) What is a 'pedal-change' event vs. a 'pedal-stop' event.
49
-  // 8) Verify the colors. (done)
50
-  // 9) Remove blank bars at end (done in xml - do in score)
51
-  //10) Need to assign section targets (always default to next section)
52
-  //11) Mark tied notes for skip. (done)
53
-  //12) Determine note off locations based on ties and slurs - defer 'pedal' to player
54
-  //13) Check that the measures are given in sorted order.
55
-  //14) Current implementation assumes meter changes only occur at measure boundaries.
56
-  //15) Score Fixes: Add meter to bar 1, fix time errors (shown in voice report)
57
-  //16) The order of notes is now correct (4/6/16) after applying
58
-  //    the grace note ordering changed specified in 'score_print_mk_edit.txt',
59
-  //    via cmXScoreReorder() however the ticks are now incorrect - fix them.
60
-  
61
-  cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn );
46
+
47
+  // Initialize an cmXScore object from a Sibelius generated MusicXML file.
48
+  // Optionally include an 'edit' file to attach additional score information.
49
+  // Note that the 'edit' file is created by marking up a file created via
50
+  // cmXScoreReport().
51
+  cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn );
62 52
   cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
63 53
 
54
+  
64 55
   bool     cmXScoreIsValid( cmXsH_t h );
65 56
 
66 57
   cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn );
67 58
 
68 59
   void     cmXScoreReport( cmXsH_t h, cmRpt_t* rpt, bool sortFl );
69 60
 
61
+  cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn );
62
+
70 63
   // Generate the CSV file suitable for use by cmScore.
71 64
   cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn );
72 65
   

+ 203
- 4
cmMidiFile.c View File

@@ -8,8 +8,11 @@
8 8
 #include "cmMallocDebug.h"
9 9
 #include "cmLinkedHeap.h"
10 10
 #include "cmTime.h"
11
+#include "cmText.h"
11 12
 #include "cmMidi.h"
12 13
 #include "cmMidiFile.h"
14
+#include "cmSvgWriter.h"
15
+
13 16
 
14 17
 #ifdef cmBIG_ENDIAN
15 18
 #define mfSwap16(v)  (v)
@@ -256,7 +259,7 @@ cmMfRC_t _cmMidiFileReadChannelMsg( _cmMidiFile_t* mfp, cmMidiByte_t* rsPtr, cmM
256 259
   unsigned byteN = cmMidiStatusToByteCount(tmp->status);
257 260
   
258 261
   if( byteN==kInvalidMidiByte || byteN > 2 )
259
-    return cmErrMsg(&mfp->err,kInvalidStatusMfRC,"Invalid status:0x%x %i.",tmp->status,tmp->status);
262
+    return cmErrMsg(&mfp->err,kInvalidStatusMfRC,"Invalid status:0x%x %i byte cnt:%i.",tmp->status,tmp->status,byteN);
260 263
 
261 264
   unsigned i;
262 265
   for(i=useRsFl; i<byteN; ++i)
@@ -339,7 +342,7 @@ cmMfRC_t _cmMidiFileReadTrack( _cmMidiFile_t* mfp, unsigned short trkIdx )
339 342
     if((rc = _cmMidiFileRead8(mfp,&status)) != kOkMfRC )
340 343
       return rc;
341 344
 
342
-    //printf("st:%i 0x%x\n",status,status);
345
+    //printf("%5i st:%i 0x%x\n",dticks,status,status);
343 346
 
344 347
     // append a track msg
345 348
     if((rc = _cmMidiFileAppendTrackMsg( mfp, trkIdx, dticks, status, &tmp )) != kOkMfRC )
@@ -677,8 +680,11 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hp, const char* fn )
677 680
     rc = cmErrMsg(&p->err,kFileFailMfRC,"MIDI file close failed.");
678 681
 
679 682
   if( rc != kOkMfRC )
683
+  {
680 684
     _cmMidiFileClose(p);
681
-
685
+    hp->h = NULL;
686
+  }
687
+  
682 688
   return rc;
683 689
 }
684 690
 
@@ -971,12 +977,75 @@ cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tm
971 977
   return rc;
972 978
 }
973 979
 
980
+cmMfRC_t _cmMidiFileInsertEotMsg( _cmMidiFile_t* p, unsigned trkIdx )
981
+{
982
+  _cmMidiTrack_t* trk = p->trkV + trkIdx;
983
+  cmMidiTrackMsg_t* m0 = NULL;
984
+  cmMidiTrackMsg_t* m = trk->base;
985
+
986
+  // locate the current EOT msg on this track
987
+  for(; m!=NULL; m=m->link)
988
+  {
989
+    if( m->status == kMetaStId && m->metaId == kEndOfTrkMdId )
990
+    {
991
+      // If this EOT msg is the last msg in the track  ...
992
+      if( m->link == NULL )
993
+      {
994
+        assert( m == trk->last );
995
+        return kOkMfRC; // ... then there is nothing else to do
996
+      }
997
+
998
+      // If this EOT msg is not the last in the track ...
999
+      if( m0 != NULL )
1000
+        m0->link = m->link;  // ... then unlink it
1001
+
1002
+      break;
1003
+    }
1004
+
1005
+    m0 = m;
1006
+  }
1007
+
1008
+  // if we get here then the last msg in the track was not an EOT msg
1009
+
1010
+  // if there was no previously allocated EOT msg
1011
+  if( m == NULL )
1012
+  {
1013
+    m   = _cmMidiFileAllocMsg(p, trkIdx, 1, kMetaStId );
1014
+    m->metaId = kEndOfTrkMdId;
1015
+    trk->cnt += 1;
1016
+    
1017
+  }
1018
+
1019
+  // link an EOT msg as the last msg on the track
1020
+
1021
+  // if the track is currently empty
1022
+  if( m0 == NULL )
1023
+  {
1024
+    trk->base = m;
1025
+    trk->last = m;
1026
+  }
1027
+  else // link the msg as the last on on the track
1028
+  {
1029
+    assert( m0 == trk->last);
1030
+    m0->link = m;
1031
+    m->link  = NULL;
1032
+    trk->last = m;
1033
+  }
1034
+
1035
+  return kOkMfRC;
1036
+
1037
+}
1038
+
974 1039
 cmMfRC_t _cmMidiFileWriteTrack( _cmMidiFile_t* mfp, unsigned trkIdx )
975 1040
 {
976 1041
   cmMfRC_t          rc        = kOkMfRC;
977 1042
   cmMidiTrackMsg_t* tmp       = mfp->trkV[trkIdx].base;
978 1043
   cmMidiByte_t      runStatus = 0;
979 1044
 
1045
+  // be sure there is a EOT msg at the end of this track
1046
+  if((rc = _cmMidiFileInsertEotMsg(mfp, trkIdx )) != kOkMfRC )
1047
+    return rc;
1048
+  
980 1049
   for(; tmp != NULL; tmp=tmp->link)
981 1050
   {
982 1051
     // write the msg tick count
@@ -1379,8 +1448,11 @@ cmMfRC_t  cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMi
1379 1448
     assert( m1->atick >= m->atick );
1380 1449
     m1->dtick = m1->atick - m->atick;
1381 1450
   }
1382
-  
1451
+
1452
+  p->trkV[trkIdx].cnt += 1;  
1383 1453
   p->msgVDirtyFl = true;
1454
+
1455
+
1384 1456
   
1385 1457
   return kOkMfRC;
1386 1458
    
@@ -1402,6 +1474,8 @@ cmMfRC_t  cmMidiFileInsertTrackChMsg( cmMidiFileH_t h, unsigned trkIdx, unsigned
1402 1474
   m.status     = status & 0xf0;
1403 1475
   m.byteCnt    = sizeof(cm);
1404 1476
   m.u.chMsgPtr = &cm;
1477
+
1478
+  assert( m.status >= kNoteOffMdId && m.status <= kPbendMdId );
1405 1479
   
1406 1480
   return cmMidiFileInsertTrackMsg(h,trkIdx,&m);
1407 1481
 }
@@ -1836,6 +1910,38 @@ void cmMidiFilePrintTracks( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt )
1836 1910
 void cmMidiFileTestPrint( void* printDataPtr, const char* fmt, va_list vl )
1837 1911
 { vprintf(fmt,vl); }
1838 1912
 
1913
+cmMidiFileDensity_t* cmMidiFileNoteDensity( cmMidiFileH_t h, unsigned* cntRef )
1914
+{
1915
+  int                      msgN = cmMidiFileMsgCount(h);
1916
+  const cmMidiTrackMsg_t** msgs = cmMidiFileMsgArray(h);
1917
+  cmMidiFileDensity_t*     dV   = cmMemAllocZ(cmMidiFileDensity_t,msgN);
1918
+  
1919
+  int i,j,k;
1920
+  for(i=0,k=0; i<msgN && k<msgN; ++i)
1921
+    if( msgs[i]->status == kNoteOnMdId && msgs[i]->u.chMsgPtr->d1 > 0 )
1922
+    {
1923
+      dV[k].uid    = msgs[i]->uid;
1924
+      dV[k].amicro = msgs[i]->amicro;
1925
+      
1926
+      for(j=i; j>=0; --j)
1927
+      {
1928
+        if( msgs[i]->amicro - msgs[j]->amicro > 1000000 )
1929
+          break;
1930
+
1931
+        dV[k].density += 1;
1932
+      }
1933
+      
1934
+      k += 1;
1935
+      
1936
+    }
1937
+
1938
+  if( cntRef != NULL )
1939
+    *cntRef = k;
1940
+
1941
+  return dV;
1942
+}
1943
+
1944
+
1839 1945
 cmMfRC_t cmMidiFileGenPlotFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* outFn )
1840 1946
 {
1841 1947
   cmMfRC_t                 rc  = kOkMfRC;
@@ -1872,6 +1978,99 @@ cmMfRC_t cmMidiFileGenPlotFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmCh
1872 1978
   return rc;
1873 1979
 }
1874 1980
 
1981
+cmMfRC_t cmMidiFileGenSvgFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* outSvgFn, const cmChar_t* cssFn )
1982
+{
1983
+  cmMfRC_t                 rc   = kOkMfRC;
1984
+  cmSvgH_t                 svgH = cmSvgNullHandle;
1985
+  cmMidiFileH_t            mfH  = cmMidiFileNullHandle;
1986
+  unsigned                 msgN = 0;
1987
+  const cmMidiTrackMsg_t**       msgs = NULL;
1988
+  unsigned noteHeight = 10;
1989
+  double micros_per_sec = 1000.0;
1990
+  unsigned i;
1991
+
1992
+  if((rc = cmMidiFileOpen(ctx,&mfH,midiFn)) != kOkMfRC )
1993
+  {
1994
+    rc = cmErrMsg(&ctx->err,rc,"Unable to open the MIDI file '%s'.",cmStringNullGuard(midiFn));
1995
+    goto errLabel;
1996
+  }
1997
+
1998
+ cmMidiFileCalcNoteDurations( mfH );
1999
+
2000
+  msgN = cmMidiFileMsgCount(mfH);
2001
+  msgs = cmMidiFileMsgArray(mfH);
2002
+
2003
+  
2004
+  if( cmSvgWriterAlloc(ctx,&svgH) != kOkSvgRC )
2005
+  {
2006
+    rc = cmErrMsg(&ctx->err,kSvgFailMfRC,"Unable to create the MIDI SVG output file '%s'.",cmStringNullGuard(outSvgFn));
2007
+    goto errLabel;
2008
+  }
2009
+
2010
+
2011
+  for(i=0; i<msgN && rc==kOkMfRC; ++i)    
2012
+    if( msgs[i]->status == kNoteOnMdId && msgs[i]->u.chMsgPtr->d1 > 0 )
2013
+    {
2014
+      const cmMidiTrackMsg_t* m = msgs[i];
2015
+
2016
+      
2017
+      if( cmSvgWriterRect(svgH, m->amicro/micros_per_sec, m->u.chMsgPtr->d0 * noteHeight,  m->u.chMsgPtr->durMicros/micros_per_sec,  noteHeight-1, "note" ) != kOkSvgRC )
2018
+        rc = kSvgFailMfRC;
2019
+
2020
+      const cmChar_t* t0 = cmMidiToSciPitch(m->u.chMsgPtr->d0,NULL,0);
2021
+
2022
+      if( cmSvgWriterText(svgH, (m->amicro + (m->u.chMsgPtr->durMicros/2)) / micros_per_sec, m->u.chMsgPtr->d0 * noteHeight, t0, "text" ) != kOkSvgRC )
2023
+        rc = kSvgFailMfRC;
2024
+
2025
+    }
2026
+
2027
+  if( rc != kOkMfRC )
2028
+  {
2029
+    cmErrMsg(&ctx->err,rc,"SVG Shape insertion failed.");
2030
+    goto errLabel;
2031
+  }
2032
+  
2033
+  unsigned             dN = 0;
2034
+  cmMidiFileDensity_t* dV = cmMidiFileNoteDensity( mfH, &dN );
2035
+  double               t0 = 0;
2036
+  double               y0 = 64.0;
2037
+  cmChar_t*            tx = NULL;
2038
+  
2039
+  for(i=0; i<dN; ++i)
2040
+  {
2041
+    const cmMidiTrackMsg_t* m;
2042
+
2043
+    if((m = _cmMidiFileUidToMsg( _cmMidiFileHandleToPtr(mfH), dV[i].uid )) == NULL )
2044
+      rc = cmErrMsg(&ctx->err,kUidNotFoundMfRC,"The MIDI msg form UID:%i was not found.",dV[i].uid);
2045
+    else
2046
+    {
2047
+      double t1 = m->amicro / micros_per_sec;
2048
+      double y1 = dV[i].density * noteHeight;
2049
+      
2050
+      cmSvgWriterLine(svgH, t0, y0, t1, y1, "density" );
2051
+      cmSvgWriterText(svgH, t1, y1, tx = cmTsPrintfP(tx,"%i",dV[i].density),"dtext");
2052
+
2053
+      t0 = t1;
2054
+      y0 = y1;
2055
+
2056
+    }
2057
+  }
2058
+
2059
+  cmMemFree(dV);
2060
+  cmMemFree(tx);
2061
+  
2062
+  if( rc == kOkMfRC )
2063
+    if( cmSvgWriterWrite(svgH,cssFn,outSvgFn) != kOkSvgRC )
2064
+      rc = cmErrMsg(&ctx->err,kSvgFailMfRC,"SVG file write to '%s' failed.",cmStringNullGuard(outSvgFn));
2065
+
2066
+
2067
+ errLabel:
2068
+  cmMidiFileClose(&mfH);
2069
+  cmSvgWriterFree(&svgH);
2070
+  
2071
+  return rc;
2072
+}
2073
+
1875 2074
 void cmMidiFilePrintControlNumbers( cmCtx_t* ctx, const char* fn )
1876 2075
 {
1877 2076
   cmMidiFileH_t h = cmMidiFileNullHandle;

+ 19
- 2
cmMidiFile.h View File

@@ -117,7 +117,8 @@ extern "C" {
117 117
     kLargeDeltaTickMfRC, // 12 (a large delta tick value was filtered)
118 118
     kUidNotFoundMfRC,    // 13
119 119
     kUidNotANoteMsgMfRC, // 14
120
-    kInvalidTrkIndexMfRC // 15
120
+    kInvalidTrkIndexMfRC,// 15
121
+    kSvgFailMfRC         // 16
121 122
   };
122 123
 
123 124
   extern cmMidiFileH_t cmMidiFileNullHandle;
@@ -212,11 +213,27 @@ extern "C" {
212 213
 
213 214
   void                  cmMidiFilePrintMsgs( cmMidiFileH_t h, cmRpt_t* rpt );
214 215
   void                  cmMidiFilePrintTrack( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt );
215
-  void                  cmMidiFileTest( const char* fn, cmCtx_t* ctx );
216
+
217
+  typedef struct
218
+  {
219
+    unsigned           uid;
220
+    unsigned long long amicro;
221
+    unsigned           density;
222
+    
223
+  } cmMidiFileDensity_t;
224
+
225
+  // Generate the note onset density measure for each note in the MIDI file.
226
+  // Delete the returned memory with a call to cmMemFree().
227
+  cmMidiFileDensity_t* cmMidiFileNoteDensity( cmMidiFileH_t h, unsigned* cntRef );
216 228
 
217 229
   // Generate a piano-roll plot description file which can be displayed with cmXScore.m
218 230
   cmMfRC_t             cmMidiFileGenPlotFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* outFn );
219 231
 
232
+  cmMfRC_t             cmMidiFileGenSvgFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* outSvgFn, const cmChar_t* cssFn );
233
+
234
+  void                  cmMidiFileTest( const char* fn, cmCtx_t* ctx );
235
+
236
+
220 237
   
221 238
   //)
222 239
   

+ 71
- 14
cmSvgWriter.c View File

@@ -167,6 +167,32 @@ void _cmSvgSize( cmSvg_t* p, double* widthRef, double* heightRef )
167 167
   *heightRef = max_y - min_y;
168 168
 }
169 169
 
170
+void _cmSvgWriterFlipY( cmSvg_t* p, unsigned height )
171
+{
172
+  cmSvgEle_t* e = p->elist;
173
+  for(; e!=NULL; e=e->link)
174
+  {
175
+    e->y0 = (-e->y0) + height;
176
+    e->y1 = (-e->y1) + height;
177
+
178
+    if( e->id == kRectSvgId )
179
+    {
180
+      double t = e->y1;
181
+      e->y1 = e->y0;
182
+      e->y0 = t;
183
+    }
184
+    
185
+  }
186
+}
187
+
188
+/*
189
+   "<script type=\"text/javascript\" src=\"svg-pan-zoom.min.js\"></script>\n"
190
+    "<script>\n"
191
+    " var panZoom = null;\n"
192
+    "  function doOnLoad() { panZoom = svgPanZoom(document.querySelector('#mysvg'), { controlIconsEnabled:true } ) }\n"
193
+    "</script>\n"
194
+ 
195
+ */
170 196
 
171 197
 cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h,  const cmChar_t* cssFn, const cmChar_t* outFn )
172 198
 {
@@ -176,15 +202,29 @@ cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h,  const cmChar_t* cssFn, const cmChar_t*
176 202
   double      svgHeight = 0;
177 203
   cmSvgEle_t* e         = p->elist;
178 204
   cmFileH_t   fH        = cmFileNullHandle;
205
+  cmChar_t*   s0        = NULL;
206
+  cmChar_t*   s1        = NULL;
207
+
208
+  cmChar_t hdr[] =
209
+    "<!DOCTYPE html>\n"
210
+    "<html>\n"
211
+    "<head>\n"
212
+    "<meta charset=\"utf-8\">\n"    
213
+    "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\">\n"
214
+    "</head>\n"
215
+    "<body onload=\"doOnLoad()\">\n"
216
+    "<svg id=\"mysvg\" width=\"%f\" height=\"%f\">\n";
217
+
218
+ 
179 219
   
180 220
   _cmSvgSize(p, &svgWidth, &svgHeight );
181
-  
182
-  if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC )
183
-    return cmErrMsg(&p->err,kFileFailSvgRC,"SVG file create failed for '%s'.",cmStringNullGuard(outFn));
184 221
 
185
-  if( cmFilePrintf(fH,"<!DOCTYPE html>\n<html>\n<head><link rel=\"stylesheet\" type=\"text/css\" href=\"%s\"></head><body>\n<svg width=\"%f\" height=\"%f\">\n",svgWidth,svgHeight,cssFn) != kOkFileRC )
222
+  _cmSvgWriterFlipY( p, svgHeight );
223
+
224
+  // print the file header
225
+  if( (s0 = cmTsPrintfP(s0,hdr,cssFn,svgWidth,svgHeight)) == NULL )
186 226
   {
187
-    rc = cmErrMsg(&p->err,kFileFailSvgRC,"File prefix write failed.");
227
+    rc = cmErrMsg(&p->err,kPrintFailSvgRC,"File prefix write failed.");
188 228
     goto errLabel;
189 229
   }
190 230
 
@@ -193,18 +233,18 @@ cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h,  const cmChar_t* cssFn, const cmChar_t*
193 233
     switch( e->id )
194 234
     {
195 235
       case kRectSvgId:
196
-        if( cmFilePrintf(fH,"<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" class=\"%s\"/>\n",e->x0,e->y0,e->x1-e->x0,e->y1-e->y0,e->cssClass) != kOkFileRC )
197
-          rc = kFileFailSvgRC;
236
+        if( (s1 = cmTsPrintfP(s1,"<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" class=\"%s\"/>\n",e->x0,e->y0,e->x1-e->x0,e->y1-e->y0,e->cssClass)) == NULL )
237
+          rc = kPrintFailSvgRC;
198 238
         break;
199 239
         
200 240
       case kLineSvgId:
201
-        if( cmFilePrintf(fH,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" class=\"%s\"/>\n",e->x0,e->y0,e->x1,e->y1,e->cssClass) != kOkFileRC )
202
-          rc = kFileFailSvgRC;
241
+        if( (s1 = cmTsPrintfP(s1,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" class=\"%s\"/>\n",e->x0,e->y0,e->x1,e->y1,e->cssClass)) == NULL )
242
+          rc = kPrintFailSvgRC;
203 243
         break;
204 244
         
205 245
       case kTextSvgId:
206
-        if( cmFilePrintf(fH,"<text x=\"%f\" y=\"%f\" class=\"%s\">%s</text>\n",e->x0,e->y0,e->cssClass,e->text) != kOkFileRC )
207
-          rc = kFileFailSvgRC;        
246
+        if( (s1 = cmTsPrintfP(s1,"<text x=\"%f\" y=\"%f\" class=\"%s\">%s</text>\n",e->x0,e->y0,e->cssClass,e->text)) == NULL )
247
+          rc = kPrintFailSvgRC;        
208 248
         break;
209 249
         
210 250
       default:
@@ -214,21 +254,38 @@ cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h,  const cmChar_t* cssFn, const cmChar_t*
214 254
 
215 255
     if( rc != kOkSvgRC )
216 256
     {
217
-      rc = cmErrMsg(&p->err,kFileFailSvgRC,"Element write failed.");
257
+      rc = cmErrMsg(&p->err,kPrintFailSvgRC,"Element write failed.");
218 258
       break;
219 259
     }
260
+
261
+    s0 = cmTextAppendSS(s0,s1);
262
+    
220 263
   }
221 264
   
222
-  if( cmFilePrint(fH,"</svg>\n</body>\n</html>\n") != kOkFileRC )
265
+  if( (s1 = cmTsPrintfP(s1,"</svg>\n</body>\n</html>\n")) == NULL )
223 266
   {
224
-    rc = cmErrMsg(&p->err,kFileFailSvgRC,"File suffix write failed.");
267
+    rc = cmErrMsg(&p->err,kPrintFailSvgRC,"File suffix write failed.");
225 268
     goto errLabel;
226 269
   }
227 270
 
271
+  if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC )
272
+  {
273
+    rc = cmErrMsg(&p->err,kFileFailSvgRC,"SVG file create failed for '%s'.",cmStringNullGuard(outFn));
274
+    goto errLabel;
275
+  }
276
+  
277
+  if( cmFilePrint(fH,s0 = cmTextAppendSS(s0,s1)) != kOkFileRC )
278
+  {    
279
+    rc = cmErrMsg(&p->err,kFileFailSvgRC,"File write failed.");
280
+    goto errLabel;
281
+  }
228 282
 
229 283
  errLabel:
230 284
   cmFileClose(&fH);
231 285
 
286
+  cmMemFree(s0);
287
+  cmMemFree(s1);
288
+  
232 289
   return rc;
233 290
 }
234 291
 

+ 6
- 1
cmSvgWriter.h View File

@@ -9,6 +9,7 @@ enum
9 9
 {
10 10
   kOkSvgRC = cmOkRC,
11 11
   kFileFailSvgRC,
12
+  kPrintFailSvgRC,
12 13
   kLHeapFailSvgRC
13 14
 };
14 15
 
@@ -21,10 +22,14 @@ enum
21 22
   cmSvgRC_t cmSvgWriterFree(    cmSvgH_t* hp );
22 23
   bool      cmSvgWriterIsValid( cmSvgH_t h );
23 24
   
24
-  cmSvgRC_t cmSvgWriterRect( cmSvgH_t h, double  x, double y,  double ww,  double hh,  const cmChar_t* cssClassLabel );
25
+  cmSvgRC_t cmSvgWriterRect( cmSvgH_t h, double  x, double y,  double ww, double hh, const cmChar_t* cssClassLabel );
25 26
   cmSvgRC_t cmSvgWriterLine( cmSvgH_t h, double x0, double y0, double x1, double y1, const cmChar_t* cssClassLabel );
26 27
   cmSvgRC_t cmSvgWriterText( cmSvgH_t h, double  x, double y,  const cmChar_t* text, const cmChar_t* cssClassLabel );
27 28
 
29
+  // Write the SVG file.  Note that header on this file references the CSS file 'cssFn'
30
+  // and the Javascript file svg-pan-zoom.min.js from https://github.com/ariutta/svg-pan-zoom.
31
+  // Both the CSS file and svg-pan-zoom.min.js should therefore be in the same directory
32
+  // as the output HTML file.
28 33
   cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h, const cmChar_t* cssFn, const cmChar_t* outFn );
29 34
   
30 35
 #ifdef __cplusplus

+ 1
- 1
dsp/cmDspKr.c View File

@@ -657,7 +657,7 @@ cmDspRC_t _cmDspTimeLineRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_
657 657
           cmTlObj_t* op;
658 658
           if((op = cmTimeLineIdToObj(p->tlH, cmInvalidId, markerId )) != NULL )
659 659
           {
660
-            assert(op->typeId == kMarkerTlId);
660
+            assert(op->typeId == kMarkerTlId || op->typeId == kMidiEvtTlId );
661 661
 
662 662
             p->afIdx = op->begSmpIdx;
663 663
 

+ 1
- 1
dsp/cmDspPgmKrChain.c View File

@@ -201,7 +201,7 @@ void _cmDspSys_TlXformChain( cmDspSysH_t h, cmDspTlXform_t* c,  unsigned preGrpS
201 201
   cmDspInst_t* max_lwr_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Max Lwr"),          0.0, -1.0, 5.0, 3.0);
202 202
   cmDspInst_t* min_off_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Min Off"),          0.0, 50.0, 0.1, 30.0);
203 203
   cmDspInst_t* max_off_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Max Off"),          0.0, 50.0, 0.1, 30.0);
204
-  cmDspInst_t* min_wet_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Min Wet"),          0.0,  1.0, 0.01, 1.0);
204
+  cmDspInst_t* min_wet_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Min Wet"),          0.0,  1.0, 0.01, 0.0);
205 205
   cmDspInst_t* max_wet_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Max Wet"),          0.0,  1.0, 0.01, 1.0);
206 206
 
207 207
 

Loading…
Cancel
Save