|
@@ -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
|
|