/*
    GDAM - Geoff & Dave's Audio Mixer
    Copyright (C) 1999    Dave Benson, Geoff Matters.

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

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

    Contact:
        daveb@ffem.org <Dave Benson>
        geoff@ugcs.caltech.edu <Geoff Matters>
*/
#ifndef __GDAM_CIRCULAR_BUFFER_H_
#define __GDAM_CIRCULAR_BUFFER_H_

typedef struct _GdamCircularBuffer GdamCircularBuffer;

#include <gdam/common/gdamsample.h>

struct _GdamCircularBuffer {
	int buffer_size;
	GdamSample* buffer;
	int read_index;
	int amount_buffered;
};

GdamCircularBuffer *gdam_circular_buffer_new   (int buffer_size);
void                gdam_circular_buffer_resize(GdamCircularBuffer *buf,
                                                int            new_buffer_size,
						gboolean            filled);
void                gdam_circular_buffer_append(GdamCircularBuffer *buf,
                                                const GdamSample   *data,
						int               data_length);

G_INLINE_FUNC void  gdam_circular_buffer_append_one
                                               (GdamCircularBuffer *buf,
                                                GdamSample          data);
int                 gdam_circular_buffer_read  (GdamCircularBuffer *buf,
                                                GdamSample         *data,
						int               data_length);
int                 gdam_circular_buffer_peek  (GdamCircularBuffer *buf,
                                                GdamSample         *data,
						int               data_length);

/* Operate without allocating space for the buffer itself. */
void                gdam_circular_buffer_construct(GdamCircularBuffer*);
void                gdam_circular_buffer_destruct(GdamCircularBuffer*);


/* Caller must insure that at least one sample is available. */
G_INLINE_FUNC GdamSample gdam_circular_buffer_read_one(GdamCircularBuffer *buf);
G_INLINE_FUNC GdamSample gdam_circular_buffer_peek_one(GdamCircularBuffer *buf);



#if G_CAN_INLINE
/* A few functions are inlined for efficiency... */
G_INLINE_FUNC GdamSample
gdam_circular_buffer_read_one(GdamCircularBuffer* buf)
{
	GdamSample rv;
	int read_index = buf->read_index;
	g_assert(buf->amount_buffered > 0);
	rv = buf->buffer[read_index];
	if (++read_index == buf->buffer_size)
		read_index = 0;
	buf->read_index = read_index;
	buf->amount_buffered--;
	return rv;
}
G_INLINE_FUNC GdamSample
gdam_circular_buffer_peek_one(GdamCircularBuffer* buf)
{
	g_assert(buf->amount_buffered > 0);
	return buf->buffer[buf->read_index];
}
G_INLINE_FUNC void
gdam_circular_buffer_append_one(GdamCircularBuffer* buf, GdamSample sample)
{
	if (buf->amount_buffered == buf->buffer_size) {
		buf->buffer[buf->read_index++] = sample;
		if (buf->read_index == buf->buffer_size)
			buf->read_index = 0;
	} else {
		int write_index = buf->read_index + buf->amount_buffered;
		write_index %= buf->buffer_size;
		buf->buffer[write_index] = sample;
		buf->amount_buffered++;
	}
}
#endif

#endif
