CFugue
MusicStringParser.cpp
1 /*
2  This is part of CFugue, a C++ Runtime for MIDI Score Programming
3  Copyright (C) 2009 Gopalakrishna Palem
4 
5  For links to further information, or to contact the author,
6  see <http://cfugue.sourceforge.net/>.
7 
8  $LastChangedDate: 2014-05-10 11:18:40 +0530 (Sat, 10 May 2014) $
9  $Rev: 205 $
10  $LastChangedBy: krishnapg $
11 */
12 
13 #include "stdafx.h"
14 #include "MusicStringParser.h"
15 #include "ChannelPressure.h"
16 #include "Chords.h"
17 #include "ControllerEvent.h"
18 #include "Instrument.h"
19 #include "Layer.h"
20 #include "PitchBend.h"
21 #include "PolyphonicPressure.h"
22 #include "Tempo.h"
23 #include "TimeToken.h"
24 #include "Voice.h"
25 
26 #include "math.h"
27 
28 //TODO: Use C++0x Futures as asynchronous constructs for the Parsing.
29 // No point in parsing in a blocking call. Use external ParserPreference
30 // object to control 'exit on first error', 'Synch/Asynch' behaviors
31 
32 namespace CFugue
33 {
34  //struct _ssHolder
35  //{
36  // static MString ss; //TODO: Single-threaded quick Hack for traces. Doesn't work multi-threaded
37  //};
38  //decltype(_ssHolder::ss) _ssHolder::ss; // static class member definition
39  //#define SSOBJ() _ssHolder::ss
40  //#define MAKESTR(x) ((decltype(SSOBJ())&)(SSOBJ() << x))
41 
42  /// <Summary>
43  /// Verbose is another mode of tracing where more verbose details of Parsing are reported.
44  /// Verbose mode requires the Tracing to be enabled with ENABLE_TRACING defined apriori.
45  /// Verbose mode reports all possible internal details for the notes being parsed.
46  /// It is possible to limit the Tracing output by defining NO_VERBOSE.
47  /// Using NO_VERBOSE with ENABLE_TRACING will only report significant parsing information and not everything.
48  /// </Summary>
49  #ifndef NO_VERBOSE
50  #define Verbose(x) { MString _str; _str << x; MusicStringParser::Trace(_str); }
51  #else
52  #define Verbose(x)
53  #endif
54  #ifndef NO_WARNINGS
55  #define Warning(x) { MString _str; _str << x; MusicStringParser::Trace(_str); }
56  #else
57  #define Warning(x)
58  #endif
59 
60  // Helper Methods
61  template<typename T>
62  inline int LoadValueFromString(const TCHAR* sz, T* pRetVal)
63  {
64  assert(_T("LoadValueFromString called with Unknown Type") == NULL);
65 
66  *pRetVal = _T('0');
67 
68  return 0;
69  }
70 
71  template<typename T>
72  inline int LoadIntegralValueFromString(const TCHAR* sz, T* pRetVal)
73  {
74  T nVal = 0;
75 
76  const TCHAR* psz = sz;
77 
78  while(/*psz != NULL &&*/ *psz >= _T('0') && *psz <= _T('9'))
79  {
80  nVal = (nVal * 10) + (*psz - _T('0'));
81  psz++;
82  }
83 
84  if(psz != sz) *pRetVal = nVal;
85 
86  return (int)(psz - sz);
87  }
88 
89  template<>
90  inline int LoadValueFromString(const TCHAR* sz, unsigned char* pRetVal) // Load Byte
91  {
92  return LoadIntegralValueFromString(sz, pRetVal);
93  }
94 
95  template<>
96  inline int LoadValueFromString(const TCHAR* sz, unsigned short* pRetVal) // Load Short int
97  {
98  return LoadIntegralValueFromString(sz, pRetVal);
99  }
100 
101  template<>
102  inline int LoadValueFromString(const TCHAR* sz, unsigned long* pRetVal) // Load Long int
103  {
104  return LoadIntegralValueFromString(sz, pRetVal);
105  }
106 
107  template<>
108  inline int LoadValueFromString(const TCHAR* sz, double* pRetVal) // Load double
109  {
110  double nVal = 0;
111 
112  const TCHAR* psz = sz;
113 
114  while(*psz >= _T('0') && *psz <= _T('9')) // Read the Decimal part
115  {
116  nVal = (nVal * 10) + (*psz - _T('0'));
117  psz++;
118  }
119 
120  if(*psz == _T('.'))
121  {
122  double nFracIndex = 10;
123  psz++;
124  while(*psz >= _T('0') && *psz <= _T('9')) // Read the fractional part
125  {
126  nVal = nVal + ((*psz - _T('0')) / nFracIndex);
127  nFracIndex *= 10;
128  psz++;
129  }
130  }
131 
132  if(psz != sz) *pRetVal = nVal;
133 
134  return (int)(psz - sz);
135  }
136 
137  inline bool IsOneOf(const TCHAR ch, const TCHAR* chrArr)
138  {
139  return _tcschr(chrArr, ch) != NULL;
140  }
141 
142  inline void EatWhiteSpace(const TCHAR* & psz, const TCHAR* chWhiteSpaces = _T(" \t\n\r"))
143  {
144  if(psz) while(*psz && IsOneOf(*psz, chWhiteSpaces)) psz++;
145  }
146 
147  inline void EatComments(const TCHAR* & psz) // CFugue allows C++ style comments: /* */ and //
148  {
149  if(psz && *psz == _T('/'))
150  {
151  const TCHAR* pchEndDelimiter = NULL; int nSkipLen=0;
152  switch(*(psz + 1))
153  {
154  case _T('*'): pchEndDelimiter = _T("*/"); nSkipLen = 2; break; // this is a /* .. */ style comment
155  case _T('/'): pchEndDelimiter = _T("\n"); nSkipLen = 1; break; // this is a single line // style comment
156  default: return;
157  }
158  const TCHAR* pszEndComment = _tcsstr(psz+2, pchEndDelimiter);
159  if(pszEndComment)
160  psz = pszEndComment + nSkipLen;
161  }
162  return ;
163  }
164 
165  // copies at most nMaxLimit chars
166  inline TCHAR* CreateToken(const TCHAR* psz, int& nTokenLen, const TCHAR* szDelim = _T(" \t\n\r")) // returns a new copy - caller need to delete it later
167  {
168  nTokenLen = 0;
169  if(psz)
170  {
171  const TCHAR* pszStart = psz;
172  while(*psz && !IsOneOf(*psz, szDelim)) psz++; // skip till a delimeter is found
173 
174  int nLen = (int)(psz - pszStart);
175  TCHAR* pszNewCopy = new TCHAR[nLen + 4]; // allocate new buffer - add extra \0s for safety in case parser shoots beyond
176  memset(pszNewCopy, 0, sizeof(TCHAR) * (nLen+4));
177 
178  _tcsncpy(pszNewCopy, pszStart, nLen); // copy the skipped chars
179 
180  nTokenLen = nLen;
181 
182  return pszNewCopy;
183  }
184 
185  return NULL;
186  }
187 
188  bool MusicStringParser::Parse(const TCHAR* szTokens)
189  {
190  if(szTokens == NULL) return true;
191 
192  bool bNonContinuableErrorOccured = false;
193 
194  int nTokenLen, nReadLen;
195  const TCHAR* psz = szTokens;
196  do
197  {
198  EatWhiteSpace(psz);
199 
200  EatComments(psz);
201 
202  //// TODO: Add XML Support
203  //if(*psz == _T('<'))
204  // ExtractXmlPortion();
205  nTokenLen=0, nReadLen=0;
206 
207  TCHAR* pszToken = CreateToken(psz, nTokenLen);
208 
209  if(nTokenLen <= 0 || pszToken == NULL) { bNonContinuableErrorOccured= (pszToken==NULL); break;}
210 
211  while(nReadLen < nTokenLen)
212  {
213  int nLen = ParseToken(pszToken, &bNonContinuableErrorOccured);
214  if(-1 == nLen && true == bNonContinuableErrorOccured)
215  break;
216  nReadLen += nLen;
217  }
218  delete[] pszToken;
219 
220  psz = psz + nReadLen;
221 
222  }while(*psz && !bNonContinuableErrorOccured);
223 
224  return !bNonContinuableErrorOccured;
225  }
226 
227  int MusicStringParser::ParseToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured/* = NULL*/)
228  {
229  bool bNonContinuableErrorOccured = false; int nLen = 0;
230 
231  TCHAR* szUppercaseToken = _tcsupr(szToken); // convert the string to upper case
232 
233  Verbose(_T("MusicStringParser::ParseToken: ") << szUppercaseToken);
234 
235  switch(szUppercaseToken[0])
236  {
237  case TOKEN_SEPERATOR: nLen = 1; break;
239  case TOKEN_DOUBLESPEED_START: nLen = ParseSpeedModulatorToken(szUppercaseToken, &bNonContinuableErrorOccured); break;
240  case TOKEN_START_VOICE: nLen = ParseVoiceToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
241  case TOKEN_START_TEMPO: nLen = ParseTempoToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
242  case TOKEN_START_INSTRUMENT: nLen = ParseInstrumentToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
243  case TOKEN_START_LAYER: nLen = ParseLayerToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
244  case TOKEN_START_KEYSIGNATURE: nLen = ParseKeySignatureToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
245  case TOKEN_START_CONTROLLER: nLen = ParseControllerToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
246  case TOKEN_START_TIME: nLen = ParseTimeToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
247  case TOKEN_START_KEYPRESSURE: nLen = ParseKeyPressureToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
248  case TOKEN_START_CHANNELPRESSURE: nLen = ParseChannelPressureToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
249  case TOKEN_START_PITCHBEND: nLen = ParsePitchBendToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
250  case TOKEN_START_MEASURE: nLen = ParseMeasureToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
251  case TOKEN_START_DICTIONARY: nLen = ParseDictionaryToken(szUppercaseToken+1, &bNonContinuableErrorOccured) + 1; break;
252  case TOKEN_START_NOTE: nLen = ParseNoteToken(szUppercaseToken, &bNonContinuableErrorOccured); break;
253  default: nLen = ParseNoteToken(szUppercaseToken, &bNonContinuableErrorOccured); break; // The first character is none of the above. Could be a Note such as A B C etc...
254  }
255 
256  if(pbNonContinuableErrorOccured != NULL)
257  *pbNonContinuableErrorOccured = bNonContinuableErrorOccured;
258 
259  return nLen;
260  }
261 
262  int MusicStringParser::ParsePitchBendToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
263  {
264  bool bSuccess = *pbNonContinuableErrorOccured = false; unsigned int nVal = 0;
265 
266  int nLen = ParseNumber(szToken, &nVal, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_PITCHBEND_MACRO_END, PARSE_ERROR_PITCHBEND_VALUE);
267  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
268  if(bSuccess)
269  {
270  szToken += nLen;
271  if(*szToken == _T(',')) // seems this is in LSB,MSB format
272  {
273  bool bSuccess = *pbNonContinuableErrorOccured = false; unsigned short nHighVal = 0;
274 
275  int nLen2 = ParseNumber(szToken, &nHighVal, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_PITCHBEND_MACRO_END, PARSE_ERROR_PITCHBEND_VALUE);
276  if(nLen2 == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
277  if(bSuccess)
278  {
279  PitchBend pbObj((unsigned char) nVal, (unsigned char) nHighVal);
280  RaiseEvent(&evPitchBend, &pbObj);
281  return nLen + nLen2;
282  }
283  }
284  else // This is in single integer format
285  {
286  PitchBend pbObj((unsigned char)(nVal % 128), (unsigned char)(nVal / 128));
287  RaiseEvent(&evPitchBend, &pbObj);
288  return nLen;
289  }
290  }
291  return 0;
292  }
293 
294  int MusicStringParser::ParseSpeedModulatorToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
295  {
296  TCHAR* pszToken = szToken;
297 
298  unsigned short nSpeed = m_KeySig.Speed();
299 
300  switch(pszToken[0])
301  {
302  case TOKEN_DOUBLESPEED_START: nSpeed++; break;
303  case TOKEN_DOUBLESPEED_END: nSpeed--; break;
304  default: return 0;
305  }
306 
307  if(nSpeed > 6 || nSpeed <= 0)
308  {
309  MString str;
310  str << _T("Speed ") << nSpeed << _T(" is beyond the range [1, 6]");
311  if(Error(PARSE_ERROR_SPEED_MAXLIMIT, str, szToken)) { *pbNonContinuableErrorOccured = true; return -1;}; // if we should stop processing any further
312  if(nSpeed <= 0)
313  nSpeed = 1;
314  else if(nSpeed > 6)
315  nSpeed = 6;
316  }
317 
318  m_KeySig.Speed() = nSpeed;
319 
320  Verbose(_T("MusicStringParser::ParseSpeedModulatorToken Speed = ") << m_KeySig.Speed());
321 
322  return 1;
323  }
324 
325  int MusicStringParser::ParseVoiceToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
326  {
327  bool bSuccess = *pbNonContinuableErrorOccured = false; unsigned short nVoice = 0;
328 
329  int nLen = ParseNumber(szToken, &nVoice, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_VOICE_MACRO_END, PARSE_ERROR_VOICE_VALUE);
330  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
331  if(bSuccess)
332  {
333  Verbose(_T("MusicStringParser::ParseVoiceToken: Voice = ") << nVoice);
334 
335  if(nVoice > 15)
336  {
337  MString str;
338  str << _T("Voice ") << nVoice << _T(" is beyond the range [0, 15]");
339  if(Error(PARSE_ERROR_VOICE_MAXLIMIT, str, szToken)) { *pbNonContinuableErrorOccured = true; return -1;}; // if we should stop processing any further
340  nVoice = 15; // if we need to continue despite the error, ceil the value
341  }
342 
343  Voice voiceObj((unsigned char) nVoice);
344 
345  RaiseEvent(&evVoice, &voiceObj);
346 
347  return nLen;
348  }
349  return 0;
350  }
351 
352  int MusicStringParser::ParseTempoToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
353  {
354  bool bSuccess = *pbNonContinuableErrorOccured = false; unsigned short nTempo = 0;
355 
356  int nLen = ParseNumber(szToken, &nTempo, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_TEMPO_MACRO_END, PARSE_ERROR_TEMPO_VALUE);
357  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
358  if(bSuccess)
359  {
360  Verbose(_T("MusicStringParser::ParseTempoToken: Tempo = ") << nTempo);
361 
362  Tempo tempoObj(nTempo);
363 
364  RaiseEvent(&evTempo, &tempoObj);
365 
366  return nLen;
367  }
368  return 0;
369  }
370 
371  int MusicStringParser::ParseTimeToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
372  {
373  bool bSuccess = *pbNonContinuableErrorOccured = false; unsigned long nTime = 0;
374 
375  int nLen = ParseNumber(szToken, &nTime, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_TIME_MACRO_END, PARSE_ERROR_TIME_VALUE);
376  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
377  if(bSuccess)
378  {
379  Verbose(_T("MusicStringParser::ParseTimeToken: Time = ") << nTime);
380 
381  Time timeObj(nTime);
382 
383  RaiseEvent(&evTime, &timeObj);
384 
385  return nLen;
386  }
387  return 0;
388  }
389 
390  int MusicStringParser::ParseChannelPressureToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
391  {
392  bool bSuccess = *pbNonContinuableErrorOccured = false; unsigned short nPressure = 0;
393 
394  int nLen = ParseNumber(szToken, &nPressure, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_CPRESSURE_MACRO_END, PARSE_ERROR_CPRESSURE_VALUE);
395  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
396  if(bSuccess)
397  {
398  Verbose(_T("MusicStringParser::ParseChannelPressureToken: Pressure = ") << nPressure);
399 
400  ChannelPressure cpObj((unsigned char) nPressure);
401 
402  RaiseEvent(&evChannelPressure, &cpObj);
403 
404  return nLen;
405  }
406  return 0;
407  }
408 
409  ///<Summary>
410  /// Parses an Instrument Element Token.
411  /// @param szToken the Token that contains the Music Instrument Element
412  /// @param pbNonContinuableErrorOccured return value that indicates the caller if further parsing should stopped
413  ///</Summary>
414  int MusicStringParser::ParseInstrumentToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
415  {
416  bool bSuccess = *pbNonContinuableErrorOccured = false; unsigned short nInstrument = 0;
417 
418  int nLen = ParseNumber(szToken, &nInstrument, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_INSTRUMENT_MACRO_END, PARSE_ERROR_INSTRUMENT_VALUE);
419  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
420  if(bSuccess)
421  {
422  Verbose(_T("MusicStringParser::ParseInstrumentToken: Instrument = ") << nInstrument);
423 
424  Instrument instrumentObj((unsigned char) nInstrument);
425 
426  RaiseEvent(&evInstrument, &instrumentObj);
427 
428  return nLen;
429  }
430  return 0;
431  }
432 
433  /// <Summary>
434  /// Parses Polyphonic Pressure Token.
435  /// The typical structure of this token is: *[NoteNumber],[PressureValue]
436  /// @param szToken the Token that contains the Music Instrument Element
437  /// @param pbNonContinuableErrorOccured return value that indicates the caller if further parsing should stopped
438  /// </Summary>
439  int MusicStringParser::ParseKeyPressureToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
440  {
441  int nReadLen =0;
442  NoteContext ctx;
443 
444  // Read the Key (Note)
445  int nLen = ParseNoteRoot(szToken, ctx);
446  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1;}
447  szToken += nLen; nReadLen += nLen;
448 
449  nLen = ParseNoteOctave(szToken, ctx);
450  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1;}
451  szToken += nLen; nReadLen += nLen;
452 
453  if(ComputeNoteValue(ctx) == -1) { *pbNonContinuableErrorOccured = true; return -1;}
454 
455  TCHAR* pszPressure = szToken;
456  while(*pszPressure != _T('\0') && *pszPressure == _T(',')) { pszPressure++; nReadLen++; }
457 
458  bool bSuccess = *pbNonContinuableErrorOccured = false; unsigned short nKeyPressure = 0;
459 
460  // Read the Pressure Value
461  nLen = ParseNumber(pszPressure, &nKeyPressure, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_KEYPRESSURE_MACRO_END, PARSE_ERROR_KEYPRESSURE_VALUE);
462  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
463  if(bSuccess)
464  {
465  Verbose(_T("MusicStringParser::ParseKeyPressureToken: Key = ") << ctx.noteNumber << " Pressure = " << nKeyPressure);
466 
467  PolyphonicPressure ppObj((unsigned char) ctx.noteNumber, (unsigned char) nKeyPressure);
468 
470 
471  nReadLen += nLen;
472  //return (pszPressure - szToken + nLen);
473  }
474  return nReadLen;
475  }
476 
477  int MusicStringParser::ParseLayerToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
478  {
479  bool bSuccess = *pbNonContinuableErrorOccured = false; unsigned short nLayer = 0;
480 
481  int nLen = ParseNumber(szToken, &nLayer, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_LAYER_MACRO_END, PARSE_ERROR_LAYER_VALUE);
482  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
483  if(bSuccess)
484  {
485  Verbose(_T("MusicStringParser::ParseLayerToken: Layer = ") << nLayer);
486 
487  Layer layerObj((unsigned char) nLayer);
488 
489  RaiseEvent(&evLayer, &layerObj);
490 
491  return nLen;
492  }
493  return 0;
494  }
495 
496  /// <Summary>
497  /// KeySignature plays an important role in differentiating Carnatic and Western style Notes
498  /// and makes it possible to seamlessly integrate both into a single MusicString.
499  /// While a Western style KeySignature accepts only the Scale value, the Carnatic counterpart
500  /// on the otherhand supports few more options such as Talam and Speed along with the Ragam.
501  ///
502  /// In other words, the Western syntax for KeySignature token is: K[SCALE]
503  /// where as the Carnatic syntax for the KeySignature token is: K[RAGAM]T[TALAM]S[SPEED]
504  ///
505  /// SCALE values are specified using any of the pre-defined macro values such as CMAJ, F#MIN etc.
506  /// RAGAM values are specified using the form MELA_x, where x is a number in the range [1, 72].
507  /// TALAM values are specified using numbers in the range [1, 35], and SPEED values are specified
508  /// using numbers in the range [1, 3]. Also, few pre-defined macros are available for RAGAM, TALAM,
509  /// and SPEED specifiers, such as KALYANI, ADI, VARNAM etc.
510  ///
511  /// The Ragam, Talam and Speed values can be changed any time during the song. For example, to
512  /// change the Talam while retaining the Ragam and Speed to their current values, use the form: KT[NEW_TALAM]
513  ///
514  /// Similarily, to Change only Ragam without affecting the Talam and Speed, omit the T and S specifiers
515  /// such as K[NEW_RAGAM]. To Change only the Speed, the form then will be KTS[NEW_SPEED].
516  ///
517  /// Note that the T and S sub-tokens are only valid in the Carnatic Music Mode. Specifying them for
518  /// Western Music will not have any effect and they will not be read or remembered.
519  /// </Summary>
520  int MusicStringParser::ParseKeySignatureToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
521  {
522  bool bSuccess = *pbNonContinuableErrorOccured = false; unsigned short nValue = 0;
523 
524  int nLen = ParseNumber(szToken, &nValue, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_KEYSIGNATURE_MACRO_END, PARSE_ERROR_KEYSIGNATURE_VALUE);
525  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
526  if(bSuccess)
527  {
528  if(nValue >= 128) // Carnatic Mode Key Signature
529  {
530  nValue = nValue - 128;
531 
532  if(nValue > 72 || nValue <= 0) // Ensure the Range. Valid Range: [1, 72]
533  {
534  MString str;
535  str << _T("KeySignature ") << nValue << _T(" is beyond the range [0~14 / 64~78 / 129~200]");
536  if(Error(PARSE_ERROR_KEYSIGNATURE_MAXLIMIT, str, szToken)) { *pbNonContinuableErrorOccured = true; return -1;}; // if we should stop processing any further
537  nValue = KeySignature::DEFAULT_RAGAM; // if we need to continue despite the error, use default Value
538  }
539 
540  Verbose(_T(" Mela = ") << nValue);
541 
542  m_KeySig.SetRagam(nValue);
543 
544  // NOTE: We do not RaiseEvent for the Carnatic Mode KeySignature
545  }
546  else // Western Mode Key Signature
547  {
548  KeySignature::Scale bScale = ((nValue >= 64) ? KeySignature::MAJOR_SCALE : KeySignature::MINOR_SCALE);
549 
550  if(nValue >= 64) nValue = nValue - 64;
551 
552  Verbose(_T(" KeySignature = ") << nValue <<
553  _T(" Scale = ") << (bScale == KeySignature::MAJOR_SCALE ? _T("Major") : _T("Minor")) );
554 
555  if(nValue >= 15) // Ensure the Range. Valid Range: [0, 14]
556  {
557  MString str;
558  str << _T("KeySignature ") << nValue << _T(" is beyond the range [0~14 / 64~78 / 129~200]");
559  if(Error(PARSE_ERROR_KEYSIGNATURE_MAXLIMIT, str, szToken)) { *pbNonContinuableErrorOccured = true; return -1;}; // if we should stop processing any further
560  nValue = KeySignature::DEFAULT_KEY; // if we need to continue despite the error, use Default Key
561  }
562 
563  KeySignature keyObj(nValue > 7 ? (7-nValue) : nValue, bScale);
564 
565  m_KeySig = keyObj; // Save a copy for computing the note values later
566 
567  RaiseEvent(&evKeySignature, &keyObj);
568 
569  return nLen;
570  }
571  }
572 
573  if(m_KeySig.GetMode() != KeySignature::CARNATIC) return 0; // [Western Mode] An error reading the KeySig value
574 
575  int nReadLen = nLen;
576 
577  // In case of Carnatic Music, KeySignature can contain an additional Tala specifier.
578  szToken += nLen; unsigned short nTalam = m_KeySig.GetTalam();
579  if(szToken[0] == _T('T')) // is there a Tala specifier present?
580  {
581  nLen = ParseNumber(++szToken, &nTalam, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_TALAM_MACRO_END, PARSE_ERROR_TALAM_VALUE);
582  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return false; } // Some irrevocable error occured
583  if(bSuccess)
584  {
585  if(nTalam > 35) // Ensure Range
586  {
587  MString str;
588  str << _T("Talam ") << nTalam << _T(" is beyond the range [0 ~ 35]");
589  if(Error(PARSE_ERROR_TALAM_MAXLIMIT, str, szToken)) { *pbNonContinuableErrorOccured = true; return -1;}; // if we should stop processing any further
590  nTalam = m_KeySig.GetTalam(); // if we need to continue despite the error, use existing Value
591  }
592  nReadLen += nLen;
593  }
594 
595  Verbose(_T(" Talam = ") << nTalam);
596  }
597  else { nLen = 0; Warning(_T(" No Talam Specified !! Using Talam: ") << nTalam); }
598 
599  m_KeySig.SetTalam(nTalam);
600 
601  // Check for Speed specifier
602  szToken += nLen; unsigned short nSpeed = m_KeySig.Speed();
603  if(szToken[0] == _T('S')) // is there a Speed specifier ?
604  {
605  nLen = ParseNumber(++szToken, &nSpeed, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_SPEED_MACRO_END, PARSE_ERROR_SPEED_VALUE);
606  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
607  if(bSuccess)
608  {
609  if(nSpeed > 6) // Ensure Range
610  {
611  MString str;
612  str << _T("Speed ") << nSpeed << _T(" is beyond the range [1 ~ 6]");
613  if(Error(PARSE_ERROR_SPEED_MAXLIMIT, str, szToken)) { *pbNonContinuableErrorOccured = true; return -1;}; // if we should stop processing any further
614  nSpeed = m_KeySig.Speed(); // if we need to continue despite the error, use existing Value
615  }
616  nReadLen += nLen;
617  }
618 
619  Verbose(_T(" Speed = ") << nSpeed);
620  }
621  else { Warning(_T(" No Speed Specified !! Using Speed: ") << nSpeed ); }
622 
623  m_KeySig.Speed() = nSpeed;
624 
625  return nReadLen;
626  }
627 
628  ///<Summary>
629  /// Parses a MIDI Controller Event Token.
630  /// The typical structure of this token is: X[ControlCode]=[ControlValue]
631  /// Some Control Codes have fine and coarse values. Users can either specify
632  /// two tokens one for fine and the other for Coarse value, or they can use
633  /// the combined Control Code in a single token.
634  /// </Summary>
635  int MusicStringParser::ParseControllerToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
636  {
637  TCHAR* pszAssignSymbol = _tcschr(szToken, ASSIGNMENT_SYMBOL); // Find the Equals sign
638  if(pszAssignSymbol == NULL)
639  {
640  MString str(ASSIGNMENT_SYMBOL + MString(_T(" Symbol Not found")));
641  if(Error(PARSE_ERROR_MISSING_ASSIGNMENT, str, szToken)) { *pbNonContinuableErrorOccured = true; return -1; }
642  return 0;
643  }
644 
645  *pszAssignSymbol = _T('\0');
646 
647  TCHAR* pszKey = szToken;
648  TCHAR* pszValue = pszAssignSymbol + 1;
649 
650  bool bSuccess = false; int nControllerIndex=-1; int nReadLen = 0;
651 
652  int nLen = ParseNumber(pszKey, &nControllerIndex, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_CONTROLLER_MACRO_END, PARSE_ERROR_CONTROLLER_VALUE);
653  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
654  if(bSuccess)
655  {
656  if(nControllerIndex >= 128)
657  {
658  int nControllerCoarse = nControllerIndex % 128; // This is in contrast to JFugue style
659  int nControllerFine = nControllerIndex / 128;
660 
661  int nControllerValue=0;
662  int nLen = ParseNumber(pszValue, &nControllerValue, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_CONTROLLER_MACRO_END, PARSE_ERROR_CONTROLLER_VALUE);
663  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
664 
665  int coarseValue = (nControllerValue / 128);
666  int fineValue = (nControllerValue % 128);
667 
668  ControllerEvent evObjCoarse((unsigned char) nControllerCoarse, (unsigned char) coarseValue);
669  RaiseEvent(&evController, &evObjCoarse);
670 
671  ControllerEvent evObjFine((unsigned char) nControllerFine, (unsigned char) fineValue);
672  RaiseEvent(&evController, &evObjFine);
673 
674  nReadLen = (int)(pszValue + nLen - szToken);
675 
676  Verbose(_T("MusicStringParser::ParseControllerToken: [") << nControllerCoarse << _T("]=") + coarseValue);
677  Verbose(_T("MusicStringParser::ParseControllerToken: [") << nControllerFine << _T("]=") << fineValue);
678  }
679  else
680  {
681  unsigned short nControllerValue=0;
682  int nLen = ParseNumber(pszValue, &nControllerValue, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_CONTROLLER_MACRO_END, PARSE_ERROR_CONTROLLER_VALUE);
683  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1; } // Some irrevocable error occured
684 
685  ControllerEvent evObj((unsigned char) nControllerIndex, (unsigned char) nControllerValue);
686  RaiseEvent(&evController, &evObj);
687 
688  nReadLen = (int)(pszValue + nLen - szToken);
689 
690  Verbose(_T("MusicStringParser::ParseControllerToken: [") << pszKey << _T("]=") << pszValue);
691  }
692  }
693 
694  return nReadLen;
695 
696  }
697 
698  int MusicStringParser::ParseMeasureToken(TCHAR* szToken, bool* )
699  {
701  RaiseEvent(&evMeasure, &args);
702 
703  Verbose(_T("MusicStringParser::ParseMeasureToken"));
704  return 0;
705  }
706 
707  ///<Summary>Parses a Dictionary Element Token. Creates or Updates the Dictionary Element Value</Summary>
708  int MusicStringParser::ParseDictionaryToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
709  {
710  TCHAR* pszAssignSymbol = _tcschr(szToken, ASSIGNMENT_SYMBOL); // Find the Equals sign
711  if(pszAssignSymbol == NULL)
712  {
713  MString str;
714  str << ASSIGNMENT_SYMBOL << _T(" Symbol Not found");
715  if(Error(PARSE_ERROR_MISSING_ASSIGNMENT, str, szToken)) { *pbNonContinuableErrorOccured = true; return -1; }
716  return 0;
717  }
718 
719  *pszAssignSymbol = _T('\0');
720 
721  const TCHAR* pszKey = szToken;
722  const TCHAR* pszValue = pszAssignSymbol + 1;
723 
724  m_Dictionary[pszKey] = pszValue; // Create or Update the value
725 
726  Verbose(_T("MusicStringParser::ParseDictionaryToken: Defined [") << pszKey << _T("]=") << pszValue);
727 
728  return (int) (_tcslen(pszKey) + _tcslen(pszValue) + 1);
729  }
730 
731  /// <Summary> Parses Tokens that look like Music Note symbols. Decides their Root and
732  /// Calls the correct method based on the Note nature, such as Numeric Note, Rest Note etc.</Summary>
733  int MusicStringParser::ParseNoteToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured)
734  {
735  NoteContext ctx;
736 
737  int nLen = 0, nReadLen = 0;
738 
739  while(ctx.existsAnotherNote && *szToken)
740  {
741  Verbose(_T("MusicStringParser::ParseNote: ") << szToken);
742 
743  DecideSequentialOrParallel(ctx);
744 
745  nLen = ParseNoteRoot(szToken, ctx);
746  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1;}
747  szToken += nLen; nReadLen += nLen;
748 
749  nLen = ParseNoteOctave(szToken, ctx);
750  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1;}
751  szToken += nLen; nReadLen += nLen;
752 
753  nLen = ParseNoteChord(szToken, ctx);
754  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1;}
755  szToken += nLen; nReadLen += nLen;
756 
757  if(ComputeNoteValue(ctx) == -1) { *pbNonContinuableErrorOccured = true; return -1;}
758 
759  nLen = ParseNoteChordInversion(szToken, ctx);
760  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1;}
761  szToken += nLen; nReadLen += nLen;
762 
763  nLen = ParseNoteDuration(szToken, ctx);
764  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1;}
765  szToken += nLen; nReadLen += nLen;
766 
767  nLen = ParseNoteVelocity(szToken, ctx);
768  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1;}
769  szToken += nLen; nReadLen += nLen;
770 
771  nLen = ParseNoteConnector(szToken, ctx);
772  if(nLen == -1) { *pbNonContinuableErrorOccured = true; return -1;}
773  szToken += nLen; nReadLen += nLen;
774 
775  RaiseNoteEvents(ctx);
776  }
777 
778  //if(szToken[0] != _T('\0')) Warning(MString(_T("Ignoring: ")) + szToken);
779 
780  return nReadLen;
781  }
782 
783  /// <Summary>
784  /// Tests if a Note is known to be Sequential (connected with _) or Parallel (connected with +)
785  ///</Summary>
786  void MusicStringParser::DecideSequentialOrParallel(NoteContext& ctx)
787  {
789 
790  if(ctx.anotherIsSequential)
791  {
792  type = Note::SEQUENTIAL;
793  Verbose(_T("About to read a sequential Note ..."));
794  }
795  if(ctx.anotherIsParallel)
796  {
797  type = Note::PARALLEL;
798  Verbose(_T("About to read a parallel Note ..."));
799  }
800  if(type != Note::FIRST)
801  {
802  ctx = NoteContext(); // We are reading Connected Notes. Reset the Previous Note Context
803  ctx.type = type;
804  }
805  }
806 
807  /// <Summary> Parses Numeric, Rest and Letter Notes.
808  /// Returns the number of characaters consumed from the string during the parsing </Summary>
809  int MusicStringParser::ParseNoteRoot(TCHAR* szToken, NoteContext& ctx)
810  {
811  switch(szToken[0])
812  {
813  case MACRO_START : return ParseNumericNote(szToken, ctx);
814  case REST_NOTE1:
815  {
816  Verbose(_T("This Note is a Rest"));
817  ctx.isRest = true;
818  ctx.numSwaras = 1;
819  return 1;
820  }
821  case REST_NOTE2:
822  {
823  Verbose(_T("This is a Rest note for Two swara durations"));
824  ctx.isRest = true;
825  ctx.numSwaras = 2;
826  return 1;
827  }
828  case WESTERN_REST_NOTE: // This Rest Note symbol is valid only for Western Music
829  {
830  if(m_KeySig.GetMode() == KeySignature::WESTERN)
831  {
832  Verbose(_T("This Note is a Rest"));
833 
834  ctx.isRest = true; return 1;
835  }
836  break;
837  }
838  default: break;
839  }
840  return ParseLetterNote(szToken, ctx);
841  }
842 
843  /// <Summary> Parses Numeric Note.
844  /// Returns the number of characaters consumed from the string during the parsing. </Summary>
845  int MusicStringParser::ParseNumericNote(TCHAR* szToken, NoteContext& ctx)
846  {
847  bool bSuccess = false; unsigned short nNoteNumber=0;
848 
849  int nLen = ParseNumber(szToken, &nNoteNumber, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_NUMERIC_NOTE_END, PARSE_ERROR_NUMERIC_NOTE_VALUE);
850  if(nLen == -1) return -1; // Some irrevocable error occured
851  if(bSuccess)
852  {
853  ctx.isNumeric = true;
854  ctx.noteNumber = nNoteNumber;
855  Verbose(_T("Numeric Note with value: ") << ctx.noteNumber);
856  }
857 
858  return nLen; // Number of characters consumed
859  }
860 
861  /// <Summary> Parses Rest Note.
862  /// Returns the number of characaters consumed from the string during the parsing </Summary>
863  int MusicStringParser::ParseRest(TCHAR* szToken, NoteContext& ctx)
864  {
865  Verbose(_T("This Note is a Rest"));
866 
867  ctx.isRest = true;
868 
869  return 1;
870  }
871 
872  /// <Summary> Parses Alphabetic Note.
873  /// Returns the number of characaters consumed from the string during the parsing. </Summary>
874  int MusicStringParser::ParseLetterNote(TCHAR* szToken, NoteContext& ctx)
875  {
876  if(m_KeySig.GetMode() == KeySignature::CARNATIC) // Carnatic Mode Notes
877  {
878  const TCHAR* pszToken = szToken;
879  switch(pszToken[0])
880  {
881  case SWARA_S:
882  {
883  pszToken++; ctx.noteNumber = SWARA_S_Value;
884  if(pszToken[0] == _T('A')) { pszToken++; ctx.numSwaras = 2; }
885  break;
886  }
887  case SWARA_P:
888  {
889  pszToken++; ctx.noteNumber = SWARA_P_Value;
890  if(pszToken[0] == _T('A')) { pszToken++; ctx.numSwaras = 2; }
891  break;
892  }
893  case SWARA_M:
894  {
895  pszToken++; ctx.noteNumber = SWARA_M_Value; // if a note isNatural it will be played as is. No lookups or alterations.
896  if(pszToken[0] == _T('A')) { pszToken++; ctx.numSwaras = 2; }
897  if(pszToken[0] == _T('1')) { pszToken++; ctx.noteNumber = 5; ctx.isNatural = true; }
898  else if(pszToken[0] == _T('2')) { pszToken++; ctx.noteNumber = 6; ctx.isNatural = true; }
899  break;
900  }
901  case SWARA_R:
902  {
903  pszToken++; ctx.noteNumber = SWARA_R_Value;
904  if(pszToken[0] == _T('I')) { pszToken++; ctx.numSwaras = 2; }
905  if(pszToken[0] == _T('1')) { pszToken++; ctx.noteNumber = 1; ctx.isNatural = true; }
906  else if(pszToken[0] == _T('2')) { pszToken++; ctx.noteNumber = 2; ctx.isNatural = true; }
907  else if(pszToken[0] == _T('3')) { pszToken++; ctx.noteNumber = 3; ctx.isNatural = true; }
908  break;
909  }
910  case SWARA_G:
911  {
912  pszToken++; ctx.noteNumber = SWARA_G_Value;
913  if(pszToken[0] == _T('A')) { pszToken++; ctx.numSwaras = 2; }
914  if(pszToken[0] == _T('1')) { pszToken++; ctx.noteNumber = 2; ctx.isNatural = true; }
915  else if(pszToken[0] == _T('2')) { pszToken++; ctx.noteNumber = 3; ctx.isNatural = true; }
916  else if(pszToken[0] == _T('3')) { pszToken++; ctx.noteNumber = 4; ctx.isNatural = true; }
917  break;
918  }
919  case SWARA_D:
920  {
921  pszToken++; ctx.noteNumber = SWARA_D_Value;
922  if(pszToken[0] == _T('A')) { pszToken++; ctx.numSwaras = 2; }
923  if(pszToken[0] == _T('1')) { pszToken++; ctx.noteNumber = 8; ctx.isNatural = true; }
924  else if(pszToken[0] == _T('2')) { pszToken++; ctx.noteNumber = 9; ctx.isNatural = true; }
925  else if(pszToken[0] == _T('3')) { pszToken++; ctx.noteNumber = 10; ctx.isNatural = true; }
926  break;
927  }
928  case SWARA_N:
929  {
930  pszToken++; ctx.noteNumber = SWARA_N_Value;
931  if(pszToken[0] == _T('I')) { pszToken++; ctx.numSwaras = 2; }
932  if(pszToken[0] == _T('1')) { pszToken++; ctx.noteNumber = 9; ctx.isNatural = true; }
933  else if(pszToken[0] == _T('2')) { pszToken++; ctx.noteNumber = 10; ctx.isNatural = true; }
934  else if(pszToken[0] == _T('3')) { pszToken++; ctx.noteNumber = 11; ctx.isNatural = true; }
935  break;
936  }
937  default:
938  {
939  ctx.isRest = true; // treat the unknown notes as rest notes
940  MString str;
941  str << _T("Invalid Note: ") << pszToken[0];
942  return Error(PARSE_ERROR_LETTER_NOTE, str, pszToken) ? -1 : 1;
943  }
944  }
945 
946  Verbose(_T("Note number within octave: ") << ctx.noteNumber);
947 
948  return (int)(pszToken - szToken); // return the number of characters read
949  }
950 
951  // Western Mode Notes
952  switch(szToken[0])
953  {
954  case NOTE_C: ctx.noteNumber = NOTE_C_Value; break;
955  case NOTE_D: ctx.noteNumber = NOTE_D_Value; break;
956  case NOTE_E: ctx.noteNumber = NOTE_E_Value; break;
957  case NOTE_F: ctx.noteNumber = NOTE_F_Value; break;
958  case NOTE_G: ctx.noteNumber = NOTE_G_Value; break;
959  case NOTE_A: ctx.noteNumber = NOTE_A_Value; break;
960  case NOTE_B: ctx.noteNumber = NOTE_B_Value; break;
961  default:
962  {
963  ctx.isRest = true; // treat the unknown notes as rest notes
964  MString str;
965  str << _T("Invalid Note: ") << szToken[0];
966  return Error(PARSE_ERROR_LETTER_NOTE, str, szToken) ? -1 : 1;
967  }
968  }
969 
970  // Apply the modifiers such as Sharp, Flat and natural to the Note Number
971  bool bCheckForModifiers = true; const TCHAR* pszSymbol = szToken + 1;
972  while(bCheckForModifiers)
973  {
974  switch(pszSymbol[0])
975  {
976  case NOTE_MODIFIER_SHARP: ctx.noteNumber++; pszSymbol++; break;
977  case NOTE_MODIFIER_FLAT: ctx.noteNumber--; pszSymbol++; break;
978  case NOTE_MODIFIER_NATURAL: ctx.isNatural = true; // follow-on
979  case _T('\0'):
980  default: bCheckForModifiers = false; break;
981  }
982  }
983 
984  Verbose(_T("Note number within octave: ") << ctx.noteNumber);
985 
986  return (int)(pszSymbol - szToken); // return the number of characters read
987  }
988 
989  /// <Summary> Parses any associated note octave </Summary>
990  int MusicStringParser::ParseNoteOctave(TCHAR* szToken, NoteContext& ctx)
991  {
992  // Rest notes or Numeric Notes do not have Octaves specified
993  if(ctx.isRest || ctx.isNumeric) return 0;
994 
995  ctx.octaveNumber = ctx.isChord ? this->m_nDefChordOctave : this->m_nDefNoteOctave;
996 
997  int nLen = 0;
998 
999  if(m_KeySig.GetMode() == KeySignature::CARNATIC)
1000  {
1001  // Carnatic Mode:
1002  // Unlike Western Music, Octaves are not absolute numbers in Carnatic Music.
1003  // They are relative to the Medium Octave, going couple of Octaves above and
1004  // couple of Octaves below the Medium.
1005  // Use XOctave token to change the default Medium Octave. For example,
1006  // XOctave=7 changes the Medium Octave to 7 instead of the default 5.
1007 
1008  // TODO: Implement the XOctave (XShruti) and XChord directives; X is already used. Try Z
1009 
1010  bool bCheckForModifiers = true; const TCHAR* pszSymbol = szToken;
1011  while(bCheckForModifiers)
1012  {
1013  switch(pszSymbol[0])
1014  {
1015  case NOTE_SHRUTI_UP: ctx.octaveNumber ++; pszSymbol++; break;
1016  case NOTE_SHRUTI_DOWN: ctx.octaveNumber --; pszSymbol++; break;
1017  default: bCheckForModifiers = false; break;
1018  }
1019  }
1020  nLen = (int)(pszSymbol - szToken); // Number of Characters consumed
1021  }
1022  else
1023  {
1024  // Western Mode:
1025  // Octaves are optional - they may or may not be present.
1026  // Only values in the range [0, 10] are valid.
1027  // Check if macro is used, otherwise scan it.
1028 
1029  bool bSuccess = false; unsigned short nOctave=0;
1030 
1031  nLen = ParseNumber(szToken, &nOctave, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_OCTAVE_MACRO_END, PARSE_ERROR_OCTAVE_VALUE);
1032  if(nLen == -1) return -1; // Some irrevocable error occured
1033  if(bSuccess)
1034  ctx.octaveNumber = nOctave;
1035  }
1036 
1037  if(ctx.octaveNumber < 0 || ctx.octaveNumber > 10) // Octave not within range
1038  {
1039  MString str;
1040  str << _T("Octave ") << ctx.octaveNumber << _T(" is beyond the range [0, 10]");
1041  if(Error(PARSE_ERROR_OCTAVE_MAXLIMIT, str, szToken)) return -1; // if we should stop processing any further, return -1
1042 
1043  if(ctx.octaveNumber < 0) ctx.octaveNumber = 0;
1044  else if(ctx.octaveNumber > 10) ctx.octaveNumber = 10;
1045  }
1046 
1047  Verbose( _T("Octave Number: ") << ctx.octaveNumber);
1048 
1049  return nLen; // Number of characters consumed here
1050  }
1051 
1052  int MusicStringParser::ParseNoteChord(TCHAR* szToken, NoteContext& ctx)
1053  {
1054  if(ctx.isRest)
1055  {
1056  Verbose(_T("ParseNoteChord: Skipping Chords inspection for Rest Note..."));
1057  return 0; // No Chords for Rest Notes
1058  }
1059 
1060  unsigned int nChordNameLen = m_pChords != NULL ?
1061  m_pChords->ExtractMatchingChord(szToken, &ctx.chord) :
1062  Chords::GetDefaultMatchingChord(szToken, &ctx.chord) ;
1063  if(nChordNameLen > 0)
1064  {
1065  ctx.isChord = true;
1066  Verbose(_T("ParseNoteChord: Found Chord ") << ctx.chord.szChordName);
1067  }
1068 
1069  return nChordNameLen;
1070  }
1071 
1072  int MusicStringParser::ParseNoteChordInversion(TCHAR* szToken, NoteContext& ctx)
1073  {
1074  if(ctx.isChord == false)
1075  {
1076  Verbose(_T("ParseNoteChordInversion: Skipping Chord Inversions..."));
1077  return 0;
1078  }
1079 
1080  TCHAR* pszToken = szToken;
1081 
1082  int nInversionCount = 0;
1083  int nInversionRootNote = -1;
1084  int nInversionOctave = -1;
1085  bool bCheckForInversion = true;
1086 
1087  while(bCheckForInversion && *pszToken != _T('\0'))
1088  {
1089  switch(pszToken[0])
1090  {
1091  case _T('^'): pszToken++; nInversionCount++; break;
1092  case _T('C'): pszToken++; nInversionRootNote = NOTE_C_Value; break;
1093  case _T('D'): pszToken++; nInversionRootNote = NOTE_D_Value; break;
1094  case _T('E'): pszToken++; nInversionRootNote = NOTE_E_Value; break;
1095  case _T('F'): pszToken++; nInversionRootNote = NOTE_F_Value; break;
1096  case _T('G'): pszToken++; nInversionRootNote = NOTE_G_Value; break;
1097  case _T('A'): pszToken++; nInversionRootNote = NOTE_A_Value; break;
1098  case _T('B'): pszToken++; // this could be note B or Flat symbol b
1099  if(nInversionRootNote == -1) nInversionRootNote = NOTE_B_Value;
1100  else nInversionRootNote--;
1101  break;
1102  case _T('#'): pszToken++; nInversionRootNote++; break;
1103  case _T('1'): pszToken++; nInversionOctave = 1; break;
1104  case _T('2'): pszToken++; nInversionOctave = 2; break;
1105  case _T('3'): pszToken++; nInversionOctave = 3; break;
1106  case _T('4'): pszToken++; nInversionOctave = 4; break;
1107  case _T('5'): pszToken++; nInversionOctave = 5; break;
1108  case _T('6'): pszToken++; nInversionOctave = 6; break;
1109  case _T('7'): pszToken++; nInversionOctave = 7; break;
1110  case _T('8'): pszToken++; nInversionOctave = 8; break;
1111  case _T('9'): pszToken++; nInversionOctave = 9; break;
1112  case _T('0'): pszToken++; // this could be 0th octave or a 0 after a digit
1113  if(nInversionOctave == -1) nInversionOctave = 0;
1114  else nInversionOctave *= 10; break;
1115  case MACRO_START: // Root note is specified as a Macro number value
1116  {
1117  unsigned short nRoot = 0; bool bSuccess = false;
1118  int nLen = ParseNumber(pszToken, &nRoot, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_CHORDINV_MACRO_END, PARSE_ERROR_CHORDINV_VALUE);
1119  if(nLen == -1) { return -1; } // Some irrevocable error occured
1120  if(bSuccess)
1121  {
1122  nInversionRootNote = nRoot;
1123  pszToken += nLen;
1124  break;
1125  }
1126  else ; // fall through
1127  }
1128  default: bCheckForInversion = false; break;
1129  }
1130  } // while
1131 
1132  // Update the values based on Inversion Specifications
1133  if(nInversionCount > 0)
1134  {
1135  if(nInversionRootNote == -1) // if No Root note specified, inversion is based on number of carets
1136  {
1137  Verbose(_T("Chord Inversion based on count: ") << nInversionCount);
1138  // Increase each halfstep before the inversion by 12, the total number of halfsteps in an octave
1139  ctx.noteNumber += 12;
1140  for(int i = nInversionCount -1; i < ctx.chord.nIntervalCount; ++i)
1141  {
1142  Verbose(_T(" Inverting ") << ctx.chord.Intervals[i] << _T(" to be ") << (ctx.chord.Intervals[i] - 12));
1143  ctx.chord.Intervals[i] -= 12;
1144  }
1145  }
1146  else // Inversion based on root note
1147  {
1148  if(nInversionOctave != -1)
1149  nInversionRootNote += (nInversionOctave * 12);
1150  else if(nInversionRootNote < 12)
1151  {
1152  int nCurOctave = ctx.noteNumber / 12; // get the current octave
1153  nInversionRootNote += (nCurOctave * 12);
1154  }
1155 
1156  // Otherwise, InversionRootNote could be a numeric value, such as [60]
1157  Verbose(_T("Chord Inversion is based on note: ") << nInversionRootNote);
1158 
1159  if((nInversionRootNote > ctx.noteNumber + ctx.chord.Intervals[ctx.chord.nIntervalCount -1])
1160  || (nInversionRootNote < ctx.noteNumber))
1161  {
1162  if(Error(PARSE_ERROR_CHORDINV_MAXLIMIT, _T("Chord Inversion Root Note is beyond range"), szToken))
1163  return -1;
1164 
1165  Verbose(_T(" Adjusted the inversion root note to be ") << ctx.noteNumber <<_T(" and continuing..."));
1166 
1167  nInversionRootNote = ctx.noteNumber;
1168  }
1169 
1170  Verbose(_T(" Inverting ") << ctx.noteNumber << _T(" to be ") << (ctx.noteNumber + 12));
1171  ctx.noteNumber += 12;
1172 
1173  for(int i=0; i < ctx.chord.nIntervalCount; ++ i)
1174  {
1175  if(ctx.noteNumber + ctx.chord.Intervals[i] >= nInversionRootNote + 12)
1176  {
1177  Verbose(_T(" Inverting ") << ctx.chord.Intervals[i] << _T(" to be ") << (ctx.chord.Intervals[i] - 12));
1178  ctx.chord.Intervals[i] -= 12;
1179  }
1180  }
1181  }
1182  }
1183 
1184  return (int)(pszToken - szToken); // return the number of characters scanned
1185  }
1186 
1187  int MusicStringParser::ComputeNoteValue(NoteContext& ctx)
1188  {
1189  if(ctx.isRest) return 0; // No note values for Rest Notes
1190 
1191  //if(ctx.octaveNumber == -1 && !ctx.isNumeric) // if Octave is not specified (and if this is non-numeric note) give some default octave value
1192  //{
1193  // if(ctx.isChord)
1194  // ctx.octaveNumber = DEFAULT_CHORD_OCTAVE;
1195  // else
1196  // ctx.octaveNumber = DEFAULT_NONCHORD_OCTAVE;
1197  //
1198  // Warning(_T("Choosing Default Octave:") + OIL::ToString(ctx.octaveNumber));
1199  //}
1200 
1201  // Adjust the Notes based on KeySignature
1202  int nKeySig = m_KeySig.GetKey();
1203 
1204  if(m_KeySig.GetMode() == KeySignature::CARNATIC)
1205  {
1206  if(!ctx.isNatural && !ctx.isNumeric) // Key Signatures are applied only to non-numeric Notes
1207  ctx.noteNumber = KeySignature::LookupSwaraSthanaForMela(ctx.noteNumber, nKeySig);
1208  }
1209  else // Western Mode
1210  {
1211  if ((nKeySig != 0) && (!ctx.isNatural) && (!ctx.isNumeric)) // Key Signatures are applied only to non-numeric Notes
1212  {
1213  if ((nKeySig <= -1) && (ctx.noteNumber == 11)) ctx.noteNumber = 10;
1214  if ((nKeySig <= -2) && (ctx.noteNumber == 4)) ctx.noteNumber = 3;
1215  if ((nKeySig <= -3) && (ctx.noteNumber == 9)) ctx.noteNumber = 8;
1216  if ((nKeySig <= -4) && (ctx.noteNumber == 2)) ctx.noteNumber = 1;
1217  if ((nKeySig <= -5) && (ctx.noteNumber == 7)) ctx.noteNumber = 6;
1218  if ((nKeySig <= -6) && (ctx.noteNumber == 0)) { ctx.noteNumber = 11; ctx.octaveNumber--; }
1219  if ((nKeySig <= -7) && (ctx.noteNumber == 5)) ctx.noteNumber = 4;
1220  if ((nKeySig >= +1) && (ctx.noteNumber == 5)) ctx.noteNumber = 6;
1221  if ((nKeySig >= +2) && (ctx.noteNumber == 0)) ctx.noteNumber = 1;
1222  if ((nKeySig >= +3) && (ctx.noteNumber == 7)) ctx.noteNumber = 8;
1223  if ((nKeySig >= +4) && (ctx.noteNumber == 2)) ctx.noteNumber = 3;
1224  if ((nKeySig >= +5) && (ctx.noteNumber == 9)) ctx.noteNumber = 10;
1225  if ((nKeySig >= +6) && (ctx.noteNumber == 4)) ctx.noteNumber = 5;
1226  if ((nKeySig >= +7) && (ctx.noteNumber == 11)) { ctx.noteNumber = 0; ctx.octaveNumber++; }
1227  }
1228  }
1229 
1230  Verbose(_T("After adjusting for Key, Note Number=") << ctx.noteNumber);
1231 
1232  if(!ctx.isNumeric) // if this is a non-numeric note, compute its value from octave and local note value
1233  {
1234  ctx.noteNumber = (ctx.octaveNumber * 12) + ctx.noteNumber;
1235 
1236  Verbose(_T("Computed Note Number:") << ctx.noteNumber);
1237  }
1238 
1239  // Check the limits
1240  if(ctx.noteNumber > 127 || ctx.noteNumber < 0)
1241  {
1242  MString str;
1243  str << _T("Computed Note Number") << ctx.noteNumber << _T(" is going beyond the range [0, 127]");
1244  if(Error(PARSE_ERROR_NOTEVALUE_MAXLIMIT, str, NULL)) return -1; // if we should stop processing any further, return -1
1245 
1246  // if we need to continue despite the error, ceil or floor the value
1247  if(ctx.noteNumber > 127)
1248  ctx.noteNumber = 127;
1249  else if(ctx.noteNumber < 0)
1250  ctx.noteNumber = 0;
1251 
1252  Warning(_T(" Adjusted the value to") << ctx.noteNumber << _T(" and continuing..."));
1253  }
1254  return 0;
1255  }
1256 
1257  /// <Summary> Parses duration of note </Summary>
1258  int MusicStringParser::ParseNoteDuration(TCHAR* szToken, NoteContext& ctx)
1259  {
1260  TCHAR* pszDuration = szToken;
1261 
1262  if(m_KeySig.GetMode() == KeySignature::WESTERN) // Western Mode
1263  {
1264  if(szToken[0] == NOTE_DURATION_NUMERIC) // Check if this is a numeric duration
1265  {
1266  bool bSuccess = false;
1267  int nLen = ParseNumber(szToken+1, &ctx.decimalDuration, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_DURATION_MACRO_END, PARSE_ERROR_DURATION_VALUE);
1268  if(nLen == -1)
1269  return -1; // Some irrevocable error occured
1270  if(bSuccess)
1271  {
1272  pszDuration = szToken + 1 + nLen; // Update the position for next scanning
1273  }
1274  else
1275  {
1276  MString str(_T("Error while reading Numeric Duration Value"));
1277  if(Error(PARSE_ERROR_DURATION_VALUE, str, szToken)) return -1;
1278 
1279  pszDuration = szToken + 1;
1280 
1281  // If we have to ignore this error, ignore this / character
1282  Warning(_T(" Ignoring / and proceeding with ") << pszDuration);
1283  }
1284  }
1285 
1286  // In case Numeric Duration failed or absent,
1287  // Try reading the duration as Alphabets (such as W, H etc..)
1288  if(!ctx.decimalDuration)
1289  pszDuration += ParseLetterDuration(pszDuration, ctx);
1290  }
1291 
1292  if(m_KeySig.GetMode() == KeySignature::CARNATIC) // Carnatic Mode does not have explicit Note durations
1293  {
1294  ctx.decimalDuration = ctx.numSwaras * 1.0f / (4.0 * pow((double)2.0f, (double)m_KeySig.Speed()-1));//(unsigned short) m_KeySig.GetTalam();
1295  }
1296 
1297  // if No Duration specified, Default to a Quarter note
1298  if(ctx.decimalDuration == 0)
1299  ctx.decimalDuration = 1.0 / 4.0;
1300 
1301  Verbose(_T("Decimal Duration is: ") << ctx.decimalDuration);
1302 
1303  // Scan for any optional Tuplet specifications
1304  int nTupletLen = ParseTuplet(pszDuration, ctx);
1305  if(nTupletLen < 0) return -1; // some irrevocable error happened
1306 
1307  ctx.duration = (long) (128.0 * ctx.decimalDuration); //TODO: Compute the duration based on the current Tempo
1308 
1309  Verbose(_T("Actual Duration is: ") << ctx.duration);
1310 
1311  return (int)(pszDuration - szToken) + nTupletLen; // Return the number of characters consumed
1312  }
1313 
1314  /// <Summary> Parses duration expressed as Alphabet W, H etc.. </Summary>
1315  int MusicStringParser::ParseLetterDuration(TCHAR* szToken, NoteContext& ctx)
1316  {
1317  TCHAR* pszDuration = szToken;
1318 
1319  while(*pszDuration != _T('\0'))
1320  {
1321  if(pszDuration[0] == NOTE_TIE)
1322  {
1323  if(!ctx.decimalDuration) // if we have not yet scanned the duration, i.e. - is preceding the duration
1324  ctx.isEndOfTie = true; // this could be an end of tie or continuation
1325  else // - is following the duration, could be a start of tie or continuation
1326  {
1327  if(ctx.isEndOfTie) // if we have seen a tie symbol before duration, then this is a continuation
1328  ctx.isEndOfTie = false;
1329  else // This is the first tie symbol on this token, mark this as start of tie
1330  ctx.isStartOfTie = true;
1331  break; // When tie symbol is seen after duration, No need to scan further.
1332  }
1333  pszDuration++;
1334  }
1335 
1336  double nDurationNumber = 0;
1337 
1338  switch(pszDuration[0])
1339  {
1340  case NOTE_DURATION_WHOLE: nDurationNumber = 1; break;
1341  case NOTE_DURATION_HALF: nDurationNumber = 2; break;
1342  case NOTE_DURATION_QUARTER: nDurationNumber = 4; break;
1343  case NOTE_DURATION_EIGTH: nDurationNumber = 8; break;
1344  case NOTE_DURATION_SIXTEENTH: nDurationNumber = 16; break;
1345  case NOTE_DURATION_THIRTYSECOND: nDurationNumber = 32; break;
1346  case NOTE_DURATION_SIXTYFOURTH: nDurationNumber = 64; break;
1347  case NOTE_DURATION_128: nDurationNumber = 128; break;
1348  case SWARA_DURATION_ONE_EXTRA: ctx.numSwaras++; nDurationNumber = 1; break;
1349  case SWARA_DURATION_TWO_EXTRA: ctx.numSwaras += 2; nDurationNumber = 0.5; break;
1350  }
1351  if(nDurationNumber > 0)
1352  {
1353  double durVal = 1.0/nDurationNumber;
1354  ctx.decimalDuration += durVal;
1355  if(pszDuration[1] == NOTE_DURATION_DOT) // if used a dot
1356  {
1357  ctx.decimalDuration += (durVal/2.0); // add extra half to the original
1358  pszDuration++;
1359  }
1360  }
1361  else
1362  break; // encountered a character that is not a valid duration symbol. Lets get out of here.
1363 
1364  pszDuration ++;
1365  }
1366 
1367  return (int)(pszDuration - szToken); // return the number of characters consumed
1368  }
1369 
1370  /// <Summary> Parses tuples expressed with * : </Summary>
1371  int MusicStringParser::ParseTuplet(TCHAR* szToken, NoteContext& ctx)
1372  {
1373  if(szToken[0] == NOTE_TUPLET_START)
1374  {
1375  Verbose(_T("Scanning a Tuplet..."));
1376 
1377  TCHAR* pszTuplet = szToken + 1;
1378 
1379  double dNumerator = 2.0;
1380  double dDenominator = 3.0;
1381 
1382  TCHAR* pszTupletRatioMark = _tcschr(pszTuplet, NOTE_TUPLET_RATIOMARK);
1383  if(pszTupletRatioMark != NULL)
1384  {
1385  *pszTupletRatioMark = _T('\0');
1386 
1387  if(!LoadValueFromString(pszTuplet, &dNumerator)) // Read the Numerator
1388  {
1389  MString str(MString(_T("Error while reading Numerator of tuplet")));
1390  if(Error(PARSE_ERROR_TUPLET_NUMERATOR, str, pszTuplet)) return -1;
1391  Warning(_T(" Defaulting to Numerator Value: ") << dNumerator);
1392  }
1393 
1394  int nLen = LoadValueFromString(pszTupletRatioMark+1, &dDenominator); // Read the Denominator
1395  if(nLen == 0)
1396  {
1397  MString str(_T("Error while reading Denominator of tuplet"));
1398  if(Error(PARSE_ERROR_TUPLET_DENOMINATOR, str, pszTupletRatioMark+1)) return -1;
1399  Warning(_T(" Defaulting to Denominator Value: ") << dDenominator);
1400  }
1401 
1402  pszTuplet = pszTupletRatioMark + 1 + nLen;
1403  }
1404 
1405  double tupletRatio = dNumerator / dDenominator;
1406 
1407  ctx.decimalDuration *= tupletRatio;
1408 
1409  Verbose(_T("Tuplet Ratio is: ") << (unsigned int)dNumerator << _T(":") << (unsigned int)dDenominator);
1410  Verbose(_T("Decimal Duration after applying Tuplet: ") << ctx.decimalDuration);
1411 
1412  return (int)(pszTuplet - szToken); // return number of characters consumed
1413  }
1414 
1415  return 0; // This is not a tuplet
1416  }
1417 
1418 
1419  /// <brief> Parses Attack and Decay velocities of note </brief>
1420  /// <Summary>
1421  /// Attack and Decay velocities come in the note token after the note duration.
1422  /// Typically specified by V&lt;attack&gt;V&lt;decay&gt;
1423  /// For example, CV20V80 indicates Mid-octave C note with attack velocity 20 and decay velocity 80.
1424  /// If the number is skipped after the V then default value of 64 will be used.
1425  /// For example, DVV80 indicates Mid-octave D note with default attack velocity 64 and decay velocity of 80
1426  /// </Summary>
1427  int MusicStringParser::ParseNoteVelocity(TCHAR* szToken, NoteContext& ctx)
1428  {
1429  if(ctx.isRest)
1430  {
1431  Verbose(_T("This is a Rest note .. Skipping the Velocities"));
1432  return 0;
1433  }
1434 
1435  TCHAR* pszVelocity = szToken; bool bAttackRead = false;
1436 
1437  do
1438  {
1439  bool bAttack = false, bDecay = false;
1440 
1441  switch(pszVelocity[0])
1442  {
1443  case NOTE_VELOCITY: bAttack = !bAttackRead; bDecay = bAttackRead; bAttackRead = bAttack; break;
1444  case NOTE_VELOCITY_ATTACK: if(m_KeySig.GetMode()==KeySignature::WESTERN) { bAttack = true; break; } // Compatibility with JFugue only in Wester mode
1445  case NOTE_VELOCITY_DECAY: if(m_KeySig.GetMode()==KeySignature::WESTERN) { bDecay = true; break; }
1446  default:
1447  {
1448  Verbose(_T("Attack Velocity: ") << (int)ctx.attackVelocity << _T(" Decay Velocity: ") << (int)ctx.decayVelocity);
1449  return (int)(pszVelocity - szToken);
1450  }
1451  }
1452 
1453  pszVelocity++;
1454 
1455  bool bSuccess = false; unsigned short nVelocity = 0;
1456 
1457  int nLen = ParseNumber(pszVelocity, &nVelocity, bSuccess, MACRO_START, MACRO_END, PARSE_ERROR_VELOCITY_MACRO_END, PARSE_ERROR_VELOCITY_VALUE);
1458  if(nLen == -1) return -1; // Some irrevocable error occured
1459  if(bSuccess)
1460  {
1461  if(bAttack) ctx.attackVelocity = nVelocity;
1462  if(bDecay) ctx.decayVelocity = nVelocity;
1463  }
1464  else Warning(_T("Unable to find Attack/Decay velocity for note, while parsing: ") << szToken);
1465 
1466  pszVelocity += nLen;
1467  }while(true); // we can have both attack and decay specified for the same note. so loop again.
1468 
1469  return (int)(pszVelocity - szToken);
1470  }
1471 
1472  /// <Summary> Checks & Parses any associated notes </Summary>
1473  int MusicStringParser::ParseNoteConnector(TCHAR* szToken, NoteContext& ctx)
1474  {
1475  ctx.existsAnotherNote = true; // we start with assumpion that there are connectors
1476 
1477  switch(szToken[0])
1478  {
1479  case NOTE_CONNECTOR_SEQUENTIAL: ctx.anotherIsSequential = true; return 1;
1480  case NOTE_CONNECTOR_PARALLEL: ctx.anotherIsParallel = true; return 1;
1481  default: Verbose(_T("No Connector Notes Found in: ") << szToken); break;
1482  }
1483 
1484  ctx.existsAnotherNote = false;
1485 
1486  return 0; // No Characters Read
1487  }
1488 
1489 
1490  /// <Summary> Upon completion of parsing a Note token, raises the Events to process the Note</Summary>
1491  void MusicStringParser::RaiseNoteEvents(NoteContext& ctx)
1492  {
1493  if(ctx.isRest)
1494  {
1495  ctx.attackVelocity = ctx.decayVelocity = 0; // Rest Notes do not make Sound !!
1496  }
1497 
1498  RaiseEvent(&evNote, (Note*)&ctx);
1499 
1500  if(ctx.isChord)
1501  {
1502  for(unsigned short i=0; i < ctx.chord.nIntervalCount; ++i)
1503  {
1504  Note noteObj;
1505  noteObj.noteNumber = ctx.noteNumber + ctx.chord.Intervals[i];
1506  noteObj.duration = ctx.duration;
1507  noteObj.decimalDuration = ctx.decimalDuration;
1508  noteObj.type = Note::PARALLEL;
1509  RaiseEvent(&evNote, &noteObj);
1510  }
1511  }
1512  }
1513 
1514 
1515  /// <Summary>
1516  /// Tries to load a value from Dictionary with the given key.
1517  /// If the key is undefined, then itself is converted to the required type
1518  /// and returned as the value.
1519  ///
1520  /// @return 0 in case of failures of lookup or conversion. Length of the string
1521  /// scanned, in case of szKey being a number. To be ignored, if szKey is a macro.
1522  /// </Summary>
1523  template<typename T>
1524  int MusicStringParser::GetValueFromDictionary(const TCHAR* szKey, T* pRetVal)
1525  {
1526  DICTIONARY::const_iterator dictEntry = m_Dictionary.find(szKey);
1527 
1528  // Lookup may fail if the key is not a macro - in such case we use the key itself as the value
1529  const TCHAR* pszVal = (dictEntry == m_Dictionary.end() ? szKey : (const TCHAR*)dictEntry->second);
1530 
1531  // *pRetVal = NULL;
1532 
1533  return LoadValueFromString(pszVal, pRetVal);
1534  }
1535 
1536  template<typename T>
1537  int MusicStringParser::ParseNumber(TCHAR* szToken, T* pRetVal, bool& bSuccess,
1538  TCHAR MacroBracketStart, TCHAR MacroBracketEnd, ErrorCode MacroReadErrorCode, ErrorCode NumberParseErrorCode)
1539  {
1540  bSuccess = false;
1541 
1542  const TCHAR* pszNumberStart = szToken;
1543 
1544  if(szToken[0] == MacroBracketStart) // if Number specified as a Macro
1545  {
1546  TCHAR* pszEndBracket = _tcschr(szToken, MacroBracketEnd);
1547  if(pszEndBracket == NULL)
1548  {
1549  MString str;
1550  str << _T("No Matching ") << MacroBracketEnd << _T(" found for ") << MacroBracketStart;
1551  if(Error(MacroReadErrorCode, str, szToken)) return -1;
1552 
1553  // if we have to ignore this error, we ignore this [ character and continue
1554  pszNumberStart = szToken+1;
1555 
1556  Warning(_T(" Ignoring ") << MacroBracketStart);
1557 
1558  return 1; // Failure; return the lentgh scanned
1559  }
1560  else // We found an End Bracket
1561  {
1562  *pszEndBracket = _T('\0');
1563 
1564  if(false == GetValueFromDictionary(szToken + 1, pRetVal)) // Convert the string between [ and ] to Number
1565  {
1566  MString str;
1567  str << _T("Unable to retrieve Number from ") << (szToken + 1);
1568  if(Error(NumberParseErrorCode, str, szToken)) return -1;
1569 
1570  // if we have to ignore this error, we ignore the whole string between the [ and ]
1571  Warning(_T(" Ignoring ") << (szToken + 1));
1572 
1573  return (int)(pszEndBracket - szToken) +1; // Failure; return the length consumed
1574  }
1575  else // The Macro got read successfully
1576  {
1577  bSuccess = true;
1578 
1579  return (int)(pszEndBracket - szToken) +1; // return the number of characters scanned
1580  }
1581  }
1582  }
1583 
1584  // Number seems to be specified as a direct value.
1585 
1586  int nStrLen = LoadValueFromString(pszNumberStart, pRetVal);
1587 
1588  if(nStrLen == 0)
1589  {
1590  //MString str(_T("Unable to retrieve Number from ") + MString(pszNumberStart));
1591  //if(Error(NumberParseErrorCode, str, szToken)) return NULL;
1592 
1593  // if we have to ignore this error, we ignore the fact that we tried to read this
1594  // string as a number. Let next portions try interpret it differently
1595  }
1596  else // The number got read successfully
1597  bSuccess = true;
1598 
1599  return (int)(pszNumberStart - szToken) + nStrLen; // return the number of characters consumed
1600  }
1601 
1602 } // namespace CFugue
1603 
Signifies the Macro end symbol.
MACRO_END missing while parsing a Voice Macro.
Definition: Parser.h:128
MACRO_END missing while parsing a Velocity Macro.
Definition: Parser.h:144
Failure while converting/retrieving a Controller Value number.
Definition: Parser.h:106
void SetRagam(const unsigned short nRagam)
Definition: KeySignature.h:137
Computed Note Value is going beyond the permitted range [0, 127].
Definition: Parser.h:146
Failure while converting/retrieving a PitchBend number.
Definition: Parser.h:115
OIL::CEventT< const CParser, const Voice > evVoice
Event Raised when Parser encounters a Voice command.
Definition: Parser.h:77
Failure while converting/retrieving a numeric note number.
Definition: Parser.h:132
Failure while conveting/retrieving the Numerator of Tuplet fraction.
Definition: Parser.h:142
unsigned int ExtractMatchingChord(const TCHAR *szToken, ChordDef *retVal) const
Definition: Chords.cpp:163
OIL::CEventT< const CParser, const PitchBend > evPitchBend
Event Raised when Parser encounters a PitchBend command.
Definition: Parser.h:74
Note Attack Velocity specifier (Obsolete. only for compatability with JFugue)
Failure while conveting/retrieving a Duration number.
Definition: Parser.h:141
const Talam & GetTalam() const
Returns the Talam Value. Valid only when the Mode is CARNATIC. Use GetMode() to find the Mode;...
Definition: KeySignature.h:125
Increments Note Shruti one level upward the Tara Sthayi.
MACRO_END missing while parsing a Speed Macro.
Definition: Parser.h:119
Signifies a Macro start symbol.
static unsigned short LookupSwaraSthanaForMela(short nSwara, unsigned short nMela)
Definition: KeySignature.h:459
Failure while converting/retrieving a Instrument number.
Definition: Parser.h:108
OIL::CEventT< const CParser, const Tempo > evTempo
Event Raised when Parser encounters a Tempo command.
Definition: Parser.h:75
MACRO_END missing while parsing a Key Signature Macro.
Definition: Parser.h:111
Specifies a seperator token for readability.
Specifies 1.5 times the normal duration.
signed char GetKey() const
Returns the Key Signature value. Based on the Mode, Value will be in the range [-7, 7] or [1, 72]. Use GetMode() to find the Mode.
Definition: KeySignature.h:113
bool Parse(const TCHAR *szTokens)
No Assignment symbol found.
Definition: Parser.h:102
Specified a KeySignature beyond permitted range [0, 14] , [64, 78], [129, 200].
Definition: Parser.h:113
void SetTalam(const Talam &talam)
Definition: KeySignature.h:141
Failure while converting/retrieving a Speed number.
Definition: Parser.h:120
Specified a Talam beyond permitted range [0, 35].
Definition: Parser.h:118
Failure while conveting/retrieving the Denominator of Tuplet fraction.
Definition: Parser.h:143
OIL::CEventT< const CParser, const ControllerEvent > evController
Event Raised when Parser encounters a MIDI Controller Event.
Definition: Parser.h:67
Used when Duration is to be expressed as a numeric value.
Used when decorating durations for ties.
Note Attack Velocity specifier (Carnatic Mode)
MACRO_END missing while parsing a Controller Index Macro.
Definition: Parser.h:103
Failure while conveting/retrieving an Octave macro number.
Definition: Parser.h:138
Invalid Alphabet encountering while trying to read a Note Symbol.
Definition: Parser.h:133
MACRO_END missing while parsing an Duration Macro.
Definition: Parser.h:140
Indicates if this is a Sequential note in a group of notes.
Definition: Note.h:32
Specified a voice that is beyond the permitted range [0, 15].
Definition: Parser.h:130
Specifies a Rest Note of one duration.
OIL::CEventT< const CParser > evMeasure
Event Raised when Parser encounters a Measure bar.
Definition: Parser.h:71
OIL::CEventT< const CParser, const KeySignature > evKeySignature
Event Raised when Parser encounters a Key Signature command.
Definition: Parser.h:69
Declares MIDI Controller Events used in MusicStrings.
unsigned short & Speed()
Returns the current Song speed. Valid only for Carnatic Mode. Use GetMode() to verify the Mode...
Definition: KeySignature.h:145
Specified a Speed beyond permitted range [1, 6].
Definition: Parser.h:121
MACRO_END missing while parsing a Polyphonic Pressure Macro.
Definition: Parser.h:109
static unsigned int GetDefaultMatchingChord(const TCHAR *szToken, ChordDef *retVal)
Definition: Chords.cpp:168
Indicates two extra time units [Carnatic Music Only].
MACRO_END missing while parsing a numeric note.
Definition: Parser.h:131
OIL::CEventT< const CParser, const Note > evNote
Event Raised when Parser encounters a Note.
Definition: Parser.h:78
MACRO_END missing while parsing a PitchBend Macro.
Definition: Parser.h:114
Specifies a Rest Note token [Western Music Only].
MACRO_END missing while parsing an Octave Macro.
Definition: Parser.h:137
Declares Instrument class.
Failure while converting/retrieving a Polyphonic Pressure number.
Definition: Parser.h:110
Mode GetMode() const
Returns if the KeySignature refers to Carnatic Mode or Western Mode.
Definition: KeySignature.h:121
Indicates if this is a Parallel note in a group of notes.
Definition: Note.h:33
MACRO_END missing while parsing a Tempo Macro.
Definition: Parser.h:124
OIL::CEventT< const CParser, const ChannelPressure > evChannelPressure
Event Raised when Parser encounters a Channel Pressure command.
Definition: Parser.h:72
Specified an inversion root note that is not with in acceptable range of values.
Definition: Parser.h:136
Failure while converting/retrieving a Time number.
Definition: Parser.h:127
MACRO_END missing while parsing a Layer Macro.
Definition: Parser.h:122
OIL::CEventT< const CParser, const PolyphonicPressure > evPolyphonicPressure
Event Raised when Parser encounters a Key Pressure command.
Definition: Parser.h:73
OIL::CEventT< const CParser, const Time > evTime
Event Raised when Parser encounters a Time command.
Definition: Parser.h:76
Specifies a Rest Note of two durations.
Indicates one extra time unit [Carnatic Music Only].
Failure while converting/retrieving a Controller Value number.
Definition: Parser.h:104
Failure while conveting/retrieving a Velocity number.
Definition: Parser.h:145
Failure while converting/retrieving a Voice number.
Definition: Parser.h:129
Failure while converting/retrieving a Chord Inversion Root Note number.
Definition: Parser.h:135
Specified an octave that is beyond the permitted range [0, 10].
Definition: Parser.h:139
MACRO_END missing while parsing a Chord Inversion.
Definition: Parser.h:134
Declares Tempo class used in Western music.
OIL::CEventT< const CParser, const Instrument > evInstrument
Event Raised when Parser encounters an Instrument command.
Definition: Parser.h:68
Failure while converting/retrieving a Layer number.
Definition: Parser.h:123
OIL::CEventT< const CParser, const Layer > evLayer
Event Raised when Parser encounters a Layer command.
Definition: Parser.h:70
Failure while converting/retrieving a Key Signature number.
Definition: Parser.h:112
Failure while converting/retrieving a Talam number.
Definition: Parser.h:117
MACRO_END missing while parsing a Talam Macro.
Definition: Parser.h:116
Indicates if this is a First note in a group of notes.
Definition: Note.h:31
void RaiseEvent(CEventT< TEventSource, TEventHandlerArgs > *pEvent, TEventHandlerArgs *pArgs)
Definition: EventHandler.h:320
int ParseToken(TCHAR *szToken, bool *pbNonContinuableErrorOccured=NULL)
Decrements Note Shruti one level downward the Mandra Sthayi.
MACRO_END missing while parsing a Time Macro.
Definition: Parser.h:126
virtual bool Error(ErrorCode argErrCode, const TCHAR *szTraceMsg, const TCHAR *szToken)
Definition: Parser.h:196
MACRO_END missing while parsing a Controller Index Macro.
Definition: Parser.h:105
MACRO_END missing while parsing a Instrument Macro.
Definition: Parser.h:107
Failure while converting/retrieving a Tempo number.
Definition: Parser.h:125

CFugue, the C++ Music Programming Library © Copyright 2009 Cenacle Research India Private Limited Gopalakrishna Palem