/* put source2 */ public static void FMSynthMulAddStmtPutDataSource2( FMSynthStmtMulAddRec Spec, string DataSource2) { EnsureVariable( Spec.Owner, DataSource2, out Spec.Source2); }
/* put factor2 */ public static void FMSynthMulAddStmtPutDataFactor2( FMSynthStmtMulAddRec Spec, string DataFactor2) { EnsureVariable( Spec.Owner, DataFactor2, out Spec.Factor2); }
/* put data target */ public static void FMSynthMulAddStmtPutDataTarget( FMSynthStmtMulAddRec Spec, string DataTarget) { EnsureVariable( Spec.Owner, DataTarget, out Spec.Target); }
/* apply optimizations */ public static void FMSynthOptimize(FMSynthSpecRec Spec) { /* reference disambiguation */ /* there may be multiple non-overlapping lifetimes for the same variable. if these */ /* are not separated, then data rate of one lifetime will apply to all lifetimes, */ /* resulting in suboptimal performance. */ /* each update creates a new lifetime for the variable. while there are more than */ /* one update of a given variable, rename the 1st update and all references. */ int cStmts = Spec.Stmts.Length; int cVars = Spec.Variables.Length; for (int i = 4 /*zero and one are never written, and refs to left, right vars can't be split*/; i < cVars /*note: vars we add here should never have multiple updates*/; i++) { /* find first update */ int iFirstUpdate = 0; while (iFirstUpdate < cStmts) { if (Spec.Stmts[iFirstUpdate].Target == i) { break; } iFirstUpdate++; } if (iFirstUpdate == cStmts) { /* no updates at all, so don't do anything */ continue; } /* find second update */ int iSecondUpdate = (iFirstUpdate + 1) % cStmts; while (iSecondUpdate != iFirstUpdate) { if (Spec.Stmts[iSecondUpdate].Target == i) { break; } iSecondUpdate = (iSecondUpdate + 1) % cStmts; } if (iSecondUpdate == iFirstUpdate) { /* only one update, so don't do anything */ continue; } /* create new anonymous variable */ int iNewVariable = Spec.Variables.Length; Array.Resize(ref Spec.Variables, Spec.Variables.Length + 1); /* walk stmt range and update all references */ int j = iFirstUpdate; //goto StartFirstIteration; /* loop is inclusive on both ends */ j--; // C# can't jump into middle of loop body - so counteract first increment of j do { j = (j + 1) % cStmts; StartFirstIteration: FMSynthStmtRootRec Stmt = Spec.Stmts[j]; /* for first statement, only update the target */ if (j == iFirstUpdate) { #if DEBUG if (Stmt.Target != i) { // first update target is wrong Debug.Assert(false); throw new ArgumentException(); } #endif Stmt.Target = iNewVariable; /* inflow vars to first stmt are outside of the lifetime, so */ /* they must not be updated */ } /* otherwise, update the references */ else { #if DEBUG if ((j != iSecondUpdate) && (Stmt.Target == i)) { // intervening update was missed Debug.Assert(false); throw new ArgumentException(); } #endif switch (Stmt.Type) { default: Debug.Assert(false); throw new ArgumentException(); case FMSynthStmtType.eFMSynthWave: FMSynthStmtWaveRec WaveStmt = (FMSynthStmtWaveRec)Stmt; if (WaveStmt.PhaseSource == i) { WaveStmt.PhaseSource = iNewVariable; } if (WaveStmt.PhaseGainSource == i) { WaveStmt.PhaseGainSource = iNewVariable; } break; case FMSynthStmtType.eFMSynthMuladd: FMSynthStmtMulAddRec MuladdStmt = (FMSynthStmtMulAddRec)Stmt; if (MuladdStmt.Source == i) { MuladdStmt.Source = iNewVariable; } if (MuladdStmt.Source2 == i) { MuladdStmt.Source2 = iNewVariable; } if (MuladdStmt.Factor2 == i) { MuladdStmt.Factor2 = iNewVariable; } break; case FMSynthStmtType.eFMSynthEnvelope: /* no inputs */ break; } } } while (j != iSecondUpdate); } cVars = Spec.Variables.Length; /* reset cuz we added some vars */ /* initialize states to unoptimized case */ FMSynthOptRate[] rgStmtState = new FMSynthOptRate[cStmts]; for (int i = 0; i < cStmts; i++) { Spec.Stmts[i].Optimize = true; /* start out assuming everything is control rate */ rgStmtState[i] = FMSynthOptRate.FMSYNTH_CONTROLRATE; } FMSynthOptRate[] rgVarState = new FMSynthOptRate[cVars]; for (int i = 0; i < cVars; i += 1) { rgVarState[i] = FMSynthOptRate.FMSYNTH_CONTROLRATE; } rgVarState[FMSYNTH_LEFT] = FMSynthOptRate.FMSYNTH_DATARATE; rgVarState[FMSYNTH_RIGHT] = FMSynthOptRate.FMSYNTH_DATARATE; /* convert control variables to data variables. those left at the end are */ /* really control variables. */ /* rules for statement conversion: */ /* - wave is always a data statement */ /* - a statement with any data input variables is a data statement */ /* - a statement that updates any data variable is a data statement */ /* rules for variable conversion: */ /* - any variable updated by a data statement is a data variable */ /* note that flow wraps around: a read can occur before a write, which means it */ /* reads the value written from the previous cycle. in this case, the 3rd rule */ /* for statements converts the updating statement into a data statement even if it */ /* has no data rate dependencies. In accordance, we treat variables as infinite */ /* lifetime, so a state change in one place affects the variable everywhere. */ /* one final rule: */ /* - if a control-rate update of a variable occurs after a data rate use of it, */ /* then there is a data-rate lifetime wraparound so the update must be data rate. */ /* that's because optimization isn't merely control vs. data rate, but also */ /* indicates whether the statement can be executed before any data rate statement. */ bool SomethingChanged = true; while (SomethingChanged) { SomethingChanged = false; for (int i = 0; i < cStmts; i += 1) { FMSynthStmtRootRec Stmt = Spec.Stmts[i]; /* apply statement and variable rules */ switch (Stmt.Type) { default: Debug.Assert(false); throw new ArgumentException(); case FMSynthStmtType.eFMSynthWave: FMSynthStmtWaveRec WaveStmt = (FMSynthStmtWaveRec)Stmt; /* waves are always data rate */ WaveStmt.Optimize = false; SomethingChanged = SomethingChanged || (rgStmtState[i] != FMSynthOptRate.FMSYNTH_DATARATE); rgStmtState[i] = FMSynthOptRate.FMSYNTH_DATARATE; /* mark output variable as data rate */ SomethingChanged = SomethingChanged || (rgVarState[WaveStmt.Target] != FMSynthOptRate.FMSYNTH_DATARATE); rgVarState[WaveStmt.Target] = FMSynthOptRate.FMSYNTH_DATARATE; /* don't bother checking inputs */ break; case FMSynthStmtType.eFMSynthMuladd: FMSynthStmtMulAddRec MuladdStmt = (FMSynthStmtMulAddRec)Stmt; /* if updating a data var, or any input is a data, then stmt is a */ /* data and it's output var is */ if ((rgStmtState[i] == FMSynthOptRate.FMSYNTH_DATARATE) || /* stmt is already data rate */ (rgVarState[MuladdStmt.Target] == FMSynthOptRate.FMSYNTH_DATARATE) || /* output var is already data rate */ (rgVarState[MuladdStmt.Source] == FMSynthOptRate.FMSYNTH_DATARATE) || /* any input is data rate */ (rgVarState[MuladdStmt.Factor2] == FMSynthOptRate.FMSYNTH_DATARATE) || /* any input is data rate */ (rgVarState[MuladdStmt.Source2] == FMSynthOptRate.FMSYNTH_DATARATE)) /* any input is data rate */ { /* update stmt */ MuladdStmt.Optimize = false; SomethingChanged = SomethingChanged || (rgStmtState[i] != FMSynthOptRate.FMSYNTH_DATARATE); rgStmtState[i] = FMSynthOptRate.FMSYNTH_DATARATE; /* update output var */ SomethingChanged = SomethingChanged || (rgVarState[MuladdStmt.Target] != FMSynthOptRate.FMSYNTH_DATARATE); rgVarState[MuladdStmt.Target] = FMSynthOptRate.FMSYNTH_DATARATE; } break; case FMSynthStmtType.eFMSynthEnvelope: FMSynthStmtEnvelopeRec EnvStmt = (FMSynthStmtEnvelopeRec)Stmt; /* if updating a data var, then become data stmt (note, no inputs for this one) */ if (rgVarState[EnvStmt.Target] == FMSynthOptRate.FMSYNTH_DATARATE) { /* update stmt */ EnvStmt.Optimize = false; SomethingChanged = SomethingChanged || (rgStmtState[i] != FMSynthOptRate.FMSYNTH_DATARATE); rgStmtState[i] = FMSynthOptRate.FMSYNTH_DATARATE; /* update output var -- not strictly necessary due to if-stmt condition */ SomethingChanged = SomethingChanged || (rgVarState[EnvStmt.Target] != FMSynthOptRate.FMSYNTH_DATARATE); rgVarState[EnvStmt.Target] = FMSynthOptRate.FMSYNTH_DATARATE; } break; } /* apply wrap-around reordering rule */ /* this algorithm assumes all references have been disambiguated. this */ /* is not true of 'left' and 'right', but anything using them will be */ /* at data rate already due to the above loop. */ if (rgVarState[Stmt.Target] == FMSynthOptRate.FMSYNTH_CONTROLRATE) { /* this is a control update, look for preceding uses (including in */ /* the inflow of this statement) */ for (int j = 0; j <= i; j++) { FMSynthStmtRootRec PrecStmt = Spec.Stmts[j]; #if DEBUG if ((j < i) && (PrecStmt.Target == Stmt.Target)) { // assignment disambiguation incomplete Debug.Assert(false); throw new ArgumentException(); } #endif switch (PrecStmt.Type) { default: Debug.Assert(false); throw new ArgumentException(); case FMSynthStmtType.eFMSynthWave: FMSynthStmtWaveRec PrecWaveStmt = (FMSynthStmtWaveRec)PrecStmt; if ((PrecWaveStmt.PhaseSource == Stmt.Target) || (PrecWaveStmt.PhaseGainSource == Stmt.Target)) { if (rgStmtState[j] == FMSynthOptRate.FMSYNTH_DATARATE) { SomethingChanged = true; rgStmtState[i] = FMSynthOptRate.FMSYNTH_DATARATE; } } break; case FMSynthStmtType.eFMSynthMuladd: FMSynthStmtMulAddRec PrecMuladdStmt = (FMSynthStmtMulAddRec)PrecStmt; if ((PrecMuladdStmt.Source == Stmt.Target) || (PrecMuladdStmt.Source2 == Stmt.Target) || (PrecMuladdStmt.Factor2 == Stmt.Target)) { if (rgStmtState[j] == FMSynthOptRate.FMSYNTH_DATARATE) { SomethingChanged = true; rgStmtState[i] = FMSynthOptRate.FMSYNTH_DATARATE; } } break; case FMSynthStmtType.eFMSynthEnvelope: /* no inputs */ break; } } } } } }
/* change the addend */ public static void FMSynthMulAddStmtPutAddend( FMSynthStmtMulAddRec Spec, double Addend) { Spec.Addend = Addend; }
/* get the addend */ public static double FMSynthMulAddStmtGetAddend(FMSynthStmtMulAddRec Spec) { return(Spec.Addend); }
/* change the factor */ public static void FMSynthMulAddStmtPutFactor( FMSynthStmtMulAddRec Spec, double Factor) { Spec.Factor = Factor; }
/* get the factor */ public static double FMSynthMulAddStmtGetFactor(FMSynthStmtMulAddRec Spec) { return(Spec.Factor); }
/* get source2 */ public static int FMSynthMulAddStmtGetDataSource2(FMSynthStmtMulAddRec Spec) { return(Spec.Source2); }
/* get factor2 */ public static int FMSynthMulAddStmtGetDataFactor2(FMSynthStmtMulAddRec Spec) { return(Spec.Factor2); }
/* get data target */ public static int FMSynthMulAddStmtGetDataTarget(FMSynthStmtMulAddRec Spec) { return(Spec.Target); }
/* accessors to add a statement */ public static void FMSynthAddStatement( FMSynthSpecRec Spec, FMSynthStmtType Type) { FMSynthStmtRootRec Base; switch (Type) { default: Debug.Assert(false); throw new ArgumentException(); case FMSynthStmtType.eFMSynthWave: FMSynthStmtWaveRec WaveStmt = new FMSynthStmtWaveRec(); Base = WaveStmt; WaveStmt.Type = FMSynthStmtType.eFMSynthWave; WaveStmt.Owner = Spec; WaveStmt.FrequencyMultiplier = 1; WaveStmt.FrequencyAdder = 0; WaveStmt.FrequencyDivisor = 1; WaveStmt.Target = -1; WaveStmt.PhaseSource = FMSYNTH_ZERO; WaveStmt.PhaseGainSource = FMSYNTH_ONE; WaveStmt.SampleSelector = NewSampleSelectorList(0); WaveStmt.IndexEnvelope = NewEnvelope(); WaveStmt.IndexLFOList = NewLFOListSpecifier(); break; case FMSynthStmtType.eFMSynthMuladd: FMSynthStmtMulAddRec MuladdStmt = new FMSynthStmtMulAddRec(); Base = MuladdStmt; MuladdStmt.Type = FMSynthStmtType.eFMSynthMuladd; MuladdStmt.Owner = Spec; MuladdStmt.Source = FMSYNTH_ZERO; MuladdStmt.Source2 = FMSYNTH_ZERO; MuladdStmt.Target = -1; MuladdStmt.Factor = 1; MuladdStmt.Addend = 0; MuladdStmt.Factor2 = FMSYNTH_ONE; break; case FMSynthStmtType.eFMSynthEnvelope: FMSynthStmtEnvelopeRec EnvStmt = new FMSynthStmtEnvelopeRec(); Base = EnvStmt; EnvStmt.Type = FMSynthStmtType.eFMSynthEnvelope; EnvStmt.Owner = Spec; EnvStmt.Target = -1; EnvStmt.Envelope = NewEnvelope(); EnvStmt.LFOList = NewLFOListSpecifier(); break; } Array.Resize(ref Spec.Stmts, Spec.Stmts.Length + 1); Spec.Stmts[Spec.Stmts.Length - 1] = Base; }