using System; namespace QuikDawEditor.EditingClasses; public partial class Clip { private double _PitchChangeValue = 0; public double PitchChangeValue { get { return _PitchChangeValue; } set { _PitchChangeValue = value; NotifyPropertyChanged(nameof(PitchChangeValue)); } } internal double preslidePitchChangeValue; internal float floatPitchValue = 1f; private int _FFTSize = 4096; //private long _osamp = 8L; private long _osamp = 4L; private SMBPitchShifter ShifterLeft = new SMBPitchShifter(); private SMBPitchShifter ShifterRight = new SMBPitchShifter(); internal float GetPitchFloatFromHalfStepValue(int halfStep) { if (halfStep > 0) return (float)((12 + halfStep) / 12f); else if (halfStep < 0) return (float)(((12 + halfStep) / 12f * 0.5f) + 0.5f); else return 1f; } public float[] PitchShiftedSamples(float[] samplesToShift, int offset, int outputSamples) { int SampRead = outputSamples; //if (Pitch == 1f) return samplesToShift; //Nothing to do. if (myClipSampleProvider.WaveFormat.Channels == 1) { float[] Mono = new float[SampRead]; int index = 0; for (int sample = offset; sample <= SampRead + offset - 1; sample++) { Mono[index] = samplesToShift[sample]; index += 1; } //ShifterLeft.PitchShift(floatPitchValue, SampRead, _FFTSize, _osamp, myClipSampleProvider.WaveFormat.SampleRate, Mono); index = 0; for (int sample = offset; sample <= SampRead + offset - 1; sample++) { samplesToShift[sample] = ShifterLeft.Limiter(Mono[index]); index += 1; } } else { //stereo float[] Left = new float[(SampRead >> 1)]; float[] Right = new float[(SampRead >> 1)]; int index = 0; for (int sample = offset; sample <= SampRead + offset - 1; sample += 2) { Left[index] = samplesToShift[sample]; Right[index] = samplesToShift[sample + 1]; index += 1; } //ShifterLeft.PitchShift(floatPitchValue, SampRead >> 1, _FFTSize, _osamp, myClipSampleProvider.WaveFormat.SampleRate, Left); //ShifterRight.PitchShift(floatPitchValue, SampRead >> 1, _FFTSize, _osamp, myClipSampleProvider.WaveFormat.SampleRate, Right); ShifterLeft.PitchShift(floatPitchValue, SampRead >> 1, myClipSampleProvider.WaveFormat.SampleRate, Left); ShifterRight.PitchShift(floatPitchValue, SampRead >> 1, myClipSampleProvider.WaveFormat.SampleRate, Right); index = 0; for (int sample = offset; sample <= SampRead + offset - 1; sample += 2) { samplesToShift[sample] = Limiter(Left[index]); samplesToShift[sample + 1] = Limiter(Right[index]); //samplesToShift[sample] = Left[index]; //samplesToShift[sample + 1] = Right[index]; index += 1; } } return samplesToShift; } //Limiter constants const float LIM_THRESH = 0.95f; const float LIM_RANGE = (1f - LIM_THRESH); const float M_PI_2 = (float)(Math.PI / 2); private float Limiter(float Sample) { float res = 0f; if (LIM_THRESH < Sample) { res = (Sample - LIM_THRESH) / LIM_RANGE; res = (float)((Math.Atan(res) / M_PI_2) * LIM_RANGE + LIM_THRESH); } else if (Sample < -LIM_THRESH) { res = -(Sample + LIM_THRESH) / LIM_RANGE; res = -(float)((Math.Atan(res) / M_PI_2) * LIM_RANGE + LIM_THRESH); } else res = Sample; return res; } }