/* do a scalar param evaluation */ public static SynthErrorCodes StaticEval( double X, PcodeRec SpecifiedFormula, ref AccentRec CurrentParameters, SynthParamRec SynthParams, out double ResultOut) { ResultOut = 0; int initialCapacity = 1 /*retval*/ + 8 + 1 /*t*/ + 1 /*x*/ + 1 /*bpm*/; SynthParams.FormulaEvalContext.EmptyParamStackEnsureCapacity(initialCapacity); StackElement[] Stack; int StackNumElements; SynthParams.FormulaEvalContext.GetRawStack(out Stack, out StackNumElements); Stack[StackNumElements++].Data.Double = CurrentParameters.Accent0; Stack[StackNumElements++].Data.Double = CurrentParameters.Accent1; Stack[StackNumElements++].Data.Double = CurrentParameters.Accent2; Stack[StackNumElements++].Data.Double = CurrentParameters.Accent3; Stack[StackNumElements++].Data.Double = CurrentParameters.Accent4; Stack[StackNumElements++].Data.Double = CurrentParameters.Accent5; Stack[StackNumElements++].Data.Double = CurrentParameters.Accent6; Stack[StackNumElements++].Data.Double = CurrentParameters.Accent7; Stack[StackNumElements++].Data.Double = SynthParams.dElapsedTimeInSeconds; /* t */ Stack[StackNumElements++].Data.Double = X; /* x */ Stack[StackNumElements++].Data.Double = SynthParams.dCurrentBeatsPerMinute; /* bpm */ StackNumElements++; /* return address placeholder */ SynthParams.FormulaEvalContext.UpdateRawStack(Stack, StackNumElements); EvalErrInfoRec ErrorInfo; EvalErrors Error = PcodeSystem.EvaluatePcode( SynthParams.FormulaEvalContext, SpecifiedFormula, SynthParams.CodeCenter, out ErrorInfo, PcodeExternsNull.Default, ref SynthParams.pcodeThreadContext); if (Error != EvalErrors.eEvalNoError) { SynthParams.ErrorInfo.ErrorEx = SynthErrorSubCodes.eSynthErrorExUserParamFunctionEvalError; SynthParams.ErrorInfo.UserEvalErrorCode = Error; SynthParams.ErrorInfo.UserEvalErrorInfo = ErrorInfo; return(SynthErrorCodes.eSynthErrorEx); } Debug.Assert(SynthParams.FormulaEvalContext.GetStackNumElements() == initialCapacity); // args - retaddr + return value ResultOut = SynthParams.FormulaEvalContext.GetStackDouble(initialCapacity - 1); return(SynthErrorCodes.eSynthDone); }
/* shared initialization */ private static SynthErrorCodes UserEffectSharedInit( UserEffectProcRec Proc, UserEffectSpecRec Template, SynthParamRec SynthParams) { Proc.disableOversampling = GetUserEffectSpecNoOversampling(Template); double sr = SynthParams.dSamplingRate; if (!((SynthParams.iOversampling == 1) || !Proc.disableOversampling)) { sr /= SynthParams.iOversampling; } /* init func */ { string FuncName = GetUserEffectSpecInitFuncName(Template); if (FuncName != null) { FuncCodeRec FuncCode = SynthParams.CodeCenter.ObtainFunctionHandle(FuncName); if (FuncCode == null) { // Function missing; should have been found by CheckUnreferencedThings Debug.Assert(false); throw new ArgumentException(); } DataTypes[] argsTypes; DataTypes returnType; UserEffectGetInitSignature(Template, out argsTypes, out returnType); FunctionSignature expectedSignature = new FunctionSignature(argsTypes, returnType); FunctionSignature actualSignature = new FunctionSignature( FuncCode.GetFunctionParameterTypeList(), FuncCode.GetFunctionReturnType()); if (!FunctionSignature.Equals(expectedSignature, actualSignature)) { // Function type mismatch; should have been found by CheckUnreferencedThings Debug.Assert(false); throw new ArgumentException(); } Proc.InitFunc = FuncCode.GetFunctionPcode(); } } /* data func */ { DataTypes[] argsTypes; DataTypes returnType; UserEffectGetDataSignature(Template, out argsTypes, out returnType); FunctionSignature expectedSignature = new FunctionSignature(argsTypes, returnType); foreach (string FuncName in GetUserEffectSpecProcessDataFuncNames(Template)) { FuncCodeRec FuncCode = SynthParams.CodeCenter.ObtainFunctionHandle(FuncName); if (FuncCode == null) { // Function missing; should have been found by CheckUnreferencedThings Debug.Assert(false); throw new ArgumentException(); } FunctionSignature actualSignature = new FunctionSignature( FuncCode.GetFunctionParameterTypeList(), FuncCode.GetFunctionReturnType()); if (FunctionSignature.Equals(expectedSignature, actualSignature)) { Proc.DataFunc = FuncCode.GetFunctionPcode(); break; } } if (Proc.DataFunc == null) { // None matched -- should have been found by CheckUnreferencedThings Debug.Assert(false); throw new ArgumentException(); } } Proc.paramCount = GetUserEffectSpecParamCount(Template); Proc.paramResults = new double[Proc.paramCount]; Proc.paramResultsPrevious = new double[Proc.paramCount]; // create state objects DataTypes[] stateTypes = UserEffectGetWorkspaceTypes(Template); Proc.userState = new ArrayHandle[stateTypes.Length]; for (int i = 0; i < Proc.userState.Length; i++) { switch (stateTypes[i]) { default: Debug.Assert(false); throw new ArgumentException(); case DataTypes.eArrayOfInteger: Proc.userState[i] = new ArrayHandleInt32(new int[0]); break; case DataTypes.eArrayOfFloat: Proc.userState[i] = new ArrayHandleFloat(new float[0]); break; case DataTypes.eArrayOfDouble: Proc.userState[i] = new ArrayHandleDouble(new double[0]); break; } } Proc.smoothingBuffers = new SmoothingEntry[Template.Items.Length]; for (int i = 0; i < Template.Items.Length; i++) { if (Template.Items[i].Smoothed) { float[] vector = new float[SynthParams.nAllocatedPointsOneChannel]; Proc.smoothingBuffers[i].vector = vector; Proc.smoothingBuffers[i].arrayHandle = new ArrayHandleFloat(vector); } } /* initialize user state */ if (Proc.InitFunc != null) { int argCount = 1 /*retval*/ + 1 /*t*/ + 1 /*bpm*/ + 1 /*samplingRate*/ + 1 /*maxSampleCount*/ + Proc.userState.Length /*user state arrays*/ + 1 /*retaddr*/; SynthParams.FormulaEvalContext.EmptyParamStackEnsureCapacity(argCount); StackElement[] StackBase; int StackNumElements; SynthParams.FormulaEvalContext.GetRawStack(out StackBase, out StackNumElements); StackBase[StackNumElements++].Data.Double = SynthParams.dElapsedTimeInSeconds; /* t */ StackBase[StackNumElements++].Data.Double = SynthParams.dCurrentBeatsPerMinute; /* bpm */ StackBase[StackNumElements++].Data.Double = sr; /* samplingRate */ StackBase[StackNumElements++].Data.Integer = SynthParams.nAllocatedPointsOneChannel; /* maxSampleCount */ for (int i = 0; i < Proc.userState.Length; i++) { StackBase[StackNumElements++].reference.arrayHandleGeneric = Proc.userState[i]; // user state } StackNumElements++; /* return address placeholder */ SynthParams.FormulaEvalContext.UpdateRawStack(StackBase, StackNumElements); EvalErrInfoRec ErrorInfo; EvalErrors Error = PcodeSystem.EvaluatePcode( SynthParams.FormulaEvalContext, Proc.InitFunc, SynthParams.CodeCenter, out ErrorInfo, PcodeExternsNull.Default, ref SynthParams.pcodeThreadContext); if (Error != EvalErrors.eEvalNoError) { SynthParams.ErrorInfo.ErrorEx = SynthErrorSubCodes.eSynthErrorExUserEffectFunctionEvalError; SynthParams.ErrorInfo.UserEvalErrorCode = Error; SynthParams.ErrorInfo.UserEvalErrorInfo = ErrorInfo; return(SynthErrorCodes.eSynthErrorEx); } Debug.Assert(SynthParams.FormulaEvalContext.GetStackNumElements() == 1); // return value SynthParams.FormulaEvalContext.Clear(); } // initialize sample data in/out staging areas Proc.leftWorkspace = new float[SynthParams.nAllocatedPointsOneChannel]; Proc.leftWorkspaceHandle = new ArrayHandleFloat(null); Proc.rightWorkspace = new float[SynthParams.nAllocatedPointsOneChannel]; Proc.rightWorkspaceHandle = new ArrayHandleFloat(null); return(SynthErrorCodes.eSynthDone); }
/* apply user effect processing to some stuff */ public SynthErrorCodes Apply( float[] workspace, int lOffset, int rOffset, int nActualFrames, SynthParamRec SynthParams) { Debug.Assert(nActualFrames % SynthParams.iOversampling == 0); // reinit each cycle because user code can reallocate or remove them leftWorkspaceHandle.floats = leftWorkspace; rightWorkspaceHandle.floats = rightWorkspace; int c = nActualFrames; double sr = SynthParams.dSamplingRate; if ((SynthParams.iOversampling == 1) || !disableOversampling) { FloatVectorCopyUnaligned( workspace, lOffset, leftWorkspaceHandle.floats, // not vector-aligned 0, nActualFrames); FloatVectorCopyUnaligned( workspace, rOffset, rightWorkspaceHandle.floats, // not vector-aligned 0, nActualFrames); } else { // downsample c /= SynthParams.iOversampling; sr /= SynthParams.iOversampling; for (int i = 0, j = 0; i < nActualFrames; i += SynthParams.iOversampling, j++) { leftWorkspaceHandle.floats[j] = workspace[i + lOffset]; rightWorkspaceHandle.floats[j] = workspace[i + rOffset]; } } int argCount = 1 /*retval*/ + 1 /*t*/ + 1 /*bpm*/ + 1 /*samplingRate*/ + 1 /*leftdata*/ + 1 /*rightdata*/ + 1 /*count*/ + userState.Length /*user state*/ + paramCount /*user params*/ + 1 /*retaddr*/; SynthParams.FormulaEvalContext.EmptyParamStackEnsureCapacity(argCount); int StackNumElements; StackElement[] StackBase; SynthParams.FormulaEvalContext.GetRawStack(out StackBase, out StackNumElements); StackBase[StackNumElements++].Data.Double = SynthParams.dElapsedTimeInSeconds; /* t */ StackBase[StackNumElements++].Data.Double = SynthParams.dCurrentBeatsPerMinute; /* bpm */ StackBase[StackNumElements++].Data.Double = sr; /* samplingRate */ StackBase[StackNumElements++].reference.arrayHandleFloat = leftWorkspaceHandle; // leftdata StackBase[StackNumElements++].reference.arrayHandleFloat = rightWorkspaceHandle; // rightdata StackBase[StackNumElements++].Data.Integer = c; for (int i = 0; i < userState.Length; i++) { StackBase[StackNumElements++].reference.arrayHandleGeneric = userState[i]; // user state } for (int i = 0; i < paramCount; i += 1) { if (smoothingBuffers[i].arrayHandle == null) { StackBase[StackNumElements++].Data.Double = paramResults[i]; // user params } else { // re-initialize handle in case user code cleared it last time smoothingBuffers[i].arrayHandle.floats = smoothingBuffers[i].vector; // compute smoothed data #if DEBUG Debug.Assert(!SynthParams.ScratchWorkspace1InUse); #endif if (smoothingBuffers[i].degraded) { FloatVectorSet( SynthParams.workspace, SynthParams.ScratchWorkspace1LOffset, nActualFrames, (float)paramResults[i]); } else { if ((params_Osc == null) || !EnvelopeCurrentSegmentExponential(params_Osc[i].Envelope)) { // linear FloatVectorAdditiveRecurrence( SynthParams.workspace, SynthParams.ScratchWorkspace1LOffset, (float)paramResultsPrevious[i], (float)paramResults[i], nActualFrames); } else { // geometric FloatVectorMultiplicativeRecurrence( SynthParams.workspace, SynthParams.ScratchWorkspace1LOffset, (float)paramResultsPrevious[i], (float)paramResults[i], nActualFrames); } } FloatVectorCopyUnaligned( SynthParams.workspace, SynthParams.ScratchWorkspace1LOffset, smoothingBuffers[i].vector, // target not aligned 0, nActualFrames); StackBase[StackNumElements++].reference.arrayHandleFloat = smoothingBuffers[i].arrayHandle; // user params } } StackNumElements++; /* return address placeholder */ SynthParams.FormulaEvalContext.UpdateRawStack(StackBase, StackNumElements); EvalErrInfoRec ErrorInfo; EvalErrors Error = PcodeSystem.EvaluatePcode( SynthParams.FormulaEvalContext, this.DataFunc, SynthParams.CodeCenter, out ErrorInfo, PcodeExternsNull.Default, ref SynthParams.pcodeThreadContext); if (Error != EvalErrors.eEvalNoError) { SynthParams.ErrorInfo.ErrorEx = SynthErrorSubCodes.eSynthErrorExUserEffectFunctionEvalError; SynthParams.ErrorInfo.UserEvalErrorCode = Error; SynthParams.ErrorInfo.UserEvalErrorInfo = ErrorInfo; return(SynthErrorCodes.eSynthErrorEx); } Debug.Assert(SynthParams.FormulaEvalContext.GetStackNumElements() == 1); // return value SynthParams.FormulaEvalContext.Clear(); if ((leftWorkspaceHandle.floats != null) && (leftWorkspaceHandle.floats.Length >= c) && (rightWorkspaceHandle.floats != null) && (rightWorkspaceHandle.floats.Length >= c)) { if ((SynthParams.iOversampling == 1) || !disableOversampling) { // remove NaN/Infinity - prevent user effect misbehavior from taking rest of system down FloatVectorCopyReplaceNaNInf( leftWorkspaceHandle.floats, // unaligned permitted 0, workspace, lOffset, nActualFrames); FloatVectorCopyReplaceNaNInf( rightWorkspaceHandle.floats, // unaligned permitted 0, workspace, rOffset, nActualFrames); } else { // upsample Upsample( leftWorkspaceHandle.floats, 0, workspace, lOffset, c, SynthParams.iOversampling, ref lastLeft); Upsample( rightWorkspaceHandle.floats, 0, workspace, rOffset, c, SynthParams.iOversampling, ref lastRight); // remove NaN/Infinity - prevent user effect misbehavior from taking rest of system down FloatVectorCopyReplaceNaNInf( workspace, lOffset, workspace, lOffset, nActualFrames); FloatVectorCopyReplaceNaNInf( workspace, rOffset, workspace, rOffset, nActualFrames); } } return(SynthErrorCodes.eSynthDone); }