Browse Source

cmXScore.h/c : Added cmXScoreProcessPedals() and _cmXsWriteMidiFile().

master
kevin 8 years ago
parent
commit
9036de70ba
2 changed files with 284 additions and 59 deletions
  1. 283
    59
      app/cmXScore.c
  2. 1
    0
      app/cmXScore.h

+ 283
- 59
app/cmXScore.c View File

50
   kTieBegXsFl    = 0x000400,
50
   kTieBegXsFl    = 0x000400,
51
   kTieEndXsFl    = 0x000800,
51
   kTieEndXsFl    = 0x000800,
52
   kTieProcXsFl   = 0x001000,
52
   kTieProcXsFl   = 0x001000,
53
-  kPedalDnXsFl   = 0x002000,
54
-  kPedalUpXsFl   = 0x004000,
55
-  kPedalUpDnXsFl = 0x008000,
53
+  kDampDnXsFl    = 0x002000,
54
+  kDampUpXsFl    = 0x004000,
55
+  kDampUpDnXsFl  = 0x008000,
56
   kSostDnXsFl    = 0x010000,
56
   kSostDnXsFl    = 0x010000,
57
   kSostUpXsFl    = 0x020000,
57
   kSostUpXsFl    = 0x020000,
58
   kMetronomeXsFl = 0x040000,  // duration holds BPM
58
   kMetronomeXsFl = 0x040000,  // duration holds BPM
680
       return _cmXScoreMissingAttribute(p, np, "type" );
680
       return _cmXScoreMissingAttribute(p, np, "type" );
681
 
681
 
682
     if( cmTextCmp(a->value,"start") == 0 )
682
     if( cmTextCmp(a->value,"start") == 0 )
683
-      flags = kPedalDnXsFl;
683
+      flags = kDampDnXsFl;
684
     else
684
     else
685
       if( cmTextCmp(a->value,"change") == 0 )
685
       if( cmTextCmp(a->value,"change") == 0 )
686
-        flags = kPedalUpDnXsFl;
686
+        flags = kDampUpDnXsFl;
687
       else
687
       else
688
         if( cmTextCmp(a->value,"stop") == 0 )
688
         if( cmTextCmp(a->value,"stop") == 0 )
689
-          flags = kPedalUpXsFl;
689
+          flags = kDampUpXsFl;
690
         else
690
         else
691
           return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Unrecognized pedal type:'%s'.",cmStringNullGuard(a->value));
691
           return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Unrecognized pedal type:'%s'.",cmStringNullGuard(a->value));
692
   }
692
   }
899
   }
899
   }
900
 }
900
 }
901
 
901
 
902
+// Set the cmXsNode_t.secs and dsecs.
902
 void _cmXScoreSetAbsoluteTime( cmXScore_t* p )
903
 void _cmXScoreSetAbsoluteTime( cmXScore_t* p )
903
 {
904
 {
904
   double          tpqn         = 0; // ticks per quarter note
905
   double          tpqn         = 0; // ticks per quarter note
925
         // dticks = np->tick - metro_tick;     // where metro_tick is the absolute tick of the last metro event
926
         // dticks = np->tick - metro_tick;     // where metro_tick is the absolute tick of the last metro event
926
         // secs   = (dticks/tps) + metro_secs; // where metro_secs is the absoute time of the last metro event
927
         // secs   = (dticks/tps) + metro_secs; // where metro_secs is the absoute time of the last metro event
927
 
928
 
928
-        unsigned dticks = np->tick - metro_tick;
929
-        double   secs   = tps==0 ? 0 : (dticks/tps) + metro_sec;
929
+        unsigned dticks = np->tick - metro_tick;                  
930
+        double   secs   = tps==0 ? 0 : (dticks/tps) + metro_sec; 
930
         double   dsecs  = secs - sec0;
931
         double   dsecs  = secs - sec0;
931
 
932
 
932
         //
933
         //
933
         if( cmIsFlag(np->flags,kMetronomeXsFl) )
934
         if( cmIsFlag(np->flags,kMetronomeXsFl) )
934
         {
935
         {
935
-          double bpm = np->duration;
936
-          double bps = bpm / 60.0;
937
-          tps        = bps * tpqn;
938
-          metro_tick = np->tick;
939
-          metro_sec  = secs;
936
+          double bpm = np->duration;  // beats per minute
937
+          double bps = bpm / 60.0;    // beats per second
938
+          tps        = bps * tpqn;    // ticks per second
939
+          metro_tick = np->tick;      // store tick of the last metronome marker
940
+          metro_sec  = secs;          // store time of the last metronome marker
940
         }
941
         }
941
 
942
 
942
-        if( cmIsFlag(np->flags,kBarXsFl|kPedalDnXsFl|kPedalUpXsFl|kPedalUpDnXsFl|kSostDnXsFl|kSostUpXsFl|kOnsetXsFl|kSectionXsFl) )
943
+        if( cmIsFlag(np->flags,kBarXsFl|kDampDnXsFl|kDampUpXsFl|kDampUpDnXsFl|kSostDnXsFl|kSostUpXsFl|kOnsetXsFl|kSectionXsFl) )
943
         {
944
         {
944
           np->secs  = secs;
945
           np->secs  = secs;
945
           np->dsecs = dsecs;
946
           np->dsecs = dsecs;
1016
       // A tick group is a group of events that share the same tick.
1017
       // A tick group is a group of events that share the same tick.
1017
       unsigned    tick0 = np->tick;
1018
       unsigned    tick0 = np->tick;
1018
 
1019
 
1020
+      // for each note 
1019
       for(; np!=NULL; np=np->slink)
1021
       for(; np!=NULL; np=np->slink)
1020
       {
1022
       {
1021
-        // if this event is the first of a new tick group
1023
+        // if this event is the first of a new tick group (then a[] holds a group completed on the previous note)
1022
         if( np->tick != tick0 )
1024
         if( np->tick != tick0 )
1023
         {
1025
         {
1024
           // if there is more than one event in the completed tick group ...
1026
           // if there is more than one event in the completed tick group ...
1370
   }
1372
   }
1371
 }
1373
 }
1372
 
1374
 
1375
+// Assign pedal down durations to pedal down events.
1376
+cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
1377
+{
1378
+  cmXsRC_t    rc = kOkXsRC;
1379
+  cmXsPart_t* pp = p->partL;
1380
+  
1381
+  for(; pp!=NULL; pp=pp->link)
1382
+  {
1383
+    cmXsNote_t* dnp = NULL;  // pointer to last damper down event
1384
+    cmXsNote_t* snp = NULL;  // pointer to last sostenuto down event
1385
+    
1386
+    cmXsMeas_t* mp   = pp->measL;
1387
+    for(; mp!=NULL; mp=mp->link)
1388
+    {
1389
+      cmXsNote_t* np  = mp->noteL;        
1390
+      for(; np!=NULL; np=np->slink )
1391
+      {
1392
+        unsigned x = np->flags & (kDampDnXsFl|kDampUpXsFl|kDampUpDnXsFl|kSostUpXsFl|kSostDnXsFl);
1393
+        switch( x )
1394
+        {
1395
+          case 0:
1396
+            break;
1397
+            
1398
+          case kDampDnXsFl:
1399
+            if( dnp != NULL )
1400
+              cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper down not preceded by damper up in measure:%i.",mp->number);
1401
+            else
1402
+              dnp = np;
1403
+            break;
1404
+            
1405
+          case kDampUpXsFl:
1406
+            if( dnp == NULL )
1407
+              cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper up not preceded by damper down in measure:%i.",mp->number);
1408
+            else
1409
+            {
1410
+              dnp->duration = np->tick - dnp->tick;
1411
+              dnp = NULL;
1412
+            }
1413
+            break;
1414
+            
1415
+          case kDampUpDnXsFl:
1416
+            if( dnp == NULL )
1417
+              cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper up/down not preceded by damper down in measure:%i.",mp->number);
1418
+            else
1419
+            {            
1420
+              dnp->duration = np->tick - dnp->tick;
1421
+              dnp = np;
1422
+            }
1423
+            break;
1424
+            
1425
+          case kSostDnXsFl:
1426
+            if( snp != NULL )
1427
+              cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto down not preceded by sostenuto up in measure:%i.",mp->number);
1428
+            else
1429
+              snp = np;            
1430
+            break;
1431
+            
1432
+          case kSostUpXsFl:
1433
+            if( snp == NULL )
1434
+              cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto up not preceded by sostenuto down in measure:%i.",mp->number);
1435
+            else
1436
+            {
1437
+              snp->duration = np->tick - snp->tick;
1438
+              snp = NULL;
1439
+            }
1440
+            break;
1441
+            
1442
+          default:
1443
+            {
1444
+              assert(0);
1445
+            }
1446
+        } // switch
1447
+          
1448
+      } // for notes
1449
+      
1450
+    } // for measures
1451
+
1452
+    if( dnp != NULL )
1453
+      cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper left down at the end of a part.");
1454
+
1455
+    if( snp != NULL )
1456
+      cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto left down at the end of a part.");
1457
+  }
1458
+
1459
+  return rc;
1460
+}
1461
+
1373
 cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn )
1462
 cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn )
1374
 {
1463
 {
1375
   cmXsRC_t rc = kOkXsRC;
1464
   cmXsRC_t rc = kOkXsRC;
1472
   cmXsNote_t* note;     // The cmXsNode_t* associated with this cmXsReorder_t record
1561
   cmXsNote_t* note;     // The cmXsNode_t* associated with this cmXsReorder_t record
1473
   
1562
   
1474
   unsigned    dynIdx;    // cmInvalidIdx=ignore otherwise index into _cmXScoreDynMarkArray[]
1563
   unsigned    dynIdx;    // cmInvalidIdx=ignore otherwise index into _cmXScoreDynMarkArray[]
1475
-  unsigned    newFlags;    // 0=ignore | kSostUp/DnXsFl | kPedalUp/DnXsFl  | kTieEndXsFl
1564
+  unsigned    newFlags;    // 0=ignore | kSostUp/DnXsFl | kDampUp/DnXsFl  | kTieEndXsFl
1476
   unsigned    newTick;   // 0=ignore >0 new tick value
1565
   unsigned    newTick;   // 0=ignore >0 new tick value
1477
   unsigned    pitch;     // 0=ignore >0 new pitch
1566
   unsigned    pitch;     // 0=ignore >0 new pitch
1478
 } cmXsReorder_t;
1567
 } cmXsReorder_t;
1560
   nn->flags = flags;
1649
   nn->flags = flags;
1561
   
1650
   
1562
   // Pedal down events occur after the event they are attached to
1651
   // Pedal down events occur after the event they are attached to
1563
-  if( cmIsFlag(flags,kSostDnXsFl | kPedalDnXsFl ) )
1652
+  if( cmIsFlag(flags,kSostDnXsFl | kDampDnXsFl ) )
1564
   {
1653
   {
1565
     nn->tick  = r->note->tick + 1;
1654
     nn->tick  = r->note->tick + 1;
1566
     _cmXScoreInsertNoteAfter(r->note,nn);
1655
     _cmXScoreInsertNoteAfter(r->note,nn);
1568
   else
1657
   else
1569
   {
1658
   {
1570
     // Pedal up events occur before the event they are attached to
1659
     // Pedal up events occur before the event they are attached to
1571
-    if( cmIsFlag(flags,kSostUpXsFl | kPedalUpXsFl ) )
1660
+    if( cmIsFlag(flags,kSostUpXsFl | kDampUpXsFl ) )
1572
     {
1661
     {
1573
       nn->tick  = r->note->tick==0 ? 0 : r->note->tick - 1;
1662
       nn->tick  = r->note->tick==0 ? 0 : r->note->tick - 1;
1574
       _cmXScoreInsertNoteBefore(r->note,nn);
1663
       _cmXScoreInsertNoteBefore(r->note,nn);
1642
     if( rV[i].newFlags != 0 )
1731
     if( rV[i].newFlags != 0 )
1643
     {
1732
     {
1644
 
1733
 
1645
-      if( cmIsFlag(rV[i].newFlags,kPedalDnXsFl ) )
1646
-        _cmXScoreInsertPedalEvent(p,rV + i,kPedalDnXsFl);
1734
+      if( cmIsFlag(rV[i].newFlags,kDampDnXsFl ) )
1735
+        _cmXScoreInsertPedalEvent(p,rV + i,kDampDnXsFl);
1647
 
1736
 
1648
       if( cmIsFlag(rV[i].newFlags,kSostDnXsFl ) )
1737
       if( cmIsFlag(rV[i].newFlags,kSostDnXsFl ) )
1649
         _cmXScoreInsertPedalEvent(p,rV + i,kSostDnXsFl);
1738
         _cmXScoreInsertPedalEvent(p,rV + i,kSostDnXsFl);
1650
       
1739
       
1651
-      if( cmIsFlag(rV[i].newFlags,kPedalUpXsFl ) )
1652
-        _cmXScoreInsertPedalEvent(p,rV + i,kPedalUpXsFl);
1740
+      if( cmIsFlag(rV[i].newFlags,kDampUpXsFl ) )
1741
+        _cmXScoreInsertPedalEvent(p,rV + i,kDampUpXsFl);
1653
 
1742
 
1654
       if( cmIsFlag(rV[i].newFlags,kSostUpXsFl ) )
1743
       if( cmIsFlag(rV[i].newFlags,kSostUpXsFl ) )
1655
         _cmXScoreInsertPedalEvent(p,rV + i,kSostUpXsFl);
1744
         _cmXScoreInsertPedalEvent(p,rV + i,kSostUpXsFl);
1764
         break;                
1853
         break;                
1765
         
1854
         
1766
       case 'D':
1855
       case 'D':
1767
-        *newFlagsRef |= kPedalDnXsFl;  // damper pedal down
1856
+        *newFlagsRef |= kDampDnXsFl;  // damper pedal down
1768
         break;
1857
         break;
1769
 
1858
 
1770
       case 'U':
1859
       case 'U':
1771
-        *newFlagsRef |= kPedalUpXsFl;  // damper pedal up
1860
+        *newFlagsRef |= kDampUpXsFl;  // damper pedal up
1772
         break;
1861
         break;
1773
 
1862
 
1774
       case '_':
1863
       case '_':
2329
         else
2418
         else
2330
         {
2419
         {
2331
           // if this is a pedal event
2420
           // if this is a pedal event
2332
-          if( cmIsFlag(np->flags,kPedalDnXsFl|kPedalUpXsFl|kPedalUpDnXsFl|kSostDnXsFl|kSostUpXsFl) )
2421
+          if( cmIsFlag(np->flags,kDampDnXsFl|kDampUpXsFl|kDampUpDnXsFl|kSostDnXsFl|kSostUpXsFl) )
2333
           {
2422
           {
2334
             unsigned d0 = cmIsFlag(np->flags,kSostDnXsFl |kSostUpXsFl) ? 66 : 64; // pedal MIDI ctl id
2423
             unsigned d0 = cmIsFlag(np->flags,kSostDnXsFl |kSostUpXsFl) ? 66 : 64; // pedal MIDI ctl id
2335
-            unsigned d1 = cmIsFlag(np->flags,kPedalDnXsFl|kSostDnXsFl) ? 64 : 0;  // pedal-dn: d1>=64 pedal-up:<64
2424
+            unsigned d1 = cmIsFlag(np->flags,kDampDnXsFl|kSostDnXsFl) ? 64 : 0;  // pedal-dn: d1>=64 pedal-up:<64
2336
             _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,np->secs,d0,d1,-1,0,"",np->flags,"","");
2425
             _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,np->secs,d0,d1,-1,0,"",np->flags,"","");
2337
             sectionIdStr = NULL;
2426
             sectionIdStr = NULL;
2338
             
2427
             
2339
-            if( cmIsFlag(np->flags,kPedalUpDnXsFl) )
2428
+            if( cmIsFlag(np->flags,kDampUpDnXsFl) )
2340
             {
2429
             {
2341
               rowIdx += 1;
2430
               rowIdx += 1;
2342
               double millisecond = 0.0;
2431
               double millisecond = 0.0;
2405
   const cmChar_t* e  = cmIsFlag(note->flags,kEvenXsFl)      ? "e" : "-";
2494
   const cmChar_t* e  = cmIsFlag(note->flags,kEvenXsFl)      ? "e" : "-";
2406
   const cmChar_t* d  = cmIsFlag(note->flags,kDynXsFl)       ? "d" : "-";
2495
   const cmChar_t* d  = cmIsFlag(note->flags,kDynXsFl)       ? "d" : "-";
2407
   const cmChar_t* t  = cmIsFlag(note->flags,kTempoXsFl)     ? "t" : "-";
2496
   const cmChar_t* t  = cmIsFlag(note->flags,kTempoXsFl)     ? "t" : "-";
2408
-  const cmChar_t* P  = cmIsFlag(note->flags,kPedalDnXsFl)   ? "V" : "-";
2497
+  const cmChar_t* P  = cmIsFlag(note->flags,kDampDnXsFl)    ? "V" : "-";
2409
   const cmChar_t* s  = cmIsFlag(note->flags,kSostDnXsFl)    ? "{" : "-";
2498
   const cmChar_t* s  = cmIsFlag(note->flags,kSostDnXsFl)    ? "{" : "-";
2410
   const cmChar_t* S  = cmIsFlag(note->flags,kSectionXsFl)   ? "S" : "-";
2499
   const cmChar_t* S  = cmIsFlag(note->flags,kSectionXsFl)   ? "S" : "-";
2411
   const cmChar_t* H  = cmIsFlag(note->flags,kHeelXsFl)      ? "H" : "-";
2500
   const cmChar_t* H  = cmIsFlag(note->flags,kHeelXsFl)      ? "H" : "-";
2412
   const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl)    ? "T" : "-";
2501
   const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl)    ? "T" : "-";
2413
   const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl)    ? "_" : "-";
2502
   const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl)    ? "_" : "-";
2414
   const cmChar_t* O  = cmIsFlag(note->flags,kOnsetXsFl)     ? "*" : "-";
2503
   const cmChar_t* O  = cmIsFlag(note->flags,kOnsetXsFl)     ? "*" : "-";
2415
-  P = cmIsFlag(note->flags,kPedalUpXsFl)   ? "^" : P;
2416
-  P = cmIsFlag(note->flags,kPedalUpDnXsFl) ? "X" : P;
2504
+  P = cmIsFlag(note->flags,kDampUpXsFl)   ? "^" : P;
2505
+  P = cmIsFlag(note->flags,kDampUpDnXsFl) ? "X" : P;
2417
   s = cmIsFlag(note->flags,kSostUpXsFl)    ? "}" : s;
2506
   s = cmIsFlag(note->flags,kSostUpXsFl)    ? "}" : s;
2418
   //const cmChar_t* N = note->pitch==0 ? " " : cmMidiToSciPitch( note->pitch, NULL, 0 );
2507
   //const cmChar_t* N = note->pitch==0 ? " " : cmMidiToSciPitch( note->pitch, NULL, 0 );
2419
 
2508
 
2548
   unsigned        noteHeight = 10;
2637
   unsigned        noteHeight = 10;
2549
   const cmChar_t* svgFn      = cmFsMakeFn(dir,fn,"html",NULL);
2638
   const cmChar_t* svgFn      = cmFsMakeFn(dir,fn,"html",NULL);
2550
   const cmChar_t* cssFn      = cmFsMakeFn(NULL,fn,"css",NULL);
2639
   const cmChar_t* cssFn      = cmFsMakeFn(NULL,fn,"css",NULL);
2551
-  cmChar_t*       t0          = NULL;  // temporary dynamic string
2640
+  cmChar_t*       t0         = NULL;  // temporary dynamic string
2641
+  
2552
   // create the SVG writer
2642
   // create the SVG writer
2553
   if( cmSvgWriterAlloc(ctx,&svgH) != kOkSvgRC )
2643
   if( cmSvgWriterAlloc(ctx,&svgH) != kOkSvgRC )
2554
   {
2644
   {
2559
   // for each MIDI file element
2649
   // for each MIDI file element
2560
   for(; e!=NULL && rc==kOkXsRC; e=e->link)
2650
   for(; e!=NULL && rc==kOkXsRC; e=e->link)
2561
   {
2651
   {
2562
-    // if this is a note
2563
-    if( cmIsFlag(e->flags,kOnsetXsFl) )
2652
+    switch( e->flags & (kOnsetXsFl|kBarXsFl|kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl))
2564
     {
2653
     {
2565
-      const cmChar_t* classLabel = "note";
2566
       
2654
       
2567
-
2568
-      t0 = cmTsPrintfP(t0,"note_%i%s",e->voice, cmIsFlag(e->flags,kGraceXsFl) ? "_g":"");
2655
+      // if this is a note
2656
+      case kOnsetXsFl:
2657
+        {
2658
+          const cmChar_t* classLabel = "note";
2569
       
2659
       
2570
-      if( cmIsFlag(e->flags,kGraceXsFl) )
2571
-        classLabel = "grace";
2660
+          t0 = cmTsPrintfP(t0,"note_%i%s",e->voice, cmIsFlag(e->flags,kGraceXsFl) ? "_g":"");
2572
       
2661
       
2573
-      if( cmSvgWriterRect(svgH, e->tick, e->d0 * noteHeight,  e->durTicks,  noteHeight-1, t0 ) != kOkSvgRC )
2574
-        rc = kSvgFailXsRC;
2575
-      else
2576
-        if( cmSvgWriterText(svgH, e->tick + e->durTicks/2, e->d0 * noteHeight + noteHeight/2, cmMidiToSciPitch( e->d0, NULL, 0), "pitch") != kOkSvgRC )
2577
-          rc = kSvgFailXsRC;
2578
-    }
2662
+          if( cmIsFlag(e->flags,kGraceXsFl) )
2663
+            classLabel = "grace";
2664
+      
2665
+          if( cmSvgWriterRect(svgH, e->tick, e->d0 * noteHeight,  e->durTicks,  noteHeight-1, t0 ) != kOkSvgRC )
2666
+            rc = kSvgFailXsRC;
2667
+          else
2668
+            if( cmSvgWriterText(svgH, e->tick + e->durTicks/2, e->d0 * noteHeight + noteHeight/2, cmMidiToSciPitch( e->d0, NULL, 0), "pitch") != kOkSvgRC )
2669
+              rc = kSvgFailXsRC;
2670
+        }
2671
+        break;
2579
 
2672
 
2580
-    // if this is a bar
2581
-    if( cmIsFlag(e->flags,kBarXsFl) )
2582
-    {
2583
-      if( cmSvgWriterLine(svgH, e->tick, 0, e->tick, 127*noteHeight, "bar") != kOkSvgRC )
2584
-        rc = kSvgFailXsRC;
2585
-      else
2586
-      {
2587
-        if( cmSvgWriterText(svgH, e->tick, 10, t0 = cmTsPrintfP(t0,"%i",e->d0), "text" ) != kOkSvgRC )
2588
-          rc = kSvgFailXsRC;
2589
-      }
2673
+        // if this is a bar
2674
+      case kBarXsFl:
2675
+        {
2676
+          if( cmSvgWriterLine(svgH, e->tick, 0, e->tick, 127*noteHeight, "bar") != kOkSvgRC )
2677
+            rc = kSvgFailXsRC;
2678
+          else
2679
+          {
2680
+            if( cmSvgWriterText(svgH, e->tick, 10, t0 = cmTsPrintfP(t0,"%i",e->d0), "text" ) != kOkSvgRC )
2681
+              rc = kSvgFailXsRC;
2682
+          }
2683
+        }
2684
+        break;
2685
+
2686
+        // if this is a pedal event
2687
+      case kDampDnXsFl:
2688
+      case kDampUpDnXsFl:
2689
+      case kSostDnXsFl:
2690
+        {
2691
+          const cmChar_t* classLabel =        cmIsFlag(e->flags,kSostDnXsFl) ? "sost" : "damp";
2692
+          unsigned        y          = (128 + cmIsFlag(e->flags,kSostDnXsFl)?1:0) * noteHeight;
2693
+          cmSvgWriterRect(svgH, e->tick, y, e->durTicks, noteHeight-1, classLabel);
2694
+        }
2695
+        break;
2590
     }
2696
     }
2591
   }
2697
   }
2592
-
2698
+  
2593
   if( rc != kOkXsRC )
2699
   if( rc != kOkXsRC )
2594
     cmErrMsg(&p->err,kSvgFailXsRC,"SVG element insert failed.");
2700
     cmErrMsg(&p->err,kSvgFailXsRC,"SVG element insert failed.");
2595
 
2701
 
2606
   return rc;
2712
   return rc;
2607
 }
2713
 }
2608
 
2714
 
2715
+cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, const cmChar_t* dir, const cmChar_t* fn )
2716
+{
2717
+  cmXsRC_t rc = kOkXsRC;
2718
+  
2719
+  if( p->partL==NULL || p->partL->measL == NULL )
2720
+    return rc;
2721
+  
2722
+  cmMidiFileH_t   mfH        = cmMidiFileNullHandle;
2723
+  unsigned        trkN       = 2;
2724
+  unsigned        ticksPerQN = p->partL->measL->divisions;
2725
+  const cmChar_t* outFn      = cmFsMakeFn(dir,fn,"mid",NULL);
2726
+
2727
+  if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
2728
+    return cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
2729
+  
2730
+  cmXsPart_t* pp = p->partL;
2731
+
2732
+  // for each part
2733
+  for(; pp!=NULL; pp=pp->link)
2734
+  {
2735
+    cmXsMeas_t* mp = pp->measL;
2736
+
2737
+    // for each measure
2738
+    for(; mp!=NULL; mp=mp->link)
2739
+    {
2740
+      cmXsNote_t* np = mp->noteL;
2741
+
2742
+      if( mp->divisions != ticksPerQN )
2743
+        cmErrWarnMsg(&p->err,kMidiFailXsRC,"The 'tick per quarter note' (divisions) field in measure %i does not match the value in the first measure (%i).",mp->divisions,ticksPerQN);
2744
+
2745
+      // for each note in this measure
2746
+      for(; np!=NULL; np=np->slink)
2747
+      {
2748
+        switch( np->flags & (kOnsetXsFl|kMetronomeXsFl|kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl) )
2749
+        {
2750
+          case kOnsetXsFl:
2751
+            if( cmMidiFileInsertTrackChMsg(mfH, 1, np->tick,                kNoteOnMdId,  np->pitch, np->vel ) != kOkMfRC
2752
+              ||cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kNoteOffMdId, np->pitch, 0 ) != kOkMfRC )
2753
+            {
2754
+              rc = kMidiFailXsRC;
2755
+            }
2756
+
2757
+            break;
2758
+            
2759
+          case kDampDnXsFl:
2760
+          case kDampUpDnXsFl:
2761
+          case kSostDnXsFl:
2762
+            {
2763
+              cmMidiByte_t d0     = cmIsFlag(np->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;              
2764
+              if( (cmMidiFileInsertTrackChMsg(mfH, 1, np->tick,                kCtlMdId, d0, 127 ) != kOkMfRC )
2765
+                ||(cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kCtlMdId, d0,   0 ) != kOkMfRC ) )
2766
+              {
2767
+                rc = kMidiFailXsRC;
2768
+              }
2769
+            }
2770
+            break;
2771
+
2772
+          case kMetronomeXsFl:
2773
+            if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration ) != kOkMfRC )
2774
+              rc = kMidiFailXsRC;            
2775
+            break;
2776
+            
2777
+          case 0:
2778
+            break;
2779
+            
2780
+          default:
2781
+            { assert(0); }
2782
+        }
2783
+
2784
+        if( rc != kOkXsRC )
2785
+        {
2786
+          rc = cmErrMsg(&p->err,rc,"MIDI message insert failed on '%s'.",cmStringNullGuard(outFn));
2787
+          goto errLabel;
2788
+        }
2789
+      }
2790
+    }
2791
+  }
2792
+  
2793
+  if( cmMidiFileWrite(mfH,outFn) != kOkMfRC )
2794
+  {
2795
+    rc = cmErrMsg(&p->err,kMidiFailXsRC,"MIDI file write failed on '%s'.",cmStringNullGuard(outFn));
2796
+    goto errLabel;
2797
+  }
2798
+  
2799
+ errLabel:
2800
+  cmFsFreeFn(outFn);
2801
+  if( cmMidiFileClose(&mfH) != kOkMfRC )
2802
+  {
2803
+    rc = cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
2804
+    goto errLabel;
2805
+  }
2806
+  
2807
+  return rc;
2808
+}
2809
+
2810
+
2609
 void _cmXsPushMidiEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1 )
2811
 void _cmXsPushMidiEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1 )
2610
 {
2812
 {
2611
   cmXsMidiEvt_t* e = cmLhAllocZ(p->lhH,cmXsMidiEvt_t,1);
2813
   cmXsMidiEvt_t* e = cmLhAllocZ(p->lhH,cmXsMidiEvt_t,1);
2613
   e->tick     = tick;
2815
   e->tick     = tick;
2614
   e->durTicks = durTick;
2816
   e->durTicks = durTick;
2615
   e->voice    = voice;
2817
   e->voice    = voice;
2616
-  e->d0       = d0;
2818
+  e->d0       = d0;       // note=pitch bar=number pedal=ctl# metronome=BPM 
2617
   e->d1       = d1;
2819
   e->d1       = d1;
2618
   if( mf->eol != NULL )
2820
   if( mf->eol != NULL )
2619
     mf->eol->link = e;
2821
     mf->eol->link = e;
2630
   mf->eol = e;
2832
   mf->eol = e;
2631
 }
2833
 }
2632
 
2834
 
2633
-cmXsRC_t _cmXScoreWriteMidi( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
2835
+cmXsRC_t _cmXScoreGenMidi( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
2634
 {
2836
 {
2635
   cmXScore_t* p  = _cmXScoreHandleToPtr(h);
2837
   cmXScore_t* p  = _cmXScoreHandleToPtr(h);
2636
   cmXsPart_t* pp = p->partL;
2838
   cmXsPart_t* pp = p->partL;
2638
   cmXsMidiFile_t mf;
2840
   cmXsMidiFile_t mf;
2639
   memset(&mf,0,sizeof(mf));
2841
   memset(&mf,0,sizeof(mf));
2640
 
2842
 
2843
+  // assign durations to pedal down events
2844
+  _cmXScoreProcessPedals(p);
2845
+
2641
   for(; pp!=NULL; pp=pp->link)
2846
   for(; pp!=NULL; pp=pp->link)
2642
   {
2847
   {
2643
     const cmXsMeas_t* meas = pp->measL;
2848
     const cmXsMeas_t* meas = pp->measL;
2647
       const cmXsNote_t* note = meas->noteL;
2852
       const cmXsNote_t* note = meas->noteL;
2648
       for(; note!=NULL; note=note->slink)
2853
       for(; note!=NULL; note=note->slink)
2649
       {
2854
       {
2855
+        // if this is a metronome marker
2856
+        if( cmIsFlag(note->flags,kMetronomeXsFl) )
2857
+        {
2858
+          // set BPM as d0
2859
+          _cmXsPushMidiEvent(p,&mf,note->flags,note->tick,0,0,note->duration,0);
2860
+          continue;
2861
+          
2862
+        }
2863
+        
2650
         // if this is a sounding note
2864
         // if this is a sounding note
2651
         if( cmIsFlag(note->flags,kOnsetXsFl) )
2865
         if( cmIsFlag(note->flags,kOnsetXsFl) )
2652
         {
2866
         {
2668
           _cmXsPushMidiEvent(p,&mf,note->flags,note->tick,0,0,note->meas->number,0);
2882
           _cmXsPushMidiEvent(p,&mf,note->flags,note->tick,0,0,note->meas->number,0);
2669
           continue;
2883
           continue;
2670
         }
2884
         }
2885
+
2886
+        // if this is a pedal event
2887
+        if( cmIsFlag(note->flags,kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl) )
2888
+        {
2889
+          unsigned d0 = cmIsFlag(note->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;          
2890
+          _cmXsPushMidiEvent(p,&mf,note->flags,note->tick,note->duration,0,d0,127);
2891
+          continue;
2892
+        }
2671
         
2893
         
2672
       }
2894
       }
2673
     }
2895
     }
2674
   }
2896
   }
2675
 
2897
 
2898
+  _cmXsWriteMidiFile( ctx, p, &mf, dir, fn );
2899
+
2676
   return _cmXsWriteMidiSvg( ctx, p, &mf, dir, fn );
2900
   return _cmXsWriteMidiSvg( ctx, p, &mf, dir, fn );
2677
 
2901
 
2678
 }
2902
 }
2719
   {
2943
   {
2720
     cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
2944
     cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
2721
     
2945
     
2722
-    _cmXScoreWriteMidi( ctx, h, pp->dirStr, pp->fnStr );
2946
+    _cmXScoreGenMidi( ctx, h, pp->dirStr, pp->fnStr );
2723
 
2947
 
2724
     cmFsFreePathParts(pp);
2948
     cmFsFreePathParts(pp);
2725
     
2949
     
2726
   }
2950
   }
2727
   
2951
   
2728
-  //cmXScoreReport(h,&ctx->rpt,true);
2952
+  //cmXScoreReport(h,&ctx->rpt,false);
2729
 
2953
 
2730
   return cmXScoreFinalize(&h);
2954
   return cmXScoreFinalize(&h);
2731
 
2955
 

+ 1
- 0
app/cmXScore.h View File

15
     kUnterminatedTieXsRC,
15
     kUnterminatedTieXsRC,
16
     kUnterminatedSlurXsRC,
16
     kUnterminatedSlurXsRC,
17
     kUnterminatedOctaveShiftXsrRC,
17
     kUnterminatedOctaveShiftXsrRC,
18
+    kPedalStateErrorXsRc,
18
     kMidiFailXsRC,
19
     kMidiFailXsRC,
19
     kFileFailXsRC,
20
     kFileFailXsRC,
20
     kSvgFailXsRC
21
     kSvgFailXsRC

Loading…
Cancel
Save