Source

QJack / qjack / ringbuffer.h

Full commit
/*
    QJack make you connect with jack soundserver system
    Copyright (C) 2011  Alessandro Siniscalchi <asiniscalchi@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef RINGBUFFER_H
#define RINGBUFFER_H

#include <QtCore/QtGlobal>

namespace QJack{

namespace DataStructure{

template <typename T>
class RingBuffer
{
public:
    RingBuffer<T>(quint32 size);
    virtual ~RingBuffer();

    quint32 write(const T *data, quint32 size);
    quint32 read(T *data, quint32 size);
    quint32 availableWrite() const;
    quint32 availableRead() const;

private:
    T* m_buffer;
    quint32 m_size;
    volatile quint32 m_first;
    volatile quint32 m_next;
};

// Definition
template <typename T> RingBuffer<T>::RingBuffer(quint32 size):
    m_size(size+1)
{
    // 1 element will be used to set the next
    m_buffer = new T[size+1];

    m_first = 0;
    m_next = 0;
}

template <typename T> RingBuffer<T>::~RingBuffer()
{
    delete(m_buffer);
}

template <typename T> quint32 RingBuffer<T>::availableRead() const
{
    // I copy the values to avoid multithread problems
    volatile quint32 first = m_first;
    volatile quint32 next = m_next;

    if (next >= first)
        return(next - first);
    else
        return(m_size - first + next);
}

template <typename T> quint32 RingBuffer<T>::availableWrite() const
{
    // I copy the values to avoid multithread problems
    volatile quint32 first = m_first;
    volatile quint32 next = m_next;

    if (next >= first)
        return(m_size - next + first - 1);
    else
        return(first - next - 1);

}

template <typename T> quint32 RingBuffer<T>::read(T *data, quint32 size)
{
    // I copy the values to avoid multithread problems
    volatile quint32 first = m_first;
    volatile quint32 toRead = 0;
    volatile quint32 available = availableRead();

    // chek how much data I have
    if (size >= available)
        toRead = available;
    else
        toRead = size;

    // reading
    for (int i=0 ; i < toRead ; ++i)
    {
        data[i] = m_buffer[first];
        ++first;

        if (first == m_size)
            first = 0;
    }

    m_first = first;

    return(toRead);
}

template <typename T> quint32 RingBuffer<T>::write(const T *data, quint32 size)
{
    // I copy the values to avoid multithread problems
    volatile quint32 next = m_next;
    volatile quint32 toWrite = 0;
    volatile quint32 available = availableWrite();

    // check if I have enought space
    if (size >= available)
        toWrite = available;
    else
        toWrite = size;

    // writing
    for (int i=0 ; i < toWrite ; ++i)
    {
        m_buffer[next] = data[i];
        ++next;

        if (next == m_size)
            next = 0;
    }

    m_next = next;

    return(toWrite);
}

} // namespace

} // namespace

#endif // RINGBUFFER_H