home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / OutOfPhase1.01Source / OutOfPhase Folder / EnvelopeState.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  27.3 KB  |  815 lines  |  [TEXT/KAHL]

  1. /* EnvelopeState.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #define ShowMeEnvelopeRec
  31. #include "EnvelopeState.h"
  32. #include "FastFixedPoint.h"
  33. #include "Envelope.h"
  34. #include "Memory.h"
  35. #include "LinearTransition.h"
  36. #include "Frequency.h"
  37. #include "FloatingPoint.h"
  38.  
  39.  
  40. /* local prototypes */
  41. static void                        EnvStepToNextInterval(EvalEnvelopeRec* State);
  42. static FastFixedType    EnvUpdateLinearAbsolute(EvalEnvelopeRec* State);
  43. static FastFixedType    EnvUpdateLinearDecibels(EvalEnvelopeRec* State);
  44. static FastFixedType    EnvUpdateSustain(EvalEnvelopeRec* State);
  45.  
  46.  
  47. typedef struct OneEnvPhaseRec
  48.     {
  49.         /* how many envelope cycles does this phase last */
  50.         long                                            Duration;
  51.         /* what amplitude are we trying to attain */
  52.         FastFixedType                            FinalAmplitude;
  53.         /* what does the curve look like */
  54.         EnvTransTypes                            TransitionType;
  55.  
  56.         /* pointer for making linked lists */
  57.         struct OneEnvPhaseRec*        PhaseLink;
  58.     } OneEnvPhaseRec;
  59.  
  60.  
  61. struct EvalEnvelopeRec
  62.     {
  63.         /* number of envelope phases. 0 phases means the envelope produces constant value */
  64.         long                                            NumPhases;
  65.         /* list of definitions for each transition phase.  when this goes NIL, then */
  66.         /* we are done. */
  67.         OneEnvPhaseRec*                        CurrentPhaseRecord;
  68.         /* this remembers the first phase */
  69.         OneEnvPhaseRec*                        PhaseListHead;
  70.  
  71.         /* phase at which first sustain occurs. (released by key-up) */
  72.         /* if the value of this is N, then sustain will occur after phase N has */
  73.         /* completed.  if it is 0, then sustain will occur after phase 0 has completed. */
  74.         /* if it is -1, then sustain will not occur.  sustain may not be NumPhases since */
  75.         /* that would be the end of envelope and would be the same as final value hold. */
  76.         long                                            SustainPhase1;
  77.         long                                            OriginalSustainPhase1;
  78.         SustainTypes                            SustainPhase1Type;
  79.         /* phase at which second sustain occurs. */
  80.         long                                            SustainPhase2;
  81.         long                                            OriginalSustainPhase2;
  82.         SustainTypes                            SustainPhase2Type;
  83.         /* phase at which note-end sustain occurs */
  84.         long                                            SustainPhase3;
  85.         long                                            OriginalSustainPhase3;
  86.         SustainTypes                            SustainPhase3Type;
  87.  
  88.         /* what output phase are we generating right now.  this is the phase index of */
  89.         /* the record currently in CurrentPhaseRecord. */
  90.         long                                            Phase;
  91.  
  92.         /* what is the origin phase */
  93.         long                                            Origin;
  94.  
  95.         /* this is the envelope transition generator */
  96.         LinearTransRec*                        LinearTransition;
  97.         /* this is the countdown for this linear transition.  this is NOT used for */
  98.         /* linear-decibel transitions.  instead, we hack it ourselves. */
  99.         long                                            LinearTransitionCounter;
  100.         /* stuff needed for linear-decibel transitions */
  101.         long                                            LinearTransitionTotalDuration;
  102.         float                                            InitialDecibels;
  103.         float                                            FinalDecibels;
  104.         /* hold value for when we are sustaining */
  105.         FastFixedType                            LastOutputtedValue;
  106.  
  107.         /* number of cycles of the envelope that occur before the origin */
  108.         long                                            PreOriginTime;
  109.  
  110.         /* this function performs one update cycle */
  111.         FastFixedType                            (*EnvelopeUpdate)(EvalEnvelopeRec* State);
  112.  
  113.         /* flag indicating that envelope has finished evaluating the last phase */
  114.         MyBoolean                                    EnvelopeHasFinished;
  115.  
  116.         /* we remember the template that was used to construct us */
  117.         EnvelopeRec*                            Template;
  118.  
  119.         /* pointer for maintaining the free list */
  120.         EvalEnvelopeRec*                    GarbageLink;
  121.     };
  122.  
  123.  
  124. static EvalEnvelopeRec*            EnvelopeStateFreeList = NIL;
  125. static OneEnvPhaseRec*            EnvelopeEntryFreeList = NIL;
  126.  
  127.  
  128. /* flush cached envelope state records */
  129. void                                FlushEvalEnvelopeStateRecords(void)
  130.     {
  131.         while (EnvelopeStateFreeList != NIL)
  132.             {
  133.                 EvalEnvelopeRec*        Temp;
  134.  
  135.                 Temp = EnvelopeStateFreeList;
  136.                 EnvelopeStateFreeList = EnvelopeStateFreeList->GarbageLink;
  137.                 ReleasePtr((char*)Temp);
  138.             }
  139.  
  140.         while (EnvelopeEntryFreeList != NIL)
  141.             {
  142.                 OneEnvPhaseRec*            Temp;
  143.  
  144.                 Temp = EnvelopeEntryFreeList;
  145.                 EnvelopeEntryFreeList = EnvelopeEntryFreeList->PhaseLink;
  146.                 ReleasePtr((char*)Temp);
  147.             }
  148.     }
  149.  
  150.  
  151. #if DEBUG
  152. static void                    DebugCheckState(EvalEnvelopeRec* State)
  153.     {
  154.         EvalEnvelopeRec*    Scan;
  155.  
  156.         Scan = EnvelopeStateFreeList;
  157.         while (Scan != NIL)
  158.             {
  159.                 if (Scan == State)
  160.                     {
  161.                         PRERR(ForceAbort,"DebugCheckState:  released envelope record passed in");
  162.                     }
  163.                 Scan = Scan->GarbageLink;
  164.             }
  165.     }
  166. #else
  167. #define DebugCheckState(x) ((void)0)
  168. #endif
  169.  
  170.  
  171. #if DEBUG
  172. static void                    DebugCheckPhase(OneEnvPhaseRec* Phase)
  173.     {
  174.         OneEnvPhaseRec*        Scan;
  175.  
  176.         Scan = EnvelopeEntryFreeList;
  177.         while (Scan != NIL)
  178.             {
  179.                 if (Scan == Phase)
  180.                     {
  181.                         PRERR(ForceAbort,"DebugCheckPhase:  released envelope phase passed in");
  182.                     }
  183.                 Scan = Scan->PhaseLink;
  184.             }
  185.     }
  186. #else
  187. #define DebugCheckPhase(x) ((void)0)
  188. #endif
  189.  
  190.  
  191. /* dispose of an envelope state record */
  192. void                                DisposeEnvelopeStateRecord(EvalEnvelopeRec* State)
  193.     {
  194.         OneEnvPhaseRec*        PhaseScan;
  195.  
  196.         CheckPtrExistence(State);
  197.         DebugCheckState(State);
  198.  
  199.         DisposeLinearTransition(State->LinearTransition);
  200.         PhaseScan = State->PhaseListHead;
  201.         while (PhaseScan != NIL)
  202.             {
  203.                 OneEnvPhaseRec*            Temp;
  204.  
  205.                 Temp = PhaseScan;
  206.                 DebugCheckPhase(Temp);
  207.                 PhaseScan = PhaseScan->PhaseLink;
  208.                 Temp->PhaseLink = EnvelopeEntryFreeList;
  209.                 EnvelopeEntryFreeList = Temp;
  210.             }
  211.         State->GarbageLink = EnvelopeStateFreeList;
  212.         EnvelopeStateFreeList = State;
  213.     }
  214.  
  215.  
  216. /* create a new envelope state record.  Accent factors have no effect with a value */
  217. /* of 1, attenuate at smaller values, and amplify at larger values. */
  218. EvalEnvelopeRec*        NewEnvelopeStateRecord(struct EnvelopeRec* Template,
  219.                                             float Accent1, float Accent2, float Accent3, float Accent4,
  220.                                             float FrequencyHertz, float Loudness, float HurryUp,
  221.                                             float TicksPerSecond, long* PreOriginTime)
  222.     {
  223.         EvalEnvelopeRec*    State;
  224.         long                            Scan;
  225.         OneEnvPhaseRec*        PhaseTail;
  226.  
  227.         CheckPtrExistence(Template);
  228.         /* we can only handle it if the envelope definition's internal values are floats */
  229.         /* this generates a type error if they aren't */
  230.         EXECUTE((void)((EnvNumberType*)NIL != (float*)NIL);)
  231.  
  232.         /* allocate state record */
  233.         if (EnvelopeStateFreeList != NIL)
  234.             {
  235.                 State = EnvelopeStateFreeList;
  236.                 EnvelopeStateFreeList = EnvelopeStateFreeList->GarbageLink;
  237.             }
  238.          else
  239.             {
  240.                 State = (EvalEnvelopeRec*)AllocPtrCanFail(sizeof(EvalEnvelopeRec),
  241.                     "EvalEnvelopeRec");
  242.                 if (State == NIL)
  243.                     {
  244.                         return NIL;
  245.                     }
  246.             }
  247.  
  248.         /* fill in the fields */
  249.         State->NumPhases = Template->NumPhases;
  250.         State->SustainPhase1 = Template->SustainPhase1;
  251.         State->OriginalSustainPhase1 = Template->SustainPhase1;
  252.         State->SustainPhase1Type = Template->SustainPhase1Type;
  253.         State->SustainPhase2 = Template->SustainPhase2;
  254.         State->OriginalSustainPhase2 = Template->SustainPhase2;
  255.         State->SustainPhase2Type = Template->SustainPhase2Type;
  256.         State->SustainPhase3 = Template->SustainPhase3;
  257.         State->OriginalSustainPhase3 = Template->SustainPhase3;
  258.         State->SustainPhase3Type = Template->SustainPhase3Type;
  259.         State->Phase = -1;
  260.         State->Origin = Template->Origin;
  261.  
  262.         /* build initial delay transition */
  263.         State->LinearTransition = NewLinearTransition(0,0,1);
  264.         if (State->LinearTransition == NIL)
  265.             {
  266.              FailurePoint1:
  267.                 State->GarbageLink = EnvelopeStateFreeList;
  268.                 EnvelopeStateFreeList = State;
  269.                 return NIL;
  270.             }
  271.         State->LinearTransitionCounter = 0;
  272.         State->LinearTransitionTotalDuration = 0;
  273.         State->EnvelopeUpdate = &EnvUpdateLinearAbsolute;
  274.         State->LastOutputtedValue = 0;
  275.         State->EnvelopeHasFinished = False;
  276.  
  277.         State->Template = Template;
  278.  
  279.         /* build list of nodes */
  280.         PhaseTail = NIL;
  281.         State->CurrentPhaseRecord = NIL;
  282.         State->PhaseListHead = NIL;
  283.         State->PreOriginTime = 0;
  284.         for (Scan = 0; Scan < State->NumPhases; Scan += 1)
  285.             {
  286.                 OneEnvPhaseRec*            Phase;
  287.  
  288.                 /* allocate phase record */
  289.                 if (EnvelopeEntryFreeList != NIL)
  290.                     {
  291.                         Phase = EnvelopeEntryFreeList;
  292.                         EnvelopeEntryFreeList = EnvelopeEntryFreeList->PhaseLink;
  293.                     }
  294.                  else
  295.                     {
  296.                         Phase = (OneEnvPhaseRec*)AllocPtrCanFail(sizeof(OneEnvPhaseRec),
  297.                             "OneEnvPhaseRec");
  298.                         if (Phase == NIL)
  299.                             {
  300.                              FailurePoint2:
  301.                                 while (State->PhaseListHead != NIL)
  302.                                     {
  303.                                         Phase = State->PhaseListHead;
  304.                                         State->PhaseListHead = State->PhaseListHead->PhaseLink;
  305.                                         Phase->PhaseLink = EnvelopeEntryFreeList;
  306.                                         EnvelopeEntryFreeList = Phase;
  307.                                     }
  308.                                 goto FailurePoint1;
  309.                             }
  310.                     }
  311.  
  312.                 /* fill in phase record parameters */
  313.                 PRNGCHK(Template->PhaseArray,&(Template->PhaseArray[Scan]),
  314.                     sizeof(Template->PhaseArray[Scan]));
  315.                 Phase->TransitionType = Template->PhaseArray[Scan].TransitionType;
  316.                 /* calculate the total duration.  the effect of accents is this: */
  317.                 /*  - the accent is the base-2 log of a multiplier for the rate.  a value of 0 */
  318.                 /*    does not change the rate.  -1 halves the rate, and 1 doubles the rate. */
  319.                 /*  - the accent scaling factor is the base-2 log for scaling the accent. */
  320.                 /*    a value of 0 eliminates the effect of the accent, a value of 1 does not */
  321.                 /*    scale the accent. */
  322.                 /*  - pitch has two factors:  normalization point and rolloff.  rolloff */
  323.                 /*    determines how much the signal will decrease with each octave.  0 */
  324.                 /*    removes effect, 1 halfs signal with each octave.  normalization point */
  325.                 /*    determines what pitch will be the invariant point. */
  326.                 Phase->Duration = TicksPerSecond * HurryUp * Template->PhaseArray[Scan].Duration
  327.                     * FPOWER(2, - (Accent1 * Template->PhaseArray[Scan].Accent1Rate
  328.                         + Accent2 * Template->PhaseArray[Scan].Accent2Rate
  329.                         + Accent3 * Template->PhaseArray[Scan].Accent3Rate
  330.                         + Accent4 * Template->PhaseArray[Scan].Accent4Rate
  331.                         + (FLN(FrequencyHertz / Template->PhaseArray[Scan].FrequencyRateNormalization)
  332.                         / (float)LOG2) * Template->PhaseArray[Scan].FrequencyRateRolloff));
  333.                 /* the final amplitude scaling values are computed similarly to the rate */
  334.                 /* scaling values. */
  335.                 Phase->FinalAmplitude = Double2FastFixed(Template->PhaseArray[Scan].EndPoint
  336.                     * Template->OverallScalingFactor * Loudness
  337.                     * FPOWER(2, - (Accent1 * Template->PhaseArray[Scan].Accent1Amp
  338.                         + Accent2 * Template->PhaseArray[Scan].Accent2Amp
  339.                         + Accent3 * Template->PhaseArray[Scan].Accent3Amp
  340.                         + Accent4 * Template->PhaseArray[Scan].Accent4Amp
  341.                         + (FLN(FrequencyHertz / Template->PhaseArray[Scan].FrequencyAmpNormalization)
  342.                         / (float)LOG2) * Template->PhaseArray[Scan].FrequencyAmpRolloff)));
  343.  
  344.                 /* append to the list */
  345.                 Phase->PhaseLink = NIL;
  346.                 if (PhaseTail != NIL)
  347.                     {
  348.                         PhaseTail->PhaseLink = Phase;
  349.                     }
  350.                  else
  351.                     {
  352.                         State->CurrentPhaseRecord = Phase;
  353.                         State->PhaseListHead = Phase;
  354.                     }
  355.                 PhaseTail = Phase;
  356.  
  357.                 /* adjust initial countdown */
  358.                 if (Scan < Template->Origin)
  359.                     {
  360.                         /* this occurs before the origin, so add it in */
  361.                         State->PreOriginTime += Phase->Duration;
  362.                     }
  363.             }
  364.         *PreOriginTime = State->PreOriginTime;
  365.  
  366.         return State;
  367.     }
  368.  
  369.  
  370. /* when all envelopes have been computed, then the total (i.e. largest) pre-origin */
  371. /* time will be known and we can tell all envelopes how long they must wait */
  372. /* before starting */
  373. void                                EnvelopeStateFixUpInitialDelay(EvalEnvelopeRec* State,
  374.                                             long MaximumPreOriginTime)
  375.     {
  376.         CheckPtrExistence(State);
  377.         DebugCheckState(State);
  378.  
  379.         State->LinearTransitionCounter = MaximumPreOriginTime - State->PreOriginTime;
  380.         State->LinearTransitionTotalDuration = MaximumPreOriginTime - State->PreOriginTime;
  381.     }
  382.  
  383.  
  384. /* perform a single cycle of the envelope and return the amplitude for it's */
  385. /* point.  should be called at key-down to obtain initial amplitude. */
  386. FastFixedType                EnvelopeUpdate(EvalEnvelopeRec* State)
  387.     {
  388.         CheckPtrExistence(State);
  389.         DebugCheckState(State);
  390.         return (*State->EnvelopeUpdate)(State);
  391.     }
  392.  
  393.  
  394. /* find out if envelope has reached the end */
  395. MyBoolean                        IsEnvelopeAtEnd(EvalEnvelopeRec* State)
  396.     {
  397.         CheckPtrExistence(State);
  398.         DebugCheckState(State);
  399.         return State->EnvelopeHasFinished;
  400.     }
  401.  
  402.  
  403. /* create key-up impulse.  call this before calling EnvelopeUpdate during a */
  404. /* given cycle.  this call preserves the current level of the envelope but */
  405. /* skips to the phase after the particular sustain. */
  406. void                                EnvelopeKeyUpSustain1(EvalEnvelopeRec* State)
  407.     {
  408.         CheckPtrExistence(State);
  409.         DebugCheckState(State);
  410.  
  411.         if (State->Phase <= State->SustainPhase1)
  412.             {
  413.                 /* find out if we should skip ahead to the sustain point */
  414.                 if ((State->SustainPhase1Type == eEnvelopeSustainPointSkip)
  415.                     || (State->SustainPhase1Type == eEnvelopeReleasePointSkip))
  416.                     {
  417.                         while ((State->CurrentPhaseRecord != NIL)
  418.                             && (State->Phase < State->SustainPhase1))
  419.                             {
  420.                                 State->Phase += 1;
  421.                                 State->CurrentPhaseRecord = State->CurrentPhaseRecord->PhaseLink;
  422.                             }
  423.                         State->SustainPhase1 = -1;
  424.                         EnvStepToNextInterval(State);
  425.                         return;
  426.                     }
  427.             }
  428.         if (State->Phase < State->SustainPhase1)
  429.             {
  430.                 /* if we haven't even reached the sustain phase, then cancel the sustain */
  431.                 /* phase so that it can't happen */
  432.                 State->SustainPhase1 = -1;
  433.             }
  434.         else if (State->Phase == State->SustainPhase1)
  435.             {
  436.                 /* or, if we are sustaining, then break the sustain */
  437.                 State->SustainPhase1 = -1;
  438.                 if (State->EnvelopeUpdate == &EnvUpdateSustain)
  439.                     {
  440.                         /* we are sustaining, so break it */
  441.                         EnvStepToNextInterval(State);
  442.                     }
  443.                 /* else we haven't reached it, but we broke it above */
  444.             }
  445.         /* otherwise, we must be past it so just ignore */
  446.     }
  447.  
  448.  
  449. /* create key-up impulse.  call this before calling EnvelopeUpdate during a */
  450. /* given cycle.  this call preserves the current level of the envelope but */
  451. /* skips to the phase after the particular sustain. */
  452. void                                EnvelopeKeyUpSustain2(EvalEnvelopeRec* State)
  453.     {
  454.         CheckPtrExistence(State);
  455.         DebugCheckState(State);
  456.  
  457.         if (State->Phase <= State->SustainPhase2)
  458.             {
  459.                 /* find out if we should skip ahead to the sustain point */
  460.                 if ((State->SustainPhase2Type == eEnvelopeSustainPointSkip)
  461.                     || (State->SustainPhase2Type == eEnvelopeReleasePointSkip))
  462.                     {
  463.                         while ((State->CurrentPhaseRecord != NIL)
  464.                             && (State->Phase < State->SustainPhase2))
  465.                             {
  466.                                 State->Phase += 1;
  467.                                 State->CurrentPhaseRecord = State->CurrentPhaseRecord->PhaseLink;
  468.                             }
  469.                         State->SustainPhase2 = -1;
  470.                         EnvStepToNextInterval(State);
  471.                         return;
  472.                     }
  473.             }
  474.         if (State->Phase < State->SustainPhase2)
  475.             {
  476.                 /* if we haven't even reached the sustain phase, then cancel the sustain */
  477.                 /* phase so that it can't happen */
  478.                 State->SustainPhase2 = -1;
  479.             }
  480.         else if (State->Phase == State->SustainPhase2)
  481.             {
  482.                 /* or, if we are sustaining, then break the sustain */
  483.                 State->SustainPhase2 = -1;
  484.                 if (State->EnvelopeUpdate == &EnvUpdateSustain)
  485.                     {
  486.                         /* we are sustaining, so break it */
  487.                         EnvStepToNextInterval(State);
  488.                     }
  489.                 /* else we haven't reached it, but we broke it above */
  490.             }
  491.         /* otherwise, we must be past it so just ignore */
  492.     }
  493.  
  494.  
  495. /* create key-up impulse.  call this before calling EnvelopeUpdate during a */
  496. /* given cycle.  this call preserves the current level of the envelope but */
  497. /* skips to the phase after the particular sustain. */
  498. void                                EnvelopeKeyUpSustain3(EvalEnvelopeRec* State)
  499.     {
  500.         CheckPtrExistence(State);
  501.         DebugCheckState(State);
  502.  
  503.         if (State->Phase <= State->SustainPhase3)
  504.             {
  505.                 /* find out if we should skip ahead to the sustain point */
  506.                 if ((State->SustainPhase3Type == eEnvelopeSustainPointSkip)
  507.                     || (State->SustainPhase3Type == eEnvelopeReleasePointSkip))
  508.                     {
  509.                         while ((State->CurrentPhaseRecord != NIL)
  510.                             && (State->Phase < State->SustainPhase3))
  511.                             {
  512.                                 State->Phase += 1;
  513.                                 State->CurrentPhaseRecord = State->CurrentPhaseRecord->PhaseLink;
  514.                             }
  515.                         State->SustainPhase3 = -1;
  516.                         EnvStepToNextInterval(State);
  517.                         return;
  518.                     }
  519.             }
  520.         if (State->Phase < State->SustainPhase3)
  521.             {
  522.                 /* if we haven't even reached the sustain phase, then cancel the sustain */
  523.                 /* phase so that it can't happen */
  524.                 State->SustainPhase3 = -1;
  525.             }
  526.         else if (State->Phase == State->SustainPhase3)
  527.             {
  528.                 /* or, if we are sustaining, then break the sustain */
  529.                 State->SustainPhase3 = -1;
  530.                 if (State->EnvelopeUpdate == &EnvUpdateSustain)
  531.                     {
  532.                         /* we are sustaining, so break it */
  533.                         EnvStepToNextInterval(State);
  534.                     }
  535.                 /* else we haven't reached it, but we broke it above */
  536.             }
  537.         /* otherwise, we must be past it so just ignore */
  538.     }
  539.  
  540.  
  541. /* update routine for linear-absolute intervals */
  542. static FastFixedType    EnvUpdateLinearAbsolute(EvalEnvelopeRec* State)
  543.     {
  544.         /* decrement the counter */
  545.         State->LinearTransitionCounter -= 1;
  546.  
  547.         /* see if we should advance to the next state */
  548.         if (State->LinearTransitionCounter < 0)
  549.             {
  550.                 /* yup */
  551.                 EnvStepToNextInterval(State);
  552.                 /* a new function is now in charge, so defer to it */
  553.                 return (*State->EnvelopeUpdate)(State);
  554.             }
  555.          else
  556.             {
  557.                 /* nope, we need to compute the next value */
  558.                 State->LastOutputtedValue = LinearTransitionUpdate(State->LinearTransition);
  559.                 return State->LastOutputtedValue;
  560.             }
  561.     }
  562.  
  563.  
  564. /* update routine for linear-decibel intervals */
  565. static FastFixedType    EnvUpdateLinearDecibels(EvalEnvelopeRec* State)
  566.     {
  567.         /* decrement the counter */
  568.         State->LinearTransitionCounter -= 1;
  569.  
  570.         /* see if we should advance to the next state */
  571.         if (State->LinearTransitionCounter < 0)
  572.             {
  573.                 /* yup */
  574.                 EnvStepToNextInterval(State);
  575.                 /* a new function is now in charge, so defer to it */
  576.                 return (*State->EnvelopeUpdate)(State);
  577.             }
  578.          else
  579.             {
  580.                 float                                Index0To1;
  581.                 long double                    NowDecibels; /* intermediate -- long double */
  582.                 MyBoolean                        Negative;
  583.  
  584.                 /* we need to compute the next value */
  585.                 /*State->LastOutputtedValue = LinearTransitionUpdate(State->LinearTransition);*/
  586.                 if (State->LinearTransitionTotalDuration > 1)
  587.                     {
  588.                         Index0To1 = 1 - ((float)State->LinearTransitionCounter
  589.                             / (State->LinearTransitionTotalDuration - 1));
  590.                     }
  591.                  else
  592.                     {
  593.                         Index0To1 = 1;
  594.                     }
  595.                 NowDecibels = (State->FinalDecibels * Index0To1)
  596.                     + (State->InitialDecibels * (1 - Index0To1));
  597.                 Negative = False;
  598.                 if (NowDecibels < 0)
  599.                     {
  600.                         NowDecibels = - NowDecibels;
  601.                         Negative = True;
  602.                     }
  603.                 /* some funny stuff might go on here since we're treating the FastFixed */
  604.                 /* numbers as integers, but it shouldn't matter since the curve should look */
  605.                 /* the same if the ratio of start to finish is the same no matter what */
  606.                 /* the actual magnitudes are. */
  607.                 /* in fact, the exponential base doesn't matter: */
  608.                 /*  exp((ln 2 + ln 3) / 2) = 2.4494897427831781 */
  609.                 /*  10^((20*log 2 + 20*log 3) / 2 / 20) = 2.4494897427831781 */
  610.                 State->LastOutputtedValue = FEXP(NowDecibels);
  611.                 if (Negative)
  612.                     {
  613.                         State->LastOutputtedValue = - State->LastOutputtedValue;
  614.                     }
  615.                 return State->LastOutputtedValue;
  616.             }
  617.     }
  618.  
  619.  
  620. /* sustain on a particular value */
  621. static FastFixedType    EnvUpdateSustain(EvalEnvelopeRec* State)
  622.     {
  623.         return State->LastOutputtedValue;
  624.     }
  625.  
  626.  
  627. /* routine to step to the next non-zero width interval */
  628. static void                        EnvStepToNextInterval(EvalEnvelopeRec* State)
  629.     {
  630.         OneEnvPhaseRec*            CurrentPhase;
  631.  
  632.         /* first, check to see if we should sustain */
  633.         if ((State->Phase >= 0)
  634.             && (((State->Phase == State->SustainPhase1)
  635.                 && ((State->SustainPhase1Type == eEnvelopeSustainPointSkip)
  636.                 || (State->SustainPhase1Type == eEnvelopeSustainPointNoSkip)))
  637.             ||
  638.             ((State->Phase == State->SustainPhase2)
  639.                 && ((State->SustainPhase2Type == eEnvelopeSustainPointSkip)
  640.                 || (State->SustainPhase2Type == eEnvelopeSustainPointNoSkip)))
  641.             ||
  642.             ((State->Phase == State->SustainPhase3)
  643.                 && ((State->SustainPhase3Type == eEnvelopeSustainPointSkip)
  644.                 || (State->SustainPhase3Type == eEnvelopeSustainPointNoSkip)))))
  645.             {
  646.                 /* yup, sustain */
  647.                 State->EnvelopeUpdate = &EnvUpdateSustain;
  648.                 return;
  649.             }
  650.  
  651.         /* if no sustain, then we can advance to the next phase */
  652.         State->Phase += 1;
  653.         CurrentPhase = State->CurrentPhaseRecord;
  654.         if (CurrentPhase == NIL)
  655.             {
  656.                 /* oh, look, no more phases, so we must be done.  just sustain */
  657.                 /* the last value indefinitely */
  658.                 State->EnvelopeUpdate = &EnvUpdateSustain;
  659.                 State->EnvelopeHasFinished = True;
  660.                 return;
  661.             }
  662.          else
  663.             {
  664.                 State->CurrentPhaseRecord = State->CurrentPhaseRecord->PhaseLink;
  665.             }
  666.  
  667.         /* well, we actually have to do some work. */
  668.         DebugCheckPhase(CurrentPhase);
  669.         if (CurrentPhase->Duration > 0)
  670.             {
  671.                 /* if duration is greater than 0, then we go normally */
  672.                 State->LinearTransitionTotalDuration = CurrentPhase->Duration;
  673.                 State->LinearTransitionCounter = State->LinearTransitionTotalDuration;
  674.                 /* figure out what routine to use */
  675.                 switch (CurrentPhase->TransitionType)
  676.                     {
  677.                         default:
  678.                             EXECUTE(PRERR(ForceAbort,"EnvStepToNextInterval:  bad envelope curve value"));
  679.                             break;
  680.                         case eEnvelopeLinearInAmplitude:
  681.                             State->EnvelopeUpdate = &EnvUpdateLinearAbsolute;
  682.                             RefillLinearTransition(State->LinearTransition,State->LastOutputtedValue,
  683.                                 CurrentPhase->FinalAmplitude,State->LinearTransitionTotalDuration);
  684.                             break;
  685.                         case eEnvelopeLinearInDecibels:
  686.                             {
  687.                                 long                            Temp;
  688.                                 MyBoolean                    Negative;
  689.  
  690.                                 /* figure out end points */
  691.                                 State->EnvelopeUpdate = &EnvUpdateLinearDecibels;
  692.                                 Temp = State->LastOutputtedValue;
  693.                                 Negative = False;
  694.                                 if (Temp < 0)
  695.                                     {
  696.                                         Temp = - Temp;
  697.                                         Negative = True;
  698.                                     }
  699.                                 if (Temp == 0)
  700.                                     {
  701.                                         Temp = 1;
  702.                                     }
  703.                                 State->InitialDecibels = FLN(Temp);
  704.                                 if (Negative)
  705.                                     {
  706.                                         State->InitialDecibels = - State->InitialDecibels;
  707.                                     }
  708.                                 Temp = CurrentPhase->FinalAmplitude;
  709.                                 Negative = False;
  710.                                 if (Temp < 0)
  711.                                     {
  712.                                         Temp = - Temp;
  713.                                         Negative = True;
  714.                                     }
  715.                                 if (Temp == 0)
  716.                                     {
  717.                                         Temp = 1;
  718.                                     }
  719.                                 State->FinalDecibels = FLN(Temp);
  720.                                 if (Negative)
  721.                                     {
  722.                                         State->FinalDecibels = - State->FinalDecibels;
  723.                                     }
  724.                             }
  725.                             break;
  726.                     }
  727.             }
  728.          else
  729.             {
  730.                 /* they want the transition immediately */
  731.                 State->LastOutputtedValue = CurrentPhase->FinalAmplitude;
  732.                 /* do it again.  this will handle ties nicely too */
  733.                 EnvStepToNextInterval(State);
  734.             }
  735.     }
  736.  
  737.  
  738. /* retrigger envelopes from the origin point */
  739. void                                EnvelopeRetriggerFromOrigin(EvalEnvelopeRec* State,
  740.                                             float Accent1, float Accent2, float Accent3, float Accent4,
  741.                                             float FrequencyHertz, float Loudness, float HurryUp,
  742.                                             float TicksPerSecond, MyBoolean ActuallyRetrigger)
  743.     {
  744.         OneEnvPhaseRec*        Phase;
  745.         long                            Scan;
  746.  
  747.         CheckPtrExistence(State);
  748.         DebugCheckState(State);
  749.  
  750.         /* if we actually retrigger, then reset the state */
  751.         if (ActuallyRetrigger)
  752.             {
  753.                 State->Phase = 0;
  754.                 State->CurrentPhaseRecord = State->PhaseListHead;
  755.                 while (State->Phase < State->Origin)
  756.                     {
  757.                         State->CurrentPhaseRecord = State->CurrentPhaseRecord->PhaseLink;
  758.                         CheckPtrExistence(State->CurrentPhaseRecord); /* must not become NIL */
  759.                         State->Phase += 1;
  760.                     }
  761.                 State->SustainPhase1 = State->OriginalSustainPhase1;
  762.                 State->SustainPhase2 = State->OriginalSustainPhase2;
  763.                 State->SustainPhase3 = State->OriginalSustainPhase3;
  764.                 State->LinearTransitionCounter = 0; /* force transition on next update */
  765.                 State->EnvelopeUpdate = &EnvUpdateLinearAbsolute;
  766.             }
  767.  
  768.         /* no matter what, refill the parameters */
  769.         Phase = State->PhaseListHead;
  770.         for (Scan = 0; Scan < State->NumPhases; Scan += 1)
  771.             {
  772.                 CheckPtrExistence(Phase);
  773.                 DebugCheckPhase(Phase);
  774.  
  775.                 /* fill in phase record parameters */
  776.                 PRNGCHK(State->Template->PhaseArray,&(State->Template->PhaseArray[Scan]),
  777.                     sizeof(State->Template->PhaseArray[Scan]));
  778.                 /* this doesn't change -- no need to reset it */
  779.                 /* Phase->TransitionType = State->Template->PhaseArray[Scan].TransitionType; */
  780.  
  781.                 /* calculate the total duration.  the effect of accents is this: */
  782.                 /*  - the accent is the base-2 log of a multiplier for the rate.  a value of 0 */
  783.                 /*    does not change the rate.  -1 halves the rate, and 1 doubles the rate. */
  784.                 /*  - the accent scaling factor is the base-2 log for scaling the accent. */
  785.                 /*    a value of 0 eliminates the effect of the accent, a value of 1 does not */
  786.                 /*    scale the accent. */
  787.                 /*  - pitch has two factors:  normalization point and rolloff.  rolloff */
  788.                 /*    determines how much the signal will decrease with each octave.  0 */
  789.                 /*    removes effect, 1 halfs signal with each octave.  normalization point */
  790.                 /*    determines what pitch will be the invariant point. */
  791.                 Phase->Duration = TicksPerSecond * HurryUp
  792.                     * State->Template->PhaseArray[Scan].Duration
  793.                     * FPOWER(2, - (Accent1 * State->Template->PhaseArray[Scan].Accent1Rate
  794.                         + Accent2 * State->Template->PhaseArray[Scan].Accent2Rate
  795.                         + Accent3 * State->Template->PhaseArray[Scan].Accent3Rate
  796.                         + Accent4 * State->Template->PhaseArray[Scan].Accent4Rate
  797.                         + (FLN(FrequencyHertz / State->Template->PhaseArray[Scan].FrequencyRateNormalization)
  798.                         / (float)LOG2) * State->Template->PhaseArray[Scan].FrequencyRateRolloff));
  799.                 /* the final amplitude scaling values are computed similarly to the rate */
  800.                 /* scaling values. */
  801.                 Phase->FinalAmplitude = Double2FastFixed(
  802.                     State->Template->PhaseArray[Scan].EndPoint
  803.                     * State->Template->OverallScalingFactor * Loudness
  804.                     * FPOWER(2, - (Accent1 * State->Template->PhaseArray[Scan].Accent1Amp
  805.                         + Accent2 * State->Template->PhaseArray[Scan].Accent2Amp
  806.                         + Accent3 * State->Template->PhaseArray[Scan].Accent3Amp
  807.                         + Accent4 * State->Template->PhaseArray[Scan].Accent4Amp
  808.                         + (FLN(FrequencyHertz / State->Template->PhaseArray[Scan].FrequencyAmpNormalization)
  809.                         / (float)LOG2) * State->Template->PhaseArray[Scan].FrequencyAmpRolloff)));
  810.  
  811.                 /* go to the next one */
  812.                 Phase = Phase->PhaseLink;
  813.             }
  814.     }
  815.