CFugue
MusicStringParser.h
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: 2013-12-18 10:59:57 +0530 (Wed, 18 Dec 2013) $
9  $Rev: 197 $
10  $LastChangedBy: krishnapg $
11 */
12 
13 #ifndef __MUSICNOTEREADER_H__506A239B_50B0_472d_B070_69BFBEF3C6CB__
14 #define __MUSICNOTEREADER_H__506A239B_50B0_472d_B070_69BFBEF3C6CB__
15 
16 #include "Parser.h"
17 #include "Note.h"
18 #include "KeySignature.h"
19 #include "Chords.h"
20 
21 namespace CFugue
22 {
23  /// <Summary> Implements a MusicString Parsing functionality </Summary>
24  class MusicStringParser : public CParser
25  {
26  protected:
27  /// <Summary>
28  /// Token constants used in the parsing for classifying their types
29  /// </Summary>
30  enum TokenSpecifiers : TCHAR
31  {
32  TOKEN_START_VOICE = _T('V'), ///< Specifies a Voice token
33  TOKEN_START_TEMPO = _T('T'), ///< Specifies a Tempo token
34  TOKEN_START_INSTRUMENT = _T('I'), ///< Specifies a Instrument token
35  TOKEN_START_LAYER = _T('L'), ///< Specifies a Layer token
36  TOKEN_START_KEYSIGNATURE = _T('K'), ///< Specifies a KeySignature token
37  TOKEN_START_CONTROLLER = _T('X'), ///< Specifies a Controller token
38  TOKEN_START_TIME = _T('@'), ///< Specifies a Time token
39  TOKEN_START_KEYPRESSURE = _T('*'), ///< Specifies a Keypressure token
40  TOKEN_START_CHANNELPRESSURE = _T('+'), ///< Specifies a Channel pressure token
41  TOKEN_START_PITCHBEND = _T('&'), ///< Specifies a Pitchbend token
42  TOKEN_START_MEASURE = _T('|'), ///< Specifies a Measure token
43  TOKEN_START_DICTIONARY = _T('$'), ///< Specifies a Dictionary token
44  TOKEN_START_NOTE = _T('['), ///< Specifies a Note token
45  TOKEN_SEPERATOR = _T('-'), ///< Specifies a seperator token for readability
46 
47  // Talam Related
48  TOKEN_DOUBLESPEED_START = _T('('), ///< Specifies the start of 2x speed
49  TOKEN_DOUBLESPEED_END = _T(')'), ///< Specifies the end of 2x speed
50 
51  // Dictionary Related
52  ASSIGNMENT_SYMBOL = _T('='),
53 
54  // Note Related
55  MACRO_START = _T('['), ///< Signifies a Macro start symbol
56  MACRO_END = _T(']'), ///< Signifies the Macro end symbol
57  WESTERN_REST_NOTE = _T('R'), ///< Specifies a Rest Note token [Western Music Only]
58  REST_NOTE1 = _T(','), ///< Specifies a Rest Note of one duration
59  REST_NOTE2 = _T(';'), ///< Specifies a Rest Note of two durations
60  };
61 
62  /// <Summary> Note Numbers </Summary>
63  enum NoteNumbers : unsigned short
64  {
65  // These are relative half-step values in an octave
66  NOTE_C = _T('C'),
67  NOTE_C_Value = 0,
68  NOTE_D = _T('D'),
69  NOTE_D_Value = 2,
70  NOTE_E = _T('E'),
71  NOTE_E_Value = 4,
72  NOTE_F = _T('F'),
73  NOTE_F_Value = 5,
74  NOTE_G = _T('G'),
75  NOTE_G_Value = 7,
76  NOTE_A = _T('A'),
77  NOTE_A_Value = 9,
78  NOTE_B = _T('B'),
79  NOTE_B_Value = 11,
80 
81  // These are array indices for SwaraSthanas[] based on KeySignature Mela
82  SWARA_S = _T('S'),
83  SWARA_S_Value = 0,
84  SWARA_R = _T('R'),
85  SWARA_R_Value = 1,
86  SWARA_G = _T('G'),
87  SWARA_G_Value = 2,
88  SWARA_M = _T('M'),
89  SWARA_M_Value = 3,
90  SWARA_P = _T('P'),
91  SWARA_P_Value = 4,
92  SWARA_D = _T('D'),
93  SWARA_D_Value = 5,
94  SWARA_N = _T('N'),
95  SWARA_N_Value = 6,
96  };
97 
98  /// <Summary> Note Modifiers</Summary>
99  enum NoteModifiers : TCHAR
100  {
101  NOTE_MODIFIER_SHARP = _T('#'), ///< Note Sharp symbol
102  NOTE_MODIFIER_FLAT = _T('B'), ///< Note Flat symbol
103  NOTE_MODIFIER_NATURAL = _T('N') ///< Note Natural symbol
104  };
105 
106  /// <Summary> Note Durations </Summary>
107  enum NoteDurations : TCHAR
108  {
109  NOTE_TIE = _T('-'), ///< Used when decorating durations for ties
110  NOTE_DURATION_NUMERIC = _T('/'), ///< Used when Duration is to be expressed as a numeric value
111  NOTE_DURATION_WHOLE = _T('W'), ///< Specifies Whole Note
112  NOTE_DURATION_HALF = _T('H'), ///< Specifies Half Note
113  NOTE_DURATION_QUARTER = _T('Q'), ///< Specifies Quarter Note
114  NOTE_DURATION_EIGTH = _T('I'), ///< Specifies One-Eight Note
115  NOTE_DURATION_SIXTEENTH = _T('S'), ///< Specifies One-Sixteenth Note
116  NOTE_DURATION_THIRTYSECOND = _T('T'), ///< Specifies One-ThirtySecond Note
117  NOTE_DURATION_SIXTYFOURTH = _T('X'), ///< Specifies One-SixtyFourth Note
118  NOTE_DURATION_128 = _T('O'), ///< Specifies 1/128th Note
119  NOTE_DURATION_DOT = _T('.'), ///< Specifies 1.5 times the normal duration
120  NOTE_TUPLET_START = _T('*'), ///< Indicates a Tuplet start
121  NOTE_TUPLET_RATIOMARK = _T(':'), ///< Indicates the Tuplet Ratio
122  SWARA_DURATION_ONE_EXTRA = _T(','), ///< Indicates one extra time unit [Carnatic Music Only]
123  SWARA_DURATION_TWO_EXTRA = _T(';'), ///< Indicates two extra time units [Carnatic Music Only]
124  };
125 
126  /// <Summary> Note Velocities </Summary>
127  enum NoteVelocities : TCHAR
128  {
129  NOTE_VELOCITY = _T('V'), ///< Note Attack Velocity specifier (Carnatic Mode)
130  NOTE_VELOCITY_ATTACK = _T('A'), ///< Note Attack Velocity specifier (Obsolete. only for compatability with JFugue)
131  NOTE_VELOCITY_DECAY = _T('D') ///< Note Decay Velocity specifier
132  };
133 
134  /// <Summary> Note Connectors </Summary>
135  enum NoteConnectors : TCHAR
136  {
137  NOTE_CONNECTOR_SEQUENTIAL = _T('_'), ///< Note Sequential connector symbol
138  NOTE_CONNECTOR_PARALLEL = _T('+') ///< Note Parallel connector symbol
139  };
140 
141  /// <Summary> Default Octave Values </Summary>
142  enum DefaultOctaves : long
143  {
144  DEFAULT_CHORD_OCTAVE = 3, ///< Default chord octave value
145  DEFAULT_NONCHORD_OCTAVE = 5, ///< Default non-chord note octave value
146  };
147 
148  /// <Summary> Note Shruti Modifiers </Summary>
149  enum NoteShrutis : TCHAR
150  {
151  NOTE_SHRUTI_UP = _T('\''), ///< Increments Note Shruti one level upward the Tara Sthayi
152  NOTE_SHRUTI_DOWN = _T('.'), ///< Decrements Note Shruti one level downward the Mandra Sthayi
153  };
154 
155  const Chords* m_pChords; // Holds the custom Chord Definitions, if any, supplied by user
156  DICTIONARY m_Dictionary; // Holds the default && custom MACRO definitions for Music Strings
157  KeySignature m_KeySig; // Holds the last seen Key Signature. Useful for computing Note value.
158 
159  unsigned short m_nDefNoteOctave; // Holds the Default Octave Value to be used for Notes
160  unsigned short m_nDefChordOctave; // Holds the Default Octave Value to be used for Chords
161 
162 
163  /// <Summary>
164  /// Parses a single token. To Parse a string that contains multiple tokens,
165  /// use the <code>Parse</code> method. We consider a string to be having multiple
166  /// tokens if there are whitespace charactes in it such as \\n \\t or Space.
167  ///
168  /// @param szToken The token to be parsed. We expect this to be a single token
169  /// free of any whitespace characters, such as \\t \\n or Space. If the input token
170  /// contains any of these characters, results are undefined.
171  ///
172  /// @param pbNonContinuableErrorOccured Indicates the event handlers' response to
173  /// the errors, if any. While calling ParseToken in a loop, when the return value
174  /// is false, use this value to check if you should continue further or exit now.
175  /// This usually will be the preference of errors handler procedures for the error.
176  /// You can ignore this parameter if you are not doing any error handling or if the
177  /// <code>ParseToken</code> is not called multiple times.
178  ///
179  /// @return -1 in case of failures, the number of characters consumed, otherwise.
180  ///
181  /// Note that it is possible to have a return value of -1, and *pbNonContinuableErrorOccured
182  /// as True or False. This happens when an event handler responding to the error modifies the
183  /// error continuability. In any case, return value of -1 indicates there was an error, but
184  /// if *pbNonContinuableErrorOccured is false, then an error event hanlder is asking you to ignore it.
185  /// </Summary>
186  int ParseToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured = NULL);
187 
188  public:
189  //typedef void (*TOKEN_HANDLER_PROC)(const TCHAR* );
190 
191  //struct TokenClassifierDef
192  //{
193  // MusicChar startChar;
194  // //TOKEN_HANDLER_PROC proc;
195  //};
196 
197  //const TokenClassifierDef* m_pDef;
198 
200  {
202  }
203 
204  /// <Summary>
205  /// Macros defined in the Music Strings are <i>remembered</i> across the Parse() method calls.
206  /// Call ResetDefinitions() before calling Parse() to clear the previous definitions.
207  /// </Summary>
209  {
210  m_Dictionary.clear();
211  PopulateStandardDefinitions(m_Dictionary); // Load standard macro definitions
214  m_pChords = NULL;
215  }
216 
217  /// Sets the KeySignature to be used for further Note parsing
218  /// @param keySig the KeySignature to be used
219  inline void SetKeySignature(const KeySignature& keySig) { m_KeySig = keySig; }
220  /// Returns the KeySignature being used
221  /// @return the KeySignature being used
222  inline const KeySignature& GetKeySignature() const { return m_KeySig; }
223  /// Sets the Default values for Note Octaves
224  inline void SetOctaveDefaults(unsigned short nNoteDefOctave = DEFAULT_NONCHORD_OCTAVE,
225  unsigned short nChordDefOctave = DEFAULT_CHORD_OCTAVE)
226  {
227  m_nDefNoteOctave = nNoteDefOctave;
228  m_nDefChordOctave = nChordDefOctave;
229  }
230 
231  /// <Summary>
232  /// \brief Resets the Chord definitions to the supplied values.
233  ///
234  /// A refernce to the supplied Chords object is stored by the Parser.
235  /// So, make sure the supplied Chords object stays valid as long as this
236  /// Parser object is valid.
237  ///
238  /// Since a reference is stored by the Parser, any modification you do for the
239  /// supplied Chords object will get refelected in the Parser too.
240  ///
241  /// See Chords::LoadDefinitions() and Chords::AddDefinitions() for more details.
242  /// </Summary>
243  inline void LoadChords(const Chords& chords)
244  {
245  m_pChords = &chords;
246  }
247 
248  /// <Summary>
249  /// Parses a string that contains multiple tokens. Raises appropriate events as and when
250  /// the tokens are parsed. We consider the input string to be having multiple
251  /// tokens seperated with whitespace charactes such as \\n \\t or Space. If there are no
252  /// whitespace characters, the whole string will be considered as a single token.
253  ///
254  /// Use MusicStringParser::AddListener method to get notified about the token events.
255  ///
256  /// @param szTokens The string to be parsed.
257  ///
258  /// @return True if success, False in case of any failures.
259  /// </Summary>
260  /// Example Usage:
261  /** <pre>
262  \#include "CFugueLib.h"
263 
264  void OnParseTrace(const CFugue::CParser*, CFugue::CParser::TraceEventHandlerArgs* pEvArgs)
265  {
266  OutputDebugString(_T("\n"));
267  OutputDebugString(pEvArgs->szTraceMsg);
268  }
269 
270  void OnParseError(const CFugue::CParser*, CFugue::CParser::ErrorEventHandlerArgs* pEvArgs)
271  {
272  OutputDebugString(_T("\nError --> "));
273  OutputDebugString(pEvArgs->szErrMsg);
274  if(pEvArgs->szToken)
275  {
276  OutputDebugString(_T("\t Token: "));
277  OutputDebugString(pEvArgs->szToken);
278  }
279  }
280 
281  CFugue::MusicStringParser Parser; // Create the Parser Object
282 
283  Parser.evTrace.Subscribe(&OnParseTrace); // To get notified about the Parse Trace Events
284  Parser.evError.Subscribe(&OnParseError); // To get notified about the Parse Error Events
285 
286  MIDIRenderer Renderer; // Create the Listener Object, in this case a MIDI Renderer
287  Parser.AddListener(&Renderer); // Add Renderer as a listener to get notified about the Tokens encountered during the Parse
288 
289  Parser.Parse(_T("I[Flute] C D E F G A B")); // Do the Parsing. Notifies the listeners during the process
290  </pre> */
291  bool Parse(const TCHAR* szTokens);
292 
293  private:
294  // Token Parserer Methods. Return value indicates the number of characters consumed. -1 for failure. 0 for none.
295  int ParseChannelPressureToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
296  int ParseControllerToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
297  int ParseDictionaryToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
298  int ParseInstrumentToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
299  int ParseKeyPressureToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
300  int ParseKeySignatureToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
301  int ParseLayerToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
302  int ParseMeasureToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
303  int ParseNoteToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
304  int ParsePitchBendToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
305  int ParseSpeedModulatorToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
306  int ParseTempoToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
307  int ParseTimeToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
308  int ParseVoiceToken(TCHAR* szToken, bool* pbNonContinuableErrorOccured);
309 
310  struct NoteContext : public Note
311  {
312  typedef ChordDef::HALFSTEP HALFSTEP;
313  bool isNumeric;
314  bool isChord;
315  bool isNatural;
316  bool existsAnotherNote;
317  bool anotherIsSequential;
318  bool anotherIsParallel;
319  short octaveNumber;
320  unsigned short numSwaras; // [Carnatic] No.of Swaras the note spans, such as Sa, Pa etc...
321  ChordDef chord; // Holds the Chord details, if isChord is true
322  NoteContext() :
323  isNumeric(0),
324  isChord(0),
325  isNatural(0),
326  existsAnotherNote(1),
327  anotherIsSequential(0),
328  anotherIsParallel(0),
329  octaveNumber(-1),
330  numSwaras(1)
331  {
332  }
333  };
334 
335  // Helper Methods
336  /// <Summary>Tests if a Note is known to be Sequential (connected with _)
337  /// or Parallel (connected with +) </Summary>
338  void DecideSequentialOrParallel(NoteContext& ctx);
339 
340  /// <Summary> Identifies Numeric, Rest, Letter Note types and calls the correct method.
341  /// Returns the index to start parsing the next part of the string </Summary>
342  int ParseNoteRoot(TCHAR* szToken, NoteContext& ctx);
343  /// <Summary> Parses Numeric Note.
344  /// Returns the number of characaters consumed from the string during the parsing </Summary>
345  int ParseNumericNote(TCHAR* szToken, NoteContext& ctx);
346  /// <Summary> Parses Rest Note.
347  /// Returns the number of characaters consumed from the string during the parsing </Summary>
348  int ParseRest(TCHAR* szToken, NoteContext& ctx);
349  /// <Summary> Parses Letters Notes (such as C, D, E etc...).
350  /// Returns the number of characaters consumed from the string during the parsing </Summary>
351  int ParseLetterNote(TCHAR* szToken, NoteContext& ctx);
352 
353  /// <Summary> Parses duration of note </Summary>
354  int ParseNoteDuration(TCHAR* szToken, NoteContext& ctx);
355  /// <Summary> Parses duration expressed as Alphabet W, H etc.. </Summary>
356  int ParseLetterDuration(TCHAR* szToken, NoteContext& ctx);
357  /// <Summary> Parses tuples expressed with * : </Summary>
358  int ParseTuplet(TCHAR* szToken, NoteContext& ctx);
359 
360  int ComputeNoteValue(NoteContext& ctx);
361 
362  /// <Summary> Parses Attack and Decay velocity of notes </Summary>
363  int ParseNoteVelocity(TCHAR* szToken, NoteContext& ctx);
364 
365  /// <Summary> Parses any associated note octave </Summary>
366  int ParseNoteOctave(TCHAR* szToken, NoteContext& ctx);
367  /// <Summary> Parses any chords specified for the note </Summary>
368  int ParseNoteChord(TCHAR* szToken, NoteContext& ctx);
369  /// <Summary> Parses any chord inversions specified for the note </Summary>
370  int ParseNoteChordInversion(TCHAR* szToken, NoteContext& ctx);
371  /// <Summary> Checks and Parses any associated notes </Summary>
372  int ParseNoteConnector(TCHAR* szToken, NoteContext& ctx);
373 
374  /// <Summary> Upon completion of parsing a Note token, raises the Events to process the Note</Summary>
375  void RaiseNoteEvents(NoteContext& ctx);
376 
377  /// <Summary>
378  /// Tries to load a value from Dictionary with the given key.
379  /// If the key is undefined, then itself is converted to the required type
380  /// and returned as the value.
381  ///
382  /// @return 0 in case of failures of lookup or conversion. Length of the string
383  /// scanned, in case of szKey being a number. To be ignored, if szKey is a macro.
384  /// </Summary>
385  template<typename T>
386  int GetValueFromDictionary(const TCHAR* szKey, T* pRetVal);
387 
388  /// <Summary>
389  /// Tries to read a number from the given token. The number might been
390  /// specified as a macro between the supplied MacroBracketStart and
391  /// MacroBracketEnd characters or as a direct number value.
392  ///
393  /// @return -1 in case of some irrovacable failures. Length of the string
394  /// scanned, otherwise. Check bSuccess if number was read successfully (despite errors).
395  /// </Summary>
396  template<typename T>
397  int ParseNumber(TCHAR* szToken, T* pRetVal, bool& bSuccess,
398  TCHAR MacroBracketStart, TCHAR MacroBracketEnd, ErrorCode MacroReadErrorCode, ErrorCode NumberParseErrorCode);
399 
400  };
401 
402 } // namespace CFugue
403 
404 #endif // __MUSICNOTEREADER_H__506A239B_50B0_472d_B070_69BFBEF3C6CB__
Signifies the Macro end symbol.
void SetOctaveDefaults(unsigned short nNoteDefOctave=DEFAULT_NONCHORD_OCTAVE, unsigned short nChordDefOctave=DEFAULT_CHORD_OCTAVE)
Sets the Default values for Note Octaves.
Note Attack Velocity specifier (Obsolete. only for compatability with JFugue)
Definition of a Chord entry.
Definition: Chords.h:19
const KeySignature & GetKeySignature() const
Increments Note Shruti one level upward the Tara Sthayi.
Signifies a Macro start symbol.
Implements a MusicString Parsing functionality
Specifies a seperator token for readability.
Specifies 1.5 times the normal duration.
bool Parse(const TCHAR *szTokens)
Used when Duration is to be expressed as a numeric value.
Used when decorating durations for ties.
Class representing the Key Signature.
Definition: KeySignature.h:79
Note Attack Velocity specifier (Carnatic Mode)
Maniuplates Chord definitions for Western Music
Definition: Chords.h:31
Specifies a Rest Note of one duration.
void SetKeySignature(const KeySignature &keySig)
Indicates two extra time units [Carnatic Music Only].
NoteShrutis
Note Shruti Modifiers
Specifies a Rest Note token [Western Music Only].
Class representing a Musical Note
Definition: Note.h:19
ErrorCode
Error code values used by ErrorEventHandlerArgs
Definition: Parser.h:99
void PopulateStandardDefinitions(DICTIONARY &dictionaryObj)
Accessor method to Populate standard macro definitions
Definition: Dictionary.cpp:10
std::map< MString, MString, StringLess< const TCHAR * > > DICTIONARY
Definition: Dictionary.h:37
DefaultOctaves
Default Octave Values
Default non-chord note octave value.
Specifies a Rest Note of two durations.
Base class that represents a Parser Object.
Definition: Parser.h:63
Indicates one extra time unit [Carnatic Music Only].
void LoadChords(const Chords &chords)
Resets the Chord definitions to the supplied values.
Declares KeySignature class used in CFugue MusicString.
int ParseToken(TCHAR *szToken, bool *pbNonContinuableErrorOccured=NULL)
Decrements Note Shruti one level downward the Mandra Sthayi.

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