/* test for zone overlap. the specified pitch range is inclusive. returns True */ /* if there is no overlap. */ public static bool MultiInstrSpecTestOverlap( MultiInstrSpecRec Spec, int BasePitch, int TopPitch) { #if DEBUG if ((BasePitch < 0) || (BasePitch > Constants.NUMNOTES - 1)) { // BasePitch out of range Debug.Assert(false); throw new ArgumentException(); } if ((TopPitch < 0) || (TopPitch > Constants.NUMNOTES - 1)) { // TopPitch out of range Debug.Assert(false); throw new ArgumentException(); } if (TopPitch < BasePitch) { // Pitch range is inverted Debug.Assert(false); throw new ArgumentException(); } #endif for (int i = 0; i < Spec.Array.Length; i++) { if (((Spec.Array[i].BasePitch >= BasePitch) && (Spec.Array[i].BasePitch <= TopPitch)) || ((Spec.Array[i].TopPitch >= BasePitch) && (Spec.Array[i].TopPitch <= TopPitch))) { return(false); } } return(true); }
/* create a new multi-instrument spec */ public static MultiInstrSpecRec NewMultiInstrSpec() { MultiInstrSpecRec Spec = new MultiInstrSpecRec(); Spec.Array = new ZoneRec[0]; return(Spec); }
/* add pitch zone to multi-instrument spec. returns False if it runs out of memory. */ /* the specified pitch range is inclusive. */ public static void MultiInstrSpecAddZone( MultiInstrSpecRec Spec, string InstrName, int BasePitch, int TopPitch, int EffectiveBasePitch) { #if DEBUG if ((BasePitch < 0) || (BasePitch > Constants.NUMNOTES - 1)) { // BasePitch out of range Debug.Assert(false); throw new ArgumentException(); } if ((TopPitch < 0) || (TopPitch > Constants.NUMNOTES - 1)) { // TopPitch out of range Debug.Assert(false); throw new ArgumentException(); } if (TopPitch < BasePitch) { // Pitch range is inverted Debug.Assert(false); throw new ArgumentException(); } if ((EffectiveBasePitch < 0) || (EffectiveBasePitch > Constants.NUMNOTES - 1)) { // EffectiveBasePitch out of range Debug.Assert(false); throw new ArgumentException(); } if (!MultiInstrSpecTestOverlap(Spec, BasePitch, TopPitch)) { // Pitch range overlaps existing range Debug.Assert(false); throw new ArgumentException(); } #endif ZoneRec Zone = new ZoneRec(); Zone.InstrName = InstrName; Zone.BasePitch = (short)BasePitch; Zone.TopPitch = (short)TopPitch; Zone.EffectiveBasePitch = (short)EffectiveBasePitch; Array.Resize(ref Spec.Array, Spec.Array.Length + 1); Spec.Array[Spec.Array.Length - 1] = Zone; }
/* create multi-instrument spec from string */ public static MultiInstrParseError MultiInstrParse( out MultiInstrSpecRec Spec, string String) { Spec = NewMultiInstrSpec(); ScannerRec <MultiInstrKeywords> Scanner = new ScannerRec <MultiInstrKeywords>(String, MultiInstrKeywordTable); /* parse all the thingies */ while (true) { TokenRec <MultiInstrKeywords> Token; string InstrName; int BasePitch; int TopPitch; int EffectiveBasePitch; int Sign; /* end of input, or "instrname" */ Token = Scanner.GetNextToken(); if (Token.GetTokenType() == TokenTypes.eTokenEndOfInput) { return(MultiInstrParseError.eMultiInstrParseOK); } if (Token.GetTokenType() != TokenTypes.eTokenString) { return(MultiInstrParseError.eMultiInstrParseExpectedInstrNameString); } InstrName = Token.GetTokenStringValue(); /* base pitch */ /* letter */ Token = Scanner.GetNextToken(); if (Token.GetTokenType() != TokenTypes.eTokenKeyword) { return(MultiInstrParseError.eMultiInstrParseExpectedPitchLetter); } switch (Token.GetTokenKeywordTag()) { default: return(MultiInstrParseError.eMultiInstrParseExpectedPitchLetter); case MultiInstrKeywords.eMIK_C: BasePitch = Constants.CENTERNOTE; break; case MultiInstrKeywords.eMIK_D: BasePitch = Constants.CENTERNOTE + 2; break; case MultiInstrKeywords.eMIK_E: BasePitch = Constants.CENTERNOTE + 4; break; case MultiInstrKeywords.eMIK_F: BasePitch = Constants.CENTERNOTE + 5; break; case MultiInstrKeywords.eMIK_G: BasePitch = Constants.CENTERNOTE + 7; break; case MultiInstrKeywords.eMIK_A: BasePitch = Constants.CENTERNOTE + 9; break; case MultiInstrKeywords.eMIK_B: BasePitch = Constants.CENTERNOTE + 11; break; } Token = Scanner.GetNextToken(); /* optional "flat" or "sharp" */ if (Token.GetTokenType() == TokenTypes.eTokenKeyword) { if (Token.GetTokenKeywordTag() == MultiInstrKeywords.eMIK_flat) { BasePitch -= 1; } else if (Token.GetTokenKeywordTag() == MultiInstrKeywords.eMIK_sharp) { BasePitch += 1; } else { return(MultiInstrParseError.eMultiInstrParseExpectedFlatOrSharp); } Token = Scanner.GetNextToken(); } /* octave number */ Sign = 1; if (Token.GetTokenType() == TokenTypes.eTokenMinus) { Sign = -1; Token = Scanner.GetNextToken(); } if (Token.GetTokenType() != TokenTypes.eTokenInteger) { return(MultiInstrParseError.eMultiInstrParseExpectedFlatOrSharpOrOctave); } BasePitch += 12 * Sign * Token.GetTokenIntegerValue(); if ((BasePitch < 0) || (BasePitch > Constants.NUMNOTES - 1)) { return(MultiInstrParseError.eMultiInstrParseBasePitchOutOfRange); } Token = Scanner.GetNextToken(); if ((Token.GetTokenType() != TokenTypes.eTokenKeyword) || (Token.GetTokenKeywordTag() != MultiInstrKeywords.eMIK_to)) { return(MultiInstrParseError.eMultiInstrParseExpectedTo); } /* top pitch */ /* letter */ Token = Scanner.GetNextToken(); if (Token.GetTokenType() != TokenTypes.eTokenKeyword) { return(MultiInstrParseError.eMultiInstrParseExpectedPitchLetter); } switch (Token.GetTokenKeywordTag()) { default: return(MultiInstrParseError.eMultiInstrParseExpectedPitchLetter); case MultiInstrKeywords.eMIK_C: TopPitch = Constants.CENTERNOTE; break; case MultiInstrKeywords.eMIK_D: TopPitch = Constants.CENTERNOTE + 2; break; case MultiInstrKeywords.eMIK_E: TopPitch = Constants.CENTERNOTE + 4; break; case MultiInstrKeywords.eMIK_F: TopPitch = Constants.CENTERNOTE + 5; break; case MultiInstrKeywords.eMIK_G: TopPitch = Constants.CENTERNOTE + 7; break; case MultiInstrKeywords.eMIK_A: TopPitch = Constants.CENTERNOTE + 9; break; case MultiInstrKeywords.eMIK_B: TopPitch = Constants.CENTERNOTE + 11; break; } Token = Scanner.GetNextToken(); /* optional "flat" or "sharp" */ if (Token.GetTokenType() == TokenTypes.eTokenKeyword) { if (Token.GetTokenKeywordTag() == MultiInstrKeywords.eMIK_flat) { TopPitch -= 1; } else if (Token.GetTokenKeywordTag() == MultiInstrKeywords.eMIK_sharp) { TopPitch += 1; } else { return(MultiInstrParseError.eMultiInstrParseExpectedFlatOrSharp); } Token = Scanner.GetNextToken(); } /* octave number */ Sign = 1; if (Token.GetTokenType() == TokenTypes.eTokenMinus) { Sign = -1; Token = Scanner.GetNextToken(); } if (Token.GetTokenType() != TokenTypes.eTokenInteger) { return(MultiInstrParseError.eMultiInstrParseExpectedFlatOrSharpOrOctave); } TopPitch += 12 * Sign * Token.GetTokenIntegerValue(); if ((TopPitch < 0) || (TopPitch > Constants.NUMNOTES - 1)) { return(MultiInstrParseError.eMultiInstrParseTopPitchOutOfRange); } Token = Scanner.GetNextToken(); if ((Token.GetTokenType() != TokenTypes.eTokenKeyword) || (Token.GetTokenKeywordTag() != MultiInstrKeywords.eMIK_as)) { return(MultiInstrParseError.eMultiInstrParseExpectedAs); } /* effective base pitch */ /* letter */ Token = Scanner.GetNextToken(); if (Token.GetTokenType() != TokenTypes.eTokenKeyword) { return(MultiInstrParseError.eMultiInstrParseExpectedPitchLetter); } switch (Token.GetTokenKeywordTag()) { default: return(MultiInstrParseError.eMultiInstrParseExpectedPitchLetter); case MultiInstrKeywords.eMIK_C: EffectiveBasePitch = Constants.CENTERNOTE; break; case MultiInstrKeywords.eMIK_D: EffectiveBasePitch = Constants.CENTERNOTE + 2; break; case MultiInstrKeywords.eMIK_E: EffectiveBasePitch = Constants.CENTERNOTE + 4; break; case MultiInstrKeywords.eMIK_F: EffectiveBasePitch = Constants.CENTERNOTE + 5; break; case MultiInstrKeywords.eMIK_G: EffectiveBasePitch = Constants.CENTERNOTE + 7; break; case MultiInstrKeywords.eMIK_A: EffectiveBasePitch = Constants.CENTERNOTE + 9; break; case MultiInstrKeywords.eMIK_B: EffectiveBasePitch = Constants.CENTERNOTE + 11; break; } Token = Scanner.GetNextToken(); /* optional "flat" or "sharp" */ if (Token.GetTokenType() == TokenTypes.eTokenKeyword) { if (Token.GetTokenKeywordTag() == MultiInstrKeywords.eMIK_flat) { EffectiveBasePitch -= 1; } else if (Token.GetTokenKeywordTag() == MultiInstrKeywords.eMIK_sharp) { EffectiveBasePitch += 1; } else { return(MultiInstrParseError.eMultiInstrParseExpectedFlatOrSharp); } Token = Scanner.GetNextToken(); } /* octave number */ Sign = 1; if (Token.GetTokenType() == TokenTypes.eTokenMinus) { Sign = -1; Token = Scanner.GetNextToken(); } if (Token.GetTokenType() != TokenTypes.eTokenInteger) { return(MultiInstrParseError.eMultiInstrParseExpectedFlatOrSharpOrOctave); } EffectiveBasePitch += 12 * Sign * Token.GetTokenIntegerValue(); if ((EffectiveBasePitch < 0) || (EffectiveBasePitch > Constants.NUMNOTES - 1)) { return(MultiInstrParseError.eMultiInstrParseTopPitchOutOfRange); } Token = Scanner.GetNextToken(); if (Token.GetTokenType() != TokenTypes.eTokenSemicolon) { return(MultiInstrParseError.eMultiInstrParseExpectedSemicolon); } /* put value */ if (BasePitch > TopPitch) { return(MultiInstrParseError.eMultiInstrParseInvertedRange); } if (!MultiInstrSpecTestOverlap( Spec, BasePitch, TopPitch)) { return(MultiInstrParseError.eMultiInstrParseOverlapExistingRange); } MultiInstrSpecAddZone( Spec, InstrName, BasePitch, TopPitch, EffectiveBasePitch); } }
/* get effective base pitch of the zone's range */ public static short MultiInstrSpecGetIndexedEffectiveBasePitch( MultiInstrSpecRec Spec, int Index) { return(Spec.Array[Index].EffectiveBasePitch); }
/* get top pitch of the zone's range */ public static short MultiInstrSpecGetIndexedTopPitch( MultiInstrSpecRec Spec, int Index) { return(Spec.Array[Index].TopPitch); }
/* get actual instrument name for the specified zone */ public static string MultiInstrSpecGetIndexedActualInstrName( MultiInstrSpecRec Spec, int Index) { return(Spec.Array[Index].InstrName); }
/* get number of instruments */ public static int MultiInstrSpecGetLength(MultiInstrSpecRec Spec) { return(Spec.Array.Length); }
/* add maximum zone */ public static void MultiInstrSpecAddMaximumDefaultZone( MultiInstrSpecRec Spec, string InstrName) { MultiInstrSpecAddZone(Spec, InstrName, 0, Constants.NUMNOTES - 1, 0); }