/// <summary> /// Output samples from beginning of the sample buffer. Copies requested /// samples to output buffer and removes them from the sample buffer. /// If there are less than /// <paramref name="maxSamples"/> samples in the buffer, returns all /// that available. /// </summary> /// <param name="output">Buffer where to copy output samples.</param> /// <param name="maxSamples">How many samples to receive at max.</param> /// <returns>Number of samples returned.</returns> public override int ReceiveSamples(ArrayPtr <TSampleType> output, int maxSamples) { int num = (maxSamples > _samplesInBuffer) ? _samplesInBuffer : maxSamples; ArrayPtr <TSampleType> .CopyBytes(output, PtrBegin(), _channels *SIZEOF_SAMPLETYPE *num); return(ReceiveSamples(num)); }
/// <summary> /// Rewind the buffer by moving data from position pointed by /// <see cref="_bufferPos"/> to real beginning of the buffer. /// </summary> /// <remarks> /// if output location pointer <see cref="_bufferPos"/> isn't zero, /// 'rewinds' the buffer and zeroes this pointer by copying samples from /// the <see cref="_bufferPos"/> pointer location on to the beginning /// of the buffer. /// </remarks> private void Rewind() { if ((_buffer == null) || (_bufferPos == 0)) { return; } ArrayPtr <TSampleType> .CopyBytes(_buffer, PtrBegin(), SIZEOF_SAMPLETYPE *_channels *_samplesInBuffer); _bufferPos = 0; }
/// <summary> /// Processes as many processing frames of the samples <see cref="_inputBuffer"/>, store /// the result into <see cref="_outputBuffer"/> /// </summary> private void ProcessSamples() { // Process samples as long as there are enough samples in '_inputBuffer' // to form a processing frame. while (_inputBuffer.AvailableSamples >= _sampleReq) { // If tempo differs from the normal ('SCALE'), scan for the best overlapping // position int offset = SeekBestOverlapPosition(_inputBuffer.PtrBegin()); // Mix the samples in the '_inputBuffer' at position of 'offset' with the // samples in 'midBuffer' using sliding overlapping // ... first partially overlap with the end of the previous sequence // (that's in 'midBuffer') Overlap(_outputBuffer.PtrEnd(_overlapLength), _inputBuffer.PtrBegin(), offset); _outputBuffer.PutSamples(_overlapLength); // ... then copy sequence samples from '_inputBuffer' to output: // length of sequence int temp = (_seekWindowLength - 2 * _overlapLength); // crosscheck that we don't have buffer overflow... if (_inputBuffer.AvailableSamples < (offset + temp + _overlapLength * 2)) { continue; // just in case, shouldn't really happen } _outputBuffer.PutSamples(_inputBuffer.PtrBegin() + _channels * (offset + _overlapLength), temp); // Copies the end of the current sequence from '_inputBuffer' to // 'midBuffer' for being mixed with the beginning of the next // processing sequence and so on Debug.Assert((offset + temp + _overlapLength * 2) <= _inputBuffer.AvailableSamples); ArrayPtr <TSampleType> .CopyBytes(_midBuffer, _inputBuffer.PtrBegin() + _channels *(offset + temp + _overlapLength), _channels *SIZEOF_SAMPLETYPE *_overlapLength); // Remove the processed samples from the input buffer. Update // the difference between integer & nominal skip step to '_skipFract' // in order to prevent the error from accumulating over time. _skipFract += _nominalSkip; // real skip size var ovlSkip = (int)_skipFract; _skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip _inputBuffer.ReceiveSamples(ovlSkip); } }
/// <summary> /// Set filter coefficients and length. /// </summary> /// <exception cref="ArgumentException">FIR filter length not divisible /// by 8</exception> public virtual void SetCoefficients(ArrayPtr <TSampleType> coeffs, int newLength, int resultDivFactor) { Debug.Assert(newLength > 0); if ((newLength % 8) != 0) { throw new ArgumentException("FIR filter length not divisible by 8"); } _lengthDiv8 = newLength / 8; _length = _lengthDiv8 * 8; Debug.Assert(_length == newLength); _resultDivFactor = resultDivFactor; var numPtr = new TSampleType[_length]; _filterCoeffs = numPtr; ArrayPtr <TSampleType> .CopyBytes(_filterCoeffs, coeffs, _length *SIZEOF_SAMPLETYPE); }
/// <summary> /// Ensures that the buffer has capacity for at least this many samples. /// </summary> private void EnsureCapacity(int capacityRequirement) { if (capacityRequirement > GetCapacity()) { // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) _sizeInBytes = (int)((capacityRequirement * _channels * SIZEOF_SAMPLETYPE + 4095) & unchecked ((uint)-4096)); Debug.Assert(_sizeInBytes % 2 == 0); var temp = new TSampleType[_sizeInBytes / SIZEOF_SAMPLETYPE + 16 / SIZEOF_SAMPLETYPE]; if (_samplesInBuffer != 0) { ArrayPtr <TSampleType> .CopyBytes(temp, PtrBegin(), _samplesInBuffer *_channels *SIZEOF_SAMPLETYPE); } _buffer = temp; _bufferPos = 0; } else { // simply rewind the buffer (if necessary) Rewind(); } }
/// <summary> /// Adds <paramref name="numSamples"/> pcs of samples from the /// <paramref name="samples"/> memory position to the sample buffer. /// </summary> /// <param name="samples">Pointer to samples.</param> /// <param name="numSamples">Number of samples to insert.</param> public override void PutSamples(ArrayPtr <TSampleType> samples, int numSamples) { ArrayPtr <TSampleType> .CopyBytes(PtrEnd(numSamples), samples, SIZEOF_SAMPLETYPE *numSamples *_channels); _samplesInBuffer += numSamples; }