为浮点值实现一个简单的环形缓冲区

时间:2015-10-25 23:19:59

标签: c++

我正在尝试实现一个非常简单的环形缓冲区,用于以浮点值的形式保存音频样本流。

我希望能够在任何时候拍摄音频输入的快照。我不需要弹出或删除任何值,只需保留最后 n 样本的移动缓冲区。

我想问一下这个实现是否存在任何潜在的问题。

class RingBuffer
{
public:
    RingBuffer (int bufferSize) : bufferSize (bufferSize), count (0), head (0)
    {
        buffer     = static_cast<float *> (malloc(bufferSize * sizeof(float)));
        readBuffer = static_cast<float *> (malloc(bufferSize * sizeof(float)));
    }

    ~RingBuffer ()
    {
        if (buffer != nullptr) free(buffer);
        buffer = nullptr;

        if (readBuffer != nullptr) free(readBuffer);
        readBuffer = nullptr;
    }

    void push (float value)
    {

        if (count < bufferSize && head == 0)
        {
            buffer[count++] = value;
        }
        else if (count == bufferSize)
        {
            // reset head to beginning if reached the end
            if (head >= bufferSize)
            {
                head = 0;
                buffer[head] = value;
            }
            else
            {
                buffer[head++] = value;
            }
        }
    }

    /**
     * Return a snapshot of the buffer as a continous array
     */
    const float* getSnapshot () 
    {
         // Set up read buffer as continuous stream
         int writeIndex = 0;
         for (int i = head; i < count; ++i) 
         {
            readBuffer[writeIndex++] = buffer[i];   
         }
         for (int i = 0; i < head; ++i)
         {
             readBuffer[writeIndex++] = buffer[i];
         }
         return readBuffer;
    }

private:
    int bufferSize, head, count;
    float* buffer;
    float* readBuffer;
};

1 个答案:

答案 0 :(得分:2)

嗯,我确实可以看到几个问题。抱歉,这是个坏消息: - /

错误

  • 此处有一个错误:buffer[head] = value;。您不会增加head,因此当下一个样本进入时,此位置的样本将会丢失(覆盖)。
  • 在构造函数中,您应该将bufferreadBuffer初始化为nullptr:如果您的某个malloc失败,您的析构函数将尝试释放
  • getSnapshot中的第一个循环有问题:终点应该是min(bufferSize,head+count)而不是count

设计问题

  • 正如数学家1975所指出的那样,你应该用new float[bufferSize]分配数组,它比mallocs更简单,更易读
  • 您应该使用std::unique_ptr保留每个缓冲区,这样您就不再需要任何析构函数(并且您的代码会更安全)
  • 在处理循环缓冲区时,应使用模数算术,例如: writeIndex = (writeIndex +1 ) % bufferSize。您的代码将更加简单,特别是在getSnapshot(一个循环而不是两个循环)