Browse Source

cmXScore.c : Completed 'add' and 'subtract' based grace note positioning.

master
kevin 7 years ago
parent
commit
d2a3d0d32e
1 changed files with 218 additions and 89 deletions
  1. 218
    89
      app/cmXScore.c

+ 218
- 89
app/cmXScore.c View File

@@ -37,30 +37,33 @@ cmXsH_t cmXsNullHandle = cmSTATIC_NULL_HANDLE;
37 37
 
38 38
 enum
39 39
 {
40
-  kSectionXsFl     = 0x000001,  // rvalue holds section number
41
-  kBarXsFl         = 0x000002,
42
-  kRestXsFl        = 0x000004,
43
-  kGraceXsFl       = 0x000008,
44
-  kDotXsFl         = 0x000010,
45
-  kChordXsFl       = 0x000020,
46
-  kDynXsFl         = 0x000040,
47
-  kEvenXsFl        = 0x000080,
48
-  kTempoXsFl       = 0x000100,
49
-  kHeelXsFl        = 0x000200,
50
-  kTieBegXsFl      = 0x000400,
51
-  kTieEndXsFl      = 0x000800,
52
-  kTieProcXsFl     = 0x001000,
53
-  kDampDnXsFl      = 0x002000,
54
-  kDampUpXsFl      = 0x004000,
55
-  kDampUpDnXsFl    = 0x008000,
56
-  kSostDnXsFl      = 0x010000,
57
-  kSostUpXsFl      = 0x020000,
58
-  kMetronomeXsFl   = 0x040000,  // duration holds BPM
59
-  kOnsetXsFl       = 0x080000,  // this is a sounding note
60
-  kBegGroupXsFl    = 0x100000,
61
-  kEndGroupXsFl    = 0x200000,
62
-  kBegGraceXsFl    = 0x400000,  // beg grace note group
63
-  kEndGraceXsFl    = 0x800000   // end grace note group
40
+  kSectionXsFl     = 0x0000001,  // rvalue holds section number
41
+  kBarXsFl         = 0x0000002,
42
+  kRestXsFl        = 0x0000004,
43
+  kGraceXsFl       = 0x0000008,
44
+  kDotXsFl         = 0x0000010,
45
+  kChordXsFl       = 0x0000020,
46
+  kDynXsFl         = 0x0000040,
47
+  kEvenXsFl        = 0x0000080,
48
+  kTempoXsFl       = 0x0000100,
49
+  kHeelXsFl        = 0x0000200,
50
+  kTieBegXsFl      = 0x0000400,
51
+  kTieEndXsFl      = 0x0000800,
52
+  kTieProcXsFl     = 0x0001000,
53
+  kDampDnXsFl      = 0x0002000,
54
+  kDampUpXsFl      = 0x0004000,
55
+  kDampUpDnXsFl    = 0x0008000,
56
+  kSostDnXsFl      = 0x0010000,
57
+  kSostUpXsFl      = 0x0020000,
58
+  kMetronomeXsFl   = 0x0040000,  // duration holds BPM
59
+  kOnsetXsFl       = 0x0080000,  // this is a sounding note
60
+  kBegGroupXsFl    = 0x0100000,
61
+  kEndGroupXsFl    = 0x0200000,
62
+  kBegGraceXsFl    = 0x0400000,  // beg grace note group
63
+  kEndGraceXsFl    = 0x0800000,  // end grace note group
64
+  kAddGraceXsFl    = 0x1000000,  // end grace note group operator flag - add time
65
+  kSubGraceXsFl    = 0x2000000,  //  "    "    "     "      "       "  - subtract time
66
+  kFirstGraceXsFl  = 0x4000000,  //  "    "    "     "      "       "  - sync to first note
64 67
   
65 68
 };
66 69
 
@@ -1464,6 +1467,57 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
1464 1467
   return rc;
1465 1468
 }
1466 1469
 
1470
+void _cmXScoreInsertTime( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* np, unsigned expand_ticks )
1471
+{
1472
+  for(; mp!=NULL; mp=mp->link)
1473
+  {  
1474
+    if( np == NULL )
1475
+      np = mp->noteL;
1476
+  
1477
+    for(; np!=NULL; np=np->slink)
1478
+      np->tick += expand_ticks;
1479
+  }   
1480
+}
1481
+
1482
+// Insert the grace notes in between the first and last note in the group
1483
+// by inserting time between the first and last note.
1484
+void _cmXScoreGraceInsertTime( cmXScore_t* p, unsigned graceGroupId, cmXsNote_t* aV[], unsigned aN )
1485
+{
1486
+  cmXsNote_t* np = NULL;
1487
+  unsigned expand_ticks = 0;
1488
+  unsigned ticks = aV[aN-1]->tick;
1489
+  unsigned i;
1490
+  for(i=0; i<aN; ++i)
1491
+    if( cmIsFlag(aV[i]->flags,kGraceXsFl) && aV[i]->graceGroupId == graceGroupId )
1492
+    {
1493
+      aV[i]->tick   = ticks;
1494
+      ticks        += aV[i]->duration;
1495
+      expand_ticks += aV[i]->duration;
1496
+      np            = aV[i];
1497
+    }
1498
+
1499
+  np = np->slink;
1500
+  if( np != NULL )
1501
+    _cmXScoreInsertTime(p,np->meas,np,expand_ticks);
1502
+}
1503
+
1504
+// Insert the grace notes in between the first and last note in the group
1505
+// but do not insert any additional time betwee the first and last note.
1506
+// In effect time is removed from the first note and taken by the grace notes.
1507
+void _cmXScoreGraceOverlayTime( cmXScore_t* p, unsigned graceGroupId, cmXsNote_t* aV[], unsigned aN )
1508
+{
1509
+  assert(aN >= 3 );
1510
+  
1511
+  unsigned t = aV[aN-1]->tick;
1512
+  int      i = (int)aN-2;
1513
+  
1514
+  for(; i>0; --i)
1515
+    if( cmIsFlag(aV[i]->flags,kGraceXsFl) && aV[i]->graceGroupId == graceGroupId )
1516
+    {
1517
+      aV[i]->tick = t - aV[i]->duration;
1518
+      t           =     aV[i]->tick;
1519
+    }
1520
+}
1467 1521
 
1468 1522
 // Adjust the locations of grace notes. Note that this must be done
1469 1523
 // after reordering so that we can be sure that the order in time of
@@ -1476,7 +1530,9 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
1476 1530
   
1477 1531
   for(; 1; ++graceGroupId)
1478 1532
   {
1479
-    cmXsNote_t* gnp         = NULL;
1533
+    cmXsNote_t* gn0p        = NULL;
1534
+    cmXsNote_t* gn1p        = NULL;
1535
+    unsigned    gN          = 0;
1480 1536
     cmXsPart_t* pp          = p->partL;
1481 1537
     double      ticksPerSec = 0;
1482 1538
     
@@ -1498,47 +1554,119 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
1498 1554
           // if this note is part of the grace note group we are searching for
1499 1555
           if( np->graceGroupId == graceGroupId )
1500 1556
           {
1501
-            // add the note to the grace note list
1502
-            np->grace = gnp;
1557
+            // track the first note in the grace note list
1558
+            if( gn0p == NULL )
1559
+              gn0p = np;
1560
+
1561
+            // add the note to the end of the grace note list
1562
+            if( gn1p != NULL )
1563
+              gn1p->grace = np;
1503 1564
 
1565
+            // track the last note in the grace note list
1566
+            gn1p = np;
1567
+              
1504 1568
             // set each grace note to have 1/20 of a second duration
1505 1569
             if( cmIsFlag(np->flags,kGraceXsFl) )
1506 1570
               np->duration = floor(ticksPerSec / 20.0);
1507 1571
 
1508
-            gnp = np;
1572
+            gN += 1;
1509 1573
           }
1510
-        }
1574
+            
1575
+        } //
1511 1576
       }
1512 1577
     }
1513 1578
 
1514 1579
     // no records were found for this grace id - we're done
1515
-    if( gnp == NULL )
1580
+    if( gn0p == NULL )
1581
+      break;
1582
+
1583
+    // grace note groups must have at least 3 members
1584
+    if( gN < 3 )
1585
+    {
1586
+      rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"The grace not group ending in meas %i has fewer than 3 (%i) members.", gn1p->meas->number, gN );
1516 1587
       break;
1588
+    }
1517 1589
 
1518
-    cmXsNote_t* p0 = NULL;
1519
-    cmXsNote_t* p1 = gnp;
1520 1590
     
1521
-    for(; p1!=NULL; p1=p1->grace)
1591
+    // gn0p is now set to the first note in th group
1592
+    // gn1p is now set to the last note in the group
1593
+
1594
+    // verify that the first note is marked with kBegGraceXsFl
1595
+    if( cmIsNotFlag(gn0p->flags,kBegGraceXsFl) )
1522 1596
     {
1523
-      if(1)
1597
+      rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"The first note in a grace note group in meas %i is not marked with a 'b'.", gn0p->meas->number );
1598
+      break;
1599
+    }
1600
+
1601
+    // verify that the last note is marked with kEndGraceXsFl
1602
+    if( cmIsNotFlag(gn1p->flags,kEndGraceXsFl) )
1603
+    {
1604
+      rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"The last note in a grace note group in meas %i is not marked with a valid operator character.", gn1p->meas->number );
1605
+      break;
1606
+    }
1607
+
1608
+    // count the total number of events between gn0p and gn1p
1609
+    cmXsNote_t* n0p = NULL;
1610
+    cmXsNote_t* n1p = gn0p;
1611
+    cmXsMeas_t* mp  = gn0p->meas;
1612
+    unsigned    aN  = 0;
1613
+    for(; n0p != gn1p; n1p=n1p->slink )
1614
+    {
1615
+      // if we are crossing a measure boundary
1616
+      if( n1p == NULL )
1524 1617
       {
1525
-        const char* type = "g";
1526
-        if( cmIsFlag(p1->flags,kBegGraceXsFl) )
1527
-          type           = "b";
1528
-        
1529
-        if( cmIsFlag(p1->flags,kEndGraceXsFl) )
1530
-          type = "i";
1531
-        
1532
-        bool fl = p0 != NULL && p0->tick < p1->tick;
1533
-        printf("%3i %s %i %5i %i\n",p1->graceGroupId,type,p1->tick,p1->duration,fl);
1618
+        mp  = mp->link;
1619
+        assert(mp!=NULL);
1620
+        n1p = mp->noteL;        
1534 1621
       }
1535 1622
 
1536
-      // TODO:
1537
-      // position grace notes here
1538
-
1623
+      if(1)
1624
+      {
1625
+        bool     fl   = n0p != NULL && n0p->tick < n1p->tick;
1626
+        unsigned type = n1p->flags & (kBegGraceXsFl|kEndGraceXsFl|kAddGraceXsFl|kSubGraceXsFl|kFirstGraceXsFl);
1627
+        printf("%3i 0x%08x %i %5i %i\n",n1p->graceGroupId,type,n1p->tick,n1p->duration,fl);
1628
+      }
1539 1629
       
1630
+      ++aN;
1631
+      n0p = n1p;
1632
+    }
1633
+
1634
+    // create a vector of pointers to all events between gn0p and gn1p
1635
+    cmXsNote_t* aV[ aN ];
1636
+    unsigned    i;
1637
+    n1p = gn0p;
1638
+    n0p = NULL;
1639
+    mp = gn0p->meas;
1640
+    for(i=0; n0p != gn1p; n1p=n1p->slink )
1641
+    {
1642
+      // if we are crossing a measure boundardy
1643
+      if( n1p == NULL )
1644
+      {
1645
+        mp  = mp->link;
1646
+        assert(mp!=NULL);
1647
+        n1p = mp->noteL;        
1648
+      }
1540 1649
       
1541
-      p0 = p1;
1650
+      assert(i<aN);
1651
+      aV[i++] = n1p;
1652
+      n0p     = n1p;
1653
+    }
1654
+
1655
+    switch( gn1p->flags & (kAddGraceXsFl | kSubGraceXsFl | kFirstGraceXsFl) )
1656
+    {
1657
+      case kAddGraceXsFl:
1658
+        _cmXScoreGraceInsertTime(p, graceGroupId, aV, aN );
1659
+        break;
1660
+        
1661
+      case kSubGraceXsFl:
1662
+        _cmXScoreGraceOverlayTime(p, graceGroupId, aV, aN );
1663
+        break;
1664
+        
1665
+      case kFirstGraceXsFl:
1666
+        break;
1667
+        
1668
+      default:
1669
+        { assert(0); }
1542 1670
     }
1543 1671
 
1544 1672
     
@@ -1648,12 +1776,12 @@ typedef struct
1648 1776
   
1649 1777
   cmXsNote_t* note;     // The cmXsNote_t* associated with this cmXsReorder_t record
1650 1778
   
1651
-  unsigned    dynIdx;    // cmInvalidIdx=ignore otherwise index into _cmXScoreDynMarkArray[]
1652
-  unsigned    newFlags;  // 0=ignore | kSostUp/DnXsFl | kDampUp/DnXsFl  | kTieEndXsFl
1653
-  unsigned    newTick;   // 0=ignore >0 new tick value
1654
-  char        graceType; // 0=ignore g=grace note i=anchor note
1779
+  unsigned    dynIdx;       // cmInvalidIdx=ignore otherwise index into _cmXScoreDynMarkArray[]
1780
+  unsigned    newFlags;     // 0=ignore | kSostUp/DnXsFl | kDampUp/DnXsFl  | kTieEndXsFl
1781
+  unsigned    newTick;      // 0=ignore >0 new tick value
1782
+  unsigned    graceFlags;   // 0=ignore See kXXXGraceXsFl
1655 1783
   unsigned    graceGroupId; // 0=ignore >0=grace note group id
1656
-  unsigned    pitch;     // 0=ignore >0 new pitch
1784
+  unsigned    pitch;        // 0=ignore >0 new pitch
1657 1785
 } cmXsReorder_t;
1658 1786
 
1659 1787
 typedef struct _cmXScoreDynMark_str
@@ -1807,25 +1935,9 @@ cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t*
1807 1935
     // if a new note value was specified
1808 1936
     if( rV[i].pitch != 0 )
1809 1937
       rV[i].note->pitch = rV[i].pitch;
1810
-
1811
-    switch(rV[i].graceType)
1812
-    {
1813
-      case 'b':
1814
-        rV[i].note->flags = cmSetFlag(rV[i].note->flags,kBegGraceXsFl);
1815
-        break;
1816
-        
1817
-      case 'g':
1818
-        break;
1819
-        
1820
-      case 'a':
1821
-      case 's':
1822
-      case 'f':
1823
-        rV[i].note->flags = cmSetFlag(rV[i].note->flags,kEndGraceXsFl);
1824
-        break;
1825
-
1826
-    }
1827
-
1828
-    rV[i].note->graceGroupId = rV[i].graceGroupId;
1938
+    
1939
+    rV[i].note->flags        |= rV[i].graceFlags;
1940
+    rV[i].note->graceGroupId  = rV[i].graceGroupId;
1829 1941
     
1830 1942
     n0p        = rV[i].note;
1831 1943
     n0p->slink = NULL;
@@ -2004,30 +2116,38 @@ cmXsRC_t  _cmXScoreReorderParseTick(cmXScore_t* p, const cmChar_t* b, unsigned l
2004 2116
   return rc;
2005 2117
 }
2006 2118
 
2007
-cmXsRC_t  _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned line, char* graceTypeRef )
2119
+cmXsRC_t  _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned line, cmXsReorder_t* r, unsigned* graceGroupIdRef )
2008 2120
 {
2009 2121
   cmXsRC_t        rc = kOkXsRC;
2010 2122
   const cmChar_t* s;
2011 2123
 
2012
-  *graceTypeRef = 0;
2013
-
2014 2124
   if((s = strchr(b,'%')) == NULL )
2015 2125
     return rc;
2016 2126
 
2017 2127
   ++s;
2018 2128
 
2019
-  switch(*s)
2129
+  r->graceGroupId = *graceGroupIdRef;
2130
+  
2131
+  while(1)
2020 2132
   {
2021
-    case 'b':
2022
-    case 'g':
2023
-    case 'a':
2024
-    case 's':
2025
-    case 'f':
2026
-      *graceTypeRef = *s;
2027
-      break;
2028
-
2029
-    default:
2030
-      { assert(0); }
2133
+    switch(*s)
2134
+    {
2135
+      case 'b': r->graceFlags |= kBegGraceXsFl;                   break;        
2136
+      case 'a': r->graceFlags |= kAddGraceXsFl   | kEndGraceXsFl; break;
2137
+      case 's': r->graceFlags |= kSubGraceXsFl   | kEndGraceXsFl; break;
2138
+      case 'f': r->graceFlags |= kFirstGraceXsFl | kEndGraceXsFl; break;
2139
+      case 'g': break;
2140
+
2141
+      case '%':
2142
+        *graceGroupIdRef += 1;
2143
+        ++s;
2144
+        continue;
2145
+        
2146
+      default:
2147
+        { assert(0); }
2148
+    }
2149
+    
2150
+    break;
2031 2151
   }
2032 2152
   
2033 2153
   return rc;
@@ -2165,7 +2285,7 @@ cmXsRC_t cmXScoreReorder( cmXsH_t h, const cmChar_t* fn )
2165 2285
               goto errLabel;
2166 2286
 
2167 2287
             // parse the %grace note marker
2168
-            if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &r.graceType)) != kOkXsRC )
2288
+            if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &r, &graceGroupId)) != kOkXsRC )
2169 2289
               goto errLabel;
2170 2290
 
2171 2291
             // parse the $pitch marker
@@ -2174,6 +2294,7 @@ cmXsRC_t cmXScoreReorder( cmXsH_t h, const cmChar_t* fn )
2174 2294
 
2175 2295
             // process grace notes - these need to be processed separate from
2176 2296
             // the _cmXScoreReorderMeas() because grace notes may cross measure boundaries.
2297
+            /*
2177 2298
             if( r.graceType != 0 )
2178 2299
             {
2179 2300
               r.graceGroupId = graceGroupId;
@@ -2185,7 +2306,8 @@ cmXsRC_t cmXScoreReorder( cmXsH_t h, const cmChar_t* fn )
2185 2306
               }
2186 2307
               
2187 2308
             }
2188
-
2309
+            */
2310
+            
2189 2311
             // store the record
2190 2312
             assert( ri < rN );
2191 2313
             rV[ri++] = r;
@@ -2225,10 +2347,14 @@ cmXsRC_t cmXScoreReorder( cmXsH_t h, const cmChar_t* fn )
2225 2347
   // the bar lines should be the first event in the measure
2226 2348
   _cmXScoreFixBarLines(p);
2227 2349
 
2228
-  // resort to force the links to be correct
2350
+  // resort to force the links to be correct 
2229 2351
   _cmXScoreSort(p);
2230 2352
 
2353
+  // process the grace notes.
2231 2354
   _cmXScoreProcessGraceNotes( p );
2355
+
2356
+  // inserting grace notes may have left the score unsorted
2357
+  _cmXScoreSort(p);
2232 2358
   
2233 2359
  errLabel:
2234 2360
   cmFileClose(&fH);
@@ -2688,6 +2814,9 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
2688 2814
   if( note->tempoGroupId != 0 )
2689 2815
     cmRptPrintf(rpt," t=%i",note->tempoGroupId);
2690 2816
 
2817
+  if( note->graceGroupId != 0)
2818
+    cmRptPrintf(rpt," g=%i",note->graceGroupId);
2819
+
2691 2820
 }
2692 2821
 
2693 2822
 
@@ -3107,7 +3236,7 @@ cmXsRC_t cmXScoreTest(
3107 3236
     
3108 3237
   }
3109 3238
   
3110
-  //cmXScoreReport(h,&ctx->rpt,false);
3239
+  cmXScoreReport(h,&ctx->rpt,true);
3111 3240
 
3112 3241
   return cmXScoreFinalize(&h);
3113 3242
 

Loading…
Cancel
Save