private static int ProcessSingleBufferFillByteBuffer( IReadOnlyList <VstAudioBuffer> vstBufOut, IReadOnlyList <VstAudioPrecisionBuffer> vstBufOut2, bool isDoublePrecision, WAVParser pcmOutput, int vstOutputCount, int samplesPerBuffer ) { for (var iSample = 0; iSample < samplesPerBuffer; iSample++) { for (int channel = 0; channel < pcmOutput.ChannelCount; channel++) { if (channel < vstOutputCount) { if (!isDoublePrecision) { float sampleF = vstBufOut[channel][iSample]; pcmOutput.Samples[channel].Add(sampleF); } else { double sampleD = vstBufOut2[channel][iSample]; pcmOutput.Samples[channel].Add(sampleD); } } } } return(0); }
public void ChangeVolumeTest( string input, double changeDb, string referenceFile, double?rmseMax ) { WAVParser newFile; { var parser = new WAVParser(ResolveDataFile(input)); newFile = parser.ChangeVolume(changeDb); } var parserReference = new WAVParser(ResolveDataFile(referenceFile)); var rmseMaxValue = rmseMax ?? 0.000_01d; for (int channelId = 0; channelId < newFile.Samples.Count; channelId++) { var expected = parserReference.Samples[channelId]; var actual = newFile.Samples[channelId]; var sum = actual.Select((t, i) => Math.Pow(t - expected[i], 2)).Sum(); var rmse = Math.Sqrt(sum / actual.Count); Assert.InRange(rmse, 0, rmseMaxValue); } }
public static void AddSilence(WAVParser input, TimeSpan duration) { var samplesCount = (int)input.GetFloorSamplesCount(duration); var buffer = new double[samplesCount]; foreach (var channel in input.Samples) { channel.AddRange(buffer); } }
public void WriteAndLoad( string filename, ushort bitsPerSample ) { var parser = new WAVParser(ResolveDataFile(filename)); var temporaryFile = Path.GetTempFileName(); parser.BitsPerSample = bitsPerSample; parser.Save(temporaryFile); // WAVParser reReader; try { reReader = new WAVParser(temporaryFile); } finally { File.Delete(temporaryFile); } Assert.Equal(parser.ChannelCount, reReader.ChannelCount); Assert.Equal(parser.SampleRate, reReader.SampleRate); Assert.Equal(parser.BitsPerSample, reReader.BitsPerSample); Assert.Equal(parser.SamplesCount, reReader.SamplesCount); Assert.Equal(parser.Duration, reReader.Duration); var minSampleRate = Math.Min(bitsPerSample, parser.BitsPerSample); var minSampleRateC = 1 << (minSampleRate - 1); for (int channelId = 0; channelId < parser.ChannelCount; channelId++) { var sum = 0d; for (int i = 0; i < parser.SamplesCount; i++) { var expected = parser.Samples[channelId][i]; var real = reReader.Samples[channelId][i]; var tE = (expected > 0) ? minSampleRateC - 1 : minSampleRateC; var tR = (real > 0) ? minSampleRateC - 1 : minSampleRateC; var expected1 = Math.Round(expected * tE) / tE; var real1 = Math.Round(real * tR) / tR; var diff = real1 - expected1; sum += Math.Pow(diff, 2); } var rmse = Math.Sqrt(sum / parser.SamplesCount); Assert.InRange(rmse, 0, 0.000_01d); } }
public void CheckWorkingPureItem() { var item = new WAVParser(); Assert.Equal(1, item.AudioFormat); Assert.InRange(item.ChannelCount, 1, int.MaxValue); Assert.Equal(0, item.BitsPerSample % 8); Assert.InRange(item.BitsPerSample, 1, 96_000); Assert.Equal((item.BitsPerSample / 8) * item.ChannelCount, item.BlockAlign); Assert.Equal(0, item.SamplesCount); Assert.Equal(TimeSpan.Zero, item.Duration); Assert.NotNull(item.ToString()); }
public static WAVParser ChangeVolume(WAVParser wavParser, double changeDb) { var newSamples = wavParser .Samples .Select(channel => ChangeVolume(channel, changeDb)) .ToList(); var outputFile = wavParser.Clone(); outputFile.Samples = newSamples; return(outputFile); }
public void WriteTest() { var rnd = new Random(); // ReSharper disable once UseObjectOrCollectionInitializer var parser = new WAVParser(); parser.ChannelCount = 1; parser.Samples = new List <List <double> >() { new List <double>() }; parser.BlockAlign = (ushort)(parser.ChannelCount * parser.BitsPerSample / 8); for (int i = 0; i < 1000; i++) { parser.Samples[0].Add(rnd.NextDouble() * 2 - 1); } // Re read var newRiff = parser.GetDataAsRiff(); var reReader = new WAVParser(newRiff); Assert.Equal(parser.ChannelCount, reReader.ChannelCount); Assert.Equal(parser.AudioFormat, reReader.AudioFormat); Assert.Equal(parser.BlockAlign, reReader.BlockAlign); Assert.Equal(parser.SampleRate, reReader.SampleRate); Assert.Equal(parser.BitsPerSample, reReader.BitsPerSample); Assert.Equal(parser.SamplesCount, reReader.SamplesCount); Assert.Equal(parser.Duration, reReader.Duration); for (int channelId = 0; channelId < parser.ChannelCount; channelId++) { for (int i = 0; i < parser.SamplesCount; i++) { var diff = reReader.Samples[channelId][i] - parser.Samples[channelId][i]; Assert.InRange(diff, -0.000_1d, 0.000_1d); } } }
/// <summary> /// Read 2-bytes octets from byteBuffer and put them to VstAudioBuffer /// </summary> /// <param name="samplesOffset"></param> /// <param name="vstBufIn"></param> /// <param name="vstBufIn2"></param> /// <param name="isDoublePrecision"></param> /// <param name="pcmInput"></param> /// <param name="pcmOutput"></param> /// <param name="vstOutputCount"></param> /// <returns></returns> private static int ProcessSingleBufferFillBufferInput( int samplesOffset, IReadOnlyList <VstAudioBuffer> vstBufIn, IReadOnlyList <VstAudioPrecisionBuffer> vstBufIn2, bool isDoublePrecision, WAVParser pcmInput, WAVParser pcmOutput, int vstOutputCount ) { for (int i = samplesOffset; i < Math.Min(pcmInput.SamplesCount, samplesOffset + pcmInput.SampleRate); i++) { var iSample = i - samplesOffset; for (int channel = 0; channel < pcmOutput.ChannelCount; channel++) { if (channel >= vstOutputCount) { continue; } double sample = pcmInput.Samples[channel][i]; if (!isDoublePrecision) { vstBufIn[channel][iSample] = (float)sample; } else { vstBufIn2[channel][iSample] = sample; } } } // int i = 0; i < bytesReadFromAudioStream return(0); }
public void ParseFiles( string filename, int channelCount, int sampleRate, int bitsPerSample, int sampleCount, string templateFilename, Tuple <int, double, bool> toneTest ) { WAVParser parser; using (var stream = File.Open(ResolveDataFile(filename), FileMode.Open)) { parser = new WAVParser(stream); Assert.Equal(channelCount, parser.ChannelCount); Assert.Equal((uint)sampleRate, parser.SampleRate); Assert.Equal(bitsPerSample, parser.BitsPerSample); Assert.NotNull(parser.ToString()); Assert.InRange(parser.StartDataSeek, 42, 1024); Assert.Equal(sampleCount, parser.SamplesCount); foreach (var list in parser.Samples) { Assert.Equal(sampleCount, list.Count); foreach (var sample in list) { Assert.InRange(sample, -1, 1); } } var durationDiff = parser.Duration - TimeSpan.FromSeconds(sampleCount * 1d / sampleRate); var durationDiffTicks = Math.Abs(durationDiff.Ticks); Assert.InRange(durationDiffTicks, 0, TimeSpan.TicksPerMillisecond - 1); Assert.Equal(TimeSpan.TicksPerSecond, parser.GetSpanForSamples(sampleRate).Ticks); Assert.Equal(sampleRate, parser.GetFloorSamplesCount(1)); } if (templateFilename != null) { Assert.NotEqual(filename, templateFilename); WAVParser parserTemplate; using (var stream = File.Open(ResolveDataFile(templateFilename), FileMode.Open)) { parserTemplate = new WAVParser(stream); } Assert.Equal(sampleCount, parserTemplate.SamplesCount); var minSampleRate = Math.Min(parserTemplate.BitsPerSample, parser.BitsPerSample); var minSampleRateC = 1 << (minSampleRate - 1); for (int channelId = 0; channelId < parser.Samples.Count; channelId++) { var sum = 0d; for (int i = 0; i < sampleCount; i++) { var expected = parserTemplate.Samples[channelId][i]; var real = parser.Samples[channelId][i]; var tE = (expected > 0) ? minSampleRateC - 1 : minSampleRateC; var tR = (real > 0) ? minSampleRateC - 1 : minSampleRateC; var expected1 = Math.Round(expected * tE) / tE; var real1 = Math.Round(real * tR) / tR; sum += Math.Pow(real1 - expected1, 2); } var rmse = Math.Sqrt(sum / sampleCount); Assert.InRange(rmse, 0, 0.006d); } } if (toneTest != null) { var(sinusoidHz, sinusoidValue, isSquare) = toneTest; var sinusoidHzR = Math.PI * 2 * sinusoidHz / parser.SampleRate; double minValue = double.NaN, maxValue = double.NaN; foreach (var channelSamples in parser.Samples) { var sum = 0d; var sumRMSE_Square = 0d; var sumRMSE_Sin = 0d; for (var i = 0; i < channelSamples.Count; i++) { var sample = channelSamples[i]; minValue = !double.IsNaN(minValue) ? Math.Min(sample, minValue) : sample; maxValue = !double.IsNaN(maxValue) ? Math.Max(sample, maxValue) : sample; sum += sample; if (isSquare) { sumRMSE_Square += Math.Pow(Math.Abs(sample) - sinusoidValue, 2); } else { var angleRad = i * sinusoidHzR; var expectedValue = Math.Sin(angleRad) * sinusoidValue; sumRMSE_Sin += Math.Pow(sample - expectedValue, 2); } } var averageValue = sum / channelSamples.Count; Assert.InRange(averageValue, 0, 0.000_02d); if (isSquare) { var rmse = Math.Sqrt(sumRMSE_Square / channelSamples.Count); Assert.InRange(rmse, 0, 0.000_1d); } else { var rmse = Math.Sqrt(sumRMSE_Sin / channelSamples.Count); Assert.InRange(rmse, 0, 0.000_1d); } } { var sinusoidValue_Min = Math.Min(sinusoidValue / 1.00037d, sinusoidValue); var sinusoidValue_Max = Math.Min(sinusoidValue * 1.00037d, 1); Assert.InRange(-minValue, sinusoidValue_Min, sinusoidValue_Max); Assert.InRange(maxValue, sinusoidValue_Min, sinusoidValue_Max); } } }
public static WAVParser ChangeSampleRate(WAVParser parser, int newSampleRate) { var newFile = parser.Clone(true); if (newFile.SampleRate == newSampleRate) { return(newFile); } int hz1, hz2; { var nok = NOK((int)parser.SampleRate, newSampleRate); hz1 = (int)(nok / newSampleRate); hz2 = (int)(nok / parser.SampleRate); } int[] indexes; double[] rCoefs; { var indexesA = new List <int>(hz2); var rCoefsA = new List <double>(hz2); for (int j = 0; j < hz2; j++) { var coef = j * 1d * hz1 / hz2; var index1 = (int)Math.Floor(coef); var r1 = coef - index1; indexesA.Add(index1); rCoefsA.Add(r1); } indexes = indexesA.ToArray(); rCoefs = rCoefsA.ToArray(); } var channelFull = new List <List <double> >(); foreach (var channelA in parser.Samples.Select(t => t.ToList())) { int maxSampleCount = (int)Math.Ceiling(channelA.Count * 1d * hz2 / hz1); double[] channel; { var fillValue = channelA.Last(); while (channelA.Count % hz1 != 0) { channelA.Add(fillValue); } channelA.Add(fillValue); channel = channelA.ToArray(); } var samplesNew = new List <double>(); channelFull.Add(samplesNew); for (int i = 0; i < channel.Length - 1; i += hz1) { samplesNew.Add(channel[i]); for (int j = 1; j < hz2; j++) { var index1 = indexes[j]; var r1 = rCoefs[j]; var v1 = channel[index1 + i]; var v2 = channel[index1 + 1 + i]; if (v1 == v2) { samplesNew.Add(v1); continue; } var value = (1 - r1) * v1 + r1 * v2; samplesNew.Add(value); } } while (samplesNew.Count > maxSampleCount) { samplesNew.RemoveAt(samplesNew.Count - 1); } } newFile.Samples = channelFull; newFile.SampleRate = (ushort)newSampleRate; return(newFile); }
public static WAVParser ChangeSampleRate(WAVParser parser, uint newSampleRate) { return(ChangeSampleRate(parser, (int)newSampleRate)); }
public static WAVParser MergeFiles( WAVParser file1, WAVParser file2, MergeFileAlgorithm algorithm = MergeFileAlgorithm.AverageX2 ) { var realFile1 = file1.Clone(); var realFile2 = file2.Clone(); if (realFile1.SampleRate > realFile2.SampleRate) { realFile2 = ChangeSampleRate(realFile2, realFile1.SampleRate); } else if (realFile1.SampleRate < realFile2.SampleRate) { realFile1 = ChangeSampleRate(realFile1, realFile2.SampleRate); } var mergeMap = new List <List <int> >(); if (realFile1.ChannelCount == realFile2.ChannelCount) { for (int i = 0; i < realFile1.ChannelCount; i++) { mergeMap.Add(new List <int>() { i, i }); } } else { if (realFile1.ChannelCount == 1) { for (int i = 0; i < realFile2.ChannelCount; i++) { mergeMap.Add(new List <int>() { 0, i }); } } else if (realFile2.ChannelCount == 1) { for (int i = 0; i < realFile1.ChannelCount; i++) { mergeMap.Add(new List <int>() { i, 0 }); } } else { throw new Exception(string.Format("File 1 has {0} channels. File 2 has {1} channels. Can't merge", realFile1.ChannelCount, realFile2.ChannelCount)); } } var samples = new List <List <double> >(); foreach (var map in mergeMap) { var channel1 = realFile1.Samples[map[0]]; var channel2 = realFile2.Samples[map[1]]; samples.Add(MergeSamples(channel1, channel2, algorithm)); } var newFile = realFile1.Clone(); newFile.Samples = samples; return(newFile); }
private static int ProcessSingleBuffer( IVstPluginContext pluginContext, int samplesOffset, VstAudioBuffer[] vstBufIn, VstAudioBuffer[] vstBufOut, VstAudioPrecisionBuffer[] vstBufIn2, VstAudioPrecisionBuffer[] vstBufOut2, bool isDoublePrecision, WAVParser pcmInput, WAVParser pcmOutput, int vstInputCount, int vstOutputCount, int samplesPerBuffer ) { var result = ProcessSingleBufferClearBuffers( vstBufIn, vstBufOut, vstBufIn2, vstBufOut2, isDoublePrecision, vstInputCount, vstOutputCount, samplesPerBuffer ); if (result != 0) { return(result); } result = ProcessSingleBufferFillBufferInput( samplesOffset, vstBufIn, vstBufIn2, isDoublePrecision, pcmInput, pcmOutput, vstOutputCount ); if (result != 0) { return(result); } if (isDoublePrecision) { pluginContext.PluginCommandStub.ProcessReplacing(vstBufIn2, vstBufOut2); } else { pluginContext.PluginCommandStub.ProcessReplacing(vstBufIn, vstBufOut); } result = ProcessSingleBufferFillByteBuffer( vstBufOut, vstBufOut2, isDoublePrecision, pcmOutput, vstOutputCount, samplesPerBuffer ); return(result); }
public static int ProcessFile( string inputFile, string outputFile, VstPluginContext pluginContext, System.Threading.CancellationToken cancellationToken ) { var isDoublePrecision = pluginContext.PluginInfo.Flags.HasFlag(VstPluginFlags.CanDoubleReplacing); var pcmInput = new WAVParser(inputFile); var pcmOutput = new WAVParser { ChannelCount = pcmInput.ChannelCount, Samples = new List <List <double> >(), SampleRate = pcmInput.SampleRate, }; for (int i = 0; i < pcmOutput.ChannelCount; i++) { pcmOutput.Samples.Add(new List <double>()); } pluginContext.PluginCommandStub.SetSampleRate(pcmInput.SampleRate); pluginContext.PluginCommandStub.SetProcessPrecision(VstProcessPrecision.Process32); // hint: samples per buffer should be equal to pcmInput.SampleRate int samplesPerBuffer = (int)pcmInput.SampleRate; pluginContext.PluginCommandStub.SetBlockSize(samplesPerBuffer); int inputCount = pluginContext.PluginInfo.AudioInputCount; int outputCount = pluginContext.PluginInfo.AudioOutputCount; VstAudioBuffer[] vstBufIn = null, vstBufOut = null; VstAudioPrecisionBuffer[] vstBufIn2 = null, vstBufOut2 = null; if (isDoublePrecision) { var vstBufManIn = new VstAudioPrecisionBufferManager(inputCount, samplesPerBuffer); var vstBufManOut = new VstAudioPrecisionBufferManager(outputCount, samplesPerBuffer); vstBufIn2 = NumeratorToArray(vstBufManIn.GetEnumerator()); vstBufOut2 = NumeratorToArray(vstBufManOut.GetEnumerator()); } else { var vstBufManIn = new VstAudioBufferManager(inputCount, samplesPerBuffer); var vstBufManOut = new VstAudioBufferManager(outputCount, samplesPerBuffer); vstBufIn = NumeratorToArray(vstBufManIn.GetEnumerator()); vstBufOut = NumeratorToArray(vstBufManOut.GetEnumerator()); } pluginContext.PluginCommandStub.MainsChanged(true); pluginContext.PluginCommandStub.StartProcess(); for (int samplesOffset = 0; samplesOffset < pcmInput.SamplesCount; samplesOffset += (int)pcmInput.SampleRate) { if (cancellationToken.IsCancellationRequested) { return(ReturnCodeOffset + 20); } var result = ProcessSingleBuffer( pluginContext, samplesOffset, vstBufIn, vstBufOut, vstBufIn2, vstBufOut2, isDoublePrecision, pcmInput, pcmOutput, inputCount, outputCount, samplesPerBuffer ); if (result != 0) { return(result); } } // Close VST Context pluginContext.PluginCommandStub.StopProcess(); pluginContext.PluginCommandStub.MainsChanged(false); // Save pcmOutput.Save(outputFile); return(0); }