Exemplo n.º 1
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;

                if (stretchedFramesToRead > _stretchedSamples[0].Length)
                {
                    stretchedFramesToRead = _stretchedSamples[0].Length;
                }

                if (_tempoChanged)
                {
                    _stretcher.SetTimeRatio(1.0 / _tempo);
                    _tempoChanged = false;
                }

                int numberOfFramesRead = (int)_stretcher.Retrieve(_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);

                        numRead += count;

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

                        return(numRead);
                    }

                    int numberOfSourceSamplesPerChannel = sourceBytesRead / 2 / _source.WaveFormat.Channels;

                    int sourceBytesInSamples = numberOfSourceSamplesPerChannel * _source.WaveFormat.Channels * 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 channel = 0; channel < _source.WaveFormat.Channels; channel++)
                    {
                        int channelOffset = channel * 2;

                        for (int i = 0; i < numberOfSourceSamplesPerChannel; i++)
                        {
                            int lo = _sourceBuffer[i * bytesPerFrame + channelOffset];
                            int hi = _sourceBuffer[i * bytesPerFrame + channelOffset + 1];

                            short sampleValue = unchecked ((short)((hi << 8) | lo));

                            _sourceSamples[channel][i] = sampleValue * (1.0f / 32768.0f);
                        }
                    }

                    _stretcher.Process(_sourceSamples, numberOfSourceSamplesPerChannel, final: false);
                }
                else
                {
                    int i       = 0;
                    int channel = 0;

                    while (i < numberOfFramesRead)
                    {
                        if (count == 0)
                        {
                            break;
                        }

                        float rawSample = _stretchedSamples[channel][i];

                        channel++;

                        if (channel == _source.WaveFormat.Channels)
                        {
                            channel = 0;
                            i++;
                        }

                        unchecked
                        {
                            short sample;

                            if (rawSample <= -1.0)
                            {
                                sample = -32768;
                            }
                            else if (rawSample >= 1.0)
                            {
                                sample = +32767;
                            }
                            else
                            {
                                int wideSample = (int)(rawSample * 32768.0f);

                                if (wideSample < -32768)
                                {
                                    sample = -32768;
                                }
                                else if (wideSample > 32767)
                                {
                                    sample = 32767;
                                }
                                else
                                {
                                    sample = (short)wideSample;
                                }
                            }

                            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--;
                        }
                    }

                    while (i < numberOfFramesRead)
                    {
                        float rawSample = _stretchedSamples[channel][i];

                        channel++;

                        if (channel == _source.WaveFormat.Channels)
                        {
                            channel = 0;
                            i++;
                        }

                        unchecked
                        {
                            short sample;

                            if (rawSample <= -1.0)
                            {
                                sample = -32768;
                            }
                            else if (rawSample >= 1.0)
                            {
                                sample = +32767;
                            }
                            else
                            {
                                int wideSample = (int)(rawSample * 32768.0f);

                                if (wideSample < -32768)
                                {
                                    sample = -32768;
                                }
                                else if (wideSample > 32767)
                                {
                                    sample = 32767;
                                }
                                else
                                {
                                    sample = (short)wideSample;
                                }
                            }

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

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

                    if (count == 0)
                    {
                        return(numRead);
                    }
                }
            }
        }
        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);
                    }
                }
            }
        }