Пример #1
0
 /// <summary>
 /// Return note length as https://en.wikipedia.org/wiki/Note_value [New 1.9]
 /// </summary>
 /// <param name="note"></param>
 /// <returns></returns>
 public MidiNote.EnumLength NoteLength(MidiNote note)
 {
     if (miditoplay != null)
     {
         return(miditoplay.NoteLength(note));
     }
     return(MidiNote.EnumLength.Sixteenth);
 }
Пример #2
0
 /// <summary>
 /// Convert a MPTKNote to a Midi Note - [New 1.7]
 /// </summary>
 /// <returns></returns>
 public MidiNote ToMidiNote()
 {
     midinote = new MidiNote()
     {
         Midi     = Note <= 0 ? 0 : (Note > 127 ? 127 : Note),
         Delay    = Delay <= 0 ? 0f : (Delay > 1000f ? 1000f : Delay),
         Patch    = Drum ? 0 : Patch <= 0 ? 0 : (Patch > 127 ? 127 : Patch),
         Drum     = Drum,
         Pan      = Pan,
         Duration = Duration <= 0 ? 200f : (Duration > 100000f ? 200f : Duration),
         Velocity = Velocity,
     };
     return(midinote);
 }
Пример #3
0
        private void LogInfoSample(MidiNote note, ImSample sample, string info = null)
        {
            //TimeSpan playtime = TimeSpan.Zero;
            //if (miditoplay != null) playtime = miditoplay.CurrentMidiTime();

            //string time = string.Format("[{0:00}:{1:00}:{2:00}:{3:000}]", playtime.Hours, playtime.Minutes, playtime.Seconds, playtime.Milliseconds);
            string time = "";

            if (sample != null)
#if DEBUGPITCHNOTE
            { Debug.Log(string.Format("{0} C:{1,2} P:{2,3:000} D:{3} Note:{4,3:000} OriginalPitch:{5} PitchCorrection:{6} FineTune:{7} CoarseTune:{8} Duration:{9,4} sec. Velocity:{10} Wave:{11}",
                                      time, note.Chanel, note.Patch, note.Drum, note.Midi,
                                      sample.OriginalPitch, sample.PitchCorrection, sample.FineTune, sample.CoarseTune, Math.Round(note.Duration / 1000d, 2), note.Velocity, sample.WaveFile)); }
#else
            { Debug.Log(string.Format("{0} C:{1,2} P:{2,3:000} D:{3} Note:{4,3:000} {5,-3} Duration:{6,4} sec. Velocity:{7} Pan:{8} Wave:{9}",
                                      time, note.Channel, note.Patch, note.Drum, note.Midi, HelperNoteLabel.LabelFromMidi(note.Midi),
                                      Math.Round(note.Duration / 1000d, 2), note.Velocity, sample.Pan, sample.WaveFile)); }
Пример #4
0
 /// <summary>
 /// https://en.wikipedia.org/wiki/Note_value
 /// </summary>
 /// <param name="note"></param>
 /// <returns></returns>
 public MidiNote.EnumLength NoteLength(MidiNote note)
 {
     if (midifile != null)
     {
         if (note.Length >= midifile.DeltaTicksPerQuarterNote * 4)
         {
             return(MidiNote.EnumLength.Whole);
         }
         else if (note.Length >= midifile.DeltaTicksPerQuarterNote * 2)
         {
             return(MidiNote.EnumLength.Half);
         }
         else if (note.Length >= midifile.DeltaTicksPerQuarterNote)
         {
             return(MidiNote.EnumLength.Quarter);
         }
         else if (note.Length >= midifile.DeltaTicksPerQuarterNote / 2)
         {
             return(MidiNote.EnumLength.Eighth);
         }
     }
     return(MidiNote.EnumLength.Sixteenth);
 }
Пример #5
0
        public List <MidiNote> ReadMidiEvents(double timeFromStartMS)
        {
            List <MidiNote> notes = null;

            try
            {
                EndMidiEvent = false;
                if (midifile != null)
                {
                    if (NextPosEvent < MidiSorted.Count)
                    {
                        // The BPM measures how many quarter notes happen in a minute. To work out the length of each pulse we can use the following formula:
                        // Pulse Length = 60 / (BPM * PPQN)
                        // Calculate current pulse to play
                        CurrentPulse += Convert.ToInt64((timeFromStartMS - LastTimeFromStartMS) / PulseLengthMs);

                        LastTimeFromStartMS = timeFromStartMS;

                        // From the last position played
                        for (int currentPosEvent = NextPosEvent; currentPosEvent < MidiSorted.Count; currentPosEvent++)
                        {
                            TrackMidiEvent trackEvent = MidiSorted[currentPosEvent];
                            if (Quantization != 0)
                            {
                                trackEvent.AbsoluteQuantize = ((trackEvent.Event.AbsoluteTime + Quantization / 2) / Quantization) * Quantization;
                            }
                            else
                            {
                                trackEvent.AbsoluteQuantize = trackEvent.Event.AbsoluteTime;
                            }

                            //Debug.Log("ReadMidiEvents - timeFromStartMS:" + Convert.ToInt32(timeFromStartMS) + " LastTimeFromStartMS:" + Convert.ToInt32(LastTimeFromStartMS) + " CurrentPulse:" + CurrentPulse + " AbsoluteQuantize:" + trackEvent.AbsoluteQuantize);

                            if (trackEvent.AbsoluteQuantize <= CurrentPulse)
                            {
                                NextPosEvent = currentPosEvent + 1;

                                if (trackEvent.Event.CommandCode == MidiCommandCode.NoteOn)
                                {
                                    if (((NoteOnEvent)trackEvent.Event).OffEvent != null)
                                    {
                                        NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event;
                                        // if (noteon.OffEvent != null)
                                        {
                                            if (notes == null)
                                            {
                                                notes = new List <MidiNote>();
                                            }

                                            //Debug.Log(string.Format("Track:{0} NoteNumber:{1,3:000} AbsoluteTime:{2,6:000000} NoteLength:{3,6:000000} OffDeltaTime:{4,6:000000} ", track, noteon.NoteNumber, noteon.AbsoluteTime, noteon.NoteLength, noteon.OffEvent.DeltaTime));
                                            MidiNote note = new MidiNote()
                                            {
                                                AbsoluteQuantize = trackEvent.AbsoluteQuantize,
                                                Midi             = noteon.NoteNumber,
                                                Channel          = trackEvent.Event.Channel,
                                                Velocity         = noteon.Velocity,
                                                Duration         = noteon.NoteLength * PulseLengthMs,
                                                Length           = noteon.NoteLength,
                                                Patch            = PatchChanel[trackEvent.Event.Channel - 1],
                                                Drum             = (trackEvent.Event.Channel == 10),
                                                Delay            = 0,
                                                Pan = EnablePanChange ? PanChanel[trackEvent.Event.Channel - 1] : -1,
                                            };
                                            if (VolumeChanel[note.Channel - 1] != 127)
                                            {
                                                note.Velocity = Mathf.RoundToInt(((float)note.Velocity) * ((float)VolumeChanel[trackEvent.Event.Channel - 1]) / 127f);
                                            }
                                            notes.Add(note);
                                            if (LogEvents)
                                            {
                                                Debug.Log(BuildInfoTrack(trackEvent) + string.Format("{0,-4} {1,3:000} Lenght:{2} {3} Veloc:{4}",
                                                                                                     noteon.NoteName, noteon.NoteNumber, noteon.NoteLength, NoteLength(note), noteon.Velocity));
                                            }
                                        }
                                    }
                                }
                                else if (trackEvent.Event.CommandCode == MidiCommandCode.NoteOff)
                                {
                                    // no need, noteoff are associated with noteon
                                }
                                else if (trackEvent.Event.CommandCode == MidiCommandCode.ControlChange)
                                {
                                    ControlChangeEvent controlchange = (ControlChangeEvent)trackEvent.Event;
                                    if (controlchange.Controller == MidiController.Expression)
                                    {
                                        VolumeChanel[trackEvent.Event.Channel - 1] = controlchange.ControllerValue;
                                    }
                                    else if (controlchange.Controller == MidiController.MainVolume)
                                    {
                                        VolumeChanel[trackEvent.Event.Channel - 1] = controlchange.ControllerValue;
                                    }
                                    else if (controlchange.Controller == MidiController.Pan)
                                    {
                                        PanChanel[trackEvent.Event.Channel - 1] = controlchange.ControllerValue;
                                    }
                                    // Other midi event
                                    if (LogEvents)
                                    {
                                        Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Control {0} {1}", controlchange.Controller, controlchange.ControllerValue));
                                    }
                                }
                                else if (trackEvent.Event.CommandCode == MidiCommandCode.PatchChange)
                                {
                                    PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event;
                                    PatchChanel[trackEvent.Event.Channel - 1] = trackEvent.Event.Channel == 10 ? 0 : change.Patch;
                                    if (LogEvents)
                                    {
                                        Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Patch   {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch)));
                                    }
                                }
                                else if (trackEvent.Event.CommandCode == MidiCommandCode.MetaEvent)
                                {
                                    MetaEvent meta = (MetaEvent)trackEvent.Event;
                                    switch (meta.MetaEventType)
                                    {
                                    case MetaEventType.SetTempo:
                                        if (EnableChangeTempo)
                                        {
                                            TempoEvent tempo = (TempoEvent)meta;
                                            //NewQuarterPerMinuteValue = tempo.Tempo;
                                            ChangeTempo(tempo.Tempo);
                                            //if (LogEvents)Debug.Log(BuildInfoTrack(trackEvent) + string.Format("SetTempo   {0} MicrosecondsPerQuarterNote:{1}", tempo.Tempo, tempo.MicrosecondsPerQuarterNote));
                                        }
                                        break;

                                    case MetaEventType.SequenceTrackName:
                                        if (!string.IsNullOrEmpty(SequenceTrackName))
                                        {
                                            SequenceTrackName += "\n";
                                        }
                                        SequenceTrackName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, ((TextEvent)meta).Text);
                                        if (LogEvents)
                                        {
                                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Sequence   '{0}'", ((TextEvent)meta).Text));
                                        }
                                        break;

                                    case MetaEventType.ProgramName:
                                        ProgramName += ((TextEvent)meta).Text + " ";
                                        if (LogEvents)
                                        {
                                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Program   '{0}'", ((TextEvent)meta).Text));
                                        }
                                        break;

                                    case MetaEventType.TrackInstrumentName:
                                        if (!string.IsNullOrEmpty(TrackInstrumentName))
                                        {
                                            TrackInstrumentName += "\n";
                                        }
                                        TrackInstrumentName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, ((TextEvent)meta).Text);
                                        if (LogEvents)
                                        {
                                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Text      '{0}'", ((TextEvent)meta).Text));
                                        }
                                        break;

                                    case MetaEventType.TextEvent:
                                        TextEvent += ((TextEvent)meta).Text + " ";
                                        if (LogEvents)
                                        {
                                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Sequence  '{0}'", ((TextEvent)meta).Text));
                                        }
                                        break;

                                    case MetaEventType.Copyright:
                                        Copyright += ((TextEvent)meta).Text + " ";
                                        if (LogEvents)
                                        {
                                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Copyright '{0}'", ((TextEvent)meta).Text));
                                        }
                                        break;

                                    case MetaEventType.Lyric:     // lyric
                                    case MetaEventType.Marker:    // marker
                                    case MetaEventType.CuePoint:  // cue point
                                    case MetaEventType.DeviceName:
                                        break;
                                    }
                                    //Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0} {1}", meta.MetaEventType, meta.ToString()));
                                }
                                else
                                {
                                    // Other midi event
                                    //Debug.Log(string.Format("Track:{0} Channel:{1,2:00} CommandCode:{2,3:000} AbsoluteTime:{3,6:000000}", track, e.Channel, e.CommandCode.ToString(), e.AbsoluteTime));
                                }
                            }
                            else
                            {
                                // Out of time, exit for loop
                                break;
                            }
                        }

                        if (notes != null)
                        {
                            //if (CancelNextReadEvents)
                            //{
                            //    notes = null;
                            //    //Debug.Log("CancelNextReadEvents");
                            //    CancelNextReadEvents = false;
                            //}
                            //else
                            //if (notes.Count > 3 && (notes[notes.Count - 1].AbsoluteQuantize - notes[0].AbsoluteQuantize) > midifile.DeltaTicksPerQuarterNote * 8)
                            //{
                            //    //notes.RemoveRange(0, notes.Count - 1);
                            //    Debug.Log("--> Too much notes " + notes.Count + " timeFromStartMS:" + Convert.ToInt32(timeFromStartMS) + " Start:" + notes[0].AbsoluteQuantize + " Ecart:" + (notes[notes.Count - 1].AbsoluteQuantize - notes[0].AbsoluteQuantize) + " CurrentPulse:" + CurrentPulse);
                            //    //notes = null;
                            //}
                        }
                    }
                    else
                    {
                        // End of midi events
                        EndMidiEvent = true;
                    }
                }
            }
            catch (System.Exception ex)
            {
                MidiPlayerGlobal.ErrorDetail(ex);
            }
            return(notes);
        }
Пример #6
0
        /// <summary>
        /// Play one note with this AudioSource
        /// </summary>
        /// <param name="audio">AudioSource</param>
        /// <param name="loop">Sound with loop</param>
        /// <param name="note"></param>
        /// <returns></returns>
        protected IEnumerator PlayNote(AudioSource audio, bool drum, ImSample sample, MidiNote note, float vTransitionTime)
        {
            if (note.Delay > 0f)
            {
                float endDelay = Time.realtimeSinceStartup + note.Delay / 1000f;
                while (Time.realtimeSinceStartup < endDelay && note.Delay > 0f)
                {
                    yield return(new WaitForSeconds(0.01f));
                }
            }

            try
            {
                audio.pitch = note.Pitch;
                if (drum)
                {
                    audio.loop = false;
                }
                else
                {
                    audio.loop = sample.IsLoop;
                }
                // Attenuation removed from current version
                //audio.volume = Mathf.Lerp(0f, 1f, note.Velocity * sample.Attenuation / 127f) * MPTK_Volume;
                audio.volume = Mathf.Lerp(0f, 1f, note.Velocity / 127f) * MPTK_Volume;

                // Pan from the SoundFont
                if (MidiPlayerGlobal.CurrentMidiSet.ActiveSounFontInfo.Panoramic)
                {
                    audio.panStereo = Mathf.Lerp(-1f, 1f, (sample.Pan + 500) / 1000f);
                }
                else
                {
                    audio.panStereo = 0f;
                }

                // Pan from the midi file or from a midi generated event
                if (note.Pan >= 0)
                {
                    audio.panStereo = Mathf.Lerp(-1f, 1f, note.Pan / 127f);
                }
                //Debug.Log(string.Format("   Pan  - note:{0,3} sample:{1,3} --> audio pan:{2,3}" , note.Pan , sample.Pan,Math.Round( audio.panStereo,2)));
                //Debug.Log(string.Format("   Vel  - note:{0,3} sample:{1,3} --> audio vel:{2,3}", note.Velocity , Math.Round(sample.Attenuation, 2), Math.Round(audio.volume, 2)));
                //Debug.Log(string.Format("   Loop - drum:{0} sample:{1}     --> audio loop:{2}" , drum , sample.IsLoop , audio.loop));

                audio.Play();
            }
            catch (Exception)
            {
            }

            // Attack & Decay taken in account by the wave, for drum (loop=false) play the wave one shot (no duration)
            if (audio.loop)
            {
                // Sustain phase until key release, constant amplitude
                float end = Time.realtimeSinceStartup + (float)(note.Duration / 1000d);
                while (note.Duration > 0f)
                {
                    try
                    {
                        if (Time.realtimeSinceStartup >= end || !audio.isPlaying)
                        {
                            break;
                        }
                    }
                    catch (Exception)
                    {
                    }
                    yield return(new WaitForSeconds(0.01f));
                }
                //Debug.Log("stop " + sample.WaveFile + " " + note.Duration);
                // Release phase
                if (vTransitionTime > 0f)
                {
                    float dtime  = 0f;
                    float volume = 0;

                    try
                    {
                        volume = audio.volume;
                        end    = Time.realtimeSinceStartup + vTransitionTime;
                    }
                    catch (Exception)
                    {
                    }

                    do
                    {
                        dtime = end - Time.realtimeSinceStartup;
                        try
                        {
                            audio.volume = Mathf.Lerp(0f, volume, dtime / vTransitionTime);
                            if (dtime < 0f || !audio.isPlaying)
                            {
                                break;
                            }
                        }
                        catch (Exception)
                        {
                            break;
                        }
                        yield return(new WaitForSeconds(0.01f));
                    }while (true);
                }

                try
                {
                    audio.Stop();
                }
                catch (Exception)
                {
                }
            }
            //else
            //{
            //    // play with no loop (drum)
            //    while (audio.isPlaying)
            //    {
            //        yield return new WaitForSeconds(0.01f);
            //    }
            //}
        }
Пример #7
0
        /// <summary>
        /// Play one note - [New 1.7]
        /// </summary>
        /// <param name="note"></param>
        public void MPTK_PlayNote(MidiNote note)
        {
            try
            {
                // Search sample associated to the preset, midi note and velocity
                int selectedBank = note.Drum ? MidiPlayerGlobal.CurrentMidiSet.ActiveSounFontInfo.DrumKitBankNumber : selectedBank = MidiPlayerGlobal.CurrentMidiSet.ActiveSounFontInfo.DefaultBankNumber;
                int noteMidi     = note.Midi;
                if (!note.Drum)
                {
                    noteMidi += MPTK_Transpose;
                }

                //ImSample smpl = MidiPlayerGlobal.GetImSample(selectedBank, note.Patch, noteMidi, note.Velocity);
                //if (smpl != null)
                {
                    List <ImSample> samples = MidiPlayerGlobal.GetImMultiSample(selectedBank, note.Patch, noteMidi, note.Velocity);
                    //LogInfoSample(note, null, " Found " + samples.Count + " samples");
                    foreach (ImSample smpl in samples)
                    {
                        note.Pitch = Mathf.Pow(_ratioHalfTone, (float)(noteMidi - smpl.OriginalPitch + smpl.CoarseTune) + (float)smpl.FineTune / 100f);
                        // Load wave from audioclip
                        AudioClip clip = DicAudioClip.Get(smpl.WaveFile);
                        if (clip != null && clip.loadState == AudioDataLoadState.Loaded)
                        {
                            if (MPTK_LogWaves)
                            {
                                LogInfoSample(note, smpl);
                            }

                            AudioSource audioSelected = null;

                            // Search audioclip not playing with the same wave
                            try
                            {
                                foreach (AudioSource audio in audiosources)
                                {
                                    //Debug.Log(audio.isPlaying + " " + audio.clip.name + " " + clip.name);
                                    if (!audio.isPlaying && audio.clip.name == clip.name)
                                    {
                                        audioSelected = audio;
                                        break;
                                    }
                                }
                            }
                            catch (System.Exception ex)
                            {
                                MidiPlayerGlobal.ErrorDetail(ex);
                            }

                            if (audioSelected == null)
                            {
                                // No audiosource available, create a new audiosource
                                audioSelected = Instantiate <AudioSource>(AudioSourceTemplate);
                                audioSelected.Stop();
                                audioSelected.transform.position = AudioSourceTemplate.transform.position;
                                audioSelected.transform.SetParent(this.transform);
                                audiosources.Add(audioSelected);
                                // Assign sound to audioclip
                                audioSelected.clip = clip;
                            }

                            // Play note
                            StartCoroutine(PlayNote(audioSelected, note.Drum, smpl, note, timeToRelease));
                        }
                        else
                        {
                            if (MPTK_LogWaves)
                            {
                                LogInfoSample(note, null, smpl.WaveFile + "         ******** Clip not ready to play or not found ******");
                            }
                        }
                    }
                    //else
                    if (samples.Count == 0)
                    {
                        if (MPTK_LogWaves)
                        {
                            LogInfoSample(note, null, "               ********* Sample not found *********");
                        }
                    }
                }
            }
            catch (System.Exception ex)
            {
                MidiPlayerGlobal.ErrorDetail(ex);
            }
        }