private float GetNoteCurveValue(MidiControl control, float time)
        {
            var tick = midiTrack.ConvertSecondToTicks(time);
            var pair = GetNoteEventsBeforeTick(tick, control.noteFilter);

            if (pair is null)
            {
                return(0);
            }

            var curve    = control.curve.Evaluate(Mathf.Max(0, time - midiTrack.ConvertTicksToSecond(pair.OnTick)));
            var velocity = pair.Velocity / 127.0f;

            return(curve * velocity);
        }
        public float GetValue(UnityEngine.Playables.Playable playable, MidiControl control)
        {
            var t = (float)(playable.GetTime() % midiTrack.TotalSeconds);

            switch (control.mode)
            {
            case MidiControl.Mode.NoteEnvelope:
                return(GetNoteEnvelopeValue(control, t));

            case MidiControl.Mode.NoteCurve:
                return(GetNoteCurveValue(control, t));

            case MidiControl.Mode.CC:
                return(GetCCValue(control, t));

            default:
                return(0);
            }
        }
        private float GetCCValue(MidiControl control, float time)
        {
            var tick = midiTrack.ConvertSecondToTicks(time);

            var(i0, i1) = GetCCEventIndexAroundTick(tick, control.ccController);

            if (i0 is null)
            {
                return(0);
            }
            if (i1 is null)
            {
                return(i0.data / 127.0f);
            }

            var v0 = i0.data / 127.0f;
            var v1 = i1.data / 127.0f;

            var t0 = midiTrack.ConvertTicksToSecond(i0.Ticks);
            var t1 = midiTrack.ConvertTicksToSecond(i1.Ticks);

            return(Mathf.Lerp(v0, v1, Mathf.Clamp01((time - t0) / (t1 - t0))));
        }
        private float GetNoteEnvelopeValue(MidiControl control, float time)
        {
            var tick = midiTrack.ConvertSecondToTicks(time);
            var pair = GetNoteEventsBeforeTick(tick, control.noteFilter);

            if (pair is null)
            {
                return(0);
            }

            // Note-off time
            var offTime = Math.Min(midiTrack.ConvertTicksToSecond(pair.OffTick), time);

            var envelope = CalculateEnvelope(
                control.envelope,
                Mathf.Max(0, offTime - midiTrack.ConvertTicksToSecond(pair.OnTick)),
                Mathf.Max(0, time - offTime)
                );

            var velocity = pair.Velocity / 127.0f;

            return(envelope * velocity);
        }