/*************************************************************************//** * @} * @defgroup SongStatFunc Static Functions * @ingroup DocSong * Functions related to @link Song Songs@endlink that can be used without having to have an actual instance of a Song. * @{ *****************************************************************************/ /** * @brief Gets the number of waveform samples required to accurately represent the @link Music::NOTE_LENGTH_BASE length of a note@endlink for a given @link DefBPM BPM@endlink and @link Music::TimeSignature time signature@endlink. * @param[in] aBPM The @link DefBPM BPM@endlink that should be accounted for. * @param[in] aSampleRate The sample rate of the note. Might need to remove since most likely everything's going to have a 44\.1KHz sample rate. * @param[in] aNoteLength The @link Music::NOTE_LENGTH_BASE note length@endlink that's being converted into a number of waveform samples. * @param[in] aTimeSignature The @link Music::TimeSignature time signature@endlink that should be accounted for. * @return The number of waveform samples that represents the given @link Music::NOTE_LENGTH_BASE note length@endlink at the given @link DefBPM BPM@endlink and @link Music::TimeSignature time signature@endlink. * */ public static int GetNoteLengthInSamples(int aBPM, int aSampleRate, Music.NoteLength aNoteLength, Music.TimeSignature aTimeSignature) { // Initialize variables for calculating the note length. float beatsPerSecond = (float)aBPM / 60f; // Since the audio data is split into two channels with even indices for the data // in the left channel and odd indices for the data in the right channel, the // actual conversion for number of samples per second is 2 * sample rate. float numSamplesPerBeat = 2f * (1f / beatsPerSecond) * (float)aSampleRate; // Calculate the length for various time signatures by relating the base beat to // a quarter note. float numQuarterNotesPerBeat = 1f; // Right now, only provide support for base beats of 4 and 8. switch (aTimeSignature.BaseBeat) { case Music.NOTE_LENGTH_BASE.E: numQuarterNotesPerBeat /= 2f; break; default: break; } // Calculate the note length in samples. return((int)(numSamplesPerBeat * (Music.GetNoteLengthRelativeToQuarterNote(aNoteLength) * numQuarterNotesPerBeat))); }
/** * @brief Sets the @link Music::NoteLength note length@endlink for the panel. * @param[in] aNoteLength The @link Music::NoteLength note length@endlink for the panel. */ public void SetSelected(Music.NoteLength aNoteLength) { mNoteLength = aNoteLength; mDotToggle.isOn = aNoteLength.Dot; mTripletToggle.isOn = aNoteLength.Triplet; mBaseLengthToggles[(int)aNoteLength.BaseLength].isOn = true; UpdateGraphics(); }
/** * @brief Handles @link Music::PITCH pitches@endlink being added. * @param[in] aPitches The selected @link Music::PITCH pitches@endlink. * @param[in] aLength The selected @link Music::NoteLength length@endlink. * @param[in] aVelocity The selected @link DefVel velocity@endlink. */ private void OnPitchesAdded(Music.PITCH[] aPitches, Music.NoteLength aLength, int aVelocity) { // Add the pitches to the display container and the melody note. foreach (Music.PITCH pitch in aPitches) { // Create a pitch/drum display panel and get its script. GameObject clone = Instantiate(Resources.Load <GameObject>(PDDP_PREFAB_PATH)); SC_PitchDrumDisplayPanel newPanel = clone.AddComponent <SC_PitchDrumDisplayPanel>(); // Initialize the panel's values and add it to the list. newPanel.InitializeAsPitchDisplay(pitch, aLength, aVelocity); newPanel.SetParentContainer(this); mPitches.Add(newPanel); // Put the new panel in the melody display. clone.transform.SetParent(mMelodyDisplay, false); } UpdateDoneButton(); }
/** * @brief Sets up the SC_PitchDrumDisplayPanel as a display panel for @link Music::PITCH pitches@endlink. * @param[in] aPitch The @link Music::PITCH pitch@endlink that is being represented. * @param[in] aLength @copydoc SC_PitchDrumDisplayPanel::mLength * @param[in] aNoteVelocity @copydoc SC_PitchDrumDisplayPanel::mNoteVelocity */ public void InitializeAsPitchDisplay(Music.PITCH aPitch, Music.NoteLength aLength, int aNoteVelocity) { // Set that the panel is not representing drums. mIsDrum = false; // Set the pitch. mPitch = aPitch; // Set the pitch display text. mPitchDisplay.text = "Pitch:\n" + Music.NoteToString(aPitch); // Set the length. mLength = aLength; // See if we need to set the length image.. if (aLength.BaseLength == Music.NOTE_LENGTH_BASE.NONE) { mLengthPanel.SetActive(false); mDotModifierPanel.SetActive(false); mTripletModifierPanel.SetActive(false); } else { // Set the length image. mLengthPanel.transform.GetChild(1).GetComponent <Image>().sprite = Music.GetImageForNoteLength(aLength.BaseLength); // Set the modifier images. if (!aLength.Dot) { mDotModifierPanel.SetActive(false); } if (!aLength.Triplet) { mTripletModifierPanel.SetActive(false); } } // Set the velocity. mNoteVelocity = aNoteVelocity; mNoteVelocityHandler.SetValue(aNoteVelocity); }
/** * @brief Handles the Add Note button being clicked by loading a @link DocSC_NDia Note Dialog@endlink. */ public void OnNewNoteButtonClicked() { // Load the dialog. GameObject dialogObj = Instantiate(Resources.Load <GameObject>(NOTE_DIALOG_PATH)); dialogObj.transform.SetParent(transform, true); SC_NoteDialog dialog = dialogObj.transform.GetChild(0).GetComponent <SC_NoteDialog>(); // Get the initial offset for the note dialog. Music.NoteLength dialogOffset = new Music.NoteLength(Music.NOTE_LENGTH_BASE.NONE); if (mSong.GetNumNotes() > 0) { // Get the last note to find the initial offset. int lastNoteIndex = mSong.GetNumNotes() - 1; Music.CombinedNote lastNote = mSong.GetNote(lastNoteIndex); // If there are pitches in the last note, then set the dialog's offset to // be the shortest length of all of the pitches in the last note. if (lastNote.NumPitches > 0) { Music.NoteLength shortestLength = lastNote.MusicalNote.Lengths[0]; for (int i = 1; i < lastNote.NumPitches; i++) { if (lastNote.MusicalNote.Lengths[i] < shortestLength) { shortestLength = lastNote.MusicalNote.Lengths[i]; } } dialogOffset = shortestLength; } // If there are not pitches in the last note, then set it to // the last note's offset. else { dialogOffset = lastNote.OffsetFromPrevNote; } } dialog.SetDefaultOffset(dialogOffset); dialog.NoteDialogFinished.AddListener(OnCreateNote); }
/** * @brief Updates the todoclength panel when a todocnote is loaded into the display panel. * @param[in] aNote The todocnote to display */ private void UpdateLengthPanel() { // Set the length panel. mLengthPanel.gameObject.SetActive(true); if (mNote.NumPitches > 0) { // See whether or not there are multiple lengths. int index = 1; bool multiple = false; Music.NoteLength firstLength = mNote.MusicalNote.Lengths[0]; while (index < mNote.NumPitches && !multiple) { if (mNote.MusicalNote.Lengths[index] != firstLength) { multiple = true; } index++; } // Display that there are multiple lengths if needed. if (multiple) { mMultipleLengthText.gameObject.SetActive(true); mNoLengthText.gameObject.SetActive(false); mBaseLengthPanel.gameObject.SetActive(false); mDotLengthPanel.gameObject.SetActive(false); mTripletLengthPanel.gameObject.SetActive(false); } // Display the common length if all pitches have the same length. else { mMultipleLengthText.gameObject.SetActive(false); // If the length is none, then display it. if (firstLength.BaseLength == Music.NOTE_LENGTH_BASE.NONE) { mNoLengthText.gameObject.SetActive(true); } // Display the length as an image if there is a length. else { mNoLengthText.gameObject.SetActive(false); mBaseLengthPanel.gameObject.SetActive(true); mBaseLengthPanel.GetChild(0).GetComponent <Image>().sprite = Music.GetImageForNoteLength(firstLength.BaseLength); // Display the length modifiers if needed. mDotLengthPanel.gameObject.SetActive(firstLength.Dot); mTripletLengthPanel.gameObject.SetActive(firstLength.Triplet); } } } // Handle when there are no pitches else { mNoLengthText.gameObject.SetActive(true); mBaseLengthPanel.gameObject.SetActive(false); mDotLengthPanel.gameObject.SetActive(false); mTripletLengthPanel.gameObject.SetActive(false); mMultipleLengthText.gameObject.SetActive(false); } }
/** * @brief Handles the done button being clicked. */ private void OnDoneButtonClicked() { // Set up the pitches. int numPitches = mPitches.Count; Music.PITCH[] pitches = null; int[] pitchVelocities = null; Music.NoteLength[] lengths = null; // If there are pitches, then get them from the panels. if (numPitches != 0) { // Get all of the pitches, velocities, and lengths. pitches = new Music.PITCH[numPitches]; pitchVelocities = new int[numPitches]; lengths = new Music.NoteLength[numPitches]; int index = 0; foreach (SC_PitchDrumDisplayPanel pitch in mPitches) { pitches[index] = pitch.GetPitch(); pitchVelocities[index] = pitch.GetNoteVelocity(); lengths[index] = pitch.GetLengthOfPitch(); index++; } } // Create the melody note. Music.MelodyNote melody = new Music.MelodyNote(pitchVelocities, lengths, pitches); // Set up the drums. int numDrums = mDrums.Count; Music.DRUM[] drums = null; int[] drumVelocities = null; // If there are drums, then get them from the panels. if (numDrums != 0) { // Get all of the drums and their velocities. drums = new Music.DRUM[numDrums]; drumVelocities = new int[numDrums]; int index = 0; foreach (SC_PitchDrumDisplayPanel drum in mDrums) { drums[index] = drum.GetDrum(); drumVelocities[index] = drum.GetNoteVelocity(); index++; } } // Create the percussion note. Music.PercussionNote percussion = new Music.PercussionNote(drumVelocities, drums); // Get the offset of the note. Music.NoteLength offset = mOffsetPanel.GetSelected(); // Create the note. Music.CombinedNote note = new Music.CombinedNote(melody, percussion, offset); // Invoke the event which signals the dialog being finished. NoteDialogFinished.Invoke(note); // Self-destruct. DestroyImmediate(transform.parent.gameObject, false); }
/** * @brief Sets the default todocoffset for the dialog. Usually based on the previous todocnote in the Song. * @param[in] aOffset The default todocoffset. */ public void SetDefaultOffset(Music.NoteLength aOffset) { mOffsetPanel.SetSelected(aOffset); }
/*************************************************************************//** * @} * @defgroup SC_APDHandlers Event Handlers * @ingroup DocSC_APD * These are functions called by the SC_AddPitchDialog in order to handle events. * @{ *****************************************************************************/ /** * @brief Sets the default length * @param[in] aLength The default length */ public void SetDefaultLength(Music.NoteLength aLength) { mLengthSelector.SetSelected(aLength); }
/*************************************************************************//** * @} * @defgroup SongPrivFunc Private Functions * @ingroup DocSong * Functions used internally by the Song. * @{ *****************************************************************************/ /** * @brief Loads a @link DocSongFileFormat Song file@endlink and uses it to set the values for this Song. * @param[in] aSongFilePath The path to the Song file. * @see @link DocSongFileFormat Song File Format@endlink */ private void LoadSongFromFile(string aSongFilePath) { // Create some variables for parsing the file. Music.PITCH[] curNotePitches = null; Music.DRUM[] curNoteDrums = null; Music.NoteLength[] curNoteLengths = null; List <Music.CombinedNote> notesInFile = new List <Music.CombinedNote>(); int splitLineIndex = 0; int[] curNoteMelodyVelocities = null; int[] curNoteDrumVelocities = null; // Open the file stream. StreamReader parser = new StreamReader(aSongFilePath); // Get the name of the Song string curLine = parser.ReadLine(); mName = curLine; // Get the Song type. curLine = parser.ReadLine(); string[] splitLine = curLine.Split(';'); mType = (SongType)int.Parse(splitLine[0]); // Get the default BPM mBPM = int.Parse(splitLine[1]); // Get the time signature mTimeSignature.BeatsPerMeasure = int.Parse(splitLine[2]); mTimeSignature.BaseBeat = (Music.NOTE_LENGTH_BASE) int.Parse(splitLine[3]); // Get the notes of the Song. curLine = parser.ReadLine(); while (curLine != null) { // Get the line and reset the split line index. splitLine = curLine.Split(';'); splitLineIndex = 0; // Get the pitches for the note if needed. if (mType != SongType.DrumLoop) { curNotePitches = ParsePitches(splitLine[splitLineIndex]); } // Get the drums for the note if needed. if (mType != SongType.Melody) { curNoteDrums = ParseDrums(splitLine[splitLineIndex]); } // Go to the next section of the line. splitLineIndex++; // If needed, get the melody note lengths. if (mType != SongType.DrumLoop) { // Reset the note length array. curNoteLengths = null; // See if there are lengths for the note. if (splitLine[splitLineIndex] != "null") { // Get the lengths string[] lengths = splitLine[splitLineIndex].Split(','); curNoteLengths = new Music.NoteLength[lengths.Length]; for (int i = 0; i < curNoteLengths.Length; i++) { // Use the constructor for the NoteLength struct that takes a string parameter. curNoteLengths[i] = new Music.NoteLength(lengths[i]); } lengths = null; } // Go to the next section. splitLineIndex++; } // Get the offset from the previous note. Music.NoteLength offset = new Music.NoteLength(splitLine[splitLineIndex]); splitLineIndex++; // Get the velocities of the note. if (mType == SongType.CombinedMelodyAndPercussion) { // If this Song is a combined Song, then get velocities for both drums and melody. string[] allVelocitiesString = splitLine[splitLineIndex].Split('|'); // Get the melody velocities if there are any for this note. if (allVelocitiesString[0] != "null") { string[] melodyVelocitiesString = allVelocitiesString[0].Split(','); curNoteMelodyVelocities = new int[melodyVelocitiesString.Length]; for (int i = 0; i < curNoteMelodyVelocities.Length; i++) { curNoteMelodyVelocities[i] = int.Parse(melodyVelocitiesString[i]); } melodyVelocitiesString = null; } // Get the drum velocities if there are any for this note. if (allVelocitiesString[1] != "null") { string[] drumVelocitiesString = allVelocitiesString[1].Split(','); curNoteDrumVelocities = new int[drumVelocitiesString.Length]; for (int i = 0; i < curNoteDrumVelocities.Length; i++) { curNoteDrumVelocities[i] = int.Parse(drumVelocitiesString[i]); } drumVelocitiesString = null; } } // If this Song is a melody, then get the melody velocities for the note. else if (mType == SongType.Melody) { string[] melodyVelocitiesString = splitLine[splitLineIndex].Split(','); curNoteMelodyVelocities = new int[melodyVelocitiesString.Length]; for (int i = 0; i < curNoteMelodyVelocities.Length; i++) { curNoteMelodyVelocities[i] = int.Parse(melodyVelocitiesString[i]); } melodyVelocitiesString = null; } // If the Song is a drum loop, then get the drum velocities for the note. else { string[] drumVelocitiesString = splitLine[splitLineIndex].Split(','); curNoteDrumVelocities = new int[drumVelocitiesString.Length]; for (int i = 0; i < curNoteDrumVelocities.Length; i++) { curNoteDrumVelocities[i] = int.Parse(drumVelocitiesString[i]); } drumVelocitiesString = null; } // Add the note to the temp list. Music.MelodyNote melody = new Music.MelodyNote(curNoteMelodyVelocities, curNoteLengths, curNotePitches); Music.PercussionNote percussion = new Music.PercussionNote(curNoteDrumVelocities, curNoteDrums); notesInFile.Add(new Music.CombinedNote(melody, percussion, offset)); curNoteMelodyVelocities = null; curNoteDrumVelocities = null; curNoteLengths = null; // Get the next line curLine = parser.ReadLine(); } parser.Close(); // Put the notes from the file into the Song. foreach (Music.CombinedNote note in notesInFile) { AddNote(note); } // Clean up. notesInFile.Clear(); notesInFile = null; Resources.UnloadUnusedAssets(); }