public AudioStreamModifier(ISampleProvider sample, double rateMult, int pitchDelta)
        {
            _sample = sample;
            WaveFormat = _sample.WaveFormat;

            _soundTouch = new SoundTouch<float, double>();

            channelCount = sample.WaveFormat.Channels;
            _soundTouch.SetSampleRate(sample.WaveFormat.SampleRate);
            _soundTouch.SetChannels(channelCount);

            rateMult = (rateMult - 1) * 100;
            _soundTouch.SetTempoChange(rateMult);
            _soundTouch.SetPitchSemiTones(pitchDelta*0.25f);
            _soundTouch.SetRateChange(1.0f);

            _soundTouch.SetSetting(SettingId.UseQuickseek, 1);
            _soundTouch.SetSetting(SettingId.UseAntiAliasFilter, 1);

            _soundTouch.SetSetting(SettingId.SequenceDurationMs, 40);
            _soundTouch.SetSetting(SettingId.SeekwindowDurationMs, 15);
            _soundTouch.SetSetting(SettingId.OverlapDurationMs, 8);

            sourceReadBuffer = new float[(WaveFormat.SampleRate * channelCount * readDurationMilliseconds) / 1000];
            soundTouchReadBuffer = new float[sourceReadBuffer.Length * 10]; // support down to 0.1 speed
        }
    public VarispeedSampleProvider(ISampleProvider sourceProvider, int readDurationMilliseconds, SoundTouchProfile soundTouchProfile)
    {
        soundTouch = new 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);
        this.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
    }
Beispiel #3
0
        /// <summary>
        /// Initializes the audio renderer.
        /// Call the Play Method to start reading samples.
        /// </summary>
        private void Initialize()
        {
            Destroy();

            // Release the audio device always upon exiting
            if (Application.Current is Application app)
            {
                app.Dispatcher?.BeginInvoke(new Action(() => { app.Exit += OnApplicationExit; }));
            }

            // Enumerate devices. The default device is the first one so we check
            // that we have more than 1 device (other than the default stub)
            var hasAudioDevices = MediaElement.RendererOptions.UseLegacyAudioOut ?
                                  LegacyAudioPlayer.EnumerateDevices().Count > 1 :
                                  DirectSoundPlayer.EnumerateDevices().Count > 1;

            // Check if we have an audio output device.
            if (hasAudioDevices == false)
            {
                WaitForReadyEvent.Complete();
                HasFiredAudioDeviceStopped = true;
                this.LogWarning(Aspects.AudioRenderer,
                                "No audio device found for output.");

                return;
            }

            // Initialize the SoundTouch Audio Processor (if available)
            AudioProcessor = (SoundTouch.IsAvailable == false) ? null : new SoundTouch();
            if (AudioProcessor != null)
            {
                AudioProcessor.SetChannels(Convert.ToUInt32(WaveFormat.Channels));
                AudioProcessor.SetSampleRate(Convert.ToUInt32(WaveFormat.SampleRate));
            }

            // Initialize the Audio Device
            AudioDevice = MediaElement.RendererOptions.UseLegacyAudioOut ?
                          new LegacyAudioPlayer(this, MediaElement.RendererOptions.LegacyAudioDevice?.DeviceId ?? -1) as IWavePlayer :
                          new DirectSoundPlayer(this, MediaElement.RendererOptions.DirectSoundDevice?.DeviceId ?? DirectSoundPlayer.DefaultPlaybackDeviceId);

            // Create the Audio Buffer
            SampleBlockSize = Constants.AudioBytesPerSample * Constants.AudioChannelCount;
            var bufferLength = WaveFormat.ConvertMillisToByteSize(2000); // 2-second buffer

            AudioBuffer = new CircularBuffer(bufferLength);
            AudioDevice.Start();
        }
        public SoundTouchWaveStream(IWaveProvider source)
        {
            if (source.WaveFormat.BitsPerSample != 16)
            {
                throw new FormatException("Can't process bit depth of " + source.WaveFormat.BitsPerSample);
            }

            _source = source;

            _sourceSamples    = new short[32768];
            _sourceBuffer     = new byte[_sourceSamples.Length * 2];
            _stretchedSamples = new short[32768];

            _stretcher = new SoundTouch <short, long>();
            _stretcher.SetSampleRate(_source.WaveFormat.SampleRate);
            _stretcher.SetChannels(_source.WaveFormat.Channels);

            _tempo = 1.0;
        }
Beispiel #5
0
        private void initializeBuffers()
        {
            // example: 44.1 kHz (44,100 samples per second) * 16 bits per sample / 8 bits per byte * 2 channels (stereo)
            // blockAlign is number of bytes per frame (samples required for all channels)

            uint fastPlaySamplesPerSecond = m_CurrentAudioPCMFormat.SampleRate;            // (int)Math.Round(m_CurrentAudioPCMFormat.SampleRate * m_FastPlayFactor);
            uint byteRate = fastPlaySamplesPerSecond * m_CurrentAudioPCMFormat.BlockAlign; // (m_CurrentAudioPCMFormat.BitDepth / 8) * m_CurrentAudioPCMFormat.NumberOfChannels;

            int pcmDataBufferSize = (int)Math.Round(byteRate * REFRESH_INTERVAL_MS / 1000.0);

            pcmDataBufferSize -= pcmDataBufferSize % m_CurrentAudioPCMFormat.BlockAlign;

            m_PcmDataBufferLength = pcmDataBufferSize;
            if (m_PcmDataBuffer == null)
            {
                Console.WriteLine("ALLOCATING m_PcmDataBuffer");
                m_PcmDataBuffer = new byte[m_PcmDataBufferLength];
            }
            else if (m_PcmDataBuffer.Length < m_PcmDataBufferLength)
            {
                Console.WriteLine("m_PcmDataBuffer.resize");
                Array.Resize(ref m_PcmDataBuffer, m_PcmDataBufferLength);
            }

            int dxBufferSize = (int)Math.Round(byteRate * (20 * REFRESH_INTERVAL_MS) / 1000.0); // ONE SECOND when 50ms refresh internal // 0.500 == 500ms

            dxBufferSize -= dxBufferSize % m_CurrentAudioPCMFormat.BlockAlign;

            //m_CircularBufferRefreshChunkSize = (int)(byteRate * 0.200); //200ms
            //m_CircularBufferRefreshChunkSize -= m_CircularBufferRefreshChunkSize % m_CurrentAudioPCMFormat.BlockAlign;

#if USE_SHARPDX
            WaveFormat waveFormat = new WaveFormat((int)m_CurrentAudioPCMFormat.SampleRate, 16, m_CurrentAudioPCMFormat.NumberOfChannels);
#else
            WaveFormat waveFormat = new WaveFormat();
            waveFormat.FormatTag = WaveFormatTag.Pcm;

            waveFormat.Channels         = (short)m_CurrentAudioPCMFormat.NumberOfChannels;
            waveFormat.SamplesPerSecond = (int)m_CurrentAudioPCMFormat.SampleRate;
            waveFormat.BitsPerSample    = (short)m_CurrentAudioPCMFormat.BitDepth;

            waveFormat.BlockAlign            = (short)m_CurrentAudioPCMFormat.BlockAlign;
            waveFormat.AverageBytesPerSecond = (int)byteRate;
#endif

#if USE_SHARPDX
            SoundBufferDescription bufferDescription = new SoundBufferDescription();
            bufferDescription.Flags =
                BufferFlags.GetCurrentPosition2 |
                //BufferFlags.ControlPositionNotify |
                BufferFlags.ControlVolume | BufferFlags.ControlFrequency | BufferFlags.GlobalFocus;
#else
            BufferDescription bufferDescription = new BufferDescription();

            bufferDescription.ControlVolume    = true;
            bufferDescription.ControlFrequency = true;
            bufferDescription.GlobalFocus      = true;
#endif
            bufferDescription.BufferBytes = dxBufferSize;
            bufferDescription.Format      = waveFormat;


            if (OutputDevice == null)
            {
                Console.WriteLine("/// OutputDevice NULL, attempting reset...");

                List <OutputDevice> outputDevices = OutputDevices;

                Console.WriteLine("/// OutputDevices: " + outputDevices.Count);

                SetOutputDevice(m_OutputDeviceControl, "dummy");
            }

#if USE_SHARPDX
            m_CircularBuffer = new SecondarySoundBuffer(OutputDevice.Device, bufferDescription);
#else
            m_CircularBuffer = new SecondaryBuffer(bufferDescription, OutputDevice.Device);
#endif

#if USE_SOUNDTOUCH
            if (m_SoundTouch == null)
            {
                m_SoundTouch = new SoundTouch <TSampleType, TLongSampleType>();

                m_SoundTouch.SetSetting(SettingId.UseAntiAliasFilter, 1);

                // Speech optimised
                m_SoundTouch.SetSetting(SettingId.SequenceDurationMs, 40);
                m_SoundTouch.SetSetting(SettingId.SeekwindowDurationMs, 15);
                m_SoundTouch.SetSetting(SettingId.OverlapDurationMs, 8);
            }

            //m_SoundTouch.Flush();
            m_SoundTouch.Clear();

            //AudioLib.SampleRate.Hz22050
            if (m_CurrentAudioPCMFormat.SampleRate > 22050)
            {
                m_SoundTouch.SetSetting(SettingId.UseQuickseek, 1);
            }
            else
            {
                m_SoundTouch.SetSetting(SettingId.UseQuickseek, 0);
            }

            m_SoundTouch.SetSampleRate((int)m_CurrentAudioPCMFormat.SampleRate);
            m_SoundTouch.SetChannels((int)m_CurrentAudioPCMFormat.NumberOfChannels);
#endif //USE_SOUNDTOUCH


            FastPlayFactor = m_FastPlayFactor; // reset
        }
        /// <summary>
        /// Stretches audio, keeps channels and samplerate.
        /// negatief value slowsdown (makes longer) the audio
        /// Positief value speedsup (make shorter) the audio
        /// </summary>
        public AudioSamples TimeStretch(float[] inputAudioSamples, int inputSampleRate = 44100, int inputChannels = 2, float rateFactor = 0.0f)
        {
            // calculate total milliseconds to read
            int totalmilliseconds = Int32.MaxValue;

            float[] data = null;

            int stream = Bass.BASS_StreamCreatePush(inputSampleRate, inputChannels, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT, IntPtr.Zero);

            ThrowIfStreamIsInvalid(stream);
            BASS_CHANNELINFO channelInfo = Bass.BASS_ChannelGetInfo(stream);

            Bass.BASS_StreamPutData(stream, inputAudioSamples, inputAudioSamples.Length * 4);

            SoundTouch <Single, Double> soundTouch = new SoundTouch <Single, Double>();

            soundTouch.SetSampleRate(channelInfo.freq);
            soundTouch.SetChannels(channelInfo.chans);
            soundTouch.SetTempoChange(0.0f);
            soundTouch.SetPitchSemiTones(0.0f);
            soundTouch.SetRateChange(rateFactor); // -1.4f = Radio 538 setting
            soundTouch.SetSetting(SettingId.UseQuickseek, 0);
            soundTouch.SetSetting(SettingId.UseAntiAliasFilter, 0);

            int bufferSize = 2048;

            float[]        buffer   = new float[bufferSize];
            List <float[]> chunks   = new List <float[]>();
            int            size     = 0;
            int            nSamples = 0;

            while ((float)(size) / channelInfo.freq * 1000 < totalmilliseconds)
            {
                // get re-sampled data
                int bytesRead = Bass.BASS_ChannelGetData(stream, buffer, bufferSize);
                if (bytesRead <= 0)
                {
                    break;
                }
                nSamples = (bytesRead / 4) / channelInfo.chans;
                // Feed the samples into SoundTouch processor
                soundTouch.PutSamples(buffer, nSamples);

                // Read ready samples from SoundTouch processor & write them output file.
                // NOTES:
                // - 'receiveSamples' doesn't necessarily return any samples at all
                //   during some rounds!
                // - On the other hand, during some round 'receiveSamples' may have more
                //   ready samples than would fit into 'sampleBuffer', and for this reason
                //   the 'receiveSamples' call is iterated for as many times as it
                //   outputs samples.
                do
                {
                    nSamples = soundTouch.ReceiveSamples(buffer, (bufferSize / channelInfo.chans));
                    if (nSamples > 0)
                    {
                        float[] chunk = new float[nSamples * channelInfo.chans];
                        Array.Copy(buffer, chunk, nSamples * channelInfo.chans);
                        chunks.Add(chunk);
                        size += nSamples * channelInfo.chans; //size of the data
                    }
                } while (nSamples != 0);
            } //while

            // Now the input file is processed, yet 'flush' few last samples that are
            // hiding in the SoundTouch's internal processing pipeline.
            soundTouch.Flush();
            do
            {
                nSamples = soundTouch.ReceiveSamples(buffer, (bufferSize / channelInfo.chans));
                if (nSamples > 0)
                {
                    float[] chunk = new float[nSamples * channelInfo.chans];
                    Array.Copy(buffer, chunk, nSamples * channelInfo.chans);
                    chunks.Add(chunk);
                    size += nSamples * channelInfo.chans; //size of the data
                }
            } while (nSamples != 0);


            if (size <= 0)
            {
                // not enough samples to return the requested data
                return(null);
            }

            // Do bass cleanup
            Bass.BASS_ChannelStop(stream);
            Bass.BASS_StreamFree(stream);

            int start = 0;
            int end   = size;

            data = new float[size];
            int index = 0;

            // Concatenate
            foreach (float[] chunk in chunks)
            {
                Array.Copy(chunk, 0, data, index, chunk.Length);
                index += chunk.Length;
            }

            // Select specific part of the song
            if (start != 0 || end != size)
            {
                float[] temp = new float[end - start];
                Array.Copy(data, start, temp, 0, end - start);
                data = temp;
            }

            // Create audiosamples object
            AudioSamples audioSamples = new AudioSamples();

            audioSamples.Origin       = "MEMORY";
            audioSamples.Channels     = channelInfo.chans;
            audioSamples.SampleRate   = channelInfo.freq;
            audioSamples.StartInMS    = start;
            audioSamples.DurationInMS = end;
            audioSamples.Samples      = data;

            return(audioSamples);
        }