Esempio n. 1
0
    /*************************************************************************//**
    * @}
    * @defgroup SongPubFunc Public Functions
    * @ingroup DocSong
    * Functions that allow other classes to interact with the Song.
    * @{
    *****************************************************************************/

    /**
     * @brief Adds a @link Music::CombinedNote note@endlink to the Song.
     * @param[in] aNewNote The @link Music::CombinedNote note@endlink to add.
     */
    public void AddNote(Music.CombinedNote aNewNote)
    {
        // Update the number of musical notes in the Song if needed.
        if (aNewNote.NumPitches > 0)
        {
            mNumMusicalNotes++;

            for (int i = 0; i < aNewNote.NumPitches; i++)
            {
                // Update the highest pitch.
                if (aNewNote.MusicalNote.Pitches[i] != Music.PITCH.REST && mHighestPitch < aNewNote.MusicalNote.Pitches[i])
                {
                    mHighestPitch = aNewNote.MusicalNote.Pitches[i];
                }

                // Update the lowest pitch.
                if (aNewNote.MusicalNote.Pitches[i] != Music.PITCH.REST && mLowestPitch > aNewNote.MusicalNote.Pitches[i])
                {
                    mLowestPitch = aNewNote.MusicalNote.Pitches[i];
                }
            }
        }

        // Update the number of notes with drum hits in the Song if needed.
        if (aNewNote.NumDrums > 0)
        {
            mNumDrumNotes++;
        }

        // Add the note to the list.
        mNotes.Add(aNewNote);

        // Update the Song type.
        UpdateSongType();
    }
Esempio n. 2
0
    /**
     * @brief Parses the @link Music::PITCH pitches@endlink from a string in a @link DocSongFileFormat Song file@endlink.
     * @param[in] aStringFromFile The string to parse.
     * @see @link DocSongFileFormat Song File Format@endlink
     */
    private Music.PITCH[] ParsePitches(string aStringFromFile)
    {
        Music.PITCH[] parsedPitches = null;

        // Get the entire string of pitches.
        string pitchString = aStringFromFile;

        if (mType == SongType.CombinedMelodyAndPercussion)
        {
            pitchString = aStringFromFile.Split('|')[0];
        }

        // If there are pitches for the note, then parse each pitch.
        if (pitchString != "null")
        {
            // Split the string into individual pitches.
            string[] pitches = pitchString.Split(',');

            // Iterate through each pitch and parse it.
            parsedPitches = new Music.PITCH[pitches.Length];
            for (int i = 0; i < pitches.Length; i++)
            {
                parsedPitches[i] = (Music.PITCH) int.Parse(pitches[i]);
            }
        }

        // Return the parsed pitches.
        return(parsedPitches);
    }
    private Toggle[] mPitches = null;                                  //!< The toggle switches for each @link Music::PITCH pitch@endlink/@link Music::DRUM drum@endlink.

    /*************************************************************************//**
    * @}
    * @defgroup SC_PSCPubFunc Public Functions
    * @ingroup DocSC_PSC
    * Functions for other classes to interact with the SC_PitchSelectionContainer
    * @{
    *****************************************************************************/

    /**
     * @brief Gets the currently selected @link Music::PITCH pitches@endlink/@link Music::DRUM drums@endlink.
     * @return The currently selected @link Music::PITCH pitches@endlink/@link Music::DRUM drums@endlink.
     */
    public Music.PITCH[] GetSelectedPitches()
    {
        Music.PITCH[] returned = null;

        // If we're currently a rest note, return the rest pitch
        if (mRestNote)
        {
            returned    = new Music.PITCH[1];
            returned[0] = Music.PITCH.REST;
        }
        // If there aren't any pitches selected, then return null.
        else if (mSelectedPitches.Count == 0)
        {
            return(null);
        }
        // If we're not currently a rest note and some pitches are selected, then return all of the selected pitches.
        else
        {
            int index = 0;
            returned = new Music.PITCH[mSelectedPitches.Count];
            foreach (int pitch in mSelectedPitches)
            {
                returned[index] = (Music.PITCH)mSelectedPitches[index];
                index++;
            }
        }
        return(returned);
    }
Esempio n. 4
0
    /*************************************************************************//**
     * @}
     * @defgroup VIBaseProFunc Protected Functions
     * @ingroup VIBase
     * Functions that are used by the subclasses.
     * @{
     ****************************************************************************/


    /**
     * @brief Loads all the audio clips associated with a pitch.
     * @param[in] aPitch The pitch to load the audio clips for.
     */
    protected void LoadAudioClipForPitch(Music.PITCH aPitch)
    {
        Assert.IsTrue(aPitch >= mLowestSupportedPitch && aPitch <= mHighestSupportedPitch,
                      "Tried to load the pitch " + Music.NoteToString(aPitch) + ", but that's out of the instrument's range from " +
                      Music.NoteToString(mLowestSupportedPitch) + " to " + Music.NoteToString(mHighestSupportedPitch));

        // Get the file index.
        int fileIndex = (int)aPitch - (int)mLowestSupportedPitch;

        // Get the audio clips for the pitch.
        AudioClip[] clips = null;

        // If Built-In Dynamics are not supported, then just get the one clip.
        if (mNumBuiltInDynamics == 0)
        {
            // Get the audio file.
            clips    = new AudioClip[1];
            clips[0] = Resources.Load <AudioClip>(mFilenames[fileIndex]);
            Assert.IsNotNull(clips[0], "Failed to load audioclip from file " + mFilenames[fileIndex]);

            // Load the audio data.
            clips[0].LoadAudioData();

            // Normalize the clip.
            NormalizeAudioClipsForPitch(aPitch, clips);
        }
        // If Built-In Dynamics are supported, then get all of the associated clips.
        else
        {
            // Allocate space for the clips.
            clips = new AudioClip[mNumBuiltInDynamics];

            // Load the clips.
            for (int i = 0; i < mNumBuiltInDynamics; i++)
            {
                // Load the wav file.
                clips[i] = Resources.Load <AudioClip>(mFilenames[fileIndex]);
                Assert.IsNotNull(clips[0], "Failed to load audioclip from file " + mFilenames[fileIndex]);

                // Load the audio data into the AudioClip.
                clips[i].LoadAudioData();

                // Go to the next file.
                fileIndex += mNumSupportedPitches;
            }

            // Normalize the clips.
            NormalizeAudioClipsForPitch(aPitch, clips);
        }

        // Clean up.
        clips = null;
        Resources.UnloadUnusedAssets();
    }
Esempio n. 5
0
    /**
     * @brief Handler for when a song begins playing.
     * @param[in] aSong The song that began playing.
     */
    private void HandlePlaySongEvent(Song aSong)
    {
        // Keep track of the current key layout.
        Music.PITCH[] currentLayout = mRepresentedPitches;

        // Get the highest note in the song.
        Music.PITCH highestPitch = aSong.GetHighestPitch();

        // Get the lowest note in the song.
        Music.PITCH lowestPitch = aSong.GetLowestPitch();

        // Get the song data.
        Song.CombinedNoteData[] noteData = aSong.GetNoteData();

        // Clear the keyboard.
        ClearKeyboard();

        // Set the range of keys.
        mRepresentedPitches = null;
        int numPitches = (int)highestPitch - (int)lowestPitch + 1;

        mRepresentedPitches = new Music.PITCH[numPitches];
        mNumWhiteKeys       = 0;
        for (int i = 0; i < numPitches; i++)
        {
            mRepresentedPitches[i] = (Music.PITCH)((int)lowestPitch + i);
            if (!Music.IsPitchABlackKey(mRepresentedPitches[i]))
            {
                mNumWhiteKeys++;
            }
        }

        // Load the proper keys.
        LoadKeys();

        // Get the sample interval (seconds between waveform samples.)
        float sampInt = VirtualInstrument.SAMPLE_INTERVAL;

        // Draw the lesson markers for each pitch.
        foreach (Song.CombinedNoteData note in noteData)
        {
            if (note.MelodyData.Pitches != null)
            {
                int index = 0;
                foreach (Music.PITCH pitch in note.MelodyData.Pitches)
                {
                    StartCoroutine(DrawLessonMarker((int)pitch - (int)lowestPitch, (float)note.TotalOffset * sampInt, (note.MelodyData.NumSamples[index] * sampInt) - .02f));
                    index++;
                }
            }
        }
    }
Esempio n. 6
0
    /**
     * @brief Replaces a note at a given index.
     * @param[in] aNote The note that will be put into the Song at the given index.
     * @param[in] aIndex The index of the place to insert the note.
     */
    public void ReplaceNote(Music.CombinedNote aNote, int aIndex)
    {
        Assert.IsTrue(aIndex < mNotes.Count,
                      "Tried to replace a note at the index " + aIndex.ToString() + " for a Song with only " + mNotes.Count.ToString() + " notes in it!");

        // Get the replaced note.
        Music.CombinedNote replacedNote = mNotes[aIndex];

        // Replace the note.
        mNotes[aIndex] = aNote;

        // Account for changes in the number of musical notes and drum notes in the Song.
        if (replacedNote.NumPitches > 0 && aNote.NumPitches == 0)
        {
            mNumMusicalNotes--;
        }
        else if (replacedNote.NumPitches == 0 && aNote.NumPitches > 0)
        {
            mNumMusicalNotes++;
        }
        if (replacedNote.NumDrums > 0 && aNote.NumDrums == 0)
        {
            mNumDrumNotes--;
        }
        else if (replacedNote.NumDrums == 0 && aNote.NumDrums > 0)
        {
            mNumDrumNotes++;
        }

        // See if we need to update the highest/lowest pitch.
        if (replacedNote.NumPitches > 0 && mNumMusicalNotes > 0)
        {
            // See if we need to set a new highest/lowest pitch.
            foreach (Music.PITCH pitch in replacedNote.MusicalNote.Pitches)
            {
                if (pitch != Music.PITCH.REST && pitch == mHighestPitch)
                {
                    mHighestPitch = Music.PITCH.C0;
                    SearchForHighestPitch();
                }
                if (pitch != Music.PITCH.REST && pitch == mLowestPitch)
                {
                    mLowestPitch = Music.PITCH.B9;
                    SearchForLowestPitch();
                }
            }
        }

        // Update the Song type.
        UpdateSongType();
    }
Esempio n. 7
0
    /**
     * @brief Removes a note from the Song.
     * @param[in] aIndex The index of the note to remove.
     */
    public void RemoveNote(int aIndex)
    {
        Assert.IsTrue(aIndex < mNotes.Count,
                      "Tried to remove a note at the index " + aIndex.ToString() + " from a Song with only " + mNotes.Count.ToString() + " notes in it!");

        // Get the note to be removed.
        Music.CombinedNote removedNote = mNotes[aIndex];

        // Remove the note.
        mNotes.RemoveAt(aIndex);

        // Update information about the pitches in the Song..
        if (removedNote.MusicalNote.Pitches != null)
        {
            // Decrease the number of musical notes.
            mNumMusicalNotes--;

            // See if we need to set a new highest/lowest pitch.
            foreach (Music.PITCH pitch in removedNote.MusicalNote.Pitches)
            {
                if (pitch != Music.PITCH.REST && pitch == mHighestPitch)
                {
                    mHighestPitch = Music.PITCH.C0;
                    SearchForHighestPitch();
                }
                if (pitch != Music.PITCH.REST && pitch == mLowestPitch)
                {
                    mLowestPitch = Music.PITCH.B9;
                    SearchForLowestPitch();
                }
            }
        }

        // Update information about the drums in the Song.
        if (removedNote.Drums.Hits != null)
        {
            mNumDrumNotes--;
        }

        // Update the Song type.
        UpdateSongType();

        // Clean up.
        GC.Collect();
        Resources.UnloadUnusedAssets();
    }
Esempio n. 8
0
    /**
     * @brief Gets the raw audio data of each built-in dynamics value for a given @link Music::PITCH pitch@endlink.
     * @param[in] aPitch The @link Music::PITCH pitch@endlink for which the data is retrieved.
     * @return a 2-D array of floats where the indices correspond to [@link DefBID BuiltInDynamicsIndex@endlink][WaveformSample].
     *
     * The array is retrived by mapping the given @link Music::PITCH pitch@endlink to the second index of the mAudioData member.
     */
    public float[][] GetAudioDataForPitch(Music.PITCH aPitch)
    {
        Assert.IsTrue((int)aPitch >= (int)mLowestSupportedPitch && (int)aPitch <= (int)mHighestSupportedPitch,
                      "Tried to load the audio data for the note " + Music.NoteToString(aPitch) + " which is not a note that is supported by this instrument!");
        Assert.IsNotNull(mAudioData, "Tried to get data from a non-loaded virtual instrument!");

        // If we need to load the clip, then load it.
        if (mAudioData[0][(int)aPitch] == null)
        {
            LoadAudioClipForPitch(aPitch);
        }

        // Declare the returned array.
        float[][] data = null;

        // If there aren't any built-in dynamics, then use a hard-coded index and copy the data to the array from the audio clip.
        if (mNumBuiltInDynamics == 0)
        {
            data = new float[1][];
            int dataLength = mAudioData[0][(int)aPitch].Length;
            data[0] = new float[dataLength];
            for (int i = 0; i < dataLength; i++)
            {
                data[0][i] = mAudioData[0][(int)aPitch][i];
            }
        }
        // If there are built-in dynamics, then get the data from the audio clips for each corresponding file.
        else
        {
            data = new float[mNumBuiltInDynamics][];
            int dataLength = 0;
            for (int i = 0; i < mNumBuiltInDynamics; i++)
            {
                dataLength = mAudioData[i][(int)aPitch].Length;
                data[i]    = new float[dataLength];
                for (int j = 0; j < dataLength; j++)
                {
                    data[i][j] = mAudioData[i][(int)aPitch][j];
                }
            }
        }

        return(data);
    }
Esempio n. 9
0
    /**
     * @brief Handles @link VirtualInstrumentManager::ChangeNoteRangeEvent a change in the note range@endlink.
     * @param[in] aNewLowestPitch The lowest pitch of the new range.
     *
     * Sets the @link KeyContainer::mRepresentedPitches represented pitches@endlink and loads a new part of the keyboard for a changed note range.
     * @sa VirtualInstrumentManager::ChangeNoteRangeEvent Music::PITCH
     */
    private void HandleChangeNoteRangeEvent(Music.PITCH aNewLowestPitch)
    {
        // Clear the keyboard.
        ClearKeyboard();
        mNumWhiteKeys = 0;

        // Update the represented pitches.
        for (int i = 0; i < NumberOfKeysToLoad; i++)
        {
            mRepresentedPitches[i] = (Music.PITCH)(i + (int)aNewLowestPitch);
            if (!Music.IsPitchABlackKey(mRepresentedPitches[i]))
            {
                mNumWhiteKeys++;
            }
        }

        // Load the keys.
        LoadKeys();
    }
    /**
     * @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);
    }
Esempio n. 11
0
 /**
  * @brief Searches through the notes for the lowest pitch.
  *
  * This function is called when a note that contains the lowest
  * pitch in the Song is removed or replaced. We have to then
  * find the new lowest pitch in the Song.
  */
 private void SearchForLowestPitch()
 {
     // Look through each note.
     foreach (Music.CombinedNote note in mNotes)
     {
         // If the note has pitches, then see if it has the lowest pitch.
         if (note.MusicalNote.Pitches != null)
         {
             // Look through each pitch in the note.
             foreach (Music.PITCH pitch in note.MusicalNote.Pitches)
             {
                 // Update the lowest pitch if needed.
                 if (pitch != Music.PITCH.REST && pitch < mLowestPitch)
                 {
                     mLowestPitch = pitch;
                 }
             }
         }
     }
 }
Esempio n. 12
0
 public void OnEndDrag(PointerEventData aPointerData)
 {
     mValue     = (Music.PITCH)mSlider.value;
     mText.text = Music.NoteToString(mValue);
     mVIM.ChangeNoteRange.Invoke(mValue);
 }
Esempio n. 13
0
 public void OnSliderValueChanged(float aNewValue)
 {
     mValue     = (Music.PITCH)aNewValue;
     mText.text = Music.NoteToString(mValue);
 }
Esempio n. 14
0
    /*************************************************************************//**
     * @}
     * @defgroup VIBasePrivFunc Private Functions
     * @ingroup VIBase
     * Functions common to all types of instruments.
     * @{
     ****************************************************************************/

    /**
     * @brief Normalizes the data from the audio clips and puts them in the mAudioData member variable.
     * @param[in] aPitch The pitch that corresponds to the audio clips.
     * @param[in] aClips The clips to normalize.
     *
     * This function makes it so that the waveforms of the samples used for the instrument
     * have a peak of -0.1. If @link DefBID Built-In Dynamics@endlink are supported, then the peak is multiplied
     * by a ratio of the @link DefBIDThresh Built-In Dynamics thresholds@endlink.
     * For example, waveforms that are used for @link DefVel velocities@endlink from 50-75 would have a peak
     * that is 75% of the peak of the waveforms used for @link DefVel velocities@endlink from 76-100.
     */
    private void NormalizeAudioClipsForPitch(Music.PITCH aPitch, AudioClip[] aClips)
    {
        // Make some temp variables for iterating through the data in the clips.
        float max = 0f;

        float[] dataFromClip = null;
        int     clipLength   = 0;
        int     pitchIndex   = (int)aPitch;

        // If the instrument doesn't support Built-In Dynamics, then the array is actually just one clip.
        if (mNumBuiltInDynamics == 0)
        {
            // Get the length of the clip.
            clipLength = aClips[0].samples;

            // Get the data of the clip
            dataFromClip = new float[clipLength];
            aClips[0].GetData(dataFromClip, 0);

            // Allocate a place in the audio data container.
            mAudioData[0][pitchIndex] = new float[clipLength];

            // Get the max value of this clip's data.
            for (int i = 0; i < clipLength; i++)
            {
                if (Mathf.Abs(dataFromClip[i]) > max)
                {
                    max = Mathf.Abs(dataFromClip[i]);
                }
            }

            // Set the normalize factor.
            float normalizeFactor = NORMALIZED_PEAK / max;

            // Normalize the clip and put it in the audio data container
            for (int i = 0; i < clipLength; i++)
            {
                mAudioData[0][pitchIndex][i] = dataFromClip[i] * normalizeFactor;
            }
        }
        // If the instrument does support Built-In Dynamics, then we need to iterate through each
        // file associated with the clip.
        else
        {
            // Set up the normalized peaks for each Built-In Dynamic.
            float[] normalizedPeaks = new float[mNumBuiltInDynamics];
            for (int i = 0; i < mNumBuiltInDynamics; i++)
            {
                normalizedPeaks[i] = NORMALIZED_PEAK * ((float)mBuiltInDynamicsThresholds[i] / (float)mBuiltInDynamicsThresholds[mNumBuiltInDynamics - 1]);
            }

            // Iterate through each clip associated with the pitch.
            for (int i = 0; i < mNumBuiltInDynamics; i++)
            {
                // Get the length of the clip data.
                clipLength = aClips[i].samples;

                // Initialize the clip's spot in the audio data container.
                mAudioData[i][pitchIndex] = new float[clipLength];

                // Get the clip's data
                dataFromClip = new float[clipLength];
                aClips[i].GetData(dataFromClip, 0);

                // Get the max value of the clip data.
                for (int j = 0; j < clipLength; j++)
                {
                    if (Mathf.Abs(dataFromClip[j]) > max)
                    {
                        max = Mathf.Abs(dataFromClip[j]);
                    }
                }

                // Get the normalize factor for this clip.
                float normalizeFactor = normalizedPeaks[i] / max;

                // Normalize the clip and put the normalized data into the audio data array.
                for (int j = 0; j < clipLength; j++)
                {
                    mAudioData[i][pitchIndex][j] = dataFromClip[j] * normalizeFactor;
                }

                // Reset the max value for the next clip.
                max = 0f;
            }
        }
    }
Esempio n. 15
0
 /**
  * @brief Gets whether or not the instrument can play a specific @link Music::PITCH pitch@endlink.
  * @param[in] aPitch The @link Music::PITCH pitch@endlink that is being checked.
  * @return True if the @link Music::PITCH pitch@endlink can be played by the instrument. False otherwise.
  */
 public bool IsPitchSupported(Music.PITCH aPitch)
 {
     return((int)aPitch >= (int)mLowestSupportedPitch && (int)aPitch <= (int)mHighestSupportedPitch);
 }
Esempio n. 16
0
    /**
     * @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);
    }