static IEnumerable<IEnumerable<float>> UpSample(WaveReader reader, int windowSize) { var fft = new MathNet.Numerics.Transformations.ComplexFourierTransformation (); var determineVolumeSource = new Complex[] { new Complex(1, 0), new Complex(1, 0), new Complex(1, 0), new Complex(1, 0), }; fft.TransformForward(determineVolumeSource); var determineVolumeDestination = new Complex[windowSize]; determineVolumeDestination[0] = determineVolumeSource[0]; for (var sampleCtr = 1; sampleCtr < windowSize; sampleCtr++) determineVolumeDestination[sampleCtr] = Complex.FromModulusArgument(0,0); fft.TransformBackward(determineVolumeDestination); var multiplier = determineVolumeDestination[0].Real; var sampleQueue = new Queue<float[]>(); for (var sampleCtr = 0; sampleCtr < 2; sampleCtr++) sampleQueue.Enqueue(new float[reader.NumChannels]); foreach (var samples in reader.ReadAllSamples_Float().Select(s => s.ToArray())) { sampleQueue.Enqueue(samples); if (sampleQueue.Count == 4) { var expanded = new float[windowSize / 2][]; for (var ctr = 0; ctr < windowSize / 2; ctr++) expanded[ctr] = new float[reader.NumChannels]; for (var channelCtr = 0; channelCtr < reader.NumChannels; channelCtr++) { var samplesToTransform = sampleQueue.Select(s => new Complex (s[channelCtr], 0)).ToArray(); fft.TransformForward (samplesToTransform); var samplesToTransformBack = new Complex[windowSize]; samplesToTransformBack[0] = samplesToTransform[0]; samplesToTransformBack[1] = samplesToTransform[1]; samplesToTransformBack[1].Modulus /= 2; samplesToTransformBack[samplesToTransformBack.Length - 1] = samplesToTransform[1]; samplesToTransformBack[samplesToTransformBack.Length - 1].Modulus /= 2; samplesToTransformBack[samplesToTransformBack.Length - 1].Argument *= -1; for (var ctr = 2; ctr < samplesToTransformBack.Length - 1; ctr++) samplesToTransformBack[ctr] = Complex.FromModulusArgument(0, 0); fft.TransformBackward(samplesToTransformBack); for (var ctr = 0; ctr < windowSize / 2; ctr++) expanded[ctr][channelCtr] = Convert.ToSingle(samplesToTransformBack[ctr + windowSize / 4].Real / multiplier); } foreach (var simplified in expanded) yield return simplified; sampleQueue.Dequeue(); sampleQueue.Dequeue(); } } }
public static IEnumerable<float[]> DownSample(IEnumerable<float[]> samplesEnumerator, int numChannels, int windowSize, Action<float[]> highSampleCallback) { var fft = new MathNet.Numerics.Transformations.ComplexFourierTransformation (); var determineVolumeSource = new Complex[windowSize]; for (var sampleCtr = 0; sampleCtr < windowSize; sampleCtr++) determineVolumeSource[sampleCtr] = new Complex(1, 0); fft.TransformForward(determineVolumeSource); var determineVolumeDestination = new Complex[] { determineVolumeSource[0], Complex.FromModulusArgument(0,0), Complex.FromModulusArgument(0,0), Complex.FromModulusArgument(0,0) }; fft.TransformBackward(determineVolumeDestination); var dcMultiplier = determineVolumeDestination[0].Modulus; var ratio = (1d / Convert.ToDouble(windowSize)) * 2d * Math.PI; for (var sampleCtr = 0; sampleCtr < windowSize; sampleCtr++) { var sampleCtrDouble = Convert.ToDouble(sampleCtr); determineVolumeSource[sampleCtr] = new Complex(Math.Cos(sampleCtrDouble * ratio), 0); } fft.TransformForward(determineVolumeSource); determineVolumeDestination = new Complex[] { Complex.FromModulusArgument(0,0), determineVolumeSource[1], Complex.FromModulusArgument(0,0), determineVolumeSource[determineVolumeSource.Length - 1], }; fft.TransformBackward(determineVolumeDestination); var midMultiplier = determineVolumeDestination.Select(s => s.Modulus).Max(); /*// This only works when windowsize is 8 for (var sampleCtr = 0; sampleCtr < windowSize; sampleCtr++) { var abs = sampleCtr % 2 == 1 ? 1 : 0; var sign = sampleCtr % 4 > 1 ? 1 : -1; determineVolumeSource[sampleCtr] = new Complex(abs * sign, 0); }*/ ratio = (1d / Convert.ToDouble(windowSize)) * 4d * Math.PI; for (var sampleCtr = 0; sampleCtr < windowSize; sampleCtr++) { var sampleCtrDouble = Convert.ToDouble(sampleCtr); determineVolumeSource[sampleCtr] = new Complex(Math.Cos(sampleCtrDouble * ratio), 0); } fft.TransformForward(determineVolumeSource); determineVolumeDestination = new Complex[] { Complex.FromModulusArgument(0,0), Complex.FromModulusArgument(0,0), determineVolumeSource[2], Complex.FromModulusArgument(0,0), }; fft.TransformBackward(determineVolumeDestination); var highMultiplier = determineVolumeDestination.Select(s => s.Modulus).Max(); var sampleQueue = new Queue<float[]>(); for (var sampleCtr = 0; sampleCtr < windowSize / 4; sampleCtr++) sampleQueue.Enqueue(new float[numChannels]); var maxOriginalSample = 0.0; var maxLowFrequencySample = 0.0; using (var sampleEnumerator = samplesEnumerator.GetEnumerator()) { int samplesFromSource; do { samplesFromSource = 0; while (sampleQueue.Count < windowSize) { if (sampleEnumerator.MoveNext()) { sampleQueue.Enqueue(sampleEnumerator.Current.ToArray()); samplesFromSource++; } else sampleQueue.Enqueue(new float[numChannels]); } var simplified = new float[][] { new float[numChannels], new float[numChannels] }; var filtered = new float[windowSize / 2][]; for (var sampleCtr = 0; sampleCtr < windowSize / 2; sampleCtr++) filtered[sampleCtr] = new float[numChannels]; for (var channelCtr = 0; channelCtr < numChannels; channelCtr++) { maxOriginalSample = Math.Max( maxOriginalSample, sampleQueue.Select(s => Math.Abs(s[channelCtr])).Max()); var samplesToTransform = sampleQueue.Select (s => new Complex (s [channelCtr], 0)).ToArray (); fft.TransformForward (samplesToTransform); var samplesToTransformBack = new Complex[] { samplesToTransform[0], samplesToTransform[1], samplesToTransform[2], samplesToTransform[samplesToTransform.Length - 1] }; samplesToTransformBack[0].Modulus /= dcMultiplier; samplesToTransformBack[1].Modulus /= midMultiplier; samplesToTransformBack[2].Modulus /= highMultiplier; samplesToTransformBack[3].Modulus /= midMultiplier; fft.TransformBackward(samplesToTransformBack); simplified[0][channelCtr] = Convert.ToSingle(samplesToTransformBack[1].Real); simplified[1][channelCtr] = Convert.ToSingle(samplesToTransformBack[2].Real); for (var filterCtr = 3; filterCtr < (samplesToTransform.Length - 1); filterCtr++) samplesToTransform[filterCtr] = Complex.FromModulusArgument(0, 0); fft.TransformBackward(samplesToTransform); for (var sampleCtr = 0; sampleCtr < windowSize / 2; sampleCtr++) filtered[sampleCtr][channelCtr] = Convert.ToSingle(samplesToTransform[sampleCtr + (windowSize / 4)].Real); } maxLowFrequencySample = Math.Max( maxLowFrequencySample, simplified.SelectMany(s => s).Select(Math.Abs).Max()); foreach (var samples in simplified) yield return samples; foreach (var samples in filtered) highSampleCallback(samples); while (sampleQueue.Count > windowSize / 2) sampleQueue.Dequeue(); } while (samplesFromSource > (windowSize / 4)); } /*Console.WriteLine("Loudest sample in source: {0}", maxOriginalSample); Console.WriteLine("Loudest sample in low frequency: {0}", maxLowFrequencySample); //Console.WriteLine("Loudest sample in high frequency: {0}", maxHighFrequencySample); Console.WriteLine();*/ }