/* * RingBuffer.h - an effective and flexible implementation of a ringbuffer for LMMS * * Copyright (c) 2014 Vesa Kivimäki * Copyright (c) 2005-2014 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * 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 (see COPYING); 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 #include "lmms_basics.h" #include "lmms_math.h" #include "MemoryManager.h" class EXPORT RingBuffer : public QObject { Q_OBJECT MM_OPERATORS public: /** \brief Constructs a ringbuffer of specified size, will not care about samplerate changes * \param size The size of the buffer in frames. The actual size will be size + period size */ RingBuffer( f_cnt_t size ); /** \brief Constructs a ringbuffer of specified samplerate-dependent size, which will be updated when samplerate changes * \param size The size of the buffer in milliseconds. The actual size will be size + period size */ RingBuffer( float size ); virtual ~RingBuffer(); //////////////////////////////////// // Provided functions // //////////////////////////////////// // utility functions /** \brief Clears the ringbuffer of any data and resets the position to 0 */ void reset(); /** \brief Changes the size of the ringbuffer. Clears all data. * \param size New size in frames */ void changeSize( f_cnt_t size ); /** \brief Changes the size of the ringbuffer. Clears all data. * \param size New size in milliseconds */ void changeSize( float size ); /** \brief Sets whether the ringbuffer size is adjusted for samplerate when samplerate changes * \param b True if samplerate should affect buffer size */ void setSamplerateAware( bool b ); // position adjustment functions /** \brief Advances the position by one period */ void advance(); /** \brief Moves position forwards/backwards by an amount of frames * \param amount Number of frames to move, may be negative */ void movePosition( f_cnt_t amount ); /** \brief Moves position forwards/backwards by an amount of milliseconds * \param amount Number of milliseconds to move, may be negative */ void movePosition( float amount ); // read functions /** \brief Destructively reads a period-sized buffer from the current position, writes it * to a specified destination, and advances the position by one period * \param dst Destination pointer */ void pop( sampleFrame * dst ); // note: ringbuffer position is unaffected by all other read functions beside pop() /** \brief Reads a period-sized buffer from the ringbuffer and writes it to a specified destination * \param dst Destination pointer * \param offset Offset in frames against current position, may be negative */ void read( sampleFrame * dst, f_cnt_t offset=0 ); /** \brief Reads a period-sized buffer from the ringbuffer and writes it to a specified destination * \param dst Destination pointer * \param offset Offset in milliseconds against current position, may be negative */ void read( sampleFrame * dst, float offset ); /** \brief Reads a buffer of specified size from the ringbuffer and writes it to a specified destination * \param dst Destination pointer * \param offset Offset in frames against current position, may be negative * \param length Length in frames of the buffer to read - must not be higher than the size of the ringbuffer! */ void read( sampleFrame * dst, f_cnt_t offset, f_cnt_t length ); /** \brief Reads a buffer of specified size from the ringbuffer and writes it to a specified destination * \param dst Destination pointer * \param offset Offset in milliseconds against current position, may be negative * \param length Length in frames of the buffer to read - must not be higher than the size of the ringbuffer! */ void read( sampleFrame * dst, float offset, f_cnt_t length ); // write functions /** \brief Writes a buffer of sampleframes to the ringbuffer at specified position * \param src Pointer to the source buffer * \param offset Offset in frames against current position, may *NOT* be negative * \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer! */ void write( sampleFrame * src, f_cnt_t offset=0, f_cnt_t length=0 ); /** \brief Writes a buffer of sampleframes to the ringbuffer at specified position * \param src Pointer to the source buffer * \param offset Offset in milliseconds against current position, may *NOT* be negative * \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer! */ void write( sampleFrame * src, float offset, f_cnt_t length=0 ); /** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position * \param src Pointer to the source buffer * \param offset Offset in frames against current position, may *NOT* be negative * \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer! */ void writeAdding( sampleFrame * src, f_cnt_t offset=0, f_cnt_t length=0 ); /** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position * \param src Pointer to the source buffer * \param offset Offset in milliseconds against current position, may *NOT* be negative * \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer! */ void writeAdding( sampleFrame * src, float offset, f_cnt_t length=0 ); /** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position, with * a specified multiplier applied to the frames * \param src Pointer to the source buffer * \param offset Offset in frames against current position, may *NOT* be negative * \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer! * \param level Multiplier applied to the frames before they're written to the ringbuffer */ void writeAddingMultiplied( sampleFrame * src, f_cnt_t offset, f_cnt_t length, float level ); /** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position, with * a specified multiplier applied to the frames * \param src Pointer to the source buffer * \param offset Offset in milliseconds against current position, may *NOT* be negative * \param length Length of the source buffer, if zero, period size is used * \param level Multiplier applied to the frames before they're written to the ringbuffer */ void writeAddingMultiplied( sampleFrame * src, float offset, f_cnt_t length, float level ); /** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position, with * a specified multiplier applied to the frames, with swapped channels * \param src Pointer to the source buffer * \param offset Offset in frames against current position, may *NOT* be negative * \param length Length of the source buffer, if zero, period size is used - must not be higher than the size of the ringbuffer! * \param level Multiplier applied to the frames before they're written to the ringbuffer */ void writeSwappedAddingMultiplied( sampleFrame * src, f_cnt_t offset, f_cnt_t length, float level ); /** \brief Mixes a buffer of sampleframes additively to the ringbuffer at specified position, with * a specified multiplier applied to the frames, with swapped channels * \param src Pointer to the source buffer * \param offset Offset in milliseconds against current position, may *NOT* be negative * \param length Length of the source buffer, if zero, period size is used * \param level Multiplier applied to the frames before they're written to the ringbuffer */ void writeSwappedAddingMultiplied( sampleFrame * src, float offset, f_cnt_t length, float level ); protected slots: void updateSamplerate(); private: inline f_cnt_t msToFrames( float ms ) { return static_cast( ceilf( ms * (float)m_samplerate * 0.001f ) ); } const fpp_t m_fpp; sample_rate_t m_samplerate; size_t m_size; sampleFrame * m_buffer; volatile unsigned int m_position; }; #endif