/* build common stuff */ private static VocoderRec VocoderBuildCommonStructure( VocoderSpecRec Template, SynthParamRec SynthParams) { int BandCount; int OrderCount; float[][] WaveTableMatrix; int FramesPerTable; int NumberOfTables; if (!WaveSampDictGetWaveTableInfo( SynthParams.Dictionary, GetVocoderSpecWaveTableName(Template), out WaveTableMatrix, out FramesPerTable, out NumberOfTables)) { Debug.Assert(false); throw new InvalidOperationException(); } BandCount = GetVocoderMaxNumBands(Template); OrderCount = GetVocoderFilterOrder(Template) / 2; if (BandCount > FramesPerTable / VOC_FIELDCOUNT) { BandCount = FramesPerTable / VOC_FIELDCOUNT; } VocoderRec Vocoder = new VocoderRec(); Vocoder.CombinedGainFactorVector = new float[2 * BandCount]; Vocoder.FilterVector = new ButterworthBandpassRec[2 * BandCount * OrderCount]; Vocoder.BandCount = BandCount; Vocoder.OrderCount = OrderCount; Vocoder.ForceFilterUpdate = true; Vocoder.PreviousOutputScaling = 0; Vocoder.PreviousWaveTableIndex = -1; Vocoder.WaveTableMatrix = WaveTableMatrix; Vocoder.FramesPerTable = FramesPerTable; Vocoder.NumberOfTablesMinus1 = NumberOfTables - 1; Vocoder.EnableCrossWaveTableInterpolation = VocoderGetEnableCrossWaveTableInterpolation(Template); /* initialize band matrix */ for (int i = 0; i < 2 * BandCount * OrderCount; i++) { Vocoder.FilterVector[i] = new ButterworthBandpassRec(); } return(Vocoder); }
/* create a new track vocoder */ public static VocoderRec NewTrackVocoder( VocoderSpecRec Template, SynthParamRec SynthParams) { /* initialize common portion of structure */ VocoderRec Vocoder = VocoderBuildCommonStructure( Template, SynthParams); Vocoder.Track = new VocTrackRec(); /* initialize variant portion */ GetVocoderSpecOutputGainAgg( Template, out Vocoder.Track.OutputScaling); GetVocoderSpecWaveTableIndexAgg( Template, out Vocoder.Track.WaveTableIndex); return(Vocoder); }
/* apply filter matrix to vector */ private static void ApplyVocoderMatrix( VocoderRec Vocoder, ButterworthBandpassRec[] BandMatrix, int BandMatrixOffset, float[] CombinedGainFactorVector, int CombinedGainFactorVectorOffset, float[] Vector, int VectorOffset, float[] SourceBase, int SourceOffset, float[] MangleBase, int MangleOffset, int Length, SynthParamRec SynthParams) { int BandCount = Vocoder.BandCount; int OrderCount = Vocoder.OrderCount; /* build source and initialize vector for output */ FloatVectorCopy( Vector, VectorOffset, SourceBase, SourceOffset, Length); FloatVectorZero( Vector, VectorOffset, Length); int i = 0; #if VECTOR if (EnableVector) { #if DEBUG Debug.Assert(!SynthParams.ScratchWorkspace2InUse); Debug.Assert(!SynthParams.ScratchWorkspace4InUse); SynthParams.ScratchWorkspace2InUse = true; SynthParams.ScratchWorkspace4InUse = true; #endif int MangleOffset2 = SynthParams.ScratchWorkspace2LOffset; int MangleOffset3 = SynthParams.ScratchWorkspace2ROffset; int MangleOffset4 = SynthParams.ScratchWorkspace4LOffset; /* process matrix */ for (; i <= BandCount - 4; i += 4) { /* initialize mangle vector with raw data */ FloatVectorCopy( SourceBase, SourceOffset, MangleBase, MangleOffset, Length); FloatVectorCopy( SourceBase, SourceOffset, MangleBase, MangleOffset2, Length); FloatVectorCopy( SourceBase, SourceOffset, MangleBase, MangleOffset3, Length); FloatVectorCopy( SourceBase, SourceOffset, MangleBase, MangleOffset4, Length); /* apply filters to succession, copying out on the last one */ for (int j = 0; j < OrderCount; j++) { if (j != OrderCount - 1) { /* interior filters modify the buffer, with unity gain */ ButterworthBandpassRec.ApplyButterworthBandpassVectorModify( BandMatrix[BandMatrixOffset + (i + 0) * OrderCount + j], BandMatrix[BandMatrixOffset + (i + 1) * OrderCount + j], BandMatrix[BandMatrixOffset + (i + 2) * OrderCount + j], BandMatrix[BandMatrixOffset + (i + 3) * OrderCount + j], MangleBase, MangleOffset, MangleOffset2, MangleOffset3, MangleOffset4, Length); } else { /* final filter adds to output */ ButterworthBandpassRec.Apply4( BandMatrix[BandMatrixOffset + (i + 0) * OrderCount + j], BandMatrix[BandMatrixOffset + (i + 1) * OrderCount + j], BandMatrix[BandMatrixOffset + (i + 2) * OrderCount + j], BandMatrix[BandMatrixOffset + (i + 3) * OrderCount + j], MangleBase, MangleOffset, MangleOffset2, MangleOffset3, MangleOffset4, Vector, VectorOffset, Length, CombinedGainFactorVector[CombinedGainFactorVectorOffset + i + 0], CombinedGainFactorVector[CombinedGainFactorVectorOffset + i + 1], CombinedGainFactorVector[CombinedGainFactorVectorOffset + i + 2], CombinedGainFactorVector[CombinedGainFactorVectorOffset + i + 3], SynthParams); } } } #if DEBUG SynthParams.ScratchWorkspace2InUse = false; SynthParams.ScratchWorkspace4InUse = false; #endif } #endif /* process matrix */ for (; i < BandCount; i++) { /* initialize mangle vector with raw data */ FloatVectorCopy( SourceBase, SourceOffset, MangleBase, MangleOffset, Length); /* apply filters to succession, copying out on the last one */ for (int j = 0; j < OrderCount; j++) { if (j != OrderCount - 1) { /* interior filters modify the buffer, with unity gain */ ButterworthBandpassRec.ApplyButterworthBandpassVectorModify( BandMatrix[BandMatrixOffset + i * OrderCount + j], MangleBase, MangleOffset, Length); } else { /* final filter adds to output */ BandMatrix[BandMatrixOffset + i * OrderCount + j].Apply( MangleBase, MangleOffset, Vector, VectorOffset, Length, CombinedGainFactorVector[CombinedGainFactorVectorOffset + i], SynthParams); } } } }
/* update a filter matrix given a wave table index and matrix base pointer */ /* first element in the list is the lowest ordered element in the wave table. */ /* wave index is scaled from 1 to #waves - 1 */ private static void VocoderUpdateMatrix( VocoderRec Vocoder, ButterworthBandpassRec[] BandMatrix, int BandMatrixOffset, float[] CombinedGainFactorVector, int CombinedGainFactorVectorOffset, SynthParamRec SynthParams) { int BandCount = Vocoder.BandCount; int OrderCount = Vocoder.OrderCount; float[][] WaveMatrix = Vocoder.WaveTableMatrix; float OverallGain = (float)Vocoder.CurrentOutputScaling; #if DEBUG if ((Vocoder.CurrentWaveTableIndex < 0) || (Vocoder.CurrentWaveTableIndex > Vocoder.NumberOfTablesMinus1)) { // table index out of range Debug.Assert(false); throw new InvalidOperationException(); } #endif if (((int)(Vocoder.CurrentWaveTableIndex) == Vocoder.NumberOfTablesMinus1) || !Vocoder.EnableCrossWaveTableInterpolation) { /* end interpolation */ float[] WaveData = WaveMatrix[(int)(Vocoder.CurrentWaveTableIndex)]; /* start at the beginning */ for (int i = 0; i < BandCount; i++) { /* L+F(R-L) */ /* consult wave table for center frequency */ float RawCenterFreq = WaveData[i * VOC_FIELDCOUNT + 0]; /* consult wave table for bandwidth */ float RawBandWidth = WaveData[i * VOC_FIELDCOUNT + 1]; /* consult wave table for gain */ float RawUncombinedGain = WaveData[i * VOC_FIELDCOUNT + 2]; /* do the mappings */ CombinedGainFactorVector[CombinedGainFactorVectorOffset + i] = RawUncombinedGain * OverallGain; double CookedCenterFreq = (VOC_MAXFREQ * 0.5) * (1 + (double)RawCenterFreq); double CookedBandWidth = (VOC_MAXFREQ * 0.5) * (1 + (double)RawBandWidth); /* set the settings */ for (int j = 0; j < OrderCount; j++) { ButterworthBandpassRec.SetButterworthBandpassCoefficients( BandMatrix[BandMatrixOffset + i * OrderCount + j], CookedCenterFreq, CookedBandWidth, SynthParams.dSamplingRate); } } } else { /* compute table weighting */ float Wave1Weight = (float)(Vocoder.CurrentWaveTableIndex - (int)(Vocoder.CurrentWaveTableIndex)); /* full interpolation */ float[] WaveData0 = WaveMatrix[(int)(Vocoder.CurrentWaveTableIndex)]; float[] WaveData1 = WaveMatrix[(int)(Vocoder.CurrentWaveTableIndex) + 1]; /* start at the beginning */ for (int i = 0; i < BandCount; i++) { float Wave0Value, Wave1Value; /* L+F(R-L) */ /* consult wave table for center frequency */ Wave0Value = WaveData0[i * VOC_FIELDCOUNT + 0]; Wave1Value = WaveData1[i * VOC_FIELDCOUNT + 0]; float RawCenterFreq = Wave0Value + (Wave1Weight * (Wave1Value - Wave0Value)); /* consult wave table for bandwidth */ Wave0Value = WaveData0[i * VOC_FIELDCOUNT + 1]; Wave1Value = WaveData1[i * VOC_FIELDCOUNT + 1]; float RawBandWidth = Wave0Value + (Wave1Weight * (Wave1Value - Wave0Value)); /* consult wave table for gain */ Wave0Value = WaveData0[i * VOC_FIELDCOUNT + 2]; Wave1Value = WaveData1[i * VOC_FIELDCOUNT + 2]; float RawUncombinedGain = Wave0Value + (Wave1Weight * (Wave1Value - Wave0Value)); /* do the mappings */ CombinedGainFactorVector[CombinedGainFactorVectorOffset + i] = RawUncombinedGain * OverallGain; double CookedCenterFreq = (VOC_MAXFREQ * 0.5) * (1 + (double)RawCenterFreq); double CookedBandWidth = (VOC_MAXFREQ * 0.5) * (1 + (double)RawBandWidth); /* set the settings */ for (int j = 0; j < OrderCount; j++) { ButterworthBandpassRec.SetButterworthBandpassCoefficients( BandMatrix[BandMatrixOffset + i * OrderCount + j], CookedCenterFreq, CookedBandWidth, SynthParams.dSamplingRate); } } } }
/* create a new oscillator vocoder */ public static VocoderRec NewOscVocoder( VocoderSpecRec Template, ref AccentRec Accents, double HurryUp, double InitialFrequency, double FreqForMultisampling, out int PreOriginTimeOut, PlayTrackInfoRec TrackInfo, SynthParamRec SynthParams) { int OnePreOrigin; /* initialize common portion of structure */ VocoderRec Vocoder = VocoderBuildCommonStructure( Template, SynthParams); Vocoder.Oscillator = new VocOscRec(); /* initialize variant portion */ int MaxPreOrigin = 0; Vocoder.Oscillator.OutputScalingEnvelope = NewEnvelopeStateRecord( GetVocoderSpecOutputGainEnvelope(Template), ref Accents, InitialFrequency, 1, HurryUp, out OnePreOrigin, _PlayTrackParamGetter, TrackInfo, SynthParams); if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } Vocoder.Oscillator.OutputScalingLFO = NewLFOGenerator( GetVocoderSpecOutputGainLFO(Template), out OnePreOrigin, ref Accents, InitialFrequency, HurryUp, 1, 1, FreqForMultisampling, _PlayTrackParamGetter, TrackInfo, SynthParams); if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } Vocoder.Oscillator.WaveTableIndexEnvelope = NewEnvelopeStateRecord( GetVocoderSpecIndexEnvelope(Template), ref Accents, InitialFrequency, 1, HurryUp, out OnePreOrigin, _PlayTrackParamGetter, TrackInfo, SynthParams); if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } Vocoder.Oscillator.WaveTableIndexLFO = NewLFOGenerator( GetVocoderSpecIndexLFO(Template), out OnePreOrigin, ref Accents, InitialFrequency, HurryUp, 1, 1, FreqForMultisampling, _PlayTrackParamGetter, TrackInfo, SynthParams); if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } PreOriginTimeOut = MaxPreOrigin; return(Vocoder); }
/* create a new oscillator effect generator */ public static SynthErrorCodes NewOscEffectGenerator( EffectSpecListRec SpecList, ref AccentRec Accents, double HurryUp, double InitialFrequency, double FreqForMultisampling, out int PreOriginTimeOut, PlayTrackInfoRec TrackInfo, SynthParamRec SynthParams, out OscEffectGenRec GeneratorOut) { int OnePreOrigin; GeneratorOut = null; PreOriginTimeOut = 0; OscEffectGenRec Generator = New(ref SynthParams.freelists.OscEffectGenRecFreeList); int count = Generator.count = GetEffectSpecListEnabledLength(SpecList); IOscillatorEffect[] List = Generator.List = New(ref SynthParams.freelists.IOscillatorEffectFreeList, count); // zeroed if (unchecked ((uint)count > (uint)List.Length)) { Debug.Assert(false); throw new IndexOutOfRangeException(); } int MaxPreOrigin = 0; /* build list of thingers */ int j = 0; for (int i = 0; j < count; i++) { /* see if effect is enabled */ if (!IsEffectFromEffectSpecListEnabled(SpecList, i)) { continue; } /* fill in fields */ EffectTypes Type = GetEffectSpecListElementType(SpecList, i); switch (Type) { default: Debug.Assert(false); throw new ArgumentException(); case EffectTypes.eDelayEffect: List[j] = DelayUnifiedRec.NewOscUnifiedDelayLineProcessor( GetDelayEffectFromEffectSpecList(SpecList, i), ref Accents, HurryUp, InitialFrequency, FreqForMultisampling, out OnePreOrigin, TrackInfo, SynthParams); if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } break; case EffectTypes.eNLProcEffect: List[j] = NLProcUnifiedRec.NewOscNLProcProcessor( GetNLProcEffectFromEffectSpecList(SpecList, i), ref Accents, HurryUp, InitialFrequency, FreqForMultisampling, out OnePreOrigin, TrackInfo, SynthParams); if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } break; case EffectTypes.eFilterEffect: List[j] = FilterArrayRec.NewOscFilterArrayProcessor( GetFilterEffectFromEffectSpecList(SpecList, i), ref Accents, HurryUp, InitialFrequency, FreqForMultisampling, out OnePreOrigin, TrackInfo, SynthParams); if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } break; case EffectTypes.eAnalyzerEffect: List[j] = AnalyzerRec.NewAnalyzer( GetAnalyzerEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eHistogramEffect: List[j] = HistogramRec.NewHistogram( GetHistogramEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eResamplerEffect: List[j] = ResamplerRec.NewResampler( GetResamplerEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eCompressorEffect: List[j] = CompressorRec.NewOscCompressor( GetCompressorEffectFromEffectSpecList(SpecList, i), ref Accents, HurryUp, InitialFrequency, FreqForMultisampling, out OnePreOrigin, TrackInfo, SynthParams); if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } break; case EffectTypes.eVocoderEffect: List[j] = VocoderRec.NewOscVocoder( GetVocoderEffectFromEffectSpecList(SpecList, i), ref Accents, HurryUp, InitialFrequency, FreqForMultisampling, out OnePreOrigin, TrackInfo, SynthParams); if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } break; case EffectTypes.eIdealLowpassEffect: List[j] = IdealLPRec.NewIdealLP( GetIdealLPEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eUserEffect: { UserEffectProcRec userEffect; SynthErrorCodes error = UserEffectProcRec.NewOscUserEffectProc( GetUserEffectFromEffectSpecList(SpecList, i), ref Accents, HurryUp, InitialFrequency, FreqForMultisampling, out OnePreOrigin, TrackInfo, SynthParams, out userEffect); if (error != SynthErrorCodes.eSynthDone) { return(error); } List[j] = userEffect; if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } } break; case EffectTypes.ePluggableEffect: { PluggableSpec Spec = GetPluggableEffectFromEffectSpecList(SpecList, i); Debug.Assert(Spec is PluggableOscSpec); PluggableOscEffectTemplate template = new PluggableOscEffectTemplate( (PluggableOscSpec)Spec, SynthParams); IOscillatorEffect effect; SynthErrorCodes error = template.Create( ref Accents, HurryUp, InitialFrequency, FreqForMultisampling, out OnePreOrigin, TrackInfo, SynthParams, out effect); if (error != SynthErrorCodes.eSynthDone) { return(error); } List[j] = effect; if (OnePreOrigin > MaxPreOrigin) { MaxPreOrigin = OnePreOrigin; } } break; } j++; } Debug.Assert(j == count); PreOriginTimeOut = MaxPreOrigin; GeneratorOut = Generator; return(SynthErrorCodes.eSynthDone); }
/* create a new track effect generator */ public static SynthErrorCodes NewTrackEffectGenerator( EffectSpecListRec SpecList, SynthParamRec SynthParams, out TrackEffectGenRec GeneratorOut) { GeneratorOut = null; TrackEffectGenRec Generator = new TrackEffectGenRec(); Generator.Enable = true; Generator.AutoQuiescence = EffectSpecListIsAutoQuiescenceEnabled(SpecList); if (Generator.AutoQuiescence) { Generator.Enable = false; /* start with it off in this case */ Generator.GateLevel = (float)(Math.Pow( 2, EffectSpecListGetAutoQuiescenceDecibels(SpecList) * (1 / -6.0205999132796239)) / SynthParams.fOverallVolumeScaling); Generator.WindowDuration = (int)(SynthParams.dEnvelopeRate * EffectSpecListGetAutoQuiescenceWindowDuration(SpecList)); Generator.CurrentWindowDuration = 0; } /* this is the current envelope update index for removing things from the */ /* scanning gap list (i.e. the back edge of the scanning gap) */ /* by setting this negative, we cause the scanning gap to open. */ Generator.ExecutionIndex = -SynthParams.iScanningGapWidthInEnvelopeTicks; /* initialize accent trackers */ InitAccentTracker(ref Generator.Accents0); InitAccentTracker(ref Generator.Accents1); InitAccentTracker(ref Generator.Accents2); InitAccentTracker(ref Generator.Accents3); InitAccentTracker(ref Generator.Accents4); InitAccentTracker(ref Generator.Accents5); InitAccentTracker(ref Generator.Accents6); InitAccentTracker(ref Generator.Accents7); /* build list of thingers */ OneEffectRec Appender = null; int l = GetEffectSpecListLength(SpecList); for (int i = 0; i < l; i += 1) { /* see if effect is enabled */ if (IsEffectFromEffectSpecListEnabled(SpecList, i)) { OneEffectRec Effect = new OneEffectRec(); /* link */ Effect.Next = null; if (Appender == null) { Generator.List = Effect; } else { Appender.Next = Effect; } Appender = Effect; /* fill in fields */ EffectTypes Type = GetEffectSpecListElementType(SpecList, i); switch (Type) { default: Debug.Assert(false); throw new ArgumentException(); case EffectTypes.eDelayEffect: Effect.u = DelayUnifiedRec.NewTrackDelayLineProcessor( GetDelayEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eNLProcEffect: Effect.u = NLProcUnifiedRec.NewTrackNLProcProcessor( GetNLProcEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eFilterEffect: Effect.u = FilterArrayRec.NewTrackFilterArrayProcessor( GetFilterEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eAnalyzerEffect: Effect.u = AnalyzerRec.NewAnalyzer( GetAnalyzerEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eHistogramEffect: Effect.u = HistogramRec.NewHistogram( GetHistogramEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eResamplerEffect: Effect.u = ResamplerRec.NewResampler( GetResamplerEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eCompressorEffect: Effect.u = CompressorRec.NewTrackCompressor( GetCompressorEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eVocoderEffect: Effect.u = VocoderRec.NewTrackVocoder( GetVocoderEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eIdealLowpassEffect: Effect.u = IdealLPRec.NewIdealLP( GetIdealLPEffectFromEffectSpecList(SpecList, i), SynthParams); break; case EffectTypes.eConvolverEffect: { ConvolverRec ConvolverEffect; SynthErrorCodes Result = ConvolverRec.NewConvolver( GetConvolverEffectFromEffectSpecList(SpecList, i), SynthParams, out ConvolverEffect); if (Result != SynthErrorCodes.eSynthDone) { return(Result); } Effect.u = ConvolverEffect; } break; case EffectTypes.eUserEffect: { UserEffectProcRec userEffect; SynthErrorCodes error = UserEffectProcRec.NewTrackUserEffectProc( GetUserEffectFromEffectSpecList(SpecList, i), SynthParams, out userEffect); if (error != SynthErrorCodes.eSynthDone) { return(error); } Effect.u = userEffect; } break; case EffectTypes.ePluggableEffect: { PluggableSpec Spec = GetPluggableEffectFromEffectSpecList(SpecList, i); Debug.Assert(Spec is PluggableTrackSpec); PluggableTrackEffectTemplate Template = new PluggableTrackEffectTemplate( (PluggableTrackSpec)Spec, SynthParams); ITrackEffect effect; SynthErrorCodes error = Template.Create( SynthParams, out effect); if (error != SynthErrorCodes.eSynthDone) { return(error); } Effect.u = effect; } break; } } } GeneratorOut = Generator; return(SynthErrorCodes.eSynthDone); }