2016-02-04 16:33:42 +00:00
# include "cmPrefix.h"
# include "cmGlobal.h"
# include "cmFloatTypes.h"
2016-02-25 00:09:29 +00:00
# include "cmComplexTypes.h"
2016-02-04 16:33:42 +00:00
# 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-19 00:10:05 +00:00
# include "cmMidiFile.h"
2016-02-09 02:46:07 +00:00
# include "cmLex.h"
# include "cmCsv.h"
2016-02-04 16:33:42 +00:00
2016-02-25 00:09:29 +00:00
# include "cmFile.h"
# include "cmSymTbl.h"
# include "cmAudioFile.h"
# include "cmAudioFile.h"
# include "cmProcObj.h"
# include "cmProcTemplate.h"
# include "cmProc.h"
# include "cmProc2.h"
# include "cmProc5.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-18 00:00:15 +00:00
kSectionXsFl = 0x00001 , // rvalue holds section number
kBarXsFl = 0x00002 ,
kRestXsFl = 0x00004 ,
kGraceXsFl = 0x00008 ,
kDotXsFl = 0x00010 ,
kChordXsFl = 0x00020 ,
kDynXsFl = 0x00040 ,
kEvenXsFl = 0x00080 ,
kTempoXsFl = 0x00100 ,
kHeelXsFl = 0x00200 ,
kTieBegXsFl = 0x00400 ,
kTieEndXsFl = 0x00800 ,
kTieProcXsFl = 0x01000 ,
kPedalDnXsFl = 0x02000 ,
kPedalUpXsFl = 0x04000 ,
kPedalUpDnXsFl = 0x08000 ,
2016-02-19 00:10:05 +00:00
kMetronomeXsFl = 0x10000 , // duration holds BPM
kOnsetXsFl = 0x20000 // this is a sounding note
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-03-02 23:52:40 +00:00
unsigned uid ; // unique id of this note record
2016-02-18 00:00:15 +00:00
unsigned flags ; // See k???XsFl
unsigned pitch ; // midi pitch
2016-02-19 00:10:05 +00:00
unsigned velocity ; // midi velocity
2016-03-30 23:18:44 +00:00
unsigned dynamics ; // dynamic level 1=pppp 9=fff
2016-02-18 00:00:15 +00:00
cmChar_t step ; // A-G
unsigned octave ; // sci pitch octave
int alter ; // +n=sharps,-n=flats
2016-02-25 00:09:29 +00:00
unsigned staff ; // 1=treble 2=bass
2016-02-18 00:00:15 +00:00
unsigned tick ; //
unsigned duration ; // duration in ticks
2016-02-25 00:09:29 +00:00
unsigned locIdx ; // location index (chords share the same location index)
2016-02-18 00:00:15 +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, ...)
const cmChar_t * tvalue ; // text value
2016-02-12 00:23:42 +00:00
2016-02-19 00:10:05 +00:00
struct cmXsVoice_str * voice ; // voice this note belongs to
struct cmXsMeas_str * meas ; // measure this note belongs to
2016-02-12 00:23:42 +00:00
2016-02-18 00:00:15 +00:00
const cmXmlNode_t * xmlNode ; // note xml ptr
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 ;
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 ;
2016-02-19 00:10:05 +00:00
typedef struct cmXsSpan_str
{
unsigned staff ;
unsigned number ;
struct cmXsMeas_str * meas ;
unsigned tick0 ;
unsigned tick1 ;
int pitch_offset ;
struct cmXsSpan_str * link ;
} cmXsSpan_t ;
2016-02-04 16:33:42 +00:00
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 ;
2016-02-19 00:10:05 +00:00
cmXsSpan_t * spanL ;
2016-03-02 23:52:40 +00:00
unsigned nextUid ;
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-03-02 23:52:40 +00:00
note - > uid = p - > nextUid + + ;
2016-02-12 00:23:42 +00:00
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-18 00:00:15 +00:00
cmXsRC_t _cmXScoreParsePitch ( cmXScore_t * p , const cmXmlNode_t * nnp , cmXsNote_t * np )
2016-02-04 22:55:22 +00:00
{
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 ;
2016-02-26 00:10:54 +00:00
np - > pitch = midi ;
np - > step = * step ;
2016-02-18 00:00:15 +00:00
np - > octave = octave ;
np - > alter = alter ;
2016-02-19 00:10:05 +00:00
np - > flags | = kOnsetXsFl ;
2016-02-04 22:55:22 +00:00
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-03-30 15:47:41 +00:00
// On input tick0Ref is set to the tick of the previous event.
// On input tickRef is set to the tick of this event.
// On output tick0Ref is set to the tick of this event.
// On output tickRef is set to the tick of the next event.
2016-02-18 00:00:15 +00:00
cmXsRC_t _cmXScoreParseNote ( cmXScore_t * p , cmXsMeas_t * meas , const cmXmlNode_t * nnp , unsigned * tick0Ref , 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-18 00:00:15 +00:00
if ( ( rc = _cmXScoreParsePitch ( p , nnp , note ) ) ! = kOkXsRC )
2016-02-04 22:55:22 +00:00
return rc ;
2016-02-19 00:10:05 +00:00
cmXmlNodeUInt ( nnp , & note - > duration , " duration " , NULL ) ; // get the note duration
cmXmlNodeUInt ( nnp , & note - > staff , " staff " , NULL ) ; // get th staff number
2016-02-07 04:36:53 +00:00
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-18 00:00:15 +00:00
// is this is first note in a tied pair
if ( cmXmlNodeHasChildWithAttrAndValue ( nnp , " tie " , " type " , " start " , NULL ) )
note - > flags | = kTieBegXsFl ;
// is this is second note in a tied pair
if ( cmXmlNodeHasChildWithAttrAndValue ( nnp , " tie " , " type " , " stop " , NULL ) )
note - > flags | = kTieEndXsFl ;
2016-02-12 00:23:42 +00:00
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
2016-02-18 00:00:15 +00:00
// if this is a chord note
if ( cmIsFlag ( note - > flags , kChordXsFl ) )
{
note - > tick = * tick0Ref ; // then use the onset time from the previous note and do not advance time
}
else
{
* tick0Ref = * tickRef ;
note - > tick = * tickRef ;
2016-02-07 04:36:53 +00:00
* tickRef + = note - > duration ;
2016-02-18 00:00:15 +00:00
}
2016-02-07 04:36:53 +00:00
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 ) ;
}
2016-02-19 00:10:05 +00:00
cmXsSpan_t * _cmXScoreFindOpenOctaveShift ( cmXScore_t * p , unsigned staff , unsigned number )
{
cmXsSpan_t * s = p - > spanL ;
for ( ; s ! = NULL ; s = s - > link )
if ( s - > tick1 = = - 1 & & s - > staff = = staff & & s - > number = = number )
return s ;
return NULL ;
}
cmXsRC_t _cmXScorePushOctaveShift ( cmXScore_t * p , cmXsMeas_t * meas , unsigned staff , unsigned span_number , const cmChar_t * type_str , unsigned tick )
{
assert ( meas ! = NULL ) ;
cmXsSpan_t * s ;
if ( cmTextCmp ( type_str , " stop " ) = = 0 )
{
if ( ( s = _cmXScoreFindOpenOctaveShift ( p , staff , span_number ) ) = = NULL )
return cmErrWarnMsg ( & p - > err , kUnterminatedOctaveShiftXsrRC , " An illegal octave shift was encounted in meas %i. \n " , meas - > number ) ;
s - > tick1 = tick ;
}
else
{
s = cmLhAllocZ ( p - > lhH , cmXsSpan_t , 1 ) ;
s - > staff = staff ;
s - > meas = meas ;
s - > number = span_number ;
s - > tick0 = tick ;
s - > tick1 = - 1 ;
s - > pitch_offset = cmTextCmp ( type_str , " up " ) = = 0 ? - 12 : 12 ;
s - > link = p - > spanL ;
p - > spanL = s ;
}
return kOkXsRC ;
}
2016-02-07 04:36:53 +00:00
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 ;
2016-02-18 00:00:15 +00:00
bool pushFl = true ;
2016-02-19 00:10:05 +00:00
unsigned staff = 0 ;
cmXmlNodeInt ( dnp , & offset , " offset " , NULL ) ;
cmXmlNodeUInt ( dnp , & staff , " staff " , NULL ) ;
2016-02-07 04:36:53 +00:00
// 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-18 00:00:15 +00:00
else
2016-02-19 00:10:05 +00:00
// if this is an 'octave-shift' direction
if ( ( np = cmXmlSearch ( dnp , " octave-shift " , NULL , 0 ) ) ! = NULL )
{
unsigned span_number = - 1 ;
if ( cmXmlAttrUInt ( np , " number " , & span_number ) ! = kOkXmlRC )
return cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " Octave-shift is missing a 'number' attribute. " ) ;
if ( ( a = cmXmlFindAttrib ( np , " type " ) ) = = NULL )
return cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " Octave-shift is missing a 'type' attribute. " ) ;
rc = _cmXScorePushOctaveShift ( p , meas , staff , span_number , a - > value , tick + offset ) ;
pushFl = false ;
}
else
2016-02-18 00:00:15 +00:00
{
pushFl = false ;
}
2016-02-07 04:36:53 +00:00
2016-02-18 00:00:15 +00:00
if ( pushFl )
rc = _cmXScorePushNonNote ( p , meas , dnp , tick + offset , duration , rvalue , tvalue , flags ) ;
return rc ;
2016-02-04 22:55:22 +00:00
}
2016-02-07 04:36:53 +00:00
2016-03-30 15:47:41 +00:00
// On input tickRef is set to the absolute tick of the bar line and on output it is set
// to the absolute tick of the next bar line.
cmXsRC_t _cmXScoreParseMeasure ( cmXScore_t * p , cmXsPart_t * pp , const cmXmlNode_t * mnp , unsigned * tickRef )
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 ;
2016-03-30 15:47:41 +00:00
unsigned tick = * tickRef ;
2016-02-18 00:00:15 +00:00
unsigned tick0 = 0 ;
2016-02-19 00:10:05 +00:00
cmXsMeas_t * m = NULL ;
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
{
2016-02-19 00:10:05 +00:00
m = pp - > measL ;
2016-02-04 16:33:42 +00:00
while ( m - > link ! = NULL )
m = m - > link ;
2016-02-07 04:36:53 +00:00
2016-02-19 00:10:05 +00:00
m - > link = meas ;
meas - > divisions = m - > divisions ;
meas - > beats = m - > beats ;
meas - > beat_type = m - > beat_type ;
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-18 00:00:15 +00:00
rc = _cmXScoreParseNote ( p , meas , np , & tick0 , & 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 ) ;
2016-02-19 00:10:05 +00:00
if ( backup > tick )
tick = 0 ;
else
tick - = backup ;
2016-02-18 00:00:15 +00:00
tick0 = tick ;
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-03-24 23:21:40 +00:00
2016-03-30 15:47:41 +00:00
* tickRef = tick ;
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 ;
2016-03-24 23:21:40 +00:00
cmXmlAttr_t partAttr = { " id " , pp - > idStr } ;
2016-03-30 15:47:41 +00:00
unsigned barTick = 0 ;
2016-02-04 16:33:42 +00:00
// 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 )
2016-03-30 15:47:41 +00:00
if ( ( rc = _cmXScoreParseMeasure ( p , pp , cnp , & barTick ) ) ! = kOkXsRC )
2016-02-04 16:33:42 +00:00
return rc ;
return rc ;
}
2016-02-25 00:09:29 +00:00
// Insert note 'np' into the sorted note list based at 's0'.
// Return a pointer to the base of the list after the insertion.
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 )
{
2016-02-25 00:09:29 +00:00
// for each part
2016-02-07 04:36:53 +00:00
cmXsPart_t * pp = p - > partL ;
for ( ; pp ! = NULL ; pp = pp - > link )
{
2016-02-25 00:09:29 +00:00
// for each measure in this part
2016-02-07 04:36:53 +00:00
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 )
{
2016-02-25 00:09:29 +00:00
// for each note in this measure
2016-02-07 04:36:53 +00:00
cmXsNote_t * np = vp - > noteL ;
for ( ; np ! = NULL ; np = np - > mlink )
mp - > noteL = _cmXScoreInsertSortedNote ( mp - > noteL , np ) ;
}
}
}
}
2016-03-17 23:30:21 +00:00
bool _cmXScoreFindTiedNote ( cmXScore_t * p , cmXsMeas_t * mp , cmXsNote_t * n0p , bool rptFl )
2016-02-18 00:00:15 +00:00
{
2016-03-17 23:30:21 +00:00
cmXsNote_t * nnp = n0p - > slink ; // begin w/ note following np
unsigned measNumb = mp - > number ;
cmChar_t acc = n0p - > alter = = - 1 ? ' b ' : ( n0p - > alter = = 1 ? ' # ' : ' ' ) ;
2016-02-18 00:00:15 +00:00
2016-03-15 14:08:44 +00:00
if ( rptFl )
2016-03-17 23:30:21 +00:00
printf ( " %i %i %s " , n0p - > meas - > number , n0p - > tick , cmMidiToSciPitch ( n0p - > pitch , NULL , 0 ) ) ;
2016-03-10 22:50:33 +00:00
2016-03-17 23:30:21 +00:00
while ( 1 )
2016-02-18 00:00:15 +00:00
{
2016-03-17 23:30:21 +00:00
// if we are at the end of a measure advance to the next measure
2016-02-18 00:00:15 +00:00
if ( nnp = = NULL )
2016-03-17 23:30:21 +00:00
{
mp = mp - > link ;
2016-02-18 00:00:15 +00:00
nnp = mp - > noteL ;
2016-03-10 22:50:33 +00:00
2016-03-17 23:30:21 +00:00
// if a measure was completed and no end note was found ... then the tie is unterminated
// (a tie must be continued in every measure which it passes through)
if ( mp - > number > measNumb + 1 )
break ;
}
// for each note starting at nnp
for ( ; nnp ! = NULL ; nnp = nnp - > slink )
{
// if this note is tied to the originating note (np)
if ( nnp - > voice - > id = = n0p - > voice - > id & & nnp - > step = = n0p - > step & & nnp - > octave = = n0p - > octave )
{
nnp - > flags | = kTieProcXsFl ;
nnp - > flags = cmClrFlag ( nnp - > flags , kOnsetXsFl ) ;
if ( rptFl )
printf ( " ---> %i %i %s " , nnp - > meas - > number , nnp - > tick , cmMidiToSciPitch ( nnp - > pitch , NULL , 0 ) ) ;
// if this note is not tied to a subsequent note
if ( cmIsNotFlag ( nnp - > flags , kTieBegXsFl ) )
return true ;
// record the measure number of the last note with a tie-start
measNumb = mp - > number ;
}
}
}
cmErrWarnMsg ( & p - > err , kUnterminatedTieXsRC , " The tied %c%c%i in measure %i was not terminated. " , n0p - > step , acc , n0p - > octave , measNumb ) ;
return false ;
}
2016-02-25 00:09:29 +00:00
void _cmXScoreResolveTiesAndLoc ( cmXScore_t * p )
2016-02-18 00:00:15 +00:00
{
2016-02-25 00:09:29 +00:00
unsigned n = 0 ;
unsigned m = 0 ;
2016-03-15 14:08:44 +00:00
bool rptFl = false ;
2016-02-18 00:00:15 +00:00
cmXsPart_t * pp = p - > partL ;
2016-03-10 22:50:33 +00:00
// for each part
2016-02-18 00:00:15 +00:00
for ( ; pp ! = NULL ; pp = pp - > link )
{
2016-02-25 00:09:29 +00:00
unsigned locIdx = 1 ;
2016-02-18 00:00:15 +00:00
cmXsMeas_t * mp = pp - > measL ;
2016-03-10 22:50:33 +00:00
// for each measure
2016-02-18 00:00:15 +00:00
for ( ; mp ! = NULL ; mp = mp - > link )
{
2016-02-25 00:09:29 +00:00
cmXsNote_t * n0 = NULL ;
2016-02-18 00:00:15 +00:00
cmXsNote_t * np = mp - > noteL ;
2016-03-10 22:50:33 +00:00
// for each note in this measure
2016-02-18 00:00:15 +00:00
for ( ; np ! = NULL ; np = np - > slink )
2016-02-25 00:09:29 +00:00
{
// if this note begins a tie and has not yet been processed
// (A note that continues a tie and therefore has a kTieBegXsFl set
// may have already been processed by an earlier tied note.)
2016-02-18 00:00:15 +00:00
if ( cmIsFlag ( np - > flags , kTieBegXsFl ) & & cmIsNotFlag ( np - > flags , kTieProcXsFl ) )
{
2016-03-15 14:08:44 +00:00
if ( _cmXScoreFindTiedNote ( p , mp , np , rptFl ) )
2016-02-18 00:00:15 +00:00
m + = 1 ;
2016-03-15 14:08:44 +00:00
if ( rptFl )
printf ( " \n " ) ;
2016-02-18 00:00:15 +00:00
n + = 1 ;
2016-02-25 00:09:29 +00:00
}
2016-03-15 14:08:44 +00:00
if ( cmIsFlag ( np - > flags , kTieEndXsFl ) & & cmIsFlag ( np - > flags , kOnsetXsFl ) )
{
cmChar_t acc = np - > alter = = - 1 ? ' b ' : ( np - > alter = = 1 ? ' # ' : ' ' ) ;
cmErrWarnMsg ( & p - > err , kUnterminatedTieXsRC , " The tied %c%c%i in measure %i marked as a tied note but is also marked to sound. " , np - > step , acc , np - > octave , mp - > number ) ;
}
2016-02-25 00:09:29 +00:00
// set the location
2016-03-24 23:21:40 +00:00
if ( cmIsFlag ( np - > flags , kOnsetXsFl | kBarXsFl ) )
2016-02-25 00:09:29 +00:00
{
2016-03-24 23:21:40 +00:00
if ( cmIsFlag ( np - > flags , kBarXsFl ) | | ( n0 ! = NULL & & n0 - > tick ! = np - > tick ) )
2016-02-25 00:09:29 +00:00
locIdx + = 1 ;
np - > locIdx = locIdx ;
n0 = np ;
}
}
2016-02-18 00:00:15 +00:00
}
}
printf ( " Found:%i Not Found:%i \n " , m , n - m ) ;
}
2016-02-19 00:10:05 +00:00
cmXsRC_t _cmXScoreResolveOctaveShift ( cmXScore_t * p )
{
const cmXsSpan_t * s ;
for ( s = p - > spanL ; s ! = NULL ; s = s - > link )
{
if ( s - > tick1 = = - 1 )
{
cmErrWarnMsg ( & p - > err , kSyntaxErrorXsRC , " An unterminated octave shift span was encountered in measure %i staff=%i. " , s - > meas - > number , s - > staff ) ;
}
else
{
cmXsMeas_t * m = p - > partL - > measL ;
for ( ; m ! = NULL ; m = m - > link )
if ( m - > number = = s - > meas - > number )
break ;
assert ( m ! = NULL ) ;
cmXsNote_t * note = m - > noteL ;
for ( ; note ! = NULL ; note = note - > slink )
if ( note - > staff = = s - > staff & & s - > tick0 < = note - > tick & & note - > tick < s - > tick1 )
note - > pitch + = s - > pitch_offset ;
}
}
return kOkXsRC ;
}
2016-03-24 23:21:40 +00:00
// The identical pitch may be notated to play simultaneously on different voices.
// As performed on the piano this will equate to a single sounding note.
// This function clears the onset flag on all except one of the duplicated notes.
void _cmXScoreRemoveDuplicateNotes ( cmXScore_t * p )
{
cmXsPart_t * pp = p - > partL ;
// for each part
for ( ; pp ! = NULL ; pp = pp - > link )
{
cmXsMeas_t * mp = pp - > measL ;
// for each measure
for ( ; mp ! = NULL ; mp = mp - > link )
{
cmXsNote_t * np = mp - > noteL ;
// for each note in this measure
for ( ; np ! = NULL ; np = np - > slink )
if ( cmIsFlag ( np - > flags , kOnsetXsFl ) )
{
cmXsNote_t * n0p = mp - > noteL ;
for ( ; n0p ! = NULL ; n0p = n0p - > slink )
if ( n0p ! = np & & cmIsFlag ( n0p - > flags , kOnsetXsFl ) & & np - > locIdx = = n0p - > locIdx & & np - > pitch = = n0p - > pitch )
n0p - > flags = cmClrFlag ( n0p - > flags , kOnsetXsFl ) ;
}
}
}
}
2016-02-19 00:10:05 +00:00
cmXsMeas_t * _cmXScoreNextNonEmptyMeas ( cmXsPart_t * pp , cmXsMeas_t * meas )
{
if ( meas = = NULL )
{
if ( pp = = NULL | | pp - > measL = = NULL )
return NULL ;
meas = pp - > measL ;
}
else
{
meas = meas - > link ;
}
while ( meas ! = NULL & & meas - > noteL = = NULL )
meas = meas - > link ;
return meas ;
}
cmXsNote_t * _cmXScoreNextNote ( cmXsPart_t * pp , cmXsNote_t * note )
{
// meas should always be valid (unless this is the first note in the score)
cmXsMeas_t * meas = note = = NULL ? NULL : note - > meas ;
do
{
if ( note = = NULL | | note - > slink = = NULL )
{
if ( ( meas = _cmXScoreNextNonEmptyMeas ( pp , meas ) ) = = NULL )
return NULL ;
assert ( meas - > noteL ! = NULL ) ;
note = meas - > noteL ;
}
else
{
note = note - > slink ;
}
assert ( note ! = NULL ) ;
meas = note - > meas ;
// note is now set to a non-NULL candidate note - advance to a sounding note
while ( note ! = NULL & & cmIsNotFlag ( note - > flags , kOnsetXsFl ) )
note = note - > slink ;
// if no note was found in this measure
} while ( note = = NULL ) ;
return note ;
}
2016-02-26 00:10:54 +00:00
cmXsRC_t _cmXScoreWriteScorePlotFile ( cmXScore_t * p , const cmChar_t * fn )
{
cmXsRC_t rc = kOkXsRC ;
cmFileH_t fH = cmFileNullHandle ;
double ticks_per_sec = 0 ;
double onset_secs = 0 ;
if ( cmFileOpen ( & fH , fn , kWriteFileFl , p - > err . rpt ) ! = kOkFileRC )
return cmErrMsg ( & p - > err , kFileFailXsRC , " Unable to create the file '%s'. " , cmStringNullGuard ( fn ) ) ;
cmXsPart_t * pp = p - > partL ;
for ( ; pp ! = NULL ; pp = pp - > link )
{
cmXsMeas_t * mp = pp - > measL ;
for ( ; mp ! = NULL ; mp = mp - > link )
{
cmFilePrintf ( fH , " b %f %i %s B \n " , onset_secs , mp - > number , " bar " ) ;
cmXsNote_t * np = mp - > noteL ;
unsigned tick0 = 0 ;
for ( ; np ! = NULL ; np = np - > slink )
{
if ( cmIsFlag ( np - > flags , kMetronomeXsFl ) )
{
double bps = np - > duration / 60.0 ;
// t b t
// - = - -
// s s b
ticks_per_sec = bps * mp - > divisions ;
}
else
{
if ( cmIsFlag ( np - > flags , kOnsetXsFl ) )
{
onset_secs + = ( np - > tick - tick0 ) / ticks_per_sec ;
tick0 = np - > tick ;
2016-03-02 23:52:40 +00:00
cmFilePrintf ( fH , " n %f %f %i %s %s \n " , onset_secs , np - > duration / ticks_per_sec , np - > uid , cmMidiToSciPitch ( np - > pitch , NULL , 0 ) , cmIsFlag ( np - > flags , kGraceXsFl ) ? " G " : " N " ) ;
2016-02-26 00:10:54 +00:00
}
}
}
onset_secs + = ( mp - > divisions * mp - > beats - tick0 ) / ticks_per_sec ;
}
}
cmFileClose ( & fH ) ;
return rc ;
}
cmXsRC_t _cmXScoreWriteMidiPlotFile ( cmXScore_t * p , cmChar_t * fn , const cmMidiTrackMsg_t * * m , unsigned mN )
{
cmXsRC_t rc = kOkXsRC ;
cmFileH_t fH = cmFileNullHandle ;
unsigned i = 0 ;
if ( cmFileOpen ( & fH , fn , kWriteFileFl , p - > err . rpt ) ! = kOkFileRC )
return cmErrMsg ( & p - > err , kFileFailXsRC , " Unable to create the file '%s'. " , cmStringNullGuard ( fn ) ) ;
for ( i = 0 ; i < mN ; + + i )
if ( ( m [ i ] ! = NULL ) & & cmMidiIsChStatus ( m [ i ] - > status ) & & cmMidiIsNoteOn ( m [ i ] - > status ) & & ( m [ i ] - > u . chMsgPtr - > d1 > 0 ) )
2016-03-02 23:52:40 +00:00
cmFilePrintf ( fH , " n %f %f %i %s \n " , m [ i ] - > amicro / 1000000.0 , m [ i ] - > u . chMsgPtr - > durMicros / 1000000.0 , m [ i ] - > uid , cmMidiToSciPitch ( m [ i ] - > u . chMsgPtr - > d0 , NULL , 0 ) ) ;
2016-02-26 00:10:54 +00:00
cmFileClose ( & fH ) ;
return rc ;
}
2016-02-25 00:09:29 +00:00
2016-02-19 00:10:05 +00:00
cmXsRC_t _cmXScoreProcessMidi ( cmXScore_t * p , cmCtx_t * ctx , const cmChar_t * midiFn )
{
cmXsRC_t rc = kOkXsRC ;
cmMidiFileH_t mfH = cmMidiFileNullHandle ;
const cmMidiTrackMsg_t * * m = NULL ;
unsigned mN = 0 ;
unsigned i = 0 ;
unsigned j = 0 ;
cmXsNote_t * note = NULL ;
if ( cmMidiFileOpen ( ctx , & mfH , midiFn ) ! = kOkMfRC )
return cmErrMsg ( & p - > err , kMidiFailXsRC , " The MIDI file object could not be opened from '%s'. " , cmStringNullGuard ( midiFn ) ) ;
if ( ( m = cmMidiFileMsgArray ( mfH ) ) = = NULL | | ( mN = cmMidiFileMsgCount ( mfH ) ) = = 0 )
{
rc = cmErrMsg ( & p - > err , kMidiFailXsRC , " The MIDI file object appears to be empty. " ) ;
goto errLabel ;
}
if ( ( note = _cmXScoreNextNote ( p - > partL , NULL ) ) = = NULL )
{
rc = cmErrWarnMsg ( & p - > err , kSyntaxErrorXsRC , " No MIDI processing to be done. The score appears to be empty. " ) ;
goto errLabel ;
}
2016-02-25 00:09:29 +00:00
cmCtx * c = cmCtxAlloc ( NULL , p - > err . rpt , cmLHeapNullHandle , cmSymTblNullHandle ) ;
cmSeqAlign_t * s = cmSeqAlignAlloc ( c , NULL ) ;
unsigned offs = 0 ;
for ( ; note ! = NULL ; note = _cmXScoreNextNote ( p - > partL , note ) )
{
if ( cmIsFlag ( note - > flags , kGraceXsFl ) )
offs + = 1 ;
cmSeqAlignInsert ( s , 0 , note - > locIdx + offs , note - > pitch ) ;
}
unsigned locIdx = 1 ;
for ( i = 0 , j = 0 ; i < mN ; + + i )
if ( ( m [ i ] ! = NULL ) & & cmMidiIsChStatus ( m [ i ] - > status ) & & cmMidiIsNoteOn ( m [ i ] - > status ) & & ( m [ i ] - > u . chMsgPtr - > d1 > 0 ) )
{
if ( m [ j ] - > atick ! = m [ i ] - > atick )
locIdx + = 1 ;
cmSeqAlignInsert ( s , 1 , locIdx , m [ i ] - > u . chMsgPtr - > d0 ) ;
//printf("%i : %s\n",locIdx,cmMidiToSciPitch(m[i]->u.chMsgPtr->d0,NULL,0));
j = i ;
}
2016-02-26 00:10:54 +00:00
cmMidiFileCalcNoteDurations ( mfH ) ;
_cmXScoreWriteScorePlotFile ( p , " /Users/kevin/temp/score.txt " ) ;
_cmXScoreWriteMidiPlotFile ( p , " /Users/kevin/temp/midi.txt " , m , mN ) ;
2016-02-25 00:09:29 +00:00
cmSeqAlignReport ( s , p - > err . rpt ) ;
cmSeqAlignFree ( & s ) ;
cmCtxFree ( & c ) ;
goto errLabel ;
2016-02-19 00:10:05 +00:00
printf ( " i j score midi \n " ) ;
printf ( " ---- ---- --- ---- --- ---- \n " ) ;
for ( j = 0 ; note ! = NULL ; note = _cmXScoreNextNote ( p - > partL , note ) , + + j )
{
unsigned midiPitch = 0 ;
for ( ; i < mN ; + + i )
if ( m [ i ] ! = NULL & & cmMidiIsChStatus ( m [ i ] - > status ) & & cmMidiIsNoteOn ( m [ i ] - > status ) & & m [ i ] - > u . chMsgPtr - > d1 > 0 )
{
midiPitch = m [ i ] - > u . chMsgPtr - > d0 ;
+ + i ;
break ;
}
char buf [ 6 ] ;
printf ( " %4i %4i %3i %4s %3i %4s \n " , j , i ,
note - > pitch ,
cmMidiToSciPitch ( note - > pitch , NULL , 0 ) ,
midiPitch ,
cmMidiToSciPitch ( midiPitch , buf , 5 ) ) ;
}
errLabel :
cmMidiFileClose ( & mfH ) ;
return rc ;
}
cmXsRC_t cmXScoreInitialize ( cmCtx_t * ctx , cmXsH_t * hp , const cmChar_t * xmlFn , const cmChar_t * midiFn )
2016-02-04 16:33:42 +00:00
{
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 ) ;
2016-02-25 00:09:29 +00:00
_cmXScoreResolveTiesAndLoc ( p ) ;
2016-02-18 00:00:15 +00:00
2016-03-24 23:21:40 +00:00
_cmXScoreRemoveDuplicateNotes ( p ) ;
2016-02-19 00:10:05 +00:00
//_cmXScoreResolveOctaveShift(p);
2016-03-10 22:50:33 +00:00
//if( midiFn != NULL )
// _cmXScoreProcessMidi(p,ctx,midiFn);
2016-02-19 00:10:05 +00:00
2016-02-09 02:46:07 +00:00
// CSV output initialize failed.
if ( cmCsvInitialize ( & p - > csvH , ctx ) ! = kOkCsvRC )
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV output object create failed. " ) ;
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-03-30 23:18:44 +00:00
/*
Dynamics File Format :
< blk > *
< blk > - > < hdr - line > < note - line > < blank - line >
< hdr - line > - > < int > " | "
< note - line > - > < float > < sci - pitch > " : " < int >
< sci - pitch > - > < A - G > < # | b | < space >
*/
typedef struct cmXsDyn_str
2016-03-17 23:30:21 +00:00
{
2016-03-30 23:18:44 +00:00
unsigned bar ;
float rval ;
unsigned pitch ;
char dyn ;
unsigned line ;
} cmXsDyn_t ;
cmXsRC_t _cmXScoreParseDynamicsFile ( cmXScore_t * p , const cmChar_t * fn , cmXsDyn_t * * aVRef , unsigned * aNRef )
2016-02-07 04:36:53 +00:00
{
2016-03-30 23:18:44 +00:00
typedef enum { hdrStateId , noteStateId } state_t ;
cmXsRC_t rc = kOkXsRC ;
cmFileH_t fH = cmFileNullHandle ;
cmChar_t * b = NULL ;
unsigned bN = 0 ;
unsigned ln = 1 ;
state_t stateId = hdrStateId ;
unsigned bar = 0 ;
if ( cmFileOpen ( & fH , fn , kReadFileFl , p - > err . rpt ) ! = kOkFileRC )
return cmErrMsg ( & p - > err , kFileFailXsRC , " File open failed on '%s'. " , cmStringNullGuard ( fn ) ) ;
unsigned aN = 0 ;
unsigned ai = 0 ;
if ( cmFileLineCount ( fH , & aN ) ! = kOkFileRC )
{
rc = cmErrMsg ( & p - > err , kFileFailXsRC , " File line count acces failed on '%s'. " , cmStringNullGuard ( fn ) ) ;
goto errLabel ;
}
cmXsDyn_t * aV = cmMemAllocZ ( cmXsDyn_t , aN ) ;
2016-02-18 00:00:15 +00:00
2016-03-30 23:18:44 +00:00
for ( ; cmFileGetLineAuto ( fH , & b , & bN ) = = kOkFileRC ; + + ln )
{
char ch ;
if ( cmTextIsEmpty ( b ) )
{
stateId = hdrStateId ;
continue ;
}
2016-02-25 00:09:29 +00:00
2016-03-30 23:18:44 +00:00
switch ( stateId )
{
case hdrStateId :
if ( sscanf ( b , " %i %c " , & bar , & ch ) ! = 2 | | ch ! = ' | ' )
{
rc = cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " Expected header string read failed on line %i in '%s'. " , ln , cmStringNullGuard ( fn ) ) ;
goto errLabel ;
}
stateId = noteStateId ;
break ;
2016-02-07 04:36:53 +00:00
2016-03-30 23:18:44 +00:00
case noteStateId :
{
float rv ;
char colon ;
char dyn ;
char sps [ 4 ] ;
sps [ 3 ] = 0 ;
if ( sscanf ( b , " %f %c%c%c %c %c " , & rv , sps , sps + 1 , sps + 2 , & colon , & dyn ) ! = 6 | | colon ! = ' : ' )
{
rc = cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " Expected note string read failed on line %i in '%s'. " , ln , cmStringNullGuard ( fn ) ) ;
goto errLabel ;
}
2016-02-07 04:36:53 +00:00
2016-03-30 23:18:44 +00:00
//printf("%3i %3.1f %3s %c\n",bar,rv,sps,dyn);
if ( sps [ 1 ] = = ' ' )
cmTextShrinkS ( sps , sps + 1 , 1 ) ;
assert ( ai < aN ) ;
aV [ ai ] . bar = bar ;
aV [ ai ] . rval = rv ;
aV [ ai ] . pitch = cmSciPitchToMidi ( sps ) ;
aV [ ai ] . dyn = dyn ;
aV [ ai ] . line = ln ;
+ + ai ;
}
break ;
}
}
* aVRef = aV ;
* aNRef = ai ;
errLabel :
cmMemFree ( b ) ;
cmFileClose ( & fH ) ;
return rc ;
}
cmXsRC_t cmXScoreInsertDynamics ( cmXsH_t h , const cmChar_t * dynFn )
{
cmXsRC_t rc = kOkXsRC ;
cmXScore_t * p = _cmXScoreHandleToPtr ( h ) ;
cmXsDyn_t * aV = NULL ;
unsigned aN = 0 ;
unsigned ai = 0 ;
if ( ( rc = _cmXScoreParseDynamicsFile ( p , dynFn , & aV , & aN ) ) ! = kOkXsRC )
return rc ;
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 , kDynXsFl ) )
{
if ( ai > = aN | | aV [ ai ] . bar ! = mp - > number | | aV [ ai ] . pitch ! = np - > pitch | | aV [ ai ] . rval ! = np - > rvalue )
{
rc = cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " Dynamics file mismatch error on dynamics line:%i. \n " , aV [ ai ] . line ) ;
goto errLabel ;
}
if ( ' 1 ' < = aV [ ai ] . dyn & & aV [ ai ] . dyn < = ' 9 ' )
np - > dynamics = strtol ( & aV [ ai ] . dyn , NULL , 10 ) ;
+ + ai ;
}
}
}
2016-02-18 00:00:15 +00:00
2016-03-30 23:18:44 +00:00
errLabel :
cmMemFree ( aV ) ;
return rc ;
2016-02-07 04:36:53 +00:00
}
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 )
{
2016-03-02 23:52:40 +00:00
if ( cmCsvInsertIdentColAfter ( p - > csvH , lcp , & lcp , s [ i ] , 0 ) ! = kOkCsvRC )
2016-02-09 02:46:07 +00:00
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 )
2016-03-02 23:52:40 +00:00
if ( cmCsvInsertIdentColAfter ( p - > csvH , * leftCellPtrPtr , leftCellPtrPtr , " " , 0 ) ! = kOkCsvRC )
2016-02-09 02:46:07 +00:00
return cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV output failed on blank column. " ) ;
return kOkCsvRC ;
}
2016-03-30 23:18:44 +00:00
const cmChar_t * _cmXScoreTranslateDynamics ( cmXScore_t * p , const cmXsNote_t * np )
{
if ( cmIsFlag ( np - > flags , kDynXsFl ) & & np - > dynamics ! = 0 )
{
switch ( np - > dynamics )
{
case 1 : return " pppp " ;
case 2 : return " ppp " ;
case 3 : return " pp " ;
case 4 : return " p " ;
case 5 : return " mp " ;
case 6 : return " mf " ;
case 7 : return " f " ;
case 8 : return " ff " ;
case 9 : return " fff " ;
}
cmErrMsg ( & p - > err , kSyntaxErrorXsRC , " An invalid dynamic value (%i) was encountered. " , np - > dynamics ) ;
}
return " " ;
}
2016-02-09 02:46:07 +00:00
cmXsRC_t _cmXScoreWriteCsvRow (
cmXScore_t * p ,
unsigned rowIdx ,
2016-03-02 23:52:40 +00:00
unsigned uid ,
2016-02-09 02:46:07 +00:00
unsigned bar ,
const cmChar_t * sectionStr ,
const cmChar_t * opCodeStr ,
double dsecs ,
double secs ,
unsigned d0 ,
unsigned d1 ,
2016-03-02 23:52:40 +00:00
unsigned pitch , // set to -1 if the pitch is not valid
2016-02-09 02:46:07 +00:00
double frac ,
2016-03-30 23:18:44 +00:00
const cmChar_t * dynStr ,
2016-02-09 02:46:07 +00:00
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 ;
}
*/
2016-03-02 23:52:40 +00:00
// col 1 : track (always 1)
if ( cmCsvInsertUIntColAfter ( p - > csvH , lcp , & lcp , 1 , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 'd0'. " ) ;
2016-02-09 02:46:07 +00:00
goto errLabel ;
2016-03-02 23:52:40 +00:00
}
2016-02-09 02:46:07 +00:00
2016-03-02 23:52:40 +00:00
// col 2 : evt (set to event uid, or blank if uid == -1)
if ( uid = = - 1 )
{
if ( ( rc = _cmXScoreWriteCsvBlankCols ( p , 1 , & lcp ) ) ! = kOkXsRC )
goto errLabel ;
}
else
if ( cmCsvInsertUIntColAfter ( p - > csvH , lcp , & lcp , uid , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 'd0'. " ) ;
goto errLabel ;
}
2016-02-09 02:46:07 +00:00
// col 3 : output the opcode
2016-03-02 23:52:40 +00:00
if ( cmCsvInsertIdentColAfter ( p - > csvH , lcp , & lcp , opCodeStr , 0 ) ! = kOkCsvRC )
2016-02-09 02:46:07 +00:00
{
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
2016-03-02 23:52:40 +00:00
if ( pitch = = - 1 )
2016-02-09 02:46:07 +00:00
{
2016-03-02 23:52:40 +00:00
if ( ( rc = _cmXScoreWriteCsvBlankCols ( p , 1 , & lcp ) ) ! = kOkXsRC )
goto errLabel ;
}
else
{
if ( cmCsvInsertIdentColAfter ( p - > csvH , lcp , & lcp , cmMidiToSciPitch ( pitch , NULL , 0 ) , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 'pitch'. " ) ;
goto errLabel ;
}
2016-02-09 02:46:07 +00:00
}
// 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 ;
2016-03-02 23:52:40 +00:00
// col 15: even (all grace notes are 'even' notes
if ( cmCsvInsertIdentColAfter ( p - > csvH , lcp , & lcp , cmIsFlag ( flags , kGraceXsFl ) | cmIsFlag ( flags , kEvenXsFl ) ? " e " : " " , 0 ) ! = kOkCsvRC )
2016-02-09 02:46:07 +00:00
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on eveness flag label. " ) ;
goto errLabel ;
}
2016-03-02 23:52:40 +00:00
// col 16: grace
if ( cmCsvInsertIdentColAfter ( p - > csvH , lcp , & lcp , cmIsFlag ( flags , kGraceXsFl ) ? " g " : " " , 0 ) ! = kOkCsvRC )
2016-02-09 02:46:07 +00:00
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on eveness flag label. " ) ;
goto errLabel ;
}
// col 17: tempo
2016-03-02 23:52:40 +00:00
if ( cmCsvInsertIdentColAfter ( p - > csvH , lcp , & lcp , cmIsFlag ( flags , kTempoXsFl ) ? " t " : " " , 0 ) ! = kOkCsvRC )
2016-02-09 02:46:07 +00:00
{
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 ;
}
}
2016-03-30 23:18:44 +00:00
// col 19: dynamic marking
if ( cmCsvInsertIdentColAfter ( p - > csvH , lcp , & lcp , dynStr , 0 ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " CSV insert failed on 'dynamics'. " ) ;
goto errLabel ;
}
//if((rc = _cmXScoreWriteCsvBlankCols(p,1,&lcp)) != kOkXsRC )
// goto errLabel;
2016-02-09 02:46:07 +00:00
// col 20: section
2016-03-02 23:52:40 +00:00
if ( cmCsvInsertIdentColAfter ( p - > csvH , lcp , & lcp , cmIsFlag ( flags , kSectionXsFl ) ? sectionStr : " " , 0 ) ! = kOkCsvRC )
2016-02-09 02:46:07 +00:00
{
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 ;
}
2016-03-30 23:18:44 +00:00
2016-02-09 02:46:07 +00:00
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
const cmChar_t * sectionIdStr = NULL ;
2016-03-30 15:47:41 +00:00
unsigned metro_tick = 0 ;
double metro_sec = 0 ;
double sec0 = 0 ;
2016-02-09 02:46:07 +00:00
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 ;
for ( ; np ! = NULL ; np = np - > slink )
{
2016-03-30 15:47:41 +00:00
// Seconds are calculated as:
// dticks = np->tick - metro_tick; // where metro_tick is the absolute tick of the last metro event
// secs = (dticks/tps) + metro_secs; // where metro_secs is the absoute time of the last metro event
unsigned dticks = np - > tick - metro_tick ;
double secs = tps = = 0 ? 0 : ( dticks / tps ) + metro_sec ;
double dsecs = secs - sec0 ;
2016-02-09 02:46:07 +00:00
//
if ( cmIsFlag ( np - > flags , kMetronomeXsFl ) )
{
double bpm = np - > duration ;
double bps = bpm / 60.0 ;
tps = bps * tpqn ;
2016-03-30 15:47:41 +00:00
metro_tick = np - > tick ;
metro_sec = secs ;
2016-02-09 02:46:07 +00:00
}
2016-03-30 23:18:44 +00:00
2016-02-09 02:46:07 +00:00
// 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 ) )
{
2016-03-30 23:18:44 +00:00
_cmXScoreWriteCsvRow ( p , rowIdx , - 1 , mp - > number , NULL , " bar " , dsecs , secs , 0 , 0 , - 1 , 0 , " " , np - > flags ) ;
2016-03-30 15:47:41 +00:00
sec0 = secs ;
2016-02-09 02:46:07 +00:00
}
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
2016-03-30 23:18:44 +00:00
_cmXScoreWriteCsvRow ( p , rowIdx , - 1 , mp - > number , NULL , " ctl " , dsecs , secs , d0 , d1 , - 1 , 0 , " " , np - > flags ) ;
2016-03-30 15:47:41 +00:00
sec0 = secs ;
2016-02-09 02:46:07 +00:00
}
else
// if this is a sounding note event
2016-03-02 23:52:40 +00:00
if ( cmIsFlag ( np - > flags , kOnsetXsFl ) )
2016-02-09 02:46:07 +00:00
{
2016-03-30 23:18:44 +00:00
double frac = np - > rvalue + ( cmIsFlag ( np - > flags , kDotXsFl ) ? ( np - > rvalue / 2 ) : 0 ) ;
const cmChar_t * dyn = _cmXScoreTranslateDynamics ( p , np ) ;
2016-02-09 02:46:07 +00:00
//
2016-03-30 23:18:44 +00:00
_cmXScoreWriteCsvRow ( p , rowIdx , np - > uid , mp - > number , sectionIdStr , " non " , dsecs , secs , np - > pitch , 60 , np - > pitch , frac , dyn , np - > flags ) ;
2016-03-30 15:47:41 +00:00
sec0 = secs ;
2016-02-09 02:46:07 +00:00
sectionIdStr = NULL ;
}
rowIdx + = 1 ;
}
2016-02-26 00:10:54 +00:00
}
2016-02-09 02:46:07 +00:00
}
if ( cmCsvWrite ( p - > csvH , csvFn ) ! = kOkCsvRC )
rc = cmErrMsg ( & p - > err , kCsvFailXsRC , " The CSV output write failed on file '%s'. " , csvFn ) ;
errLabel :
return rc ;
}
2016-03-30 23:18:44 +00:00
void _cmXScoreReportTitle ( cmRpt_t * rpt )
{
cmRptPrintf ( rpt , " voc loc tick durtn rval flags \n " ) ;
cmRptPrintf ( rpt , " --- ----- ------- ----- ---- --- ------------- \n " ) ;
}
void _cmXScoreReportNote ( cmRpt_t * rpt , const cmXsNote_t * note )
{
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 * S = cmIsFlag ( note - > flags , kSectionXsFl ) ? " S " : " - " ;
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 ) ? " _ " : " - " ;
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 );
cmChar_t N [ ] = { ' \0 ' , ' \0 ' , ' \0 ' , ' \0 ' } ;
cmChar_t acc = note - > alter = = - 1 ? ' b ' : ( note - > alter = = 1 ? ' # ' : ' ' ) ;
snprintf ( N , 4 , " %c%c%1i " , note - > step , acc , note - > octave ) ;
cmRptPrintf ( rpt , " %3i %5i %7i %5i %4.1f %3s %s%s%s%s%s%s%s%s%s%s%s%s%s " ,
note - > voice - > id ,
note - > locIdx ,
note - > tick ,
note - > duration ,
note - > rvalue ,
N , B , R , G , D , C , e , d , t , P , S , H , T0 , T1 ) ;
if ( cmIsFlag ( note - > flags , kSectionXsFl ) )
cmRptPrintf ( rpt , " %s " , cmStringNullGuard ( note - > tvalue ) ) ;
if ( cmIsFlag ( note - > flags , kMetronomeXsFl ) )
cmRptPrintf ( rpt , " %i bpm " , note - > duration ) ;
}
2016-02-09 02:46:07 +00:00
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-19 00:10:05 +00:00
cmRptPrintf ( rpt , " %i : div:%i beat:%i beat-type:%i (%i) \n " , meas - > number , meas - > divisions , meas - > beats , meas - > beat_type , meas - > divisions * meas - > beats ) ;
2016-02-07 04:36:53 +00:00
2016-03-30 23:18:44 +00:00
_cmXScoreReportTitle ( rpt ) ;
2016-02-07 04:36:53 +00:00
if ( sortFl )
{
2016-03-17 23:30:21 +00:00
2016-02-07 04:36:53 +00:00
const cmXsNote_t * note = meas - > noteL ;
for ( ; note ! = NULL ; note = note - > slink )
2016-02-19 00:10:05 +00:00
{
_cmXScoreReportNote ( rpt , note ) ;
if ( note - > slink ! = NULL | | note - > voice - > id = = 0 )
cmRptPrintf ( rpt , " \n " ) ;
else
cmRptPrintf ( rpt , " %i \n " , note - > tick + note - > duration ) ;
}
2016-02-07 04:36:53 +00:00
}
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 )
2016-02-19 00:10:05 +00:00
{
2016-02-07 04:36:53 +00:00
_cmXScoreReportNote ( rpt , note ) ;
2016-02-19 00:10:05 +00:00
if ( note - > mlink ! = NULL | | note - > voice - > id = = 0 )
cmRptPrintf ( rpt , " \n " ) ;
else
cmRptPrintf ( rpt , " %i \n " , note - > tick + note - > duration ) ;
}
2016-02-07 04:36:53 +00:00
}
2016-02-19 00:10:05 +00:00
}
2016-02-07 04:36:53 +00:00
}
}
2016-02-04 16:33:42 +00:00
}
2016-02-26 00:10:54 +00:00
2016-02-18 00:00:15 +00:00
cmXsRC_t cmXScoreWriteMidi ( cmXsH_t h , const cmChar_t * fn )
{
assert ( 0 ) ; // function not implemented
cmXScore_t * p = _cmXScoreHandleToPtr ( h ) ;
cmXsPart_t * pp = p - > partL ;
for ( ; pp ! = NULL ; pp = pp - > link )
{
const cmXsMeas_t * meas = pp - > measL ;
for ( ; meas ! = NULL ; meas = meas - > link )
{
const cmXsNote_t * note = meas - > noteL ;
for ( ; note ! = NULL ; note = note - > slink )
{
}
}
}
}
2016-02-04 16:33:42 +00:00
2016-03-30 23:18:44 +00:00
cmXsRC_t cmXScoreTest ( cmCtx_t * ctx , const cmChar_t * xmlFn , const cmChar_t * midiFn , const cmChar_t * outFn , const cmChar_t * dynFn )
2016-02-04 16:33:42 +00:00
{
cmXsRC_t rc ;
cmXsH_t h = cmXsNullHandle ;
2016-02-19 00:10:05 +00:00
if ( ( rc = cmXScoreInitialize ( ctx , & h , xmlFn , midiFn ) ) ! = kOkXsRC )
2016-02-04 16:33:42 +00:00
return cmErrMsg ( & ctx - > err , rc , " XScore alloc failed. " ) ;
2016-03-30 23:18:44 +00:00
if ( dynFn ! = NULL )
cmXScoreInsertDynamics ( h , dynFn ) ;
2016-03-24 16:12:28 +00:00
if ( outFn ! = NULL )
cmXScoreWriteCsv ( h , outFn ) ;
2016-03-30 23:18:44 +00:00
//cmXScoreReport(h,&ctx->rpt,true);
2016-02-04 16:33:42 +00:00
return cmXScoreFinalize ( & h ) ;
}