Selaa lähdekoodia

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

master
kevin 8 vuotta sitten
vanhempi
commit
9036de70ba
2 muutettua tiedostoa jossa 284 lisäystä ja 59 poistoa
  1. 283
    59
      app/cmXScore.c
  2. 1
    0
      app/cmXScore.h

+ 283
- 59
app/cmXScore.c Näytä tiedosto

@@ -50,9 +50,9 @@ enum
50 50
   kTieBegXsFl    = 0x000400,
51 51
   kTieEndXsFl    = 0x000800,
52 52
   kTieProcXsFl   = 0x001000,
53
-  kPedalDnXsFl   = 0x002000,
54
-  kPedalUpXsFl   = 0x004000,
55
-  kPedalUpDnXsFl = 0x008000,
53
+  kDampDnXsFl    = 0x002000,
54
+  kDampUpXsFl    = 0x004000,
55
+  kDampUpDnXsFl  = 0x008000,
56 56
   kSostDnXsFl    = 0x010000,
57 57
   kSostUpXsFl    = 0x020000,
58 58
   kMetronomeXsFl = 0x040000,  // duration holds BPM
@@ -680,13 +680,13 @@ cmXsRC_t  _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNo
680 680
       return _cmXScoreMissingAttribute(p, np, "type" );
681 681
 
682 682
     if( cmTextCmp(a->value,"start") == 0 )
683
-      flags = kPedalDnXsFl;
683
+      flags = kDampDnXsFl;
684 684
     else
685 685
       if( cmTextCmp(a->value,"change") == 0 )
686
-        flags = kPedalUpDnXsFl;
686
+        flags = kDampUpDnXsFl;
687 687
       else
688 688
         if( cmTextCmp(a->value,"stop") == 0 )
689
-          flags = kPedalUpXsFl;
689
+          flags = kDampUpXsFl;
690 690
         else
691 691
           return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Unrecognized pedal type:'%s'.",cmStringNullGuard(a->value));
692 692
   }
@@ -899,6 +899,7 @@ void _cmXScoreSort( cmXScore_t* p )
899 899
   }
900 900
 }
901 901
 
902
+// Set the cmXsNode_t.secs and dsecs.
902 903
 void _cmXScoreSetAbsoluteTime( cmXScore_t* p )
903 904
 {
904 905
   double          tpqn         = 0; // ticks per quarter note
@@ -925,21 +926,21 @@ void _cmXScoreSetAbsoluteTime( cmXScore_t* p )
925 926
         // dticks = np->tick - metro_tick;     // where metro_tick is the absolute tick of the last metro event
926 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 931
         double   dsecs  = secs - sec0;
931 932
 
932 933
         //
933 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 945
           np->secs  = secs;
945 946
           np->dsecs = dsecs;
@@ -1016,9 +1017,10 @@ void _cmXScoreSpreadGraceNotes( cmXScore_t* p )
1016 1017
       // A tick group is a group of events that share the same tick.
1017 1018
       unsigned    tick0 = np->tick;
1018 1019
 
1020
+      // for each note 
1019 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 1024
         if( np->tick != tick0 )
1023 1025
         {
1024 1026
           // if there is more than one event in the completed tick group ...
@@ -1370,6 +1372,93 @@ void _cmXScoreFixBarLines( cmXScore_t* p )
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 1462
 cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn )
1374 1463
 {
1375 1464
   cmXsRC_t rc = kOkXsRC;
@@ -1472,7 +1561,7 @@ typedef struct
1472 1561
   cmXsNote_t* note;     // The cmXsNode_t* associated with this cmXsReorder_t record
1473 1562
   
1474 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 1565
   unsigned    newTick;   // 0=ignore >0 new tick value
1477 1566
   unsigned    pitch;     // 0=ignore >0 new pitch
1478 1567
 } cmXsReorder_t;
@@ -1560,7 +1649,7 @@ void _cmXScoreInsertPedalEvent( cmXScore_t* p, const cmXsReorder_t* r, unsigned
1560 1649
   nn->flags = flags;
1561 1650
   
1562 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 1654
     nn->tick  = r->note->tick + 1;
1566 1655
     _cmXScoreInsertNoteAfter(r->note,nn);
@@ -1568,7 +1657,7 @@ void _cmXScoreInsertPedalEvent( cmXScore_t* p, const cmXsReorder_t* r, unsigned
1568 1657
   else
1569 1658
   {
1570 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 1662
       nn->tick  = r->note->tick==0 ? 0 : r->note->tick - 1;
1574 1663
       _cmXScoreInsertNoteBefore(r->note,nn);
@@ -1642,14 +1731,14 @@ cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t*
1642 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 1737
       if( cmIsFlag(rV[i].newFlags,kSostDnXsFl ) )
1649 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 1743
       if( cmIsFlag(rV[i].newFlags,kSostUpXsFl ) )
1655 1744
         _cmXScoreInsertPedalEvent(p,rV + i,kSostUpXsFl);
@@ -1764,11 +1853,11 @@ cmXsRC_t  _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned
1764 1853
         break;                
1765 1854
         
1766 1855
       case 'D':
1767
-        *newFlagsRef |= kPedalDnXsFl;  // damper pedal down
1856
+        *newFlagsRef |= kDampDnXsFl;  // damper pedal down
1768 1857
         break;
1769 1858
 
1770 1859
       case 'U':
1771
-        *newFlagsRef |= kPedalUpXsFl;  // damper pedal up
1860
+        *newFlagsRef |= kDampUpXsFl;  // damper pedal up
1772 1861
         break;
1773 1862
 
1774 1863
       case '_':
@@ -2329,14 +2418,14 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
2329 2418
         else
2330 2419
         {
2331 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 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 2425
             _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,np->secs,d0,d1,-1,0,"",np->flags,"","");
2337 2426
             sectionIdStr = NULL;
2338 2427
             
2339
-            if( cmIsFlag(np->flags,kPedalUpDnXsFl) )
2428
+            if( cmIsFlag(np->flags,kDampUpDnXsFl) )
2340 2429
             {
2341 2430
               rowIdx += 1;
2342 2431
               double millisecond = 0.0;
@@ -2405,15 +2494,15 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
2405 2494
   const cmChar_t* e  = cmIsFlag(note->flags,kEvenXsFl)      ? "e" : "-";
2406 2495
   const cmChar_t* d  = cmIsFlag(note->flags,kDynXsFl)       ? "d" : "-";
2407 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 2498
   const cmChar_t* s  = cmIsFlag(note->flags,kSostDnXsFl)    ? "{" : "-";
2410 2499
   const cmChar_t* S  = cmIsFlag(note->flags,kSectionXsFl)   ? "S" : "-";
2411 2500
   const cmChar_t* H  = cmIsFlag(note->flags,kHeelXsFl)      ? "H" : "-";
2412 2501
   const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl)    ? "T" : "-";
2413 2502
   const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl)    ? "_" : "-";
2414 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 2506
   s = cmIsFlag(note->flags,kSostUpXsFl)    ? "}" : s;
2418 2507
   //const cmChar_t* N = note->pitch==0 ? " " : cmMidiToSciPitch( note->pitch, NULL, 0 );
2419 2508
 
@@ -2548,7 +2637,8 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
2548 2637
   unsigned        noteHeight = 10;
2549 2638
   const cmChar_t* svgFn      = cmFsMakeFn(dir,fn,"html",NULL);
2550 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 2642
   // create the SVG writer
2553 2643
   if( cmSvgWriterAlloc(ctx,&svgH) != kOkSvgRC )
2554 2644
   {
@@ -2559,37 +2649,53 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
2559 2649
   // for each MIDI file element
2560 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 2699
   if( rc != kOkXsRC )
2594 2700
     cmErrMsg(&p->err,kSvgFailXsRC,"SVG element insert failed.");
2595 2701
 
@@ -2606,6 +2712,102 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
2606 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 2811
 void _cmXsPushMidiEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsigned tick, unsigned durTick, unsigned voice, unsigned d0, unsigned d1 )
2610 2812
 {
2611 2813
   cmXsMidiEvt_t* e = cmLhAllocZ(p->lhH,cmXsMidiEvt_t,1);
@@ -2613,7 +2815,7 @@ void _cmXsPushMidiEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsi
2613 2815
   e->tick     = tick;
2614 2816
   e->durTicks = durTick;
2615 2817
   e->voice    = voice;
2616
-  e->d0       = d0;
2818
+  e->d0       = d0;       // note=pitch bar=number pedal=ctl# metronome=BPM 
2617 2819
   e->d1       = d1;
2618 2820
   if( mf->eol != NULL )
2619 2821
     mf->eol->link = e;
@@ -2630,7 +2832,7 @@ void _cmXsPushMidiEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsi
2630 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 2837
   cmXScore_t* p  = _cmXScoreHandleToPtr(h);
2636 2838
   cmXsPart_t* pp = p->partL;
@@ -2638,6 +2840,9 @@ cmXsRC_t _cmXScoreWriteMidi( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
2638 2840
   cmXsMidiFile_t mf;
2639 2841
   memset(&mf,0,sizeof(mf));
2640 2842
 
2843
+  // assign durations to pedal down events
2844
+  _cmXScoreProcessPedals(p);
2845
+
2641 2846
   for(; pp!=NULL; pp=pp->link)
2642 2847
   {
2643 2848
     const cmXsMeas_t* meas = pp->measL;
@@ -2647,6 +2852,15 @@ cmXsRC_t _cmXScoreWriteMidi( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
2647 2852
       const cmXsNote_t* note = meas->noteL;
2648 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 2864
         // if this is a sounding note
2651 2865
         if( cmIsFlag(note->flags,kOnsetXsFl) )
2652 2866
         {
@@ -2668,11 +2882,21 @@ cmXsRC_t _cmXScoreWriteMidi( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
2668 2882
           _cmXsPushMidiEvent(p,&mf,note->flags,note->tick,0,0,note->meas->number,0);
2669 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 2900
   return _cmXsWriteMidiSvg( ctx, p, &mf, dir, fn );
2677 2901
 
2678 2902
 }
@@ -2719,13 +2943,13 @@ cmXsRC_t cmXScoreTest(
2719 2943
   {
2720 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 2948
     cmFsFreePathParts(pp);
2725 2949
     
2726 2950
   }
2727 2951
   
2728
-  //cmXScoreReport(h,&ctx->rpt,true);
2952
+  //cmXScoreReport(h,&ctx->rpt,false);
2729 2953
 
2730 2954
   return cmXScoreFinalize(&h);
2731 2955
 

+ 1
- 0
app/cmXScore.h Näytä tiedosto

@@ -15,6 +15,7 @@ extern "C" {
15 15
     kUnterminatedTieXsRC,
16 16
     kUnterminatedSlurXsRC,
17 17
     kUnterminatedOctaveShiftXsrRC,
18
+    kPedalStateErrorXsRc,
18 19
     kMidiFailXsRC,
19 20
     kFileFailXsRC,
20 21
     kSvgFailXsRC

Loading…
Peruuta
Tallenna