Exemplo n.º 1
0
        /// <summary>
        /// Processes the sound.
        /// </summary>
        private static void Process(SoundTouch <TSampleType, TLongSampleType> pSoundTouch, WavInFile inFile, WavOutFile outFile)
        {
            int nSamples;
            var sampleBuffer = new TSampleType[BUFF_SIZE];

            if ((inFile == null) || (outFile == null))
            {
                return;                                        // nothing to do.
            }
            int nChannels = inFile.GetNumChannels();

            Debug.Assert(nChannels > 0);
            int buffSizeSamples = BUFF_SIZE / nChannels;

            // Process samples read from the input file
            while (!inFile.Eof())
            {
                // Read a chunk of samples from the input file
                int num = inFile.Read(sampleBuffer, BUFF_SIZE);
                nSamples = num / inFile.GetNumChannels();

                // Feed the samples into SoundTouch processor
                pSoundTouch.PutSamples(sampleBuffer, 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 = pSoundTouch.ReceiveSamples(sampleBuffer, buffSizeSamples);
                    outFile.Write(sampleBuffer, nSamples * nChannels);
                } while (nSamples != 0);
            }

            // Now the input file is processed, yet 'flush' few last samples that are
            // hiding in the SoundTouch's internal processing pipeline.
            pSoundTouch.Flush();
            do
            {
                nSamples = pSoundTouch.ReceiveSamples(sampleBuffer, buffSizeSamples);
                outFile.Write(sampleBuffer, nSamples * nChannels);
            } while (nSamples != 0);
        }
        public int Read(float[] buffer, int offset, int count)
        {
            int samplesRead = 0;

            while (samplesRead < count)
            {
                if (!reachedEndOfSource)
                {
                    var readFromSource = _sample.Read(sourceReadBuffer, 0, sourceReadBuffer.Length);
                    if (readFromSource > 0)
                    {
                        _soundTouch.PutSamples(sourceReadBuffer, readFromSource / channelCount);
                    }
                    else
                    {
                        reachedEndOfSource = true;
                        // we've reached the end, tell SoundTouch we're done
                        _soundTouch.Flush();
                    }
                }
                var desiredSampleFrames = (count - samplesRead) / channelCount;
                var received            = _soundTouch.ReceiveSamples(soundTouchReadBuffer, desiredSampleFrames) * channelCount;
                // use loop instead of Array.Copy due to WaveBuffer
                for (int n = 0; n < received; n++)
                {
                    buffer[offset + samplesRead++] = soundTouchReadBuffer[n];
                }
                if (received == 0 && reachedEndOfSource)
                {
                    break;
                }
            }
            return(samplesRead);
        }
        /// <summary>
        /// Overridden Read function that returns samples processed with SoundTouch. Returns data in same format as
        /// WaveChannel32 i.e. stereo float samples.
        /// </summary>
        /// <param name="buffer">Buffer where to return sample data</param>
        /// <param name="offset">Offset from beginning of the buffer</param>
        /// <param name="count">Number of bytes to return</param>
        /// <returns>Number of bytes copied to buffer</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            try
            {
                if (ArcaeaSpeedChanger.GlobalVariable.soundParseFormat == SupportedAudioFormat.OGG)
                {
                    if (ArcaeaSpeedChanger.GlobalVariable.soundParseProgress <= 50)
                    {
                        ArcaeaSpeedChanger.GlobalVariable.soundParseProgress += 2;
                    }
                }
                else
                {
                    ArcaeaSpeedChanger.GlobalVariable.soundParseProgress += 5;
                }
                //Console.WriteLine("Change!" + ArcaeaSpeedChanger.GlobalVariable.soundParseProgress);
                // Iterate until enough samples available for output:
                // - read samples from input stream
                // - put samples to SoundStretch processor
                while (st.AvailableSampleCount < count)
                {
                    int nbytes = inputStr.Read(bytebuffer, 0, bytebuffer.Length);
                    if (nbytes == 0)
                    {
                        // end of stream. flush final samples from SoundTouch buffers to output
                        if (endReached == false)
                        {
                            endReached = true;  // do only once to avoid continuous flushing
                            st.Flush();
                        }
                        break;
                    }

                    // binary copy data from "byte[]" to "float[]" buffer
                    Buffer.BlockCopy(bytebuffer, 0, floatbuffer, 0, nbytes);
                    st.PutSamples(floatbuffer, (uint)(nbytes / 8));
                }

                // ensure that buffer is large enough to receive desired amount of data out
                if (floatbuffer.Length < count / 4)
                {
                    floatbuffer = new float[count / 4];
                }
                // get processed output samples from SoundTouch
                int numsamples = (int)st.ReceiveSamples(floatbuffer, (uint)(count / 8));
                // binary copy data from "float[]" to "byte[]" buffer
                Buffer.BlockCopy(floatbuffer, 0, buffer, offset, numsamples * 8);
                return(numsamples * 8);  // number of bytes
            }
            catch (Exception)
            {
                return(0);
            }
        }
        public int Read(float[] buffer, int offset, int count)
        {
            if (playbackRate == 0) // play silence
            {
                for (int n = 0; n < count; n++)
                {
                    buffer[offset++] = 0;
                }
                return(count);
            }

            if (repositionRequested)
            {
                soundTouch.Clear();
                repositionRequested = false;
            }

            int  samplesRead        = 0;
            bool reachedEndOfSource = false;


            while (samplesRead < count)
            {
                if (soundTouch.NumberOfSamplesAvailable == 0)
                {
                    var readFromSource = sourceProvider.Read(sourceReadBuffer, 0, sourceReadBuffer.Length);
                    if (readFromSource > 0)
                    {
                        soundTouch.PutSamples(sourceReadBuffer, readFromSource / channelCount);
                    }
                    else
                    {
                        reachedEndOfSource = true;
                        // we've reached the end, tell SoundTouch we're done
                        soundTouch.Flush();
                    }
                }
                var desiredSampleFrames = (count - samplesRead) / channelCount;

                var received = soundTouch.ReceiveSamples(soundTouchReadBuffer, desiredSampleFrames) * channelCount;
                // use loop instead of Array.Copy due to WaveBuffer
                for (int n = 0; n < received; n++)
                {
                    buffer[offset + samplesRead++] = soundTouchReadBuffer[n];
                }
                if (received == 0 && reachedEndOfSource)
                {
                    break;
                }
            }
            return(samplesRead);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Overridden Read function that returns samples processed with SoundTouch. Returns data in same format as
        /// WaveChannel32 i.e. stereo float samples.
        /// </summary>
        /// <param name="buffer">Buffer where to return sample data</param>
        /// <param name="offset">Offset from beginning of the buffer</param>
        /// <param name="count">Number of bytes to return</param>
        /// <returns>Number of bytes copied to buffer</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            try
            {
                // Iterate until enough samples available for output:
                // - read samples from input stream
                // - put samples to SoundStretch processor
                while (st.AvailableSampleCount < count)
                {
                    int nbytes = inputStr.Read(bytebuffer, 0, bytebuffer.Length);
                    if (nbytes == 0)
                    {
                        // end of stream. flush final samples from SoundTouch buffers to output
                        if (endReached == false)
                        {
                            endReached = true;  // do only once to avoid continuous flushing
                            st.Flush();
                        }
                        break;
                    }

                    // binary copy data from "byte[]" to "float[]" buffer
                    Buffer.BlockCopy(bytebuffer, 0, floatbuffer, 0, nbytes);
                    st.PutSamples(floatbuffer, (uint)(nbytes / 8));
                }

                // ensure that buffer is large enough to receive desired amount of data out
                if (floatbuffer.Length < count / 4)
                {
                    floatbuffer = new float[count / 4];
                }
                // get processed output samples from SoundTouch
                int numsamples = (int)st.ReceiveSamples(floatbuffer, (uint)(count / 8));
                // binary copy data from "float[]" to "byte[]" buffer
                for (int i = 0; i < count / 4; i++)
                {
                    floatbuffer[i + offset] = equaliser.TransformSample(floatbuffer[i + offset]);
                }

                Buffer.BlockCopy(floatbuffer, 0, buffer, offset, numsamples * 8);
                return(numsamples * 8);  // number of bytes
            }
            catch (Exception exp)
            {
                StatusMessage.Write("exception in WaveStreamProcessor.Read: " + exp.Message);
                return(0);
            }
        }
        /// <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);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Overridden Read function that returns samples processed with SoundTouch. Returns data in same format as
        /// WaveChannel32 i.e. stereo float samples.
        /// </summary>
        /// <param name="buffer">Buffer where to return sample data</param>
        /// <param name="offset">Offset from beginning of the buffer</param>
        /// <param name="count">Number of bytes to return</param>
        /// <returns>Number of bytes copied to buffer</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            var normalb4 = normal;

            currentFrameCount++;
            try
            {
                // Iterate until enough samples available for output:
                // - read samples from input stream
                // - put samples to SoundStretch processor
                while (st.AvailableSamples < count)
                {
                    int nbytes;
                    if (inputWC32 != null)
                    {
                        nbytes = inputWC32.Read(bytebuffer, 0, bytebuffer.Length);
                    }
                    else
                    {
                        nbytes = inputAFR.Read(bytebuffer, 0, bytebuffer.Length);
                    }


                    if (nbytes == 0)
                    {
                        // end of stream. flush final samples from SoundTouch buffers to output
                        if (EndReached == false)
                        {
                            EndReached = true;  // do only once to avoid continuous flushing
                            st.Flush();
                        }
                        break;
                    }

                    // binary copy data from "byte[]" to "float[]" buffer
                    Buffer.BlockCopy(bytebuffer, 0, floatbuffer, 0, nbytes);
                    var max = GetMaxVolume(floatbuffer);

                    if (max >= options.silent_threshold)
                    {
                        normal = true;
                        st.SetTempoChange((options.sounded_speed - 1) * 100);
                    }
                    else
                    {
                        normal = false;
                        st.SetTempoChange((options.silent_speed - 1) * 100);
                    }

                    st.PutSamples(floatbuffer, (nbytes / 8));
                }

                // ensure that buffer is large enough to receive desired amount of data out
                if (floatbuffer.Length < count / 4)
                {
                    floatbuffer = new float[count / 4];
                }
                // get processed output samples from SoundTouch
                int numsamples = st.ReceiveSamples(floatbuffer, (count / 8));
                // binary copy data from "float[]" to "byte[]" buffer
                Buffer.BlockCopy(floatbuffer, 0, buffer, offset, numsamples * 8);

                if (normal != normalb4)
                {
                    OnAudioFrameRendered();
                }


                return(numsamples * 8);  // number of bytes
            }
            catch (Exception) {
                return(0);
            }
        }
        public int Read(byte[] buffer, int offset, int count)
        {
            int numRead = 0;

            // Mismatched formats/interpretations:
            //
            // - Source returns raw bytes, lets us interpret.
            // - SoundTouch takes samples (Int16), counts one frame across all channels as a single sample (one left + one right == one sample).
            // - When converting to/from bytes, we need to count each channel in a frame as a separate sample (one left + one right == two samples).
            // - We implement IWaveProvider, the same as source, and are thus expected to return raw bytes.
            // - We may be asked for a number of bytes that isn't a multiple of the stretcher's output block size.
            // - We may be provided with source data that isn't a multiple of the stretcher's input block size.
            //
            // Hooray!

            if (_outputExtraBytes.Count > 0)
            {
                if (_outputExtraBytes.Count > count)
                {
                    _outputExtraBytes.CopyTo(0, buffer, offset, count);
                    _outputExtraBytes.RemoveRange(0, count);

                    return(count);
                }
                else
                {
                    _outputExtraBytes.CopyTo(buffer);

                    count   -= _outputExtraBytes.Count;
                    numRead += _outputExtraBytes.Count;

                    _outputExtraBytes.Clear();
                }
            }

            int bytesPerFrame = 2 * _source.WaveFormat.Channels;

            while (true)
            {
                int stretchedFramesToRead = (count + bytesPerFrame - 1) / bytesPerFrame;
                int stretchedFramesBytes  = stretchedFramesToRead * bytesPerFrame;

                if (stretchedFramesBytes > _stretchedSamples.Length)
                {
                    stretchedFramesToRead = _stretchedSamples.Length / bytesPerFrame;
                    stretchedFramesBytes  = stretchedFramesToRead * bytesPerFrame;
                }

                int numberOfFramesRead = _stretcher.ReceiveSamples(_stretchedSamples, stretchedFramesToRead);

                if (numberOfFramesRead == 0)
                {
                    int sourceBytesRead = _sourceExtraBytes.Count;

                    if (sourceBytesRead > 0)
                    {
                        _sourceExtraBytes.CopyTo(_sourceBuffer);
                        _sourceExtraBytes.Clear();
                    }

                    sourceBytesRead += _source.Read(_sourceBuffer, sourceBytesRead, _sourceBuffer.Length - sourceBytesRead);

                    SourceRead?.Invoke(this, EventArgs.Empty);

                    if (sourceBytesRead == 0)
                    {
                        // End of stream, zero pad
                        Array.Clear(buffer, offset, count);

                        //the calling method will handle not filled arrays
                        //              if (offset == 0 && count == buffer.Length)
                        //                  numRead = 0;
                        //               //else
                        ////numRead += count;

                        EndOfStream?.Invoke(this, EventArgs.Empty);

                        return(numRead);
                    }

                    int numberOfSourceSamples = (sourceBytesRead / 2 / _source.WaveFormat.Channels) * _source.WaveFormat.Channels;

                    int sourceBytesInSamples = numberOfSourceSamples * 2;

                    if (sourceBytesInSamples < sourceBytesRead)
                    {
                        // We got a misaligned read, stash the bytes we aren't going to process for the next pass.
                        for (int i = sourceBytesInSamples; i < sourceBytesRead; i++)
                        {
                            _sourceExtraBytes.Add(_sourceBuffer[i]);
                        }
                    }

                    for (int i = 0; i < numberOfSourceSamples; i++)
                    {
                        int lo = _sourceBuffer[i + i];
                        int hi = _sourceBuffer[i + i + 1];

                        _sourceSamples[i] = unchecked ((short)((hi << 8) | lo));
                    }

                    _stretcher.PutSamples(_sourceSamples, numberOfSourceSamples / _source.WaveFormat.Channels);
                }
                else
                {
                    int numberOfBytesAvailable = numberOfFramesRead * bytesPerFrame;

                    int numberOfSamplesAvailable = numberOfBytesAvailable / 2;

                    int i;

                    for (i = 0; i < numberOfSamplesAvailable; i++)
                    {
                        if (count == 0)
                        {
                            break;
                        }

                        int sample = _stretchedSamples[i];

                        unchecked
                        {
                            byte hi = (byte)(sample >> 8);
                            byte lo = (byte)(sample & 0xFF);

                            buffer[offset++] = lo;
                            numRead++;
                            count--;

                            if (count == 0)
                            {
                                _outputExtraBytes.Add(hi);
                                break;
                            }

                            buffer[offset++] = hi;
                            numRead++;
                            count--;
                        }
                    }

                    for (; i < numberOfSamplesAvailable; i++)
                    {
                        int sample = _stretchedSamples[i];

                        unchecked
                        {
                            byte hi = (byte)(sample >> 8);
                            byte lo = (byte)(sample & 0xFF);

                            _outputExtraBytes.Add(lo);
                            _outputExtraBytes.Add(hi);
                        }
                    }

                    if (count == 0)
                    {
                        return(numRead);
                    }
                }
            }
        }