2016-02-04 16:33:42 +00:00
# include "cmPrefix.h"
# include "cmGlobal.h"
# include "cmFloatTypes.h"
# include "cmRpt.h"
# include "cmErr.h"
# include "cmCtx.h"
# include "cmMem.h"
# include "cmMallocDebug.h"
# include "cmLinkedHeap.h"
# include "cmXml.h"
# include "cmText.h"
# include "cmXScore.h"
2016-02-04 22:55:22 +00:00
# include "cmTime.h"
# include "cmMidi.h"
2016-02-09 02:46:07 +00:00
# include "cmLex.h"
# include "cmCsv.h"
2016-02-04 16:33:42 +00:00
cmXsH_t cmXsNullHandle = cmSTATIC_NULL_HANDLE ;
2016-02-04 22:55:22 +00:00
enum
{
2016-02-07 04:36:53 +00:00
kSectionXsFl = 0x0001 , // rvalue holds section number
kBarXsFl = 0x0002 ,
kRestXsFl = 0x0004 ,
kGraceXsFl = 0x0008 ,
kDotXsFl = 0x0010 ,
kChordXsFl = 0x0020 ,
kDynXsFl = 0x0040 ,
kEvenXsFl = 0x0080 ,
kTempoXsFl = 0x0100 ,
2016-02-11 00:03:17 +00:00
kHeelXsFl = 0x0200 ,
2016-02-12 00:23:42 +00:00
kTieBegXsFl = 0x0400 ,
kTieEndXsFl = 0x0800 ,
kPedalDnXsFl = 0x1000 ,
kPedalUpXsFl = 0x2000 ,
kPedalUpDnXsFl = 0x4000 ,
kMetronomeXsFl = 0x8000 // duration holds BPM
2016-02-04 22:55:22 +00:00
} ;
2016-02-12 00:23:42 +00:00
struct cmXsMeas_str ;
struct cmXsVoice_str ;
2016-02-04 22:55:22 +00:00
2016-02-04 16:33:42 +00:00
typedef struct cmXsNote_str
{
2016-02-07 04:36:53 +00:00
unsigned flags ; // See k???XsFl
unsigned pitch ; // midi pitch
unsigned tick ; //
unsigned duration ; // duration in ticks
2016-02-12 00:23:42 +00:00
unsigned pticks ; // play ticks (0 for non-sounding notes)
2016-02-11 00:03:17 +00:00
double rvalue ; // 1/rvalue = rythmic value (1/0.5 double whole 1/1 whole 1/2 half 1/4=quarter note, 1/8=eighth note, ...)
2016-02-09 02:46:07 +00:00
const cmChar_t * tvalue ; // text value
2016-02-12 00:23:42 +00:00
const struct cmXsVoice_str * voice ; // voice this note belongs to
const struct cmXsMeas_str * meas ; // measure this note belongs to
const cmXmlNode_t * xmlNode ; // note xml ptr
2016-02-07 04:36:53 +00:00
struct cmXsNote_str * mlink ; // measure note list
struct cmXsNote_str * slink ; // time sorted event list
2016-02-12 00:23:42 +00:00
2016-02-04 16:33:42 +00:00
} cmXsNote_t ;
2016-02-12 00:23:42 +00:00
typedef struct cmXsConnect_str
{
bool doneFl ; // this tie has been completed (slurs only occur in pairs)
bool closeFl ; // this tie was properly closed
const cmXsNote_t * note ; // associated
struct cmXsConnect_str * nlink ; // next connected note
struct cmXsConnect_str * link ; // p->tieL,p->slurL links
} cmXsConnect_t ;
2016-02-04 16:33:42 +00:00
typedef struct cmXsVoice_str
{
unsigned id ; // Voice id
cmXsNote_t * noteL ; // List of notes in this voice
struct cmXsVoice_str * link ; // Link to other voices in this measure
} cmXsVoice_t ;
typedef struct cmXsMeas_str
{
2016-02-09 02:46:07 +00:00
unsigned number ; // Measure number
unsigned divisions ; // ticks-per-quarter-note
unsigned beats ; // beats per measure
unsigned beat_type ; // whole/half/quarter/eighth ...
2016-02-04 16:33:42 +00:00
2016-02-09 02:46:07 +00:00
cmXsVoice_t * voiceL ; // List of voices in this measure
cmXsNote_t * noteL ; // List of time sorted notes in this measure
2016-02-04 16:33:42 +00:00
struct cmXsMeas_str * link ; // Link to other measures in this part.
} cmXsMeas_t ;
typedef struct cmXsPart_str
{
const cmChar_t * idStr ; // Id of this part
cmXsMeas_t * measL ; // List of measures in this part.
struct cmXsPart_str * link ; // Link to other parts in this score
} cmXsPart_t ;
typedef struct
{
2016-02-09 02:46:07 +00:00
cmErr_t err ;
cmXmlH_t xmlH ;
cmLHeapH_t lhH ;
cmXsPart_t * partL ;
2016-02-12 00:23:42 +00:00
cmCsvH_t csvH ;
cmXsConnect_t * slurL ;
cmXsConnect_t * tieL ;
2016-02-04 16:33:42 +00:00
} cmXScore_t ;
cmXScore_t * _cmXScoreHandleToPtr ( cmXsH_t h )
{
cmXScore_t * p = ( cmXScore_t * ) h . h ;
assert ( p ! = NULL ) ;
return p ;
}
cmXsRC_t _cmXScoreFinalize ( cmXScore_t * p )
{
cmXsRC_t rc = kOkXsRC ;
// release the XML file
2016-02-09 02:46:07 +00:00
cmXmlFree ( & p - > xmlH ) ;
2016-02-04 16:33:42 +00:00
// release the local linked heap memory
2016-02-09 02:46:07 +00:00
cmLHeapDestroy ( & p - > lhH ) ;
// release the CSV output object
cmCsvFinalize ( & p - > csvH ) ;
2016-02-04 16:33:42 +00:00
cmMemFree ( p ) ;
return rc ;
}
2016-02-07 04:36:53 +00:00
cmXsRC_t _cmXScoreMissingNode ( cmXScore_t * p , const cmXmlNode_t * parent , const cmChar_t * label )
2016-02-04 16:33:42 +00:00
{
2016-02-07 04:36:53 +00:00
return cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " Missing XML node '%s'. Parent line:%i " , label , parent - > line ) ;
2016-02-04 16:33:42 +00:00
}
cmXsRC_t _cmXScoreMissingAttribute ( cmXScore_t * p , const cmXmlNode_t * np , const cmChar_t * attrLabel )
{
return cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " Missing XML attribute '%s' from node '%s'. " , attrLabel , np - > label ) ;
}
2016-02-07 04:36:53 +00:00
cmXsVoice_t * _cmXScoreIdToVoice ( cmXsMeas_t * meas , unsigned voiceId )
{
cmXsVoice_t * v = meas - > voiceL ;
for ( ; v ! = NULL ; v = v - > link )
if ( v - > id = = voiceId )
return v ;
return NULL ;
}
cmXsRC_t _cmXScorePushNote ( cmXScore_t * p , cmXsMeas_t * meas , unsigned voiceId , cmXsNote_t * note )
{
cmXsVoice_t * v ;
// get the voice recd
if ( ( v = _cmXScoreIdToVoice ( meas , voiceId ) ) = = NULL )
{
// the voice recd doesn't exist for this voiceId - allocate one
v = cmLhAllocZ ( p - > lhH , cmXsVoice_t , 1 ) ;
v - > id = voiceId ;
// add the voice record to the meas->voiceL
if ( meas - > voiceL = = NULL )
meas - > voiceL = v ;
else
{
cmXsVoice_t * vp = meas - > voiceL ;
while ( vp - > link ! = NULL )
vp = vp - > link ;
vp - > link = v ;
}
}
// add the note record to the end of meas->voiceL
if ( v - > noteL = = NULL )
v - > noteL = note ;
else
{
cmXsNote_t * n = v - > noteL ;
while ( n - > mlink ! = NULL )
n = n - > mlink ;
n - > mlink = note ;
}
2016-02-12 00:23:42 +00:00
note - > voice = v ;
2016-02-07 04:36:53 +00:00
return kOkXsRC ;
}
2016-02-04 16:33:42 +00:00
cmXsRC_t _cmXScoreParsePartList ( cmXScore_t * p )
{
cmXsRC_t rc = kOkXsRC ;
cmXsPart_t * lastPartPtr = NULL ;
const cmXmlNode_t * xnp ;
// find the 'part-list'
if ( ( xnp = cmXmlSearch ( cmXmlRoot ( p - > xmlH ) , " part-list " , NULL , 0 ) ) = = NULL )
2016-02-07 04:36:53 +00:00
return _cmXScoreMissingNode ( p , cmXmlRoot ( p - > xmlH ) , " part-list " ) ;
2016-02-04 16:33:42 +00:00
const cmXmlNode_t * cnp = xnp - > children ;
// for each child of the 'part-list'
for ( ; cnp ! = NULL ; cnp = cnp - > sibling )
if ( cmTextCmp ( cnp - > label , " score-part " ) = = 0 )
{
const cmXmlAttr_t * a ;
// find the 'score-part' id
if ( ( a = cmXmlFindAttrib ( cnp , " id " ) ) = = NULL )
return _cmXScoreMissingAttribute ( p , cnp , " id " ) ;
// allocate a new part record
cmXsPart_t * pp = cmLhAllocZ ( p - > lhH , cmXsPart_t , 1 ) ;
pp - > idStr = a - > value ; // set the part id
// link the new part record to the end of the part list
if ( lastPartPtr = = NULL )
p - > partL = pp ;
else
lastPartPtr - > link = pp ;
lastPartPtr = pp ;
}
return rc ;
}
2016-02-04 22:55:22 +00:00
cmXsRC_t _cmXScoreParsePitch ( cmXScore_t * p , const cmXmlNode_t * nnp , unsigned * midiPitchRef )
{
cmXsRC_t rc = kOkXsRC ;
unsigned octave = 0 ;
double alter = 0 ;
const cmChar_t * step = NULL ;
if ( ( step = cmXmlNodeValue ( nnp , " pitch " , " step " , NULL ) ) = = NULL )
2016-02-07 04:36:53 +00:00
return _cmXScoreMissingNode ( p , nnp , " step " ) ;
2016-02-04 22:55:22 +00:00
if ( ( rc = cmXmlNodeUInt ( nnp , & octave , " pitch " , " octave " , NULL ) ) ! = kOkXmlRC )
2016-02-07 04:36:53 +00:00
return _cmXScoreMissingNode ( p , nnp , " octave " ) ;
2016-02-04 22:55:22 +00:00
cmXmlNodeDouble ( nnp , & alter , " pitch " , " alter " , NULL ) ;
cmChar_t buf [ 3 ] = { * step , ' 0 ' , ' \0 ' } ;
unsigned midi = cmSciPitchToMidi ( buf ) ;
midi + = ( 12 * octave ) ;
midi + = alter ;
* midiPitchRef = midi ;
return rc ;
}
2016-02-12 00:23:42 +00:00
cmXsConnect_t * _cmXScoreFindTie ( const cmXScore_t * p , unsigned pitch )
{
cmXsConnect_t * c = p - > tieL ;
for ( ; c ! = NULL ; c = c - > link )
{
assert ( c - > note ! = NULL ) ;
if ( c - > doneFl = = false & & c - > note - > pitch = = pitch )
return c ;
}
return NULL ;
}
cmXsRC_t _cmXScoreNewTie ( cmXScore_t * p , const cmXsNote_t * note )
{
cmXsConnect_t * c ;
// check that an open tie with the same pitch does not exist
if ( ( c = _cmXScoreFindTie ( p , note - > pitch ) ) ! = NULL )
{
cmErrWarnMsg ( & p - > err , kUnterminatedTieXsRC , " The tie begun from note on line %i was not terminated. (pitch=%i) " , c - > note - > xmlNode - > line , c - > note - > pitch ) ;
c - > doneFl = true ; // close the unterminated tie
}
// allocate a new connection record
c = cmLhAllocZ ( p - > lhH , cmXsConnect_t , 1 ) ;
// set the first note in the connection
c - > note = note ;
// append the new record to the end of the tie list
if ( p - > tieL = = NULL )
p - > tieL = c ;
else
{
cmXsConnect_t * cp = p - > tieL ;
while ( cp - > link ! = NULL )
cp = cp - > link ;
cp - > link = c ;
}
return kOkXsRC ;
}
cmXsRC_t _cmXScoreContinueTie ( cmXScore_t * p , const cmXsNote_t * note , unsigned measNumb )
{
cmXsConnect_t * c ;
// find an open tie with the same pitch
if ( ( c = _cmXScoreFindTie ( p , note - > pitch ) ) = = NULL )
{
cmErrWarnMsg ( & p - > err , kUnterminatedTieXsRC , " The tie ending on the note on line %i does not have an associated starting note. (pitch=%i) " , note - > xmlNode - > line , note - > pitch ) ;
return kOkXsRC ;
}
// allocate a new connection record
cmXsConnect_t * nc = cmLhAllocZ ( p - > lhH , cmXsConnect_t , 1 ) ;
nc - > note = note ;
// add the note to the end of the tie list
if ( c - > nlink = = NULL )
c - > nlink = nc ;
else
{
cmXsConnect_t * cp = c - > nlink ;
while ( cp - > nlink ! = NULL )
cp = cp - > nlink ;
cp - > nlink = nc ;
}
// if this is the last note in the tie ...
if ( cmIsFlag ( note - > flags , kTieEndXsFl ) & & cmIsNotFlag ( note - > flags , kTieBegXsFl ) )
{
c - > doneFl = true ; // ... mark the tie list as complete ...
c - > closeFl = true ; // ... and properly closed
printf ( " tie done: meas=%i line=%i pitch=%i \n " , measNumb , note - > xmlNode - > line , note - > pitch ) ;
}
return kOkXsRC ;
}
cmXsRC_t _cmXScoreProcessTie ( cmXScore_t * p , const cmXmlNode_t * np , cmXsNote_t * note , unsigned measNumb )
{
cmXsRC_t rc = kOkXsRC ;
// is this is first note in a tied pair
if ( cmXmlNodeHasChildWithAttrAndValue ( np , " tie " , " type " , " start " , NULL ) )
note - > flags | = kTieBegXsFl ;
// is this is second note in a tied pair
if ( cmXmlNodeHasChildWithAttrAndValue ( np , " tie " , " type " , " stop " , NULL ) )
note - > flags | = kTieEndXsFl ;
// if this is a tie start (and not a tie continue)
if ( cmIsFlag ( note - > flags , kTieBegXsFl ) & & cmIsNotFlag ( note - > flags , kTieEndXsFl ) )
rc = _cmXScoreNewTie ( p , note ) ;
else
// if this is a tie continue or end
if ( cmIsFlag ( note - > flags , kTieEndXsFl ) )
rc = _cmXScoreContinueTie ( p , note , measNumb ) ; // this is a tie end or continue
return rc ;
}
const cmXsNote_t * _cmXScoreResolveTie ( const cmXsNote_t * note )
{
const cmXsMeas_t * m = note - > meas ;
const cmXsNote_t * n = note - > slink ;
while ( n ! = NULL )
{
for ( ; n ! = NULL ; n = n - > slink )
if ( note - > pitch = = n - > pitch & & note - > voice = = n - > voice )
return n ;
if ( m - > link = = NULL )
break ;
// got to next measure
if ( ( m = m - > link ) = = NULL )
break ;
n = m - > noteL ;
}
return NULL ;
}
cmXsRC_t _cmXScoreResolveTies ( cmXScore_t * p )
{
cmXsRC_t rc = kOkXsRC ;
cmXsPart_t * pp = p - > partL ;
for ( ; pp ! = NULL ; pp = pp - > link )
{
cmXsMeas_t * mp = pp - > measL ;
for ( ; mp ! = NULL ; mp = mp - > link )
{
cmXsNote_t * np = mp - > noteL ;
for ( ; np ! = NULL ; np = np - > slink )
if ( cmIsFlag ( np - > flags , kTieBegXsFl ) )
{
const cmXsNote_t * tnp ;
if ( ( tnp = _cmXScoreResolveTie ( np ) ) = = NULL )
{
}
else
{
}
}
}
}
return rc ;
}
2016-02-11 00:03:17 +00:00
cmXsRC_t _cmXScoreParseNoteRValue ( cmXScore_t * p , const cmXmlNode_t * nnp , const cmChar_t * label , double * rvalueRef )
2016-02-04 22:55:22 +00:00
{
typedef struct map_str
{
2016-02-11 00:03:17 +00:00
double rvalue ;
2016-02-04 22:55:22 +00:00
const cmChar_t * label ;
} map_t ;
map_t mapV [ ] =
{
2016-02-11 00:03:17 +00:00
{ - 1.0 , " measure " } , // whole measure rest
{ 0.5 , " breve " } , // double whole
{ 1.0 , " whole " } ,
{ 2.0 , " half " } ,
{ 4.0 , " quarter " } ,
{ 8.0 , " eighth " } ,
{ 16.0 , " 16th " } ,
{ 32.0 , " 32nd " } ,
{ 64.0 , " 64th " } ,
{ 128.0 , " 128th " } ,
{ 0.0 , " " }
2016-02-04 22:55:22 +00:00
} ;
2016-02-07 04:36:53 +00:00
const cmChar_t * str ;
2016-02-11 00:03:17 +00:00
// get the XML rvalue label
2016-02-07 04:36:53 +00:00
if ( ( str = cmXmlNodeValue ( nnp , label , NULL ) ) = = NULL )
2016-02-09 02:46:07 +00:00
{
if ( ( nnp = cmXmlSearch ( nnp , " rest " , NULL , 0 ) ) ! = NULL )
{
const cmXmlAttr_t * a ;
if ( ( a = cmXmlFindAttrib ( nnp , " measure " ) ) ! = NULL & & cmTextCmp ( a - > value , " yes " ) = = 0 )
2016-02-11 00:03:17 +00:00
{
* rvalueRef = - 1 ;
return kOkXsRC ;
}
2016-02-09 02:46:07 +00:00
}
2016-02-11 00:03:17 +00:00
return cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " The 'beat-unit' metronome value is missing on line %i. " , nnp - > line ) ;
2016-02-09 02:46:07 +00:00
}
2016-02-07 04:36:53 +00:00
unsigned i ;
2016-02-11 00:03:17 +00:00
// lookup the rvalue numeric value from the mapV[] table
2016-02-07 04:36:53 +00:00
for ( i = 0 ; mapV [ i ] . rvalue ! = 0 ; + + i )
if ( cmTextCmp ( mapV [ i ] . label , str ) = = 0 )
2016-02-11 00:03:17 +00:00
{
* rvalueRef = mapV [ i ] . rvalue ;
return kOkXsRC ;
}
2016-02-07 04:36:53 +00:00
2016-02-11 00:03:17 +00:00
// the rvalue label was not found
return cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " Unknown rvalue type='%s'. " , str ) ;
2016-02-04 22:55:22 +00:00
}
2016-02-07 04:36:53 +00:00
cmXsRC_t _cmXScoreParseColor ( cmXScore_t * p , const cmXmlNode_t * nnp , cmXsNote_t * note )
2016-02-04 22:55:22 +00:00
{
2016-02-07 04:36:53 +00:00
cmXsRC_t rc = kOkXsRC ;
const cmXmlAttr_t * a ;
2016-02-04 16:33:42 +00:00
2016-02-07 04:36:53 +00:00
typedef struct map_str
2016-02-04 22:55:22 +00:00
{
2016-02-07 04:36:53 +00:00
unsigned value ;
const cmChar_t * label ;
} map_t ;
2016-02-04 22:55:22 +00:00
2016-02-07 04:36:53 +00:00
map_t mapV [ ] =
2016-02-04 22:55:22 +00:00
{
2016-02-11 00:03:17 +00:00
{ kEvenXsFl , " #0000FF " } , // blue (even)
{ kTempoXsFl , " #00FF00 " } , // green (tempo)
{ kDynXsFl , " #FF0000 " } , // red (dynamics)
{ kTempoXsFl | kEvenXsFl , " #00FFFF " } , // green + blue (turquoise)
{ kDynXsFl | kEvenXsFl , " #FF00FF " } , // red + blue
{ kDynXsFl | kEvenXsFl , " #FF0CF7 " } , // magenta (even+dyn)
{ kDynXsFl | kTempoXsFl , " #FF7F00 " } , // red + green (brown)
{ kTempoXsFl | kEvenXsFl | kDynXsFl , " #996633 " } , // (purple)
{ kDynXsFl , " #FF6A03 " } , // 176 orange (dynamics)
{ kEvenXsFl , " #2F00E8 " } , // 1001 blue (even)
{ kTempoXsFl , " #01CD1F " } , // 1196 green (tempo)
{ kEvenXsFl , " #3600E8 " } , // 1627 blue (even)
{ kDynXsFl | kTempoXsFl , " #9E8F15 " } , // 8827 brown (dyn + tempo)
{ kEvenXsFl , " #2E00E6 " } , // 5393 blue (even)
{ kEvenXsFl , " #2C00DD " } , // 5895 blue (even)
{ kDynXsFl , " #FF5B03 " } , // 6498 orange (dyn)
{ kDynXsFl , " #FF6104 " } , // 6896 orange
{ kEvenXsFl , " #2A00E6 " } , // 7781 blue
{ kEvenXsFl , " #2300DD " } , // 8300 blue (even)
{ kTempoXsFl , " #03CD22 " } , // 10820 green (tempo)
{ kEvenXsFl , " #3400DB " } , // 11627 blue (dyn)
{ - 1 , " " }
2016-02-07 04:36:53 +00:00
} ;
2016-02-11 00:03:17 +00:00
/*
orange # FF6A03
magenta # FF0CF7
blue # 2F 00E8
green # 01 CD1F
gold # 9E8 F15
green # 03 CD22
*/
2016-02-07 04:36:53 +00:00
if ( ( a = cmXmlFindAttrib ( nnp , " color " ) ) ! = NULL )
{
unsigned i ;
2016-02-11 00:03:17 +00:00
for ( i = 0 ; mapV [ i ] . value ! = - 1 ; + + i )
2016-02-07 04:36:53 +00:00
if ( cmTextCmp ( a - > value , mapV [ i ] . label ) = = 0 )
{
note - > flags + = mapV [ i ] . value ;
break ;
}
2016-02-04 22:55:22 +00:00
2016-02-11 00:03:17 +00:00
if ( mapV [ i ] . value = = - 1 )
cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " The note color '%s' was not found on line %i. " , a - > value , nnp - > line ) ;
2016-02-04 22:55:22 +00:00
}
2016-02-07 04:36:53 +00:00
return rc ;
2016-02-04 22:55:22 +00:00
}
2016-02-07 04:36:53 +00:00
cmXsRC_t _cmXScoreParseNote ( cmXScore_t * p , cmXsMeas_t * meas , const cmXmlNode_t * nnp , unsigned * tickRef )
2016-02-04 22:55:22 +00:00
{
cmXsRC_t rc = kOkXsRC ;
cmXsNote_t * note = cmLhAllocZ ( p - > lhH , cmXsNote_t , 1 ) ;
2016-02-07 04:36:53 +00:00
unsigned voiceId ;
2016-02-04 22:55:22 +00:00
2016-02-12 00:23:42 +00:00
note - > meas = meas ;
note - > xmlNode = nnp ;
2016-02-04 22:55:22 +00:00
// get the voice id for this node
if ( cmXmlNodeUInt ( nnp , & voiceId , " voice " , NULL ) ! = kOkXmlRC )
2016-02-07 04:36:53 +00:00
return _cmXScoreMissingNode ( p , nnp , " voice " ) ;
2016-02-04 22:55:22 +00:00
// if this note has a pitch
2016-02-07 04:36:53 +00:00
if ( cmXmlNodeHasChild ( nnp , " pitch " , NULL ) )
2016-02-04 22:55:22 +00:00
if ( ( rc = _cmXScoreParsePitch ( p , nnp , & note - > pitch ) ) ! = kOkXsRC )
return rc ;
2016-02-07 04:36:53 +00:00
// get the note duration
cmXmlNodeUInt ( nnp , & note - > duration , " duration " , NULL ) ;
2016-02-04 22:55:22 +00:00
// is 'rest'
2016-02-07 04:36:53 +00:00
if ( cmXmlNodeHasChild ( nnp , " rest " , NULL ) )
2016-02-04 22:55:22 +00:00
note - > flags | = kRestXsFl ;
// is 'grace'
2016-02-07 04:36:53 +00:00
if ( cmXmlNodeHasChild ( nnp , " grace " , NULL ) )
2016-02-04 22:55:22 +00:00
note - > flags | = kGraceXsFl ;
// is 'dot'
2016-02-07 04:36:53 +00:00
if ( cmXmlNodeHasChild ( nnp , " dot " , NULL ) )
2016-02-04 22:55:22 +00:00
note - > flags | = kDotXsFl ;
2016-02-07 04:36:53 +00:00
// is 'chord'
if ( cmXmlNodeHasChild ( nnp , " chord " , NULL ) )
note - > flags | = kChordXsFl ;
2016-02-12 00:23:42 +00:00
// process ties attached to this note
if ( ( rc = _cmXScoreProcessTie ( p , nnp , note , meas - > number ) ) ! = kOkXsRC )
return rc ;
2016-02-11 00:03:17 +00:00
// has 'heel' mark
if ( cmXmlNodeHasChild ( nnp , " notations " , " technical " , " heel " , NULL ) )
note - > flags | = kHeelXsFl ;
2016-02-07 04:36:53 +00:00
// set color coded flags
if ( ( rc = _cmXScoreParseColor ( p , nnp , note ) ) ! = kOkXsRC )
return rc ;
// get the note's rythmic value
2016-02-11 00:03:17 +00:00
if ( ( rc = _cmXScoreParseNoteRValue ( p , nnp , " type " , & note - > rvalue ) ) ! = kOkXsRC )
return rc ;
2016-02-07 04:36:53 +00:00
note - > tick = * tickRef ;
if ( cmIsNotFlag ( note - > flags , kChordXsFl ) )
* tickRef + = note - > duration ;
return _cmXScorePushNote ( p , meas , voiceId , note ) ;
}
2016-02-12 00:23:42 +00:00
cmXsRC_t _cmXScorePushNonNote ( cmXScore_t * p , cmXsMeas_t * meas , const cmXmlNode_t * noteXmlNode , unsigned tick , unsigned duration , double rvalue , const cmChar_t * tvalue , unsigned flags )
2016-02-07 04:36:53 +00:00
{
cmXsNote_t * note = cmLhAllocZ ( p - > lhH , cmXsNote_t , 1 ) ;
unsigned voiceId = 0 ; // non-note's are always assigned to voiceId=0;
note - > tick = tick ;
note - > flags = flags ;
note - > rvalue = rvalue ;
2016-02-09 02:46:07 +00:00
note - > tvalue = tvalue ;
2016-02-07 04:36:53 +00:00
note - > duration = duration ;
2016-02-12 00:23:42 +00:00
note - > meas = meas ;
note - > xmlNode = noteXmlNode ;
2016-02-07 04:36:53 +00:00
return _cmXScorePushNote ( p , meas , voiceId , note ) ;
}
cmXsRC_t _cmXScoreParseDirection ( cmXScore_t * p , cmXsMeas_t * meas , const cmXmlNode_t * dnp , unsigned tick )
{
2016-02-11 00:03:17 +00:00
cmXsRC_t rc = kOkXsRC ;
const cmXmlNode_t * np = NULL ;
const cmXmlAttr_t * a = NULL ;
2016-02-07 04:36:53 +00:00
unsigned flags = 0 ;
int offset = 0 ;
2016-02-11 00:03:17 +00:00
double rvalue = 0 ;
2016-02-09 02:46:07 +00:00
const cmChar_t * tvalue = NULL ;
2016-02-07 04:36:53 +00:00
unsigned duration = 0 ;
cmXmlNodeInt ( dnp , & offset , " offset " , NULL ) ;
// if this is a metronome direction
if ( ( np = cmXmlSearch ( dnp , " metronome " , NULL , 0 ) ) ! = NULL )
{
if ( cmXmlNodeUInt ( np , & duration , " per-minute " , NULL ) ! = kOkXmlRC )
return cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " The 'per-minute' metronome value is missing on line %i. " , np - > line ) ;
2016-02-11 00:03:17 +00:00
if ( ( rc = _cmXScoreParseNoteRValue ( p , np , " beat-unit " , & rvalue ) ) ! = kOkXsRC )
return rc ;
2016-02-07 04:36:53 +00:00
flags = kMetronomeXsFl ;
}
else
// if this is a pedal direction
if ( ( np = cmXmlSearch ( dnp , " pedal " , NULL , 0 ) ) ! = NULL )
{
2016-02-04 22:55:22 +00:00
2016-02-07 04:36:53 +00:00
if ( ( a = cmXmlFindAttrib ( np , " type " ) ) = = NULL )
return _cmXScoreMissingAttribute ( p , np , " type " ) ;
if ( cmTextCmp ( a - > value , " start " ) = = 0 )
flags = kPedalDnXsFl ;
else
if ( cmTextCmp ( a - > value , " change " ) = = 0 )
flags = kPedalUpDnXsFl ;
else
if ( cmTextCmp ( a - > value , " stop " ) = = 0 )
flags = kPedalUpXsFl ;
else
return cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " Unrecognized pedal type:'%s'. " , cmStringNullGuard ( a - > value ) ) ;
}
else
// if this is a 'words' direction
if ( ( np = cmXmlSearch ( dnp , " words " , NULL , 0 ) ) ! = NULL )
{
if ( ( a = cmXmlFindAttrib ( np , " enclosure " ) ) ! = NULL & & cmTextCmp ( a - > value , " rectangle " ) = = 0 )
{
2016-02-09 02:46:07 +00:00
if ( cmTextIsEmpty ( tvalue = np - > dataStr ) )
return cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " Section number is blank or missing on line %i. " , np - > line ) ;
2016-02-07 04:36:53 +00:00
flags = kSectionXsFl ;
}
}
2016-02-12 00:23:42 +00:00
return _cmXScorePushNonNote ( p , meas , dnp , tick + offset , duration , rvalue , tvalue , flags ) ;
2016-02-07 04:36:53 +00:00
2016-02-04 22:55:22 +00:00
}
2016-02-07 04:36:53 +00:00
2016-02-04 22:55:22 +00:00
cmXsRC_t _cmXScoreParseMeasure ( cmXScore_t * p , cmXsPart_t * pp , const cmXmlNode_t * mnp )
2016-02-04 16:33:42 +00:00
{
2016-02-07 04:36:53 +00:00
cmXsRC_t rc = kOkXsRC ;
const cmXmlNode_t * np = NULL ;
unsigned tick = 0 ;
2016-02-04 16:33:42 +00:00
2016-02-04 22:55:22 +00:00
// allocate the 'measure' record
2016-02-04 16:33:42 +00:00
cmXsMeas_t * meas = cmLhAllocZ ( p - > lhH , cmXsMeas_t , 1 ) ;
// get measure number
if ( cmXmlAttrUInt ( mnp , " number " , & meas - > number ) ! = kOkXmlRC )
return _cmXScoreMissingAttribute ( p , mnp , " number " ) ;
if ( pp - > measL = = NULL )
pp - > measL = meas ;
else
{
cmXsMeas_t * m = pp - > measL ;
while ( m - > link ! = NULL )
m = m - > link ;
2016-02-07 04:36:53 +00:00
m - > link = meas ;
2016-02-04 16:33:42 +00:00
}
// get measure attributes node
2016-02-09 02:46:07 +00:00
if ( ( np = cmXmlSearch ( mnp , " attributes " , NULL , 0 ) ) ! = NULL )
{
cmXmlNodeUInt ( np , & meas - > divisions , " divisions " , NULL ) ;
cmXmlNodeUInt ( np , & meas - > beats , " time " , " beats " , NULL ) ;
cmXmlNodeUInt ( np , & meas - > beat_type , " time " , " beat-type " , NULL ) ;
}
2016-02-07 04:36:53 +00:00
// store the bar line
2016-02-12 00:23:42 +00:00
if ( ( rc = _cmXScorePushNonNote ( p , meas , mnp , tick , 0 , 0 , NULL , kBarXsFl ) ) ! = kOkXsRC )
2016-02-07 04:36:53 +00:00
return rc ;
2016-02-04 22:55:22 +00:00
np = mnp - > children ;
2016-02-07 04:36:53 +00:00
// for each child of the 'meas' XML node
for ( ; rc = = kOkXsRC & & np ! = NULL ; np = np - > sibling )
{
// if this is a 'note' node
if ( cmTextCmp ( np - > label , " note " ) = = 0 )
2016-02-04 22:55:22 +00:00
{
2016-02-07 04:36:53 +00:00
rc = _cmXScoreParseNote ( p , meas , np , & tick ) ;
2016-02-04 22:55:22 +00:00
}
else
2016-02-07 04:36:53 +00:00
// if this is a 'backup' node
if ( cmTextCmp ( np - > label , " backup " ) = = 0 )
2016-02-04 22:55:22 +00:00
{
2016-02-07 04:36:53 +00:00
unsigned backup ;
cmXmlNodeUInt ( np , & backup , " duration " , NULL ) ;
tick - = backup ;
2016-02-04 22:55:22 +00:00
}
2016-02-07 04:36:53 +00:00
else
// if this is a 'direction' node
if ( cmTextCmp ( np - > label , " direction " ) = = 0 )
{
rc = _cmXScoreParseDirection ( p , meas , np , tick ) ;
}
2016-02-04 22:55:22 +00:00
2016-02-07 04:36:53 +00:00
}
2016-02-04 16:33:42 +00:00
return rc ;
}
cmXsRC_t _cmXScoreParsePart ( cmXScore_t * p , cmXsPart_t * pp )
{
cmXsRC_t rc = kOkXsRC ;
const cmXmlNode_t * xnp ;
cmXmlAttr_t partAttr = { " id " , pp - > idStr } ;
// find the 'part'
if ( ( xnp = cmXmlSearch ( cmXmlRoot ( p - > xmlH ) , " part " , & partAttr , 1 ) ) = = NULL )
2016-02-07 04:36:53 +00:00
return cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " The part '%s' was not found. " , pp - > idStr ) ;
2016-02-04 16:33:42 +00:00
// for each child of this part - find each measure
const cmXmlNode_t * cnp = xnp - > children ;
for ( ; cnp ! = NULL ; cnp = cnp - > sibling )
if ( cmTextCmp ( cnp - > label , " measure " ) = = 0 )
if ( ( rc = _cmXScoreParseMeasure ( p , pp , cnp ) ) ! = kOkXsRC )
return rc ;
return rc ;
}
2016-02-07 04:36:53 +00:00
cmXsNote_t * _cmXScoreInsertSortedNote ( cmXsNote_t * s0 , cmXsNote_t * np )
{
if ( s0 = = NULL )
return np ;
if ( np - > tick < s0 - > tick )
{
np - > slink = s0 ;
return np ;
}
cmXsNote_t * s1 = s0 ;
cmXsNote_t * s2 = s0 - > slink ;
while ( s2 ! = NULL )
{
if ( s2 - > tick > np - > tick )
{
s1 - > slink = np ;
np - > slink = s2 ;
return s0 ;
}
s1 = s2 ;
s2 = s2 - > slink ;
}
s1 - > slink = np ;
return s0 ;
}
void _cmXScoreSort ( cmXScore_t * p )
{
cmXsPart_t * pp = p - > partL ;
for ( ; pp ! = NULL ; pp = pp - > link )
{
cmXsMeas_t * mp = pp - > measL ;
for ( ; mp ! = NULL ; mp = mp - > link )
{
// for each voice in this measure
cmXsVoice_t * vp = mp - > voiceL ;
for ( ; vp ! = NULL ; vp = vp - > link )
{
cmXsNote_t * np = vp - > noteL ;
for ( ; np ! = NULL ; np = np - > mlink )
mp - > noteL = _cmXScoreInsertSortedNote ( mp - > noteL , np ) ;
}
}
}
}
2016-02-04 16:33:42 +00:00
cmXsRC_t cmXScoreInitialize ( cmCtx_t * ctx , cmXsH_t * hp , const cmChar_t * xmlFn )
{
cmXsRC_t rc = kOkXsRC ;
if ( ( rc = cmXScoreFinalize ( hp ) ) ! = kOkXsRC )
return rc ;
cmXScore_t * p = cmMemAllocZ ( cmXScore_t , 1 ) ;
cmErrSetup ( & p - > err , & ctx - > rpt , " XScore " ) ;
// create a local linked heap
if ( cmLHeapIsValid ( p - > lhH = cmLHeapCreate ( 8196 , ctx ) ) = = false )
return cmErrMsg ( & p - > err , kLHeapFailXsRC , " Lheap create failed. " ) ;
// open the music xml file
if ( cmXmlAlloc ( ctx , & p - > xmlH , xmlFn ) ! = kOkXmlRC )
{
rc = cmErrMsg ( & p - > err , kXmlFailXsRC , " Unable to open the MusicXML file '%s'. " , cmStringNullGuard ( xmlFn ) ) ;
goto errLabel ;
}
2016-02-09 02:46:07 +00:00
//cmXmlPrint(p->xmlH,&ctx->rpt);
2016-02-04 16:33:42 +00:00
// parse the part-list
if ( ( rc = _cmXScoreParsePartList ( p ) ) ! = kOkXsRC )
goto errLabel ;
2016-02-07 04:36:53 +00:00
// parse each score 'part'
2016-02-04 16:33:42 +00:00
cmXsPart_t * pp = p - > partL ;
for ( ; pp ! = NULL ; pp = pp - > link )
if ( ( rc = _cmXScoreParsePart ( p , pp ) ) ! = kOkXsRC )
goto errLabel ;
2016-02-07 04:36:53 +00:00
// fill in the note->slink chain to link the notes in each measure in time order
2016-02-09 02:46:07 +00:00
_cmXScoreSort ( p ) ;
// CSV output initialize failed.
if ( cmCsvInitialize ( & p - > csvH , ctx ) ! = kOkCsvRC )
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV output object create failed. " ) ;
2016-02-12 00:23:42 +00:00
cmXsConnect_t * c = p - > tieL ;
for ( ; c ! = NULL ; c = c - > link )
cmErrWarnMsg ( & p - > err , kUnterminatedTieXsRC , " The tie begun from note on line %i was not terminated. (pitch=%i) " , c - > note - > xmlNode - > line , c - > note - > pitch ) ;
2016-02-04 16:33:42 +00:00
errLabel :
if ( rc ! = kOkXsRC )
_cmXScoreFinalize ( p ) ;
else
hp - > h = p ;
return rc ;
}
cmXsRC_t cmXScoreFinalize ( cmXsH_t * hp )
{
cmXsRC_t rc = kOkXsRC ;
if ( hp = = NULL | | cmXScoreIsValid ( * hp ) = = false )
return kOkXsRC ;
cmXScore_t * p = _cmXScoreHandleToPtr ( * hp ) ;
if ( ( rc = _cmXScoreFinalize ( p ) ) ! = kOkXsRC )
return rc ;
hp - > h = NULL ;
2016-02-07 04:36:53 +00:00
return rc ;
2016-02-04 16:33:42 +00:00
}
bool cmXScoreIsValid ( cmXsH_t h )
{ return h . h ! = NULL ; }
2016-02-07 04:36:53 +00:00
void _cmXScoreReportNote ( cmRpt_t * rpt , const cmXsNote_t * note )
{
2016-02-12 00:23:42 +00:00
const cmChar_t * B = cmIsFlag ( note - > flags , kBarXsFl ) ? " | " : " - " ;
const cmChar_t * R = cmIsFlag ( note - > flags , kRestXsFl ) ? " R " : " - " ;
const cmChar_t * G = cmIsFlag ( note - > flags , kGraceXsFl ) ? " G " : " - " ;
const cmChar_t * D = cmIsFlag ( note - > flags , kDotXsFl ) ? " D " : " - " ;
const cmChar_t * C = cmIsFlag ( note - > flags , kChordXsFl ) ? " C " : " - " ;
const cmChar_t * e = cmIsFlag ( note - > flags , kEvenXsFl ) ? " e " : " - " ;
const cmChar_t * d = cmIsFlag ( note - > flags , kDynXsFl ) ? " d " : " - " ;
const cmChar_t * t = cmIsFlag ( note - > flags , kTempoXsFl ) ? " t " : " - " ;
const cmChar_t * P = cmIsFlag ( note - > flags , kPedalDnXsFl ) ? " V " : " - " ;
const cmChar_t * H = cmIsFlag ( note - > flags , kHeelXsFl ) ? " H " : " - " ;
const cmChar_t * T0 = cmIsFlag ( note - > flags , kTieBegXsFl ) ? " T " : " - " ;
const cmChar_t * T1 = cmIsFlag ( note - > flags , kTieEndXsFl ) ? " _ " : " - " ;
2016-02-07 04:36:53 +00:00
P = cmIsFlag ( note - > flags , kPedalUpXsFl ) ? " ^ " : P ;
P = cmIsFlag ( note - > flags , kPedalUpDnXsFl ) ? " X " : P ;
const cmChar_t * N = note - > pitch = = 0 ? " " : cmMidiToSciPitch ( note - > pitch , NULL , 0 ) ;
2016-02-12 00:23:42 +00:00
cmRptPrintf ( rpt , " %5i %5i %4.1f %3s %s%s%s%s%s%s%s%s%s%s%s%s " , note - > tick , note - > duration , note - > rvalue , N , B , R , G , D , C , e , d , t , P , H , T0 , T1 ) ;
2016-02-07 04:36:53 +00:00
if ( cmIsFlag ( note - > flags , kSectionXsFl ) )
2016-02-12 00:23:42 +00:00
cmRptPrintf ( rpt , " %s " , cmStringNullGuard ( note - > tvalue ) ) ;
2016-02-07 04:36:53 +00:00
printf ( " \n " ) ;
}
2016-02-09 02:46:07 +00:00
/*
kMidiFileIdColScIdx = 0 ,
kTypeLabelColScIdx = 3 ,
kDSecsColScIdx = 4 ,
kSecsColScIdx = 5 ,
kD0ColScIdx = 9 ,
kD1ColScIdx = 10 ,
kPitchColScIdx = 11 ,
kBarColScIdx = 13 ,
kSkipColScIdx = 14 ,
kEvenColScIdx = 15 ,
kGraceColScIdx = 16 ,
kTempoColScIdx = 17 ,
kFracColScIdx = 18 ,
kDynColScIdx = 19 ,
kSectionColScIdx = 20 ,
kRecdPlayColScIdx = 21 ,
kRemarkColScIdx = 22
*/
cmXsRC_t _cmXScoreWriteCsvHdr ( cmXScore_t * p )
2016-02-04 16:33:42 +00:00
{
2016-02-09 02:46:07 +00:00
const cmChar_t * s [ ] =
{
" id " , " trk " , " evt " , " opcode " , " dticks " , " micros " , " status " ,
" meta " , " ch " , " d0 " , " d1 " , " arg0 " , " arg1 " , " bar " , " skip " ,
" even " , " grace " , " tempo " , " t frac " , " dyn " , " section " , " play_recd " , " remark " , NULL
} ;
2016-02-04 16:33:42 +00:00
2016-02-09 02:46:07 +00:00
cmCsvCell_t * lcp = NULL ;
if ( cmCsvAppendRow ( p - > csvH , & lcp , cmCsvInsertSymText ( p - > csvH , s [ 0 ] ) , 0 , 0 ) ! = kOkCsvRC )
return cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV append row failed. " ) ;
unsigned i ;
for ( i = 1 ; s [ i ] ! = NULL ; + + i )
{
if ( cmCsvInsertTextColAfter ( p - > csvH , lcp , & lcp , s [ i ] , 0 ) ! = kOkCsvRC )
return cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV error inserting CSV title %i. \n " , i ) ;
}
return kOkXsRC ;
}
cmXsRC_t _cmXScoreWriteCsvBlankCols ( cmXScore_t * p , unsigned cnt , cmCsvCell_t * * leftCellPtrPtr )
{
unsigned i ;
for ( i = 0 ; i < cnt ; + + i )
if ( cmCsvInsertTextColAfter ( p - > csvH , * leftCellPtrPtr , leftCellPtrPtr , 0 , 0 ) ! = kOkCsvRC )
return cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV output failed on blank column. " ) ;
return kOkCsvRC ;
}
cmXsRC_t _cmXScoreWriteCsvRow (
cmXScore_t * p ,
unsigned rowIdx ,
unsigned bar ,
const cmChar_t * sectionStr ,
const cmChar_t * opCodeStr ,
double dsecs ,
double secs ,
unsigned d0 ,
unsigned d1 ,
unsigned pitch ,
double frac ,
unsigned flags )
{
cmXsRC_t rc = kOkXsRC ;
cmCsvCell_t * lcp = NULL ;
// append an empty row to the CSV object
if ( cmCsvAppendRow ( p - > csvH , & lcp , cmCsvInsertSymUInt ( p - > csvH , rowIdx ) , 0 , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV append row failed. " ) ;
goto errLabel ;
}
/*
// col 0 : blanks
if ( cmCsvInsertUIntColAfter ( p - > csvH , lcp , & lcp , rowIdx , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV output row index failed. " ) ;
goto errLabel ;
}
*/
// cols 1,2
if ( ( rc = _cmXScoreWriteCsvBlankCols ( p , 2 , & lcp ) ) ! = kOkXsRC )
goto errLabel ;
// col 3 : output the opcode
if ( cmCsvInsertTextColAfter ( p - > csvH , lcp , & lcp , opCodeStr , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on opcode label. " ) ;
goto errLabel ;
}
// col 4 : dsecs
if ( cmCsvInsertDoubleColAfter ( p - > csvH , lcp , & lcp , dsecs , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 'dsecs'. " ) ;
goto errLabel ;
}
// col 5 : secs
if ( cmCsvInsertDoubleColAfter ( p - > csvH , lcp , & lcp , secs , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 'secs'. " ) ;
goto errLabel ;
}
// cols 6,7,8 blanks
if ( ( rc = _cmXScoreWriteCsvBlankCols ( p , 3 , & lcp ) ) ! = kOkXsRC )
goto errLabel ;
// col 9 : d0
if ( cmCsvInsertUIntColAfter ( p - > csvH , lcp , & lcp , d0 , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 'd0'. " ) ;
goto errLabel ;
}
// col 10 : d1
if ( cmCsvInsertUIntColAfter ( p - > csvH , lcp , & lcp , d1 , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 'd1'. " ) ;
goto errLabel ;
}
// col 11 : pitch
if ( cmCsvInsertUIntColAfter ( p - > csvH , lcp , & lcp , pitch , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 'pitch'. " ) ;
goto errLabel ;
}
// col 12 : blanks
if ( ( rc = _cmXScoreWriteCsvBlankCols ( p , 1 + ( cmIsFlag ( flags , kBarXsFl ) ? 0 : 1 ) , & lcp ) ) ! = kOkXsRC )
goto errLabel ;
// col 13 : bar number
if ( cmIsFlag ( flags , kBarXsFl ) )
{
if ( cmCsvInsertUIntColAfter ( p - > csvH , lcp , & lcp , bar , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 'pitch'. " ) ;
goto errLabel ;
}
}
// col 14 : skip (blank for now)
if ( ( rc = _cmXScoreWriteCsvBlankCols ( p , 1 , & lcp ) ) ! = kOkXsRC )
goto errLabel ;
// col 15: even
if ( cmCsvInsertTextColAfter ( p - > csvH , lcp , & lcp , cmIsFlag ( flags , kEvenXsFl ) ? " e " : " " , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on eveness flag label. " ) ;
goto errLabel ;
}
// col 16: grace
if ( cmCsvInsertTextColAfter ( p - > csvH , lcp , & lcp , cmIsFlag ( flags , kGraceXsFl ) ? " g " : " " , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on eveness flag label. " ) ;
goto errLabel ;
}
// col 17: tempo
if ( cmCsvInsertTextColAfter ( p - > csvH , lcp , & lcp , cmIsFlag ( flags , kTempoXsFl ) ? " t " : " " , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on eveness flag label. " ) ;
goto errLabel ;
}
// col 18: frac
if ( frac = = 0 )
{
if ( ( rc = _cmXScoreWriteCsvBlankCols ( p , 1 , & lcp ) ) ! = kOkXsRC )
goto errLabel ;
}
else
{
if ( cmCsvInsertDoubleColAfter ( p - > csvH , lcp , & lcp , 1.0 / frac , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 't frac'. " ) ;
goto errLabel ;
}
}
// col 19: dynamic marking (blank for now)
if ( ( rc = _cmXScoreWriteCsvBlankCols ( p , 1 , & lcp ) ) ! = kOkXsRC )
goto errLabel ;
// col 20: section
if ( cmCsvInsertTextColAfter ( p - > csvH , lcp , & lcp , cmIsFlag ( flags , kSectionXsFl ) ? sectionStr : " " , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on eveness flag label. " ) ;
goto errLabel ;
}
// col 21, 22 : recd-play, remark (blank for now)
if ( ( rc = _cmXScoreWriteCsvBlankCols ( p , 2 , & lcp ) ) ! = kOkXsRC )
goto errLabel ;
errLabel :
return rc ;
}
cmXsRC_t cmXScoreWriteCsv ( cmXsH_t h , const cmChar_t * csvFn )
{
cmXsRC_t rc = kOkXsRC ;
cmXScore_t * p = _cmXScoreHandleToPtr ( h ) ;
unsigned rowIdx = 1 ;
double tpqn = 0 ; // ticks per quarter note
double tps = 0 ; // ticks per second
double sec = 0 ; // current time in seconds
const cmChar_t * sectionIdStr = NULL ;
if ( ! cmCsvIsValid ( p - > csvH ) )
return cmErrMsg ( & p - > err , kCsvFailXsRC , " The CSV output object is not initialized. " ) ;
if ( ( rc = _cmXScoreWriteCsvHdr ( p ) ) ! = kOkXsRC )
goto errLabel ;
cmXsPart_t * pp = p - > partL ;
for ( ; pp ! = NULL ; pp = pp - > link )
{
cmXsMeas_t * mp = pp - > measL ;
for ( ; mp ! = NULL ; mp = mp - > link )
{
if ( mp - > divisions ! = 0 )
tpqn = mp - > divisions ;
cmXsNote_t * np = mp - > noteL ;
double sec0 = sec ;
for ( ; np ! = NULL ; np = np - > slink )
{
//
if ( cmIsFlag ( np - > flags , kMetronomeXsFl ) )
{
double bpm = np - > duration ;
double bps = bpm / 60.0 ;
tps = bps * tpqn ;
}
double meas_sec = tps = = 0 ? 0 : np - > tick / tps ;
double sec1 = sec + meas_sec ;
double dsecs = sec1 - sec0 ;
sec0 = sec1 ;
// if this is a section event
if ( cmIsFlag ( np - > flags , kSectionXsFl ) )
sectionIdStr = np - > tvalue ;
// if this is a bar event
if ( cmIsFlag ( np - > flags , kBarXsFl ) )
{
_cmXScoreWriteCsvRow ( p , rowIdx , mp - > number , NULL , " bar " , dsecs , sec1 , 0 , 0 , 0 , 0 , np - > flags ) ;
}
else
// if this is a pedal event
if ( cmIsFlag ( np - > flags , kPedalDnXsFl | kPedalUpXsFl | kPedalUpDnXsFl ) )
{
unsigned d0 = 64 ; // pedal MIDI ctl id
unsigned d1 = cmIsFlag ( np - > flags , kPedalDnXsFl ) ? 64 : 0 ; // pedal-dn: d1>=64 pedal-up:<64
_cmXScoreWriteCsvRow ( p , rowIdx , mp - > number , NULL , " ctl " , dsecs , sec1 , d0 , d1 , 0 , 0 , np - > flags ) ;
}
else
// if this is a sounding note event
if ( cmIsNotFlag ( np - > flags , kRestXsFl ) )
{
double frac = np - > rvalue + ( cmIsFlag ( np - > flags , kDotXsFl ) ? ( np - > rvalue / 2 ) : 0 ) ;
//
_cmXScoreWriteCsvRow ( p , rowIdx , mp - > number , sectionIdStr , " non " , dsecs , sec1 , 0 , 0 , np - > pitch , frac , np - > flags ) ;
sectionIdStr = NULL ;
}
rowIdx + = 1 ;
}
sec = sec0 ;
}
}
if ( cmCsvWrite ( p - > csvH , csvFn ) ! = kOkCsvRC )
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " The CSV output write failed on file '%s'. " , csvFn ) ;
errLabel :
return rc ;
}
void cmXScoreReport ( cmXsH_t h , cmRpt_t * rpt , bool sortFl )
{
cmXScore_t * p = _cmXScoreHandleToPtr ( h ) ;
2016-02-04 16:33:42 +00:00
cmXsPart_t * pp = p - > partL ;
2016-02-09 02:46:07 +00:00
2016-02-04 16:33:42 +00:00
for ( ; pp ! = NULL ; pp = pp - > link )
{
cmRptPrintf ( rpt , " Part:%s \n " , pp - > idStr ) ;
const cmXsMeas_t * meas = pp - > measL ;
for ( ; meas ! = NULL ; meas = meas - > link )
2016-02-07 04:36:53 +00:00
{
2016-02-04 16:33:42 +00:00
cmRptPrintf ( rpt , " %i : div:%i beat:%i beat-type:%i \n " , meas - > number , meas - > divisions , meas - > beats , meas - > beat_type ) ;
2016-02-07 04:36:53 +00:00
if ( sortFl )
{
const cmXsNote_t * note = meas - > noteL ;
for ( ; note ! = NULL ; note = note - > slink )
_cmXScoreReportNote ( rpt , note ) ;
}
else
{
const cmXsVoice_t * v = meas - > voiceL ;
for ( ; v ! = NULL ; v = v - > link )
{
const cmXsNote_t * note = v - > noteL ;
cmRptPrintf ( rpt , " voice:%i \n " , v - > id ) ;
for ( ; note ! = NULL ; note = note - > mlink )
_cmXScoreReportNote ( rpt , note ) ;
}
}
}
}
2016-02-04 16:33:42 +00:00
}
cmXsRC_t cmXScoreTest ( cmCtx_t * ctx , const cmChar_t * fn )
{
cmXsRC_t rc ;
cmXsH_t h = cmXsNullHandle ;
if ( ( rc = cmXScoreInitialize ( ctx , & h , fn ) ) ! = kOkXsRC )
return cmErrMsg ( & ctx - > err , rc , " XScore alloc failed. " ) ;
2016-02-11 00:03:17 +00:00
cmXScoreWriteCsv ( h , " /Users/kevin/temp/a0.csv " ) ;
2016-02-07 04:36:53 +00:00
cmXScoreReport ( h , & ctx - > rpt , true ) ;
2016-02-04 16:33:42 +00:00
return cmXScoreFinalize ( & h ) ;
}