Browse Source

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

master
kevin 8 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
 
37
 
38
 enum
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
   return rc;
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
 // Adjust the locations of grace notes. Note that this must be done
1522
 // Adjust the locations of grace notes. Note that this must be done
1469
 // after reordering so that we can be sure that the order in time of
1523
 // after reordering so that we can be sure that the order in time of
1476
   
1530
   
1477
   for(; 1; ++graceGroupId)
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
     cmXsPart_t* pp          = p->partL;
1536
     cmXsPart_t* pp          = p->partL;
1481
     double      ticksPerSec = 0;
1537
     double      ticksPerSec = 0;
1482
     
1538
     
1498
           // if this note is part of the grace note group we are searching for
1554
           // if this note is part of the grace note group we are searching for
1499
           if( np->graceGroupId == graceGroupId )
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
             // set each grace note to have 1/20 of a second duration
1568
             // set each grace note to have 1/20 of a second duration
1505
             if( cmIsFlag(np->flags,kGraceXsFl) )
1569
             if( cmIsFlag(np->flags,kGraceXsFl) )
1506
               np->duration = floor(ticksPerSec / 20.0);
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
     // no records were found for this grace id - we're done
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
       break;
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
   
1776
   
1649
   cmXsNote_t* note;     // The cmXsNote_t* associated with this cmXsReorder_t record
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
   unsigned    graceGroupId; // 0=ignore >0=grace note group id
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
 } cmXsReorder_t;
1785
 } cmXsReorder_t;
1658
 
1786
 
1659
 typedef struct _cmXScoreDynMark_str
1787
 typedef struct _cmXScoreDynMark_str
1807
     // if a new note value was specified
1935
     // if a new note value was specified
1808
     if( rV[i].pitch != 0 )
1936
     if( rV[i].pitch != 0 )
1809
       rV[i].note->pitch = rV[i].pitch;
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
     n0p        = rV[i].note;
1942
     n0p        = rV[i].note;
1831
     n0p->slink = NULL;
1943
     n0p->slink = NULL;
2004
   return rc;
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
   cmXsRC_t        rc = kOkXsRC;
2121
   cmXsRC_t        rc = kOkXsRC;
2010
   const cmChar_t* s;
2122
   const cmChar_t* s;
2011
 
2123
 
2012
-  *graceTypeRef = 0;
2013
-
2014
   if((s = strchr(b,'%')) == NULL )
2124
   if((s = strchr(b,'%')) == NULL )
2015
     return rc;
2125
     return rc;
2016
 
2126
 
2017
   ++s;
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
   return rc;
2153
   return rc;
2165
               goto errLabel;
2285
               goto errLabel;
2166
 
2286
 
2167
             // parse the %grace note marker
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
               goto errLabel;
2289
               goto errLabel;
2170
 
2290
 
2171
             // parse the $pitch marker
2291
             // parse the $pitch marker
2174
 
2294
 
2175
             // process grace notes - these need to be processed separate from
2295
             // process grace notes - these need to be processed separate from
2176
             // the _cmXScoreReorderMeas() because grace notes may cross measure boundaries.
2296
             // the _cmXScoreReorderMeas() because grace notes may cross measure boundaries.
2297
+            /*
2177
             if( r.graceType != 0 )
2298
             if( r.graceType != 0 )
2178
             {
2299
             {
2179
               r.graceGroupId = graceGroupId;
2300
               r.graceGroupId = graceGroupId;
2185
               }
2306
               }
2186
               
2307
               
2187
             }
2308
             }
2188
-
2309
+            */
2310
+            
2189
             // store the record
2311
             // store the record
2190
             assert( ri < rN );
2312
             assert( ri < rN );
2191
             rV[ri++] = r;
2313
             rV[ri++] = r;
2225
   // the bar lines should be the first event in the measure
2347
   // the bar lines should be the first event in the measure
2226
   _cmXScoreFixBarLines(p);
2348
   _cmXScoreFixBarLines(p);
2227
 
2349
 
2228
-  // resort to force the links to be correct
2350
+  // resort to force the links to be correct 
2229
   _cmXScoreSort(p);
2351
   _cmXScoreSort(p);
2230
 
2352
 
2353
+  // process the grace notes.
2231
   _cmXScoreProcessGraceNotes( p );
2354
   _cmXScoreProcessGraceNotes( p );
2355
+
2356
+  // inserting grace notes may have left the score unsorted
2357
+  _cmXScoreSort(p);
2232
   
2358
   
2233
  errLabel:
2359
  errLabel:
2234
   cmFileClose(&fH);
2360
   cmFileClose(&fH);
2688
   if( note->tempoGroupId != 0 )
2814
   if( note->tempoGroupId != 0 )
2689
     cmRptPrintf(rpt," t=%i",note->tempoGroupId);
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
     
3236
     
3108
   }
3237
   }
3109
   
3238
   
3110
-  //cmXScoreReport(h,&ctx->rpt,false);
3239
+  cmXScoreReport(h,&ctx->rpt,true);
3111
 
3240
 
3112
   return cmXScoreFinalize(&h);
3241
   return cmXScoreFinalize(&h);
3113
 
3242
 

Loading…
Cancel
Save