Ejemplo n.º 1
0
 /* trigger immediate release of envelopes */
 public static void OscStateBankReleaseEnvelopesNow(
     OscStateBankRec State,
     WhichEnvType eWhichEnv,
     bool ForceIfScheduled)
 {
     /* If release is scheduled, allow it to go on schedule, but if not, */
     /* then force it to happen on the next cycle.  (If it already happened, */
     /* we make it happen again, but that's ok because envelope generator */
     /* does nothing once it's past the phase with the releasepoint.) */
     /* If it's already scheduled, but ForceIfScheduled is set, then force */
     /* it right now anyway. */
     if ((eWhichEnv & WhichEnvType.eRls1) != 0)
     {
         if (ForceIfScheduled || (State.Release1Countdown < 0))
         {
             State.Release1Countdown = 0;
         }
     }
     if ((eWhichEnv & WhichEnvType.eRls2) != 0)
     {
         if (ForceIfScheduled || (State.Release2Countdown < 0))
         {
             State.Release2Countdown = 0;
         }
     }
     if ((eWhichEnv & WhichEnvType.eRls3) != 0)
     {
         if (ForceIfScheduled || (State.Release3Countdown < 0))
         {
             State.Release3Countdown = 0;
         }
     }
 }
Ejemplo n.º 2
0
        /* ask if there are sample oscillators */
        public static bool OscStateBankContainsSampled(
            OscStateBankRec State)
        {
            OscStateRec OneStateScan;

            OneStateScan = State.OscillatorList;
            while (OneStateScan != null)
            {
                if (OneStateScan.Template.TemplateReference.Type == OscillatorTypes.eOscillatorSampled)
                {
                    return(true);
                }

                OneStateScan = OneStateScan.Next;
            }

            return(false);
        }
Ejemplo n.º 3
0
 /* restart portamento cycle prior to full restart for tie continuation */
 /* only the portamento stuff from FrozenNote is used */
 public static void RestartOscBankStatePortamento(
     OscStateBankRec State,
     ref FrozenNoteRec FrozenNote)
 {
     if (FrozenNote.PortamentoDuration > 0)
     {
         State.PortamentoCounter    = FrozenNote.PortamentoDuration;
         State.TotalPortamentoTicks = FrozenNote.PortamentoDuration;
         State.InitialFrequency     = State.CurrentFrequency; /* save current pitch */
         State.FinalFrequency       = FrozenNote.NominalFrequency;
         State.PortamentoHertz      = ((FrozenNote.OriginalNote.Flags & NoteFlags.ePortamentoUnitsHertzNotHalfsteps) != 0);
     }
     else
     {
         State.PortamentoCounter = 0;
         State.CurrentFrequency  = FrozenNote.NominalFrequency;
     }
 }
Ejemplo n.º 4
0
        public static void FreeOscStateBank(
            OscStateBankRec State,
            SynthParamRec SynthParams)
        {
            OscStateRec StateScan = State.OscillatorList;

            while (StateScan != null)
            {
                OscStateRec one = StateScan;
                StateScan = StateScan.Next;

                Free(ref SynthParams.freelists.oscStateFreeList, ref one);
            }

            FreeLFOGenerator(ref State.PitchLFO, SynthParams);

            Free(ref SynthParams.freelists.oscStateBankFreeList, ref State);
        }
Ejemplo n.º 5
0
        /* finalize before termination */
        public static void FinalizeOscStateBank(
            OscStateBankRec State,
            SynthParamRec SynthParams,
            bool writeOutputLogs)
        {
            OscStateRec OneStateScan = State.OscillatorList;

            while (OneStateScan != null)
            {
                OneStateScan.StateReference.Finalize(
                    SynthParams,
                    writeOutputLogs);
                OneStateScan = OneStateScan.Next;
            }

            if (State.CombinedOscEffectGenerator != null)
            {
                FinalizeOscEffectGenerator(
                    State.CombinedOscEffectGenerator,
                    SynthParams,
                    writeOutputLogs);
            }
        }
Ejemplo n.º 6
0
        /* use the state of the object to generate a cycle of waveform. */
        public static SynthErrorCodes ApplyOscStateBank(
            OscStateBankRec State,
            float[] workspace,
            int nActualFrames,
            int OutputDataLOffset,
            int OutputDataROffset,
            int PrivateOscillatorWorkspaceLOffset,
            int PrivateOscillatorWorkspaceROffset,
            int PrivateCombinedOscillatorWorkspaceLOffset,
            int PrivateCombinedOscillatorWorkspaceROffset,
            SynthParamRec SynthParams)
        {
            OscStateRec OneStateScan;

            OneStateScan = State.OscillatorList;
            if (State.CombinedOscEffectGenerator != null)
            {
                /* resampling when you have combined oscillator effects */

                /* initialize combined workspace */
                FloatVectorZero(
                    workspace,
                    PrivateCombinedOscillatorWorkspaceLOffset,
                    nActualFrames);
                FloatVectorZero(
                    workspace,
                    PrivateCombinedOscillatorWorkspaceROffset,
                    nActualFrames);

                /* do oscillator processing */
                while (OneStateScan != null)
                {
                    OneStateScan.StateReference.Generate(
                        nActualFrames,
                        workspace,
                        PrivateCombinedOscillatorWorkspaceLOffset,
                        PrivateCombinedOscillatorWorkspaceROffset,
                        PrivateOscillatorWorkspaceLOffset,
                        PrivateOscillatorWorkspaceROffset,
                        SynthParams);
                    OneStateScan = OneStateScan.Next;
                }

                /* process combined effects */
                SynthErrorCodes error = ApplyOscEffectGenerator(
                    State.CombinedOscEffectGenerator,
                    workspace,
                    PrivateCombinedOscillatorWorkspaceLOffset,
                    PrivateCombinedOscillatorWorkspaceROffset,
                    nActualFrames,
                    SynthParams);
                if (error != SynthErrorCodes.eSynthDone)
                {
                    return(error);
                }

                /* accumulate combined oscillator buffer to output buffer */
                FloatVectorAcc(
                    workspace,
                    PrivateCombinedOscillatorWorkspaceLOffset,
                    workspace,
                    OutputDataLOffset,
                    nActualFrames);
                FloatVectorAcc(
                    workspace,
                    PrivateCombinedOscillatorWorkspaceROffset,
                    workspace,
                    OutputDataROffset,
                    nActualFrames);
            }
            else
            {
                /* resampling without combined oscillator effects */
                while (OneStateScan != null)
                {
                    OneStateScan.StateReference.Generate(
                        nActualFrames,
                        workspace,
                        OutputDataLOffset,
                        OutputDataROffset,
                        PrivateOscillatorWorkspaceLOffset,
                        PrivateOscillatorWorkspaceROffset,
                        SynthParams);
                    OneStateScan = OneStateScan.Next;
                }
            }

            return(SynthErrorCodes.eSynthDone);
        }
Ejemplo n.º 7
0
        // Perform one envelope clock cycle on a state bank. This returns False in OscillatorsRunning when
        // all oscillators are 'finished' (at end of loudness envelope cycle).
        public static SynthErrorCodes OscStateBankGenerateEnvelopes(
            OscStateBankRec State,
            bool fReleaseTimerOnly,
            SynthParamRec SynthParams,
            out bool OscillatorsRunning)
        {
            SynthErrorCodes error;
            OscStateRec     OneStateScan;

            OscillatorsRunning = false;

            if (State.Release1Countdown >= 0)
            {
                if (State.Release1Countdown == 0)
                {
                    OneStateScan = State.OscillatorList;
                    while (OneStateScan != null)
                    {
                        OneStateScan.StateReference.KeyUpSustain1();
                        OneStateScan = OneStateScan.Next;
                    }
                    LFOGeneratorKeyUpSustain1(State.PitchLFO);
                    if (State.CombinedOscEffectGenerator != null)
                    {
                        OscEffectKeyUpSustain1(State.CombinedOscEffectGenerator);
                    }
                }
                State.Release1Countdown -= 1;
            }

            if (State.Release2Countdown >= 0)
            {
                if (State.Release2Countdown == 0)
                {
                    OneStateScan = State.OscillatorList;
                    while (OneStateScan != null)
                    {
                        OneStateScan.StateReference.KeyUpSustain2();
                        OneStateScan = OneStateScan.Next;
                    }
                    LFOGeneratorKeyUpSustain2(State.PitchLFO);
                    if (State.CombinedOscEffectGenerator != null)
                    {
                        OscEffectKeyUpSustain2(State.CombinedOscEffectGenerator);
                    }
                }
                State.Release2Countdown -= 1;
            }

            if (State.Release3Countdown >= 0)
            {
                if (State.Release3Countdown == 0)
                {
                    OneStateScan = State.OscillatorList;
                    while (OneStateScan != null)
                    {
                        OneStateScan.StateReference.KeyUpSustain3();
                        OneStateScan = OneStateScan.Next;
                    }
                    LFOGeneratorKeyUpSustain3(State.PitchLFO);
                    if (State.CombinedOscEffectGenerator != null)
                    {
                        OscEffectKeyUpSustain3(State.CombinedOscEffectGenerator);
                    }
                }
                State.Release3Countdown -= 1;
            }

            if (!fReleaseTimerOnly)
            {
                /* perform portamento */
                if (State.PortamentoCounter > 0)
                {
                    /* decrement is done before interpolation so that the final frequency */
                    /* will actually be reached. */
                    State.PortamentoCounter -= 1;
                    if (State.PortamentoHertz)
                    {
                        /* this transition is linear, so it's easy to compute */
                        /* L+F(R-L) */
                        State.CurrentFrequency = State.InitialFrequency
                                                 + ((double)(State.TotalPortamentoTicks
                                                             - State.PortamentoCounter) / State.TotalPortamentoTicks)
                                                 * (State.FinalFrequency - State.InitialFrequency);
                    }
                    else
                    {
                        /* this transition is log-linear, so it's a bit messier */
                        State.CurrentFrequency = State.InitialFrequency * Math.Exp(
                            ((double)(State.TotalPortamentoTicks - State.PortamentoCounter)
                             / State.TotalPortamentoTicks)
                            * ((Math.Log(State.FinalFrequency) * Constants.INVLOG2)
                               - (Math.Log(State.InitialFrequency) * Constants.INVLOG2)) * Constants.LOG2);
                    }
                }

                /* update the pitch LFO modulation & figure out what the current pitch is */
                double Frequency;
                if (State.PitchLFOStartCountdown > 0)
                {
                    State.PitchLFOStartCountdown -= 1;
                    Frequency = State.CurrentFrequency;
                }
                else
                {
                    /* do some pitch stuff */
                    error     = SynthErrorCodes.eSynthDone;
                    Frequency = LFOGenUpdateCycle(
                        State.PitchLFO,
                        State.CurrentFrequency,
                        State.CurrentFrequency,
                        SynthParams,
                        ref error);
                    if (error != SynthErrorCodes.eSynthDone)
                    {
                        return(error);
                    }
                }

                /* perform a cycle of resampling */
                OscillatorsRunning = false;
                /* do oscillator processing */
                OneStateScan = State.OscillatorList;
                while (OneStateScan != null)
                {
                    OneStateScan.StateReference.UpdateEnvelopes(
                        Frequency,
                        SynthParams);
                    OscillatorsRunning = OscillatorsRunning || !OneStateScan.StateReference.IsItFinished();
                    OneStateScan       = OneStateScan.Next;
                }
                /* process combined effects */
                if (State.CombinedOscEffectGenerator != null)
                {
                    error = OscEffectGeneratorUpdateEnvelopes(
                        State.CombinedOscEffectGenerator,
                        State.CurrentFrequency,
                        SynthParams);
                    if (error != SynthErrorCodes.eSynthDone)
                    {
                        return(error);
                    }
                }
            }
            else
            {
                // If osc bank has entered fReleaseTimerOnly mode (aka fDontUpdateEnvelopes, aka fScheduledSkip),
                // it remains in suspended animation until scheduled skip period is over - so that it can finish
                // it's release phases without abrupt glitch of termination.
                OscillatorsRunning = true;
            }

            return(SynthErrorCodes.eSynthDone);
        }
Ejemplo n.º 8
0
 /* get the reference to the note that this bank ties to.  null if it doesn't */
 public static NoteNoteObjectRec GetOscStateTieTarget(
     OscStateBankRec State)
 {
     return(State.TieToNote);
 }
Ejemplo n.º 9
0
        /* this is used for resetting a note for a tie */
        /* the FrozenNote object is NOT disposed */
        public static void ResetOscBankState(
            OscStateBankRec State,
            ref FrozenNoteRec FrozenNote,
            SynthParamRec SynthParams)
        {
            bool RetriggerEnvelopes = ((FrozenNote.OriginalNote.Flags & NoteFlags.eRetriggerEnvelopesOnTieFlag) != 0);

            /* go through the oscillators and retrigger them */
            OscStateRec OneState = State.OscillatorList;

            while (OneState != null)
            {
                OneState.StateReference.Restart(
                    ref FrozenNote.Accents,
                    FrozenNote.LoudnessAdjust * State.BankTemplate.InstrOverallLoudness,
                    FrozenNote.HurryUpFactor,
                    RetriggerEnvelopes,
                    FrozenNote.StereoPosition,
                    FrozenNote.NominalFrequency,
                    FrozenNote.PitchDisplacementDepthLimit,
                    FrozenNote.PitchDisplacementRateLimit,
                    SynthParams);
                OneState = OneState.Next;
            }

            LFOGeneratorRetriggerFromOrigin(
                State.PitchLFO,
                ref FrozenNote.Accents,
                FrozenNote.NominalFrequency,
                FrozenNote.HurryUpFactor,
                FrozenNote.PitchDisplacementDepthLimit,
                FrozenNote.PitchDisplacementRateLimit,
                RetriggerEnvelopes,
                SynthParams);

            if (State.CombinedOscEffectGenerator != null)
            {
                OscEffectGeneratorRetriggerFromOrigin(
                    State.CombinedOscEffectGenerator,
                    ref FrozenNote.Accents,
                    FrozenNote.NominalFrequency,
                    FrozenNote.HurryUpFactor,
                    RetriggerEnvelopes,
                    SynthParams);
            }

            /* if this object ties to a note, then this is the note to tie to.  this is */
            /* used for finding existing oscillators for tie continuations. */
            State.TieToNote = FrozenNote.OriginalNote._Tie;

            /* portamento control parameters */
            if (!FrozenNote.PortamentoBeforeNote)
            {
                /* if PortamentoBeforeNote is not set, then we have to restart the portamento */
                /* with the current note, otherwise it has already been restarted earlier */
                RestartOscBankStatePortamento(State, ref FrozenNote);
            }

            /* various counters (in terms of envelope ticks) */
            if (State.TieToNote == null)
            {
                State.Release1Countdown = FrozenNote.ReleasePoint1;
                State.Release2Countdown = FrozenNote.ReleasePoint2;
                State.Release3Countdown = FrozenNote.ReleasePoint3;
            }
            else
            {
                /* for ties, only honor releases from start */
                if (FrozenNote.Release1FromStart)
                {
                    State.Release1Countdown = FrozenNote.ReleasePoint1;
                }
                else
                {
                    State.Release1Countdown = -1;
                }
                if (FrozenNote.Release2FromStart)
                {
                    State.Release2Countdown = FrozenNote.ReleasePoint2;
                }
                else
                {
                    State.Release2Countdown = -1;
                }
                if (FrozenNote.Release3FromStart)
                {
                    State.Release3Countdown = FrozenNote.ReleasePoint3;
                }
                else
                {
                    State.Release3Countdown = -1;
                }
            }
            /* do not reset PitchLFOStartCountdown since we can't give it a proper value */
            /* to do the expected thing, and we'd be interrupting the phase of the LFO */
            /* wave generator */
        }
Ejemplo n.º 10
0
        /* construct a new oscillator bank state object based on the note.  the note is */
        /* assumed to start "now" in terms of the parameters in the ParameterUpdator.  */
        /* the ScanningGapWidth is the number of envelope clock ticks in the current scanning */
        /* gap.  this is used to determine how far later than "now" in terms of the back */
        /* edge of the scanning gap (different from above) the osc bank should start playing. */
        /* *WhenToStartPlayingOut returns the number of envelope ticks after the back edge */
        /* of the scanning gap that the note should be started. */
        /*     <already played>       |    <scanning gap>     |    <not yet analyzed> */
        /*   time ---.    time ---.    time ---.    time ---.    time ---.   time ---. */
        /*                            ^A                      ^B     */
        /* point A is the back edge of the scanning gap.  as this edge moves forward in time, */
        /*   oscillator bank state objects are removed from the queue and playback is commenced */
        /*   for them. */
        /* point B is the front edge of the scanning gap.  as this edge moves forward in time, */
        /*   notes are extracted from the track and state bank objects are created for them. */
        /*   ParameterUpdator always reflects parameters at this point in time. */
        public static SynthErrorCodes NewOscBankState(
            OscBankTemplateRec Template,
            out int WhenToStartPlayingOut,
            NoteNoteObjectRec Note,
            double EnvelopeTicksPerDurationTick,
            short PitchIndexAdjust,
            PlayTrackInfoRec TrackInfo,
            SynthParamRec SynthParams,
            out OscStateBankRec StateOut)
        {
            int ThisPreOriginTime;
            int StartPointAdjust;

            WhenToStartPlayingOut = 0;
            StateOut = null;

            int MaxOscillatorPreOriginTime = 0;

            OscStateBankRec State = New(ref SynthParams.freelists.oscStateBankFreeList);

            // all fields must be assigned: State

            State.PortamentoHertz      = false;
            State.TotalPortamentoTicks = 0;
            State.InitialFrequency     = 0;
            State.FinalFrequency       = 0;

            State.BankTemplate = Template;

            /* freeze the parameters */
            FrozenNoteRec FrozenNote = new FrozenNoteRec();

            FixNoteParameters(
                Template.ParamUpdator,
                Note,
                out StartPointAdjust,
                EnvelopeTicksPerDurationTick,
                PitchIndexAdjust,
                ref FrozenNote,
                SynthParams);


            /* this calculates the differential values for periodic pitch displacements */
            State.PitchLFO = NewLFOGenerator(
                Template.PitchLFOTemplate,
                out ThisPreOriginTime,
                ref FrozenNote.Accents,
                FrozenNote.NominalFrequency,
                FrozenNote.HurryUpFactor,
                FrozenNote.PitchDisplacementDepthLimit,
                FrozenNote.PitchDisplacementRateLimit,
                FrozenNote.MultisampleFrequency,
                _PlayTrackParamGetter,
                TrackInfo,
                SynthParams);
            if (ThisPreOriginTime > MaxOscillatorPreOriginTime)
            {
                MaxOscillatorPreOriginTime = ThisPreOriginTime;
            }

            /* list of oscillators that this oscillator bank is comprised of */
            State.OscillatorList = null;
            for (int i = 0; i < Template.NumOscillatorsInBank; i++)
            {
                OscStateRec OneState = New(ref SynthParams.freelists.oscStateFreeList);

                // all fields must be assigned: OneState

                /* link it in */
                OneState.Next        = State.OscillatorList;
                State.OscillatorList = OneState;

                /* copy over the function vectors */
                OneState.Template = Template.TemplateArray[i];

                /* create the oscillator */
                SynthErrorCodes Result = OneState.Template.TemplateReference.NewState(
                    FrozenNote.MultisampleFrequency,
                    ref FrozenNote.Accents,
                    FrozenNote.LoudnessAdjust * Template.InstrOverallLoudness,
                    FrozenNote.HurryUpFactor,
                    out ThisPreOriginTime,
                    FrozenNote.StereoPosition,
                    FrozenNote.NominalFrequency,
                    FrozenNote.PitchDisplacementDepthLimit,
                    FrozenNote.PitchDisplacementRateLimit,
                    FrozenNote.PitchDisplacementStartPoint,
                    TrackInfo,
                    SynthParams,
                    out OneState.StateReference);
                if (Result != SynthErrorCodes.eSynthDone)
                {
                    return(Result);
                }
                if (ThisPreOriginTime > MaxOscillatorPreOriginTime)
                {
                    MaxOscillatorPreOriginTime = ThisPreOriginTime;
                }
            }

            State.CombinedOscEffectGenerator = null;
            if ((Template.CombinedOscillatorEffects != null) && (GetEffectSpecListLength(Template.CombinedOscillatorEffects) > 0))
            {
                SynthErrorCodes Result = NewOscEffectGenerator(
                    Template.CombinedOscillatorEffects,
                    ref FrozenNote.Accents,
                    FrozenNote.HurryUpFactor,
                    FrozenNote.NominalFrequency,
                    FrozenNote.MultisampleFrequency,
                    out ThisPreOriginTime,
                    TrackInfo,
                    SynthParams,
                    out State.CombinedOscEffectGenerator);
                if (Result != SynthErrorCodes.eSynthDone)
                {
                    return(Result);
                }
                if (ThisPreOriginTime > MaxOscillatorPreOriginTime)
                {
                    MaxOscillatorPreOriginTime = ThisPreOriginTime;
                }
            }
            /* else no combined oscillator effects, State.CombinedOscEffectGenerator is null */

            /* if this object ties to a note, then this is the note */
            /* to tie to.  this is used for finding existing oscillators */
            /* for tie continuations. */
            State.TieToNote = Note._Tie;

            /* portamento control parameters */
            State.PortamentoCounter = 0;
            State.CurrentFrequency  = FrozenNote.NominalFrequency;


            /* fix up pre-origin times */
            OscStateRec StateScan = State.OscillatorList;

            while (StateScan != null)
            {
                StateScan.StateReference.FixUpPreOrigin(
                    MaxOscillatorPreOriginTime);
                StateScan = StateScan.Next;
            }
            LFOGeneratorFixEnvelopeOrigins(
                State.PitchLFO,
                MaxOscillatorPreOriginTime);
            if (State.CombinedOscEffectGenerator != null)
            {
                FixUpOscEffectGeneratorPreOrigin(
                    State.CombinedOscEffectGenerator,
                    MaxOscillatorPreOriginTime);
            }

            /* various counters (in terms of envelope ticks) */
            if (State.TieToNote == null)
            {
                State.Release1Countdown = FrozenNote.ReleasePoint1 + MaxOscillatorPreOriginTime;
                State.Release2Countdown = FrozenNote.ReleasePoint2 + MaxOscillatorPreOriginTime;
                State.Release3Countdown = FrozenNote.ReleasePoint3 + MaxOscillatorPreOriginTime;
            }
            else
            {
                /* for ties, only honor releases from start */
                if (FrozenNote.Release1FromStart)
                {
                    State.Release1Countdown = FrozenNote.ReleasePoint1 + MaxOscillatorPreOriginTime;
                }
                else
                {
                    State.Release1Countdown = -1;
                }
                if (FrozenNote.Release2FromStart)
                {
                    State.Release2Countdown = FrozenNote.ReleasePoint2 + MaxOscillatorPreOriginTime;
                }
                else
                {
                    State.Release2Countdown = -1;
                }
                if (FrozenNote.Release3FromStart)
                {
                    State.Release3Countdown = FrozenNote.ReleasePoint3 + MaxOscillatorPreOriginTime;
                }
                else
                {
                    State.Release3Countdown = -1;
                }
            }
            State.PitchLFOStartCountdown = FrozenNote.PitchDisplacementStartPoint
                                           /*+ MaxOscillatorPreOriginTime*/;
            /* pre origin relationship must be preserved for */
            /* pitch LFO trigger */

            /* done */
            WhenToStartPlayingOut = StartPointAdjust - MaxOscillatorPreOriginTime;
            StateOut = State;
            return(SynthErrorCodes.eSynthDone);
        }