using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace QuikDawEditor.SampleProviders; internal class CircularFloatBuffer { private readonly float[] buffer; private readonly object lockObject; private int writePosition; private int readPosition; private int sampCount; public CircularFloatBuffer(int size) { buffer = new float[size]; lockObject = new object(); } public int Write(float[] samples, int offset, int count) { lock (lockObject) { var samplesWritten = 0; if (count > buffer.Length - sampCount) { count = buffer.Length - sampCount; } // write to end int writeToEnd = Math.Min(buffer.Length - writePosition, count); Array.Copy(samples, offset, buffer, writePosition, writeToEnd); writePosition += writeToEnd; writePosition %= buffer.Length; samplesWritten += writeToEnd; if (samplesWritten < count) { Debug.Assert(writePosition == 0); // must have wrapped round. Write to start Array.Copy(samples, offset + samplesWritten, buffer, writePosition, count - samplesWritten); writePosition += (count - samplesWritten); samplesWritten = count; } sampCount += samplesWritten; return samplesWritten; } } public int Read(float[] samples, int offset, int count) { lock (lockObject) { if (count > sampCount) count = sampCount; int sampsRead = 0; int readToEnd = Math.Min(buffer.Length - readPosition, count); Array.Copy(buffer, readPosition, samples, offset, readToEnd); sampsRead += readToEnd; readPosition += readToEnd; readPosition %= buffer.Length; if (sampsRead < count) { // must have wrapped round. Read from start Debug.Assert(readPosition == 0); Array.Copy(buffer, readPosition, samples, offset + sampsRead, count - sampsRead); readPosition += (count - sampsRead); sampsRead = count; } sampCount -= sampsRead; Debug.Assert(sampCount >= 0); return sampsRead; } } public int MaxLength => buffer.Length; public int Count { get { lock (lockObject) { return sampCount; } } } public void Reset() { lock (lockObject) { ResetInner(); } } private void ResetInner() { sampCount = 0; readPosition = 0; writePosition = 0; } int taperLength = 1400; public void ResetTaper() { ResetInner(); return; //Debug.WriteLine("circularbufSampCount=" + sampCount); int thisTaperLength = Math.Min(taperLength, sampCount); if (sampCount >= thisTaperLength) { for (int tapoffno = 0; tapoffno < thisTaperLength; tapoffno++) { float tapfac = ((float)thisTaperLength - tapoffno - 1) / thisTaperLength; //Debug.WriteLine("tapfac=" + tapfac); buffer[tapoffno] *= tapfac; } } if (sampCount >= thisTaperLength * 2) { //Debug.WriteLine("\ngoing up now\n"); for (int tapoffno = 0; tapoffno < thisTaperLength; tapoffno++) { float tapfac = (float)tapoffno / thisTaperLength; //Debug.WriteLine("tapfacUP=" + tapfac); buffer[thisTaperLength + tapoffno] *= tapfac; } } sampCount = thisTaperLength * 2; readPosition = 0; writePosition = thisTaperLength * 2; //float[] newvals = new float[thisTaperLength * 2]; //Array.Copy(buffer, newvals, newvals.Length); //Debug.WriteLine("buffer=" + string.Join("\n", newvals.ToList().ConvertAll(f => f.ToString()))); } // Advances the buffer, discarding bytes public void Advance(int count) { lock (lockObject) { if (count >= sampCount) ResetInner(); else { sampCount -= count; readPosition += count; readPosition %= MaxLength; } } } }