/*
    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 __GDAS_BUFFERING_FILTER_H_
#define __GDAS_BUFFERING_FILTER_H_

typedef struct _GdasBufferingFilter GdasBufferingFilter;
typedef struct _GdasBufferingFilterClass GdasBufferingFilterClass;
typedef struct _GdasBufferingFilterElement GdasBufferingFilterElement;

#include "gdasfilter.h"

GtkType gdas_buffering_filter_get_type();
#define GDAS_TYPE_BUFFERING_FILTER   gdas_buffering_filter_get_type()
#define GDAS_BUFFERING_FILTER(ptr) ((GdasBufferingFilter*) gtk_type_check_object_cast ((GtkTypeObject*) (ptr), GDAS_TYPE_BUFFERING_FILTER))

struct _GdasBufferingFilterClass {
	GdasFilterClass		filter_class;
};

struct _GdasBufferingFilter {
	GdasFilter		filter;
	int			buffer_length;

	/* Invariant: 0 <= buffer_inbound_pos < buffer_length */
	int			buffer_inbound_pos;

	int			buffer_current_amount;
	GdamSample*		buffer;
};

void gdas_buffering_filter_buffer(GdasBufferingFilter *buffering_filter,
                                  const GdamSample *in, int n);

int gdas_buffering_filter_buffer_from_source(GdasBufferingFilter *filter,
                                              GdasSource *src, int max);

/* The number returned is the number of samples discarded
 * from the filter's buffer to make room for the n bytes of buf. */
/* offsets into the filters buffer should be shifted by return value. */
int  gdas_buffering_filter_append(GdasBufferingFilter *filter,
                                  const GdamSample    *buf,
                                  int                  n);

void gdas_buffering_filter_ensure_space(GdasBufferingFilter *filter,
                                        int                  amount);

int gdas_buffering_filter_peek_from_buffer(GdasBufferingFilter *filter,
                                           GdamSample *dest, int n);

G_INLINE_FUNC void gdas_buffering_filter_append_sample
                                                (GdasBufferingFilter *filter,
                                                 GdamSample           sample);
G_INLINE_FUNC GdamSample gdas_buffering_filter_sample_at
						(GdasBufferingFilter *filter,
						 int                  delay);
G_INLINE_FUNC GdamSample gdas_buffering_filter_sample_from_start
						(GdasBufferingFilter *filter,
						 int                  offset);

#ifdef G_CAN_INLINE
G_INLINE_FUNC void gdas_buffering_filter_append_sample
						(GdasBufferingFilter *filter,
						 GdamSample           sample)
{
	if (filter->buffer_length == 0)
		return;
	++(filter->buffer_inbound_pos);
	if (filter->buffer_inbound_pos == filter->buffer_length)
		filter->buffer_inbound_pos = 0;
	filter->buffer[filter->buffer_inbound_pos] = sample;
	if (filter->buffer_current_amount < filter->buffer_length)
		filter->buffer_current_amount++;
}
	

G_INLINE_FUNC GdamSample gdas_buffering_filter_sample_at
						(GdasBufferingFilter *filter,
						 int                  delay)
{
	int pos = filter->buffer_inbound_pos - delay;
	if (pos < 0)
		pos += filter->buffer_length;
	return filter->buffer[pos];
}

G_INLINE_FUNC GdamSample gdas_buffering_filter_sample_from_start
						(GdasBufferingFilter *filter,
						 int                  offset)
{
	int pos = filter->buffer_inbound_pos
	        - filter->buffer_current_amount
		+ offset;
	if (pos < 0)
		pos += filter->buffer_length;
	return filter->buffer[pos];
}
#endif /* G_CAN_INLINE */

#endif
