/* SymbolicPitch.c */
/*****************************************************************************/
/*                                                                           */
/*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
/*    Copyright (C) 1994  Thomas R. Lawrence                                 */
/*                                                                           */
/*    This program is free software; you can redistribute it and/or modify   */
/*    it under the terms of the GNU General Public License as published by   */
/*    the Free Software Foundation; either version 2 of the License, or      */
/*    (at your option) any later version.                                    */
/*                                                                           */
/*    This program is distributed in the hope that it will be useful,        */
/*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/*    GNU General Public License for more details.                           */
/*                                                                           */
/*    You should have received a copy of the GNU General Public License      */
/*    along with this program; if not, write to the Free Software            */
/*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
/*                                                                           */
/*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
/*                                                                           */
/*****************************************************************************/

#include "MiscInfo.h"
#include "Audit.h"
#include "Debug.h"
#include "Definitions.h"

#include "SymbolicPitch.h"
#include "Frequency.h"
#include "DataMunging.h"
#include "Memory.h"
#include "NoteObject.h"
#include "Numbers.h"
#include "SymbolicIsItInThere.h"


/* convert a pitch number into a heap allocated string describing it */
char*						NumericPitchToString(short Pitch, unsigned long SharpFlatThing)
	{
		long					Octave;
		long					NoteIndex;
		char*					NullTerminatedNoteSymbol;
		char*					OctaveNumber;
		char*					ReturnString;

		/* find out what octave */
		Octave = (Pitch / 12);
		NoteIndex = Pitch % 12;

		/* figure out what note symbol to use */
		switch (NoteIndex)
			{
				default:
					EXECUTE(PRERR(ForceAbort,"NumericPitchToString:  bizarre % error"));
					break;
				case 0: /* B#/C */
					if ((SharpFlatThing & eSharpModifier) != 0)
						{
							NullTerminatedNoteSymbol = "B sharp ";
						}
					else
						{
							NullTerminatedNoteSymbol = "C ";
						}
					break;
				case 1: /* C#/Db */
					if ((SharpFlatThing & eSharpModifier) != 0)
						{
							NullTerminatedNoteSymbol = "C sharp ";
						}
					 else
						{
							NullTerminatedNoteSymbol = "D flat ";
						}
					break;
				case 2: /* D */
					NullTerminatedNoteSymbol = "D ";
					break;
				case 3: /* D#/Eb */
					if ((SharpFlatThing & eSharpModifier) != 0)
						{
							NullTerminatedNoteSymbol = "D sharp ";
						}
					 else
						{
							NullTerminatedNoteSymbol = "E flat ";
						}
					break;
				case 4: /* E/Fb */
					if ((SharpFlatThing & eFlatModifier) != 0)
						{
							NullTerminatedNoteSymbol = "F flat ";
						}
					 else
						{
							NullTerminatedNoteSymbol = "E ";
						}
					break;
				case 5: /* E#/F */
					if ((SharpFlatThing & eSharpModifier) != 0)
						{
							NullTerminatedNoteSymbol = "E sharp ";
						}
					 else
						{
							NullTerminatedNoteSymbol = "F ";
						}
					break;
				case 6: /* F#/Gb */
					if ((SharpFlatThing & eSharpModifier) != 0)
						{
							NullTerminatedNoteSymbol = "F sharp ";
						}
					 else
						{
							NullTerminatedNoteSymbol = "G flat ";
						}
					break;
				case 7: /* G */
					NullTerminatedNoteSymbol = "G ";
					break;
				case 8: /* G#/Ab */
					if ((SharpFlatThing & eSharpModifier) != 0)
						{
							NullTerminatedNoteSymbol = "G sharp ";
						}
					 else
						{
							NullTerminatedNoteSymbol = "A flat ";
						}
					break;
				case 9: /* A */
					NullTerminatedNoteSymbol = "A ";
					break;
				case 10: /* A#/Bb */
					if ((SharpFlatThing & eSharpModifier) != 0)
						{
							NullTerminatedNoteSymbol = "A sharp ";
						}
					 else
						{
							NullTerminatedNoteSymbol = "B flat ";
						}
					break;
				case 11: /* B/Cb */
					if ((SharpFlatThing & eFlatModifier) != 0)
						{
							NullTerminatedNoteSymbol = "C flat ";
						}
					 else
						{
							NullTerminatedNoteSymbol = "B ";
						}
					break;
			}

		ReturnString = NIL;

		/* figure out octave */
		OctaveNumber = IntegerToString(Octave - (CENTERNOTE / 12));
		if (OctaveNumber != NIL)
			{
				char*					SymbolNoNull;

				SymbolNoNull = StringToBlockCopy(NullTerminatedNoteSymbol);
				if (SymbolNoNull != NIL)
					{
						ReturnString = ConcatBlockCopy(SymbolNoNull,OctaveNumber);
						if (ReturnString != NIL)
							{
								SetTag(ReturnString,"NumericPitchToString");
							}
						ReleasePtr(SymbolNoNull);
					}
				ReleasePtr(OctaveNumber);
			}

		return ReturnString;
	}


/* convert the string into a pitch and sharp/flat word. */
void						StringToNumericPitch(char* String, short* Pitch,
									unsigned long* SharpFlatThing)
	{
		long					LocalPitch;
		long					Octave;
		long					Index;

		CheckPtrExistence(String);
		LocalPitch = (*Pitch) % 12; /* get the default */
		Octave = (*Pitch) / 12; /* defaults */

		if (PtrSize(String) == 0)
			{
				/* return without changing anything */
				return;
			}

		/* check the pitch specifier */
		switch (String[0])
			{
				default:
					break;
				case 'a': case 'A':
					if (IsItInThere(String,"sharp") || IsItInThere(String,"#"))
						{
							/* A# */
							LocalPitch = 9 + 1;
							*SharpFlatThing = eSharpModifier;
						}
					else if (IsItInThere(String,"flat"))
						{
							/* Ab */
							LocalPitch = 9 - 1;
							*SharpFlatThing = eFlatModifier;
						}
					else
						{
							/* A */
							LocalPitch = 9;
							*SharpFlatThing = 0;
						}
					break;
				case 'B': case 'b':
					if (IsItInThere(String,"sharp") || IsItInThere(String,"#"))
						{
							/* B# */
							LocalPitch = 11 + 1;
							*SharpFlatThing = eSharpModifier;
						}
					else if (IsItInThere(String,"flat"))
						{
							/* Bb */
							LocalPitch = 11 - 1;
							*SharpFlatThing = eFlatModifier;
						}
					else
						{
							/* B */
							LocalPitch = 11;
							*SharpFlatThing = 0;
						}
					break;
				case 'C': case 'c':
					if (IsItInThere(String,"sharp") || IsItInThere(String,"#"))
						{
							/* C# */
							LocalPitch = 0 + 1;
							*SharpFlatThing = eSharpModifier;
						}
					else if (IsItInThere(String,"flat"))
						{
							/* Cb */
							LocalPitch = 0 - 1 + 12;
							*SharpFlatThing = eFlatModifier;
						}
					else
						{
							/* C */
							LocalPitch = 0;
							*SharpFlatThing = 0;
						}
					break;
				case 'D': case 'd':
					if (IsItInThere(String,"sharp") || IsItInThere(String,"#"))
						{
							/* D# */
							LocalPitch = 2 + 1;
							*SharpFlatThing = eSharpModifier;
						}
					else if (IsItInThere(String,"flat"))
						{
							/* Db */
							LocalPitch = 2 - 1;
							*SharpFlatThing = eFlatModifier;
						}
					else
						{
							/* D */
							LocalPitch = 2;
							*SharpFlatThing = 0;
						}
					break;
				case 'E': case 'e':
					if (IsItInThere(String,"sharp") || IsItInThere(String,"#"))
						{
							/* E# */
							LocalPitch = 4 + 1;
							*SharpFlatThing = eSharpModifier;
						}
					else if (IsItInThere(String,"flat"))
						{
							/* Eb */
							LocalPitch = 4 - 1;
							*SharpFlatThing = eFlatModifier;
						}
					else
						{
							/* E */
							LocalPitch = 4;
							*SharpFlatThing = 0;
						}
					break;
				case 'F': case 'f':
					if (IsItInThere(String,"sharp") || IsItInThere(String,"#"))
						{
							/* F# */
							LocalPitch = 5 + 1;
							*SharpFlatThing = eSharpModifier;
						}
					else if (IsItInThere(String,"flat"))
						{
							/* Fb */
							LocalPitch = 5 - 1;
							*SharpFlatThing = eFlatModifier;
						}
					else
						{
							/* F */
							LocalPitch = 5;
							*SharpFlatThing = 0;
						}
					break;
				case 'G': case 'g':
					if (IsItInThere(String,"sharp") || IsItInThere(String,"#"))
						{
							/* G# */
							LocalPitch = 7 + 1;
							*SharpFlatThing = eSharpModifier;
						}
					else if (IsItInThere(String,"flat"))
						{
							/* Gb */
							LocalPitch = 7 - 1;
							*SharpFlatThing = eFlatModifier;
						}
					else
						{
							/* G */
							LocalPitch = 7;
							*SharpFlatThing = 0;
						}
					break;
			}

		/* try to figure out what octave they want */
		Index = 0;
		while ((Index < PtrSize(String)) && (String[Index] != '-')
			&& ((String[Index] < '0') || (String[Index] > '9')))
			{
				Index += 1;
			}
		if (Index < PtrSize(String))
			{
				Octave = StringToInteger(&(String[Index]),PtrSize(String) - Index);
			}
		if ((Octave * 12) + CENTERNOTE < 0)
			{
				Octave = - CENTERNOTE / 12;
			}
		if ((Octave * 12) + CENTERNOTE > NUMNOTES - 1)
			{
				Octave = CENTERNOTE / 12 - 1;
			}

		*Pitch = ((Octave + (CENTERNOTE / 12)) * 12) + LocalPitch;
	}
