|
@@ -37,33 +37,34 @@ cmXsH_t cmXsNullHandle = cmSTATIC_NULL_HANDLE;
|
37
|
37
|
|
38
|
38
|
enum
|
39
|
39
|
{
|
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
|
|
40
|
+ kSectionXsFl = 0x00000001, // rvalue holds section number
|
|
41
|
+ kBarXsFl = 0x00000002,
|
|
42
|
+ kRestXsFl = 0x00000004,
|
|
43
|
+ kGraceXsFl = 0x00000008,
|
|
44
|
+ kDotXsFl = 0x00000010,
|
|
45
|
+ kChordXsFl = 0x00000020,
|
|
46
|
+ kDynXsFl = 0x00000040,
|
|
47
|
+ kEvenXsFl = 0x00000080,
|
|
48
|
+ kTempoXsFl = 0x00000100,
|
|
49
|
+ kHeelXsFl = 0x00000200,
|
|
50
|
+ kTieBegXsFl = 0x00000400,
|
|
51
|
+ kTieEndXsFl = 0x00000800,
|
|
52
|
+ kTieProcXsFl = 0x00001000,
|
|
53
|
+ kDampDnXsFl = 0x00002000,
|
|
54
|
+ kDampUpXsFl = 0x00004000,
|
|
55
|
+ kDampUpDnXsFl = 0x00008000,
|
|
56
|
+ kSostDnXsFl = 0x00010000,
|
|
57
|
+ kSostUpXsFl = 0x00020000,
|
|
58
|
+ kMetronomeXsFl = 0x00040000, // duration holds BPM
|
|
59
|
+ kOnsetXsFl = 0x00080000, // this is a sounding note
|
|
60
|
+ kBegGroupXsFl = 0x00100000,
|
|
61
|
+ kEndGroupXsFl = 0x00200000,
|
|
62
|
+ kBegGraceXsFl = 0x00400000, // (b) beg grace note group
|
|
63
|
+ kEndGraceXsFl = 0x00800000, // end grace note group
|
|
64
|
+ kAddGraceXsFl = 0x01000000, // (a) end grace note group operator flag - add time
|
|
65
|
+ kSubGraceXsFl = 0x02000000, // (s) " " " " " " - subtract time
|
|
66
|
+ kAFirstGraceXsFl = 0x04000000, // (A) add time after first note
|
|
67
|
+ kNFirstGraceXsFl = 0x08000000 // (n) grace notes start as soon as possible after first note and add time
|
67
|
68
|
|
68
|
69
|
};
|
69
|
70
|
|
|
@@ -1464,6 +1465,9 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p )
|
1464
|
1465
|
cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto left down at the end of a part.");
|
1465
|
1466
|
}
|
1466
|
1467
|
|
|
1468
|
+
|
|
1469
|
+ _cmXScoreSort(p);
|
|
1470
|
+
|
1467
|
1471
|
return rc;
|
1468
|
1472
|
}
|
1469
|
1473
|
|
|
@@ -1479,21 +1483,30 @@ void _cmXScoreInsertTime( cmXScore_t* p, cmXsMeas_t* mp, cmXsNote_t* np, unsigne
|
1479
|
1483
|
}
|
1480
|
1484
|
}
|
1481
|
1485
|
|
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 )
|
|
1486
|
+void _cmXScoreGraceInsertTimeBase( cmXScore_t* p, unsigned graceGroupId, cmXsNote_t* aV[], unsigned aN, unsigned initTick )
|
1485
|
1487
|
{
|
1486
|
|
- cmXsNote_t* np = NULL;
|
1487
|
|
- unsigned expand_ticks = 0;
|
1488
|
|
- unsigned ticks = aV[aN-1]->tick;
|
1489
|
|
- unsigned i;
|
|
1488
|
+ cmXsNote_t* np = NULL;
|
|
1489
|
+ unsigned expand_ticks = 0;
|
|
1490
|
+ unsigned ticks = initTick;
|
|
1491
|
+
|
|
1492
|
+ unsigned t0 = 0;
|
|
1493
|
+ unsigned i;
|
|
1494
|
+
|
1490
|
1495
|
for(i=0; i<aN; ++i)
|
1491
|
1496
|
if( cmIsFlag(aV[i]->flags,kGraceXsFl) && aV[i]->graceGroupId == graceGroupId )
|
1492
|
1497
|
{
|
1493
|
|
- aV[i]->tick = ticks;
|
1494
|
|
- ticks += aV[i]->duration;
|
1495
|
|
- expand_ticks += aV[i]->duration;
|
1496
|
|
- np = aV[i];
|
|
1498
|
+ // if this grace note falls on the same tick as the previous grace note
|
|
1499
|
+ if( np != NULL && aV[i]->tick == t0 )
|
|
1500
|
+ aV[i]->tick = np->tick;
|
|
1501
|
+ else
|
|
1502
|
+ {
|
|
1503
|
+ t0 = aV[i]->tick; // store the unmodified tick value of this note
|
|
1504
|
+ aV[i]->tick = ticks; // set the new tick value
|
|
1505
|
+ ticks += aV[i]->duration; // calc the next grace not location
|
|
1506
|
+ expand_ticks += aV[i]->duration; // track how much we are expanding time by
|
|
1507
|
+ }
|
|
1508
|
+
|
|
1509
|
+ np = aV[i];
|
1497
|
1510
|
}
|
1498
|
1511
|
|
1499
|
1512
|
np = np->slink;
|
|
@@ -1502,23 +1515,58 @@ void _cmXScoreGraceInsertTime( cmXScore_t* p, unsigned graceGroupId, cmXsNote_t*
|
1502
|
1515
|
}
|
1503
|
1516
|
|
1504
|
1517
|
// Insert the grace notes in between the first and last note in the group
|
|
1518
|
+// by inserting time between the first and last note.
|
|
1519
|
+// Note that in effect his means that the last note is pushed back
|
|
1520
|
+// in time by the total duration of the grace notes.
|
|
1521
|
+void _cmXScoreGraceInsertTime( cmXScore_t* p, unsigned graceGroupId, cmXsNote_t* aV[], unsigned aN )
|
|
1522
|
+{
|
|
1523
|
+ _cmXScoreGraceInsertTimeBase( p, graceGroupId,aV,aN, aV[aN-1]->tick );
|
|
1524
|
+}
|
|
1525
|
+
|
|
1526
|
+// Insert the grace notes in between the first and last note in the group
|
1505
|
1527
|
// but do not insert any additional time betwee the first and last note.
|
1506
|
1528
|
// In effect time is removed from the first note and taken by the grace notes.
|
|
1529
|
+// The time position of the last note is therefore unchanged.
|
1507
|
1530
|
void _cmXScoreGraceOverlayTime( cmXScore_t* p, unsigned graceGroupId, cmXsNote_t* aV[], unsigned aN )
|
1508
|
1531
|
{
|
1509
|
1532
|
assert(aN >= 3 );
|
1510
|
1533
|
|
1511
|
|
- unsigned t = aV[aN-1]->tick;
|
1512
|
|
- int i = (int)aN-2;
|
|
1534
|
+ int i = (int)aN-2;
|
|
1535
|
+ cmXsNote_t* np = aV[aN-1];
|
|
1536
|
+ unsigned t0 = -1;
|
1513
|
1537
|
|
1514
|
1538
|
for(; i>0; --i)
|
1515
|
1539
|
if( cmIsFlag(aV[i]->flags,kGraceXsFl) && aV[i]->graceGroupId == graceGroupId )
|
1516
|
1540
|
{
|
1517
|
|
- aV[i]->tick = t - aV[i]->duration;
|
1518
|
|
- t = aV[i]->tick;
|
|
1541
|
+ if( aV[i]->tick == t0)
|
|
1542
|
+ aV[i]->tick = np->tick;
|
|
1543
|
+ else
|
|
1544
|
+ {
|
|
1545
|
+ t0 = aV[i]->tick;
|
|
1546
|
+ aV[i]->tick = np->tick - aV[i]->duration;
|
|
1547
|
+ }
|
|
1548
|
+
|
|
1549
|
+ np = aV[i];
|
1519
|
1550
|
}
|
1520
|
1551
|
}
|
1521
|
1552
|
|
|
1553
|
+// Play the first grace at the time of the first note in the group (which is a non-grace note)
|
|
1554
|
+// and then expand time while inserting the other grace notes.
|
|
1555
|
+void _cmXScoreGraceInsertAfterFirst( cmXScore_t* p, unsigned graceGroupId, cmXsNote_t* aV[], unsigned aN )
|
|
1556
|
+{
|
|
1557
|
+ _cmXScoreGraceInsertTimeBase( p, graceGroupId,aV,aN, aV[0]->tick );
|
|
1558
|
+}
|
|
1559
|
+
|
|
1560
|
+
|
|
1561
|
+// Play the first grace not shortly (one grace note duration) after the first note
|
|
1562
|
+// in the group (which is a non-grace note) and then expand time while inserting the other
|
|
1563
|
+// grace notes.
|
|
1564
|
+void _cmXScoreGraceInsertSoonAfterFirst( cmXScore_t* p, unsigned graceGroupId, cmXsNote_t* aV[], unsigned aN )
|
|
1565
|
+{
|
|
1566
|
+ _cmXScoreGraceInsertTimeBase( p, graceGroupId,aV,aN, aV[0]->tick + aV[1]->duration );
|
|
1567
|
+}
|
|
1568
|
+
|
|
1569
|
+
|
1522
|
1570
|
// Adjust the locations of grace notes. Note that this must be done
|
1523
|
1571
|
// after reordering so that we can be sure that the order in time of
|
1524
|
1572
|
// the notes in each group has been set prior to building the
|
|
@@ -1528,14 +1576,18 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
|
1528
|
1576
|
cmXsRC_t rc = kOkXsRC;
|
1529
|
1577
|
unsigned graceGroupId = 1;
|
1530
|
1578
|
double graceDurSec = 1.0/15.0; // duration of all grace notes in seconds
|
1531
|
|
-
|
|
1579
|
+
|
1532
|
1580
|
for(; 1; ++graceGroupId)
|
1533
|
1581
|
{
|
1534
|
|
- cmXsNote_t* gn0p = NULL;
|
1535
|
|
- cmXsNote_t* gn1p = NULL;
|
|
1582
|
+ cmXsNote_t* gn0p = NULL; // first note in the grace group
|
|
1583
|
+ cmXsNote_t* gn1p = NULL; // last note in the grace group
|
1536
|
1584
|
unsigned gN = 0;
|
1537
|
1585
|
cmXsPart_t* pp = p->partL;
|
1538
|
1586
|
double ticksPerSec = 0;
|
|
1587
|
+
|
|
1588
|
+ // Build a note chain, using cmXsNote_t.grace, between gn0p and
|
|
1589
|
+ // gn1p containing all the grace notes with
|
|
1590
|
+ // cmXsNote_t.graceGroupId == graceGroupId.
|
1539
|
1591
|
|
1540
|
1592
|
for(; pp!=NULL; pp=pp->link)
|
1541
|
1593
|
{
|
|
@@ -1571,11 +1623,11 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
|
1571
|
1623
|
np->duration = floor(ticksPerSec * graceDurSec);
|
1572
|
1624
|
|
1573
|
1625
|
gN += 1;
|
1574
|
|
- }
|
|
1626
|
+ }
|
1575
|
1627
|
|
1576
|
|
- } //
|
1577
|
|
- }
|
1578
|
|
- }
|
|
1628
|
+ } // for each note in this meassure
|
|
1629
|
+ } // for each measure
|
|
1630
|
+ } // for each part
|
1579
|
1631
|
|
1580
|
1632
|
// no records were found for this grace id - we're done
|
1581
|
1633
|
if( gn0p == NULL )
|
|
@@ -1587,7 +1639,6 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
|
1587
|
1639
|
rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"The grace not group ending in meas %i has fewer than 3 (%i) members.", gn1p->meas->number, gN );
|
1588
|
1640
|
break;
|
1589
|
1641
|
}
|
1590
|
|
-
|
1591
|
1642
|
|
1592
|
1643
|
// gn0p is now set to the first note in th group
|
1593
|
1644
|
// gn1p is now set to the last note in the group
|
|
@@ -1606,7 +1657,7 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
|
1606
|
1657
|
break;
|
1607
|
1658
|
}
|
1608
|
1659
|
|
1609
|
|
- // count the total number of events between gn0p and gn1p
|
|
1660
|
+ // Count the total number of events between gn0p and gn1p
|
1610
|
1661
|
cmXsNote_t* n0p = NULL;
|
1611
|
1662
|
cmXsNote_t* n1p = gn0p;
|
1612
|
1663
|
cmXsMeas_t* mp = gn0p->meas;
|
|
@@ -1624,8 +1675,8 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
|
1624
|
1675
|
if(1)
|
1625
|
1676
|
{
|
1626
|
1677
|
bool fl = n0p != NULL && n0p->tick < n1p->tick;
|
1627
|
|
- unsigned type = n1p->flags & (kBegGraceXsFl|kEndGraceXsFl|kAddGraceXsFl|kSubGraceXsFl|kFirstGraceXsFl);
|
1628
|
|
- printf("%3i 0x%08x %i %5i %i\n",n1p->graceGroupId,type,n1p->tick,n1p->duration,fl);
|
|
1678
|
+ unsigned type = n1p->flags & (kBegGraceXsFl|kEndGraceXsFl|kAddGraceXsFl|kSubGraceXsFl|kAFirstGraceXsFl|kNFirstGraceXsFl);
|
|
1679
|
+ printf("%3i 0x%08x %i %3i %5i %i\n",n1p->graceGroupId,type,n1p->meas->number,n1p->tick,n1p->duration,fl);
|
1629
|
1680
|
}
|
1630
|
1681
|
|
1631
|
1682
|
++aN;
|
|
@@ -1653,7 +1704,7 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
|
1653
|
1704
|
n0p = n1p;
|
1654
|
1705
|
}
|
1655
|
1706
|
|
1656
|
|
- switch( gn1p->flags & (kAddGraceXsFl | kSubGraceXsFl | kFirstGraceXsFl) )
|
|
1707
|
+ switch( gn1p->flags & (kAddGraceXsFl | kSubGraceXsFl | kAFirstGraceXsFl | kNFirstGraceXsFl ) )
|
1657
|
1708
|
{
|
1658
|
1709
|
case kAddGraceXsFl:
|
1659
|
1710
|
_cmXScoreGraceInsertTime(p, graceGroupId, aV, aN );
|
|
@@ -1663,7 +1714,12 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p )
|
1663
|
1714
|
_cmXScoreGraceOverlayTime(p, graceGroupId, aV, aN );
|
1664
|
1715
|
break;
|
1665
|
1716
|
|
1666
|
|
- case kFirstGraceXsFl:
|
|
1717
|
+ case kAFirstGraceXsFl:
|
|
1718
|
+ _cmXScoreGraceInsertAfterFirst(p,graceGroupId,aV,aN);
|
|
1719
|
+ break;
|
|
1720
|
+
|
|
1721
|
+ case kNFirstGraceXsFl:
|
|
1722
|
+ _cmXScoreGraceInsertSoonAfterFirst(p,graceGroupId,aV,aN);
|
1667
|
1723
|
break;
|
1668
|
1724
|
|
1669
|
1725
|
default:
|
|
@@ -2136,7 +2192,8 @@ cmXsRC_t _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned
|
2136
|
2192
|
case 'b': r->graceFlags |= kBegGraceXsFl; break;
|
2137
|
2193
|
case 'a': r->graceFlags |= kAddGraceXsFl | kEndGraceXsFl; break;
|
2138
|
2194
|
case 's': r->graceFlags |= kSubGraceXsFl | kEndGraceXsFl; break;
|
2139
|
|
- case 'f': r->graceFlags |= kFirstGraceXsFl | kEndGraceXsFl; break;
|
|
2195
|
+ case 'A': r->graceFlags |= kAFirstGraceXsFl| kEndGraceXsFl; break;
|
|
2196
|
+ case 'n': r->graceFlags |= kNFirstGraceXsFl| kEndGraceXsFl; break;
|
2140
|
2197
|
case 'g': break;
|
2141
|
2198
|
|
2142
|
2199
|
case '%':
|
|
@@ -3015,7 +3072,7 @@ cmXsRC_t _cmXsWriteMidiSvg( cmCtx_t* ctx, cmXScore_t* p, cmXsMidiFile_t* mf, con
|
3015
|
3072
|
{
|
3016
|
3073
|
cmXsRC_t rc = kOkXsRC;
|
3017
|
3074
|
cmSvgH_t svgH = cmSvgNullHandle;
|
3018
|
|
- cmXsSvgEvt_t* e = mf->elist;
|
|
3075
|
+ cmXsSvgEvt_t* e = mf->elist;
|
3019
|
3076
|
unsigned noteHeight = 10;
|
3020
|
3077
|
const cmChar_t* svgFn = cmFsMakeFn(dir,fn,"html",NULL);
|
3021
|
3078
|
const cmChar_t* cssFn = cmFsMakeFn(NULL,fn,"css",NULL);
|
|
@@ -3198,7 +3255,11 @@ cmXsRC_t cmXScoreTest(
|
3198
|
3255
|
return cmErrMsg(&ctx->err,rc,"XScore alloc failed.");
|
3199
|
3256
|
|
3200
|
3257
|
if( reorderFn != NULL )
|
3201
|
|
- cmXScoreReorder(h,reorderFn);
|
|
3258
|
+ if((rc = cmXScoreReorder(h,reorderFn)) != kOkXsRC )
|
|
3259
|
+ {
|
|
3260
|
+ cmErrMsg(&ctx->err,rc,"XScore reorder failed.");
|
|
3261
|
+ goto errLabel;
|
|
3262
|
+ }
|
3202
|
3263
|
|
3203
|
3264
|
// assign durations to pedal down events
|
3204
|
3265
|
_cmXScoreProcessPedals(_cmXScoreHandleToPtr(h));
|
|
@@ -3239,6 +3300,7 @@ cmXsRC_t cmXScoreTest(
|
3239
|
3300
|
|
3240
|
3301
|
cmXScoreReport(h,&ctx->rpt,true);
|
3241
|
3302
|
|
|
3303
|
+ errLabel:
|
3242
|
3304
|
return cmXScoreFinalize(&h);
|
3243
|
3305
|
|
3244
|
3306
|
}
|