public VariableSpeedSampleProvider(ISampleProvider sourceProvider, int readDurationMilliseconds, SoundTouchProfile soundTouchProfile) { _soundTouch = new SoundTouch.SoundTouch(); // explore what the default values are before we change them: //Debug.WriteLine(String.Format("SoundTouch Version {0}", soundTouch.VersionString)); //Debug.WriteLine("Use QuickSeek: {0}", soundTouch.GetUseQuickSeek()); //Debug.WriteLine("Use AntiAliasing: {0}", soundTouch.GetUseAntiAliasing()); SetSoundTouchProfile(soundTouchProfile); _sourceProvider = sourceProvider; _soundTouch.SetSampleRate(WaveFormat.SampleRate); _channelCount = WaveFormat.Channels; _soundTouch.SetChannels(_channelCount); _sourceReadBuffer = new float[(WaveFormat.SampleRate * _channelCount * (long)readDurationMilliseconds) / 1000]; _soundTouchReadBuffer = new float[_sourceReadBuffer.Length * 10]; // support down to 0.1 speed }
private int VocodeAudioChunk(Chunk chunk, AudioFileReader audioFileReader, WaveFileWriter audioFileWriter) { ///TODO Create the soundtouch outside this loop, and just reset it!!!!!! var speed = (chunk.GetSpeed(ref options) - 1) * 100; var samplesLeft = false; soundTouch = new SoundTouch.SoundTouch <float, double>(); //Init soundtouch soundTouch.SetRate(1.0f); soundTouch.SetPitchOctaves(0f); soundTouch.SetTempo(0); //Set soundtouch rates soundTouch.SetSampleRate((int)(audioFileReader.WaveFormat.SampleRate)); soundTouch.SetChannels(audioFileReader.WaveFormat.Channels); soundTouch.SetTempoChange(speed); //Sample count of chunk var chunkSamplesLength = ((chunk.endFrame * options.samplesPerFrame) - (chunk.startFrame * options.samplesPerFrame)); int totalSamplesRead = 0; //Set buffer size to 6750 or chunkSamplesLength if its less int bufferSize = reAlignBuffer(chunkSamplesLength < 6750 ? chunkSamplesLength : 6750, audioFileReader.WaveFormat.BlockAlign); //Init buffers float[] inputBuffer = new float[bufferSize]; float[] outputBuffer = new float[bufferSize]; var samplesRead = 0; var readAll = false; int nSamples; while (!readAll || samplesLeft) { if (!readAll) { utils.ReportStatus(WRITE_AUDIO_MESSAGE, chunk.startFrame + (totalSamplesRead / options.samplesPerFrame), options.frame_count, 2); //Shorten buffer if needed if (bufferSize > chunkSamplesLength - totalSamplesRead) { bufferSize = reAlignBuffer(chunkSamplesLength - totalSamplesRead, audioFileReader.WaveFormat.BlockAlign); } //Read next block of samples samplesRead = audioFileReader.Read(inputBuffer, 0, bufferSize); //End of stream or chunk finished if (samplesRead == 0 || totalSamplesRead >= chunkSamplesLength) { //Stop reading more and flush the soundtouch buffer readAll = true; if (samplesRead > 0) { //Read the next block and and input them into soundtouch nSamples = samplesRead / audioFileReader.WaveFormat.Channels; soundTouch.PutSamples(inputBuffer, nSamples); } soundTouch.Flush(); } else { //Read the next block and and input them into soundtouch nSamples = samplesRead / audioFileReader.WaveFormat.Channels; soundTouch.PutSamples(inputBuffer, nSamples); } } do { //Get samples from soundtouch nSamples = soundTouch.ReceiveSamples(outputBuffer, outputBuffer.Length / audioFileReader.WaveFormat.Channels); //Write samples to file audioFileWriter.WriteSamples(outputBuffer, 0, nSamples * audioFileReader.WaveFormat.Channels); } while (nSamples != 0); totalSamplesRead += samplesRead; samplesLeft = soundTouch?.AvailableSamples > 0; } soundTouch.Clear(); return(totalSamplesRead); }