Переглянути джерело

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

master
kevin larke 7 роки тому
джерело
коміт
e426f5dbd1
15 змінених файлів з 1210 додано та 371 видалено
  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 Переглянути файл

1
 Makefile.in
1
 Makefile.in
2
+.DS_Store
3
+

+ 38
- 26
app/cmMidiScoreFollow.c Переглянути файл

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
 // Write one scScoreMatcherResult_t record to the file fH.
123
 // Write one scScoreMatcherResult_t record to the file fH.
116
 unsigned _cmMsf_WriteMatchFileLine( cmFileH_t fH, cmScH_t scH, const cmScMatcherResult_t* r )
124
 unsigned _cmMsf_WriteMatchFileLine( cmFileH_t fH, cmScH_t scH, const cmScMatcherResult_t* r )
117
 {
125
 {
130
     cmMidiToSciPitch(e->pitch,buf,5);
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
     loc==NULL ? 0 : loc->barNumb,              // score evt bar
142
     loc==NULL ? 0 : loc->barNumb,              // score evt bar
135
     scUid,                                     // score event uuid
143
     scUid,                                     // score event uuid
136
     buf,                                       // score event pitch
144
     buf,                                       // score event pitch
147
   r->rV[r->rN++] = *rp;
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
   double                   srate    = 96000.0;
169
   double                   srate    = 96000.0;
162
   cmScMatcher*             smp      = NULL;  
170
   cmScMatcher*             smp      = NULL;  
163
   cmScH_t                  scH      = cmScNullHandle;
171
   cmScH_t                  scH      = cmScNullHandle;
179
   cmCtx* prCtx   = cmCtxAlloc(NULL, err.rpt, cmLHeapNullHandle, cmSymTblNullHandle );
187
   cmCtx* prCtx   = cmCtxAlloc(NULL, err.rpt, cmLHeapNullHandle, cmSymTblNullHandle );
180
   
188
   
181
   // initialize the score
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
     goto errLabel;
193
     goto errLabel;
186
   }
194
   }
187
 
195
 
188
   // setup the callback record
196
   // setup the callback record
189
   if((sfr.rAllocN  = cmScoreEvtCount( scH )*2) == 0)
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
     goto errLabel;
200
     goto errLabel;
193
   }
201
   }
194
 
202
 
229
   printf("MIDI notes:%i Score Events:%i\n",mN,cmScoreEvtCount(scH));
237
   printf("MIDI notes:%i Score Events:%i\n",mN,cmScoreEvtCount(scH));
230
 
238
 
231
   // create the output file
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
     goto errLabel;    
243
     goto errLabel;    
236
   }
244
   }
237
 
245
 
238
   // allocate the graphics object
246
   // allocate the graphics object
239
-  if( cmScoreMatchGraphicAlloc( ctx, &smgH, scoreFn, midiFn ) != kOkSmgRC )
247
+  if( cmScoreMatchGraphicAlloc( ctx, &smgH, scoreCsvFn, midiFn ) != kOkSmgRC )
240
   {
248
   {
241
     rc = cmErrMsg(&err,kFailMsfRC,"Score Match Graphics allocation failed..");
249
     rc = cmErrMsg(&err,kFailMsfRC,"Score Match Graphics allocation failed..");
242
     goto errLabel;    
250
     goto errLabel;    
243
   }
251
   }
244
 
252
 
253
+  // write the match report output file header
254
+  _cmMsf_WriteMatchFileHeader(fH);
245
 
255
 
246
   // for each score follower callback record 
256
   // for each score follower callback record 
247
   for(i=0; i<sfr.rN; ++i)
257
   for(i=0; i<sfr.rN; ++i)
267
   //cmMidiFilePrintMsgs( mfH, &ctx->rpt );
277
   //cmMidiFilePrintMsgs( mfH, &ctx->rpt );
268
 
278
 
269
   // write the tracking match file as an SVG file.
279
   // write the tracking match file as an SVG file.
270
-  cmScoreMatchGraphicWrite( smgH, svgFn );
280
+  cmScoreMatchGraphicWrite( smgH, matchSvgOutFn );
271
 
281
 
272
   // write a cmTimeLine file which contains markers at each bar position
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
  errLabel:
290
  errLabel:
286
 
298
 
287
   cmCtxFree(&prCtx);
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
   return rc;
308
   return rc;
297
 }
309
 }

+ 9
- 1
app/cmMidiScoreFollow.h Переглянути файл

15
   typedef cmRC_t cmMsfRC_t;
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
 #ifdef __cplusplus
28
 #ifdef __cplusplus
21
 }
29
 }

+ 63
- 26
app/cmScore.c Переглянути файл

154
 
154
 
155
 cmScEvtRef_t _cmScDynRefArray[] = 
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
   { kInvalidDynScId,0, "***" },
167
   { kInvalidDynScId,0, "***" },
167
 };
168
 };
168
 
169
 
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
 void _cmScFreeSetList( cmScSet_t* setList )
381
 void _cmScFreeSetList( cmScSet_t* setList )
365
 {
382
 {
366
   cmScSet_t* tp = setList;
383
   cmScSet_t* tp = setList;
412
     cmMemFree(p->sets);
429
     cmMemFree(p->sets);
413
   }
430
   }
414
 
431
 
432
+  _cmScFreeSectList( p );
433
+
415
   _cmScFreeSetList(p->setList);
434
   _cmScFreeSetList(p->setList);
416
 
435
 
417
   _cmScFreeMarkList(p->markList);
436
   _cmScFreeMarkList(p->markList);
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
   cmScRC_t rc = kOkScRC;
1148
   cmScRC_t rc = kOkScRC;
1149
+  cmScSect_t* sectList = p->sectList;
1130
   unsigned i;
1150
   unsigned i;
1131
 
1151
 
1132
   // count the sections
1152
   // count the sections
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
   //_cmScPrintSets("Sets",p->setList );
1197
   //_cmScPrintSets("Sets",p->setList );
1185
 
1198
 
1186
   _cmScProcSets(p);
1199
   _cmScProcSets(p);
1592
   if((rc = _cmScInitLocArray(p)) != kOkScRC )
1605
   if((rc = _cmScInitLocArray(p)) != kOkScRC )
1593
     goto errLabel;
1606
     goto errLabel;
1594
 
1607
 
1595
-  if((rc = _cmScProcSections(p,p->sectList)) != kOkScRC )
1608
+  if((rc = _cmScProcSections(p)) != kOkScRC )
1596
     goto errLabel;
1609
     goto errLabel;
1597
 
1610
 
1598
   if((rc = _cmScProcMarkers(p)) != kOkScRC )
1611
   if((rc = _cmScProcMarkers(p)) != kOkScRC )
2409
   return kOkScRC;
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
 void _cmScorePrintHdr( cmRpt_t* rpt )
2435
 void _cmScorePrintHdr( cmRpt_t* rpt )
2413
 {
2436
 {
2414
   cmRptPrintf(rpt,"evnt  CSV             bar\n");
2437
   cmRptPrintf(rpt,"evnt  CSV             bar\n");
2416
   cmRptPrintf(rpt,"----- ----- ----- --- --- ----- ----- --- -------\n");  
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
   switch(r->type)
2445
   switch(r->type)
2422
   {
2446
   {
2423
     case kBarEvtScId:
2447
     case kBarEvtScId:
2424
-      cmRptPrintf(rpt,"%5i %5i %3i bar\n",
2448
+      cmRptPrintf(rpt,"%5i %5i %3i bar ",
2425
         i,
2449
         i,
2426
         r->line,
2450
         r->line,
2427
         r->barNumb );
2451
         r->barNumb );
2429
 
2453
 
2430
     case kPedalEvtScId:
2454
     case kPedalEvtScId:
2431
     case kNonEvtScId:
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
         i,
2457
         i,
2434
         r->line,
2458
         r->line,
2435
         r->locIdx,
2459
         r->locIdx,
2440
         cmIsFlag(r->flags,kEvenScFl)  ? 'e' : ' ',
2464
         cmIsFlag(r->flags,kEvenScFl)  ? 'e' : ' ',
2441
         cmIsFlag(r->flags,kTempoScFl) ? 't' : ' ',
2465
         cmIsFlag(r->flags,kTempoScFl) ? 't' : ' ',
2442
         cmIsFlag(r->flags,kDynScFl)   ? 'd' : ' ',
2466
         cmIsFlag(r->flags,kDynScFl)   ? 'd' : ' ',
2467
+        //cmIsFlag(r->flags,kDynScFl)   ? 7-strlen(cmScDynIdToLabel(r->dynVal)) : 7,
2443
         cmIsFlag(r->flags,kDynScFl)   ? cmScDynIdToLabel(r->dynVal) : "");          
2468
         cmIsFlag(r->flags,kDynScFl)   ? cmScDynIdToLabel(r->dynVal) : "");          
2444
       break;
2469
       break;
2445
 
2470
 
2446
     default:
2471
     default:
2472
+      eolFl = false;
2447
       break;
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
   _cmScorePrintHdr(rpt);
2490
   _cmScorePrintHdr(rpt);
2459
   
2491
   
2460
   for(i=0; i<p->cnt; ++i)
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
         
2515
         
2484
       _cmScorePrintHdr(rpt);
2516
       _cmScorePrintHdr(rpt);
2485
       for(j=0; j<s->eleCnt; ++j)
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
       cmRptPrintf(rpt,"Targets Section: ");
2520
       cmRptPrintf(rpt,"Targets Section: ");
2489
       for(j=0; j<s->sectCnt; ++j)
2521
       for(j=0; j<s->sectCnt; ++j)
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
   cmScH_t h = cmScNullHandle;
2746
   cmScH_t h = cmScNullHandle;
2715
   if( cmScoreInitialize(ctx,&h,fn,0,NULL,0,NULL,NULL, cmSymTblNullHandle ) != kOkScRC )
2747
   if( cmScoreInitialize(ctx,&h,fn,0,NULL,0,NULL,NULL, cmSymTblNullHandle ) != kOkScRC )
2720
   cmScoreFinalize(&h);
2752
   cmScoreFinalize(&h);
2721
 }
2753
 }
2722
 
2754
 
2755
+void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn )
2756
+{
2757
+}
2758
+
2759
+
2723
 // 1. Fix absolute message time which was incorrect on original score file.
2760
 // 1. Fix absolute message time which was incorrect on original score file.
2724
 // 2. 
2761
 // 2. 
2725
 void cmScoreFix( cmCtx_t* ctx )
2762
 void cmScoreFix( cmCtx_t* ctx )

+ 5
- 1
app/cmScore.h Переглянути файл

280
   // Generate a new score file from a MIDI file.
280
   // Generate a new score file from a MIDI file.
281
   cmScRC_t      cmScoreFileFromMidi( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* scoreFn );
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
 #ifdef __cplusplus
291
 #ifdef __cplusplus

+ 2
- 4
app/cmScoreMatchGraphic.c Переглянути файл

538
   svgHeight += 10; // add a right and lower border
538
   svgHeight += 10; // add a right and lower border
539
   svgWidth  += 10;
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
   for(i=0; i<p->locN; ++i)
543
   for(i=0; i<p->locN; ++i)
544
   {
544
   {
690
   cmMidiByte_t midi_vel     = pedalDnFl ? 64 :   0;
690
   cmMidiByte_t midi_vel     = pedalDnFl ? 64 :   0;
691
   cmMidiByte_t midi_ch      = 0;
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
   // insert a pedal msg relative to the reference event
695
   // insert a pedal msg relative to the reference event
696
   if( cmMidiFileInsertMsg(mfH, m->uid, dtick_offset, midi_ch, kCtlMdId, kSostenutoCtlMdId, midi_vel ) != kOkMfRC )
696
   if( cmMidiFileInsertMsg(mfH, m->uid, dtick_offset, midi_ch, kCtlMdId, kSostenutoCtlMdId, midi_vel ) != kOkMfRC )
798
     goto errLabel;
798
     goto errLabel;
799
   }
799
   }
800
 
800
 
801
-  cmMidiFilePrintMsgs(mfH, p->err.rpt );
802
-
803
 
801
 
804
  errLabel:
802
  errLabel:
805
   cmMidiFileClose(&mfH);
803
   cmMidiFileClose(&mfH);

+ 20
- 14
app/cmTimeLine.c Переглянути файл

134
   if( op==NULL || op->typeId != kMidiFileTlId )
134
   if( op==NULL || op->typeId != kMidiFileTlId )
135
   {
135
   {
136
     if( errFl && p != NULL)
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
     return NULL;
138
     return NULL;
139
   }
139
   }
140
 
140
 
147
   if( op==NULL || op->typeId != kMidiEvtTlId )
147
   if( op==NULL || op->typeId != kMidiEvtTlId )
148
   {
148
   {
149
     if( errFl && p != NULL )
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
     return NULL;
151
     return NULL;
152
   }
152
   }
153
 
153
 
173
   if( op==NULL || op->typeId != kAudioEvtTlId )
173
   if( op==NULL || op->typeId != kAudioEvtTlId )
174
   {
174
   {
175
     if( errFl && p != NULL)
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
     return NULL;
177
     return NULL;
178
   }
178
   }
179
   return (cmTlAudioEvt_t*)op;
179
   return (cmTlAudioEvt_t*)op;
186
   if( op==NULL || op->typeId != kMarkerTlId )
186
   if( op==NULL || op->typeId != kMarkerTlId )
187
   {
187
   {
188
     if( errFl && p != NULL)
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
     return NULL;
190
     return NULL;
191
   }
191
   }
192
   return (cmTlMarker_t*)op;
192
   return (cmTlMarker_t*)op;
1227
   _cmTlObj_t* op      = p->seq[seqId].first;
1227
   _cmTlObj_t* op      = p->seq[seqId].first;
1228
   _cmTlObj_t* min_op  = NULL;
1228
   _cmTlObj_t* min_op  = NULL;
1229
   unsigned    minDist = UINT_MAX;
1229
   unsigned    minDist = UINT_MAX;
1230
-
1230
+  bool        inFl    = false;
1231
+  
1232
+  // for each object in the requested sequence
1231
   for(; op!=NULL; op=op->next)
1233
   for(; op!=NULL; op=op->next)
1232
     if( typeId==cmInvalidId || op->obj->typeId == typeId )
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
       if((op->obj->seqSmpIdx <= seqSmpIdx && seqSmpIdx < (op->obj->seqSmpIdx + op->obj->durSmpCnt)))
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
       // measure the distance from seqSmpIdx to the begin and end of this object
1248
       // measure the distance from seqSmpIdx to the begin and end of this object
1239
       unsigned d0 =  op->obj->seqSmpIdx                    < seqSmpIdx ? seqSmpIdx - op->obj->seqSmpIdx                    : op->obj->seqSmpIdx - seqSmpIdx;
1249
       unsigned d0 =  op->obj->seqSmpIdx                    < seqSmpIdx ? seqSmpIdx - op->obj->seqSmpIdx                    : op->obj->seqSmpIdx - seqSmpIdx;
1240
       unsigned d1 =  op->obj->seqSmpIdx+op->obj->durSmpCnt < seqSmpIdx ? seqSmpIdx - op->obj->seqSmpIdx+op->obj->durSmpCnt : op->obj->seqSmpIdx+op->obj->durSmpCnt - seqSmpIdx;
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
       // track the min dist and the assoc'd obj
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
         minDist = d0;
1256
         minDist = d0;
1251
         min_op  = op;
1257
         min_op  = op;
1252
       }
1258
       }
1253
 
1259
 
1254
-      if( d1 < minDist )
1260
+      if( d1 < minDist && (inFl==false || inFl==in0Fl))
1255
       {
1261
       {
1256
         minDist = d1;
1262
         minDist = d1;
1257
         min_op  = op;
1263
         min_op  = op;

+ 758
- 257
app/cmXScore.c
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 12
- 19
app/cmXScore.h Переглянути файл

18
     kPedalStateErrorXsRc,
18
     kPedalStateErrorXsRc,
19
     kMidiFailXsRC,
19
     kMidiFailXsRC,
20
     kFileFailXsRC,
20
     kFileFailXsRC,
21
-    kSvgFailXsRC
21
+    kSvgFailXsRC,
22
+    kOverlapWarnXsRC,
23
+    kZeroLengthEventXsRC
22
   };
24
   };
23
 
25
 
24
   typedef cmRC_t     cmXsRC_t;
26
   typedef cmRC_t     cmXsRC_t;
41
   //
43
   //
42
   // M-x load-file ~/src/emacs/proc_music_xml.el
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
   cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
52
   cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
63
 
53
 
54
+  
64
   bool     cmXScoreIsValid( cmXsH_t h );
55
   bool     cmXScoreIsValid( cmXsH_t h );
65
 
56
 
66
   cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn );
57
   cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn );
67
 
58
 
68
   void     cmXScoreReport( cmXsH_t h, cmRpt_t* rpt, bool sortFl );
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
   // Generate the CSV file suitable for use by cmScore.
63
   // Generate the CSV file suitable for use by cmScore.
71
   cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn );
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 Переглянути файл

8
 #include "cmMallocDebug.h"
8
 #include "cmMallocDebug.h"
9
 #include "cmLinkedHeap.h"
9
 #include "cmLinkedHeap.h"
10
 #include "cmTime.h"
10
 #include "cmTime.h"
11
+#include "cmText.h"
11
 #include "cmMidi.h"
12
 #include "cmMidi.h"
12
 #include "cmMidiFile.h"
13
 #include "cmMidiFile.h"
14
+#include "cmSvgWriter.h"
15
+
13
 
16
 
14
 #ifdef cmBIG_ENDIAN
17
 #ifdef cmBIG_ENDIAN
15
 #define mfSwap16(v)  (v)
18
 #define mfSwap16(v)  (v)
256
   unsigned byteN = cmMidiStatusToByteCount(tmp->status);
259
   unsigned byteN = cmMidiStatusToByteCount(tmp->status);
257
   
260
   
258
   if( byteN==kInvalidMidiByte || byteN > 2 )
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
   unsigned i;
264
   unsigned i;
262
   for(i=useRsFl; i<byteN; ++i)
265
   for(i=useRsFl; i<byteN; ++i)
339
     if((rc = _cmMidiFileRead8(mfp,&status)) != kOkMfRC )
342
     if((rc = _cmMidiFileRead8(mfp,&status)) != kOkMfRC )
340
       return rc;
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
     // append a track msg
347
     // append a track msg
345
     if((rc = _cmMidiFileAppendTrackMsg( mfp, trkIdx, dticks, status, &tmp )) != kOkMfRC )
348
     if((rc = _cmMidiFileAppendTrackMsg( mfp, trkIdx, dticks, status, &tmp )) != kOkMfRC )
677
     rc = cmErrMsg(&p->err,kFileFailMfRC,"MIDI file close failed.");
680
     rc = cmErrMsg(&p->err,kFileFailMfRC,"MIDI file close failed.");
678
 
681
 
679
   if( rc != kOkMfRC )
682
   if( rc != kOkMfRC )
683
+  {
680
     _cmMidiFileClose(p);
684
     _cmMidiFileClose(p);
681
-
685
+    hp->h = NULL;
686
+  }
687
+  
682
   return rc;
688
   return rc;
683
 }
689
 }
684
 
690
 
971
   return rc;
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
 cmMfRC_t _cmMidiFileWriteTrack( _cmMidiFile_t* mfp, unsigned trkIdx )
1039
 cmMfRC_t _cmMidiFileWriteTrack( _cmMidiFile_t* mfp, unsigned trkIdx )
975
 {
1040
 {
976
   cmMfRC_t          rc        = kOkMfRC;
1041
   cmMfRC_t          rc        = kOkMfRC;
977
   cmMidiTrackMsg_t* tmp       = mfp->trkV[trkIdx].base;
1042
   cmMidiTrackMsg_t* tmp       = mfp->trkV[trkIdx].base;
978
   cmMidiByte_t      runStatus = 0;
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
   for(; tmp != NULL; tmp=tmp->link)
1049
   for(; tmp != NULL; tmp=tmp->link)
981
   {
1050
   {
982
     // write the msg tick count
1051
     // write the msg tick count
1379
     assert( m1->atick >= m->atick );
1448
     assert( m1->atick >= m->atick );
1380
     m1->dtick = m1->atick - m->atick;
1449
     m1->dtick = m1->atick - m->atick;
1381
   }
1450
   }
1382
-  
1451
+
1452
+  p->trkV[trkIdx].cnt += 1;  
1383
   p->msgVDirtyFl = true;
1453
   p->msgVDirtyFl = true;
1454
+
1455
+
1384
   
1456
   
1385
   return kOkMfRC;
1457
   return kOkMfRC;
1386
    
1458
    
1402
   m.status     = status & 0xf0;
1474
   m.status     = status & 0xf0;
1403
   m.byteCnt    = sizeof(cm);
1475
   m.byteCnt    = sizeof(cm);
1404
   m.u.chMsgPtr = &cm;
1476
   m.u.chMsgPtr = &cm;
1477
+
1478
+  assert( m.status >= kNoteOffMdId && m.status <= kPbendMdId );
1405
   
1479
   
1406
   return cmMidiFileInsertTrackMsg(h,trkIdx,&m);
1480
   return cmMidiFileInsertTrackMsg(h,trkIdx,&m);
1407
 }
1481
 }
1836
 void cmMidiFileTestPrint( void* printDataPtr, const char* fmt, va_list vl )
1910
 void cmMidiFileTestPrint( void* printDataPtr, const char* fmt, va_list vl )
1837
 { vprintf(fmt,vl); }
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
 cmMfRC_t cmMidiFileGenPlotFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* outFn )
1945
 cmMfRC_t cmMidiFileGenPlotFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* outFn )
1840
 {
1946
 {
1841
   cmMfRC_t                 rc  = kOkMfRC;
1947
   cmMfRC_t                 rc  = kOkMfRC;
1872
   return rc;
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
 void cmMidiFilePrintControlNumbers( cmCtx_t* ctx, const char* fn )
2074
 void cmMidiFilePrintControlNumbers( cmCtx_t* ctx, const char* fn )
1876
 {
2075
 {
1877
   cmMidiFileH_t h = cmMidiFileNullHandle;
2076
   cmMidiFileH_t h = cmMidiFileNullHandle;

+ 19
- 2
cmMidiFile.h Переглянути файл

117
     kLargeDeltaTickMfRC, // 12 (a large delta tick value was filtered)
117
     kLargeDeltaTickMfRC, // 12 (a large delta tick value was filtered)
118
     kUidNotFoundMfRC,    // 13
118
     kUidNotFoundMfRC,    // 13
119
     kUidNotANoteMsgMfRC, // 14
119
     kUidNotANoteMsgMfRC, // 14
120
-    kInvalidTrkIndexMfRC // 15
120
+    kInvalidTrkIndexMfRC,// 15
121
+    kSvgFailMfRC         // 16
121
   };
122
   };
122
 
123
 
123
   extern cmMidiFileH_t cmMidiFileNullHandle;
124
   extern cmMidiFileH_t cmMidiFileNullHandle;
212
 
213
 
213
   void                  cmMidiFilePrintMsgs( cmMidiFileH_t h, cmRpt_t* rpt );
214
   void                  cmMidiFilePrintMsgs( cmMidiFileH_t h, cmRpt_t* rpt );
214
   void                  cmMidiFilePrintTrack( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt );
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
   // Generate a piano-roll plot description file which can be displayed with cmXScore.m
229
   // Generate a piano-roll plot description file which can be displayed with cmXScore.m
218
   cmMfRC_t             cmMidiFileGenPlotFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* outFn );
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 Переглянути файл

167
   *heightRef = max_y - min_y;
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
 cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h,  const cmChar_t* cssFn, const cmChar_t* outFn )
197
 cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h,  const cmChar_t* cssFn, const cmChar_t* outFn )
172
 {
198
 {
176
   double      svgHeight = 0;
202
   double      svgHeight = 0;
177
   cmSvgEle_t* e         = p->elist;
203
   cmSvgEle_t* e         = p->elist;
178
   cmFileH_t   fH        = cmFileNullHandle;
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
   _cmSvgSize(p, &svgWidth, &svgHeight );
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
     goto errLabel;
228
     goto errLabel;
189
   }
229
   }
190
 
230
 
193
     switch( e->id )
233
     switch( e->id )
194
     {
234
     {
195
       case kRectSvgId:
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
         break;
238
         break;
199
         
239
         
200
       case kLineSvgId:
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
         break;
243
         break;
204
         
244
         
205
       case kTextSvgId:
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
         break;
248
         break;
209
         
249
         
210
       default:
250
       default:
214
 
254
 
215
     if( rc != kOkSvgRC )
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
       break;
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
     goto errLabel;
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
  errLabel:
283
  errLabel:
230
   cmFileClose(&fH);
284
   cmFileClose(&fH);
231
 
285
 
286
+  cmMemFree(s0);
287
+  cmMemFree(s1);
288
+  
232
   return rc;
289
   return rc;
233
 }
290
 }
234
 
291
 

+ 6
- 1
cmSvgWriter.h Переглянути файл

9
 {
9
 {
10
   kOkSvgRC = cmOkRC,
10
   kOkSvgRC = cmOkRC,
11
   kFileFailSvgRC,
11
   kFileFailSvgRC,
12
+  kPrintFailSvgRC,
12
   kLHeapFailSvgRC
13
   kLHeapFailSvgRC
13
 };
14
 };
14
 
15
 
21
   cmSvgRC_t cmSvgWriterFree(    cmSvgH_t* hp );
22
   cmSvgRC_t cmSvgWriterFree(    cmSvgH_t* hp );
22
   bool      cmSvgWriterIsValid( cmSvgH_t h );
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
   cmSvgRC_t cmSvgWriterLine( cmSvgH_t h, double x0, double y0, double x1, double y1, const cmChar_t* cssClassLabel );
26
   cmSvgRC_t cmSvgWriterLine( cmSvgH_t h, double x0, double y0, double x1, double y1, const cmChar_t* cssClassLabel );
26
   cmSvgRC_t cmSvgWriterText( cmSvgH_t h, double  x, double y,  const cmChar_t* text, const cmChar_t* cssClassLabel );
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
   cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h, const cmChar_t* cssFn, const cmChar_t* outFn );
33
   cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h, const cmChar_t* cssFn, const cmChar_t* outFn );
29
   
34
   
30
 #ifdef __cplusplus
35
 #ifdef __cplusplus

+ 1
- 1
dsp/cmDspKr.c Переглянути файл

657
           cmTlObj_t* op;
657
           cmTlObj_t* op;
658
           if((op = cmTimeLineIdToObj(p->tlH, cmInvalidId, markerId )) != NULL )
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
             p->afIdx = op->begSmpIdx;
662
             p->afIdx = op->begSmpIdx;
663
 
663
 

+ 1
- 1
dsp/cmDspPgmKrChain.c Переглянути файл

201
   cmDspInst_t* max_lwr_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Max Lwr"),          0.0, -1.0, 5.0, 3.0);
201
   cmDspInst_t* max_lwr_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Max Lwr"),          0.0, -1.0, 5.0, 3.0);
202
   cmDspInst_t* min_off_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Min Off"),          0.0, 50.0, 0.1, 30.0);
202
   cmDspInst_t* min_off_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Min Off"),          0.0, 50.0, 0.1, 30.0);
203
   cmDspInst_t* max_off_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Max Off"),          0.0, 50.0, 0.1, 30.0);
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
   cmDspInst_t* max_wet_ctl   = cmDspSysAllocScalarP( h,preGrpSymId, NULL, lbl("Max Wet"),          0.0,  1.0, 0.01, 1.0);
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
 

Завантаження…
Відмінити
Зберегти