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

#include <gtk/gtkobject.h>

typedef struct _GdamCacheBuffer GdamCacheBuffer;

#include "gdassource.h"
#include "gdamconnection.h"

GtkType gdam_cache_buffer_get_type ();
#define GDAM_TYPE_CACHE_BUFFER              (gdam_cache_buffer_get_type ())
#define GDAM_CACHE_BUFFER(obj)              (GTK_CHECK_CAST ((obj), GDAM_TYPE_CACHE_BUFFER, GdamCacheBuffer))
#define GDAM_CACHE_BUFFER_CLASS(klass)      (GTK_CHECK_CLASS_CAST ((klass), GDAM_TYPE_CACHE_BUFFER, GdamCacheBufferClass))
#define GDAM_IS_CACHE_BUFFER(obj)           (GTK_CHECK_TYPE ((obj), GDAM_TYPE_CACHE_BUFFER))
#define GDAM_IS_CACHE_BUFFER_CLASS(klass)   (GTK_CHECK_CLASS_TYPE ((klass), GDAM_TYPE_CACHE_BUFFER))

guint gdam_cache_buffer_get_done_event();
#define GDAM_CACHE_BUFFER_EVENT_DONE            (gdam_cache_buffer_get_done_event())

typedef struct _GdamCacheBufferClass GdamCacheBufferClass;
struct _GdamCacheBufferClass {
  GdamServerObjectClass klass;

  /* before draining, this appends data into a "loading buffer" */
  void                  (*append)    (GdamCacheBuffer  *cache_buffer,
                                      GdamSample       *buffer,
                                      int               num_samples);
  /* after draining, this moves the loading buffer into a real buffer */
  void                  (*finished)  (GdamCacheBuffer  *cache_buffer);

  /* read samples out of the buffer, at a certain offset. */
  int                   (*read)      (GdamCacheBuffer  *buffer,
                                      GdamSample       *output,
				      int               index,
				      guint32           index_frac,
				      int              *end_index,
				      guint32          *end_index_frac,
                                      int               max_output,
                                      GdamFixed         rate,
                                      GdamFixed         gain,
                                      gboolean          add);

  GdamSample            (*index)     (GdamCacheBuffer  *buffer,
                                      int               index);
};

struct _GdamCacheBuffer {
  GdamServerObject      object;

  GdasSource           *to_drain;

  /* if the buffer is virtual,
   *    you have to use the class methods;
   * otherwise, 
   *    you may, but the direct buffer access can be faster. */
  gboolean              is_virtual;

  /* special hack to support storing of 16-bit (rather than 24+8-bit) 
   * in the non-virtual "buffer" */
  gboolean              is_16bit;

  /* buffer to use while draining. */
  GdamBuffer            loading_buffer;

  /* if is_16bit these are pairs of 16-bit signed samples,
   * or otherwise, GdamSamples. */
  void                 *_buffer;

  /* length of the buffer in samples */
  int                   buffer_length;

  /* g_free() usually, although maybe munmap() or free() will
   * be common later. */
  GDestroyNotify        free_func;

  /* optional name (mostly for esound compatibility) */
  char                 *name;

  /* the connection that created this, if it is still alive */
  GdamConnection       *owner;

  guint                 source_id;      /* in gmainloop */

  guint                 read_only : 1;
};

/* Call `new' then `register' to avoid memory leaks, as long
 * as you unregister it. */
GdamCacheBuffer  *gdam_cache_buffer_new       (GdasSource      *to_drain);

/* Don't call `gtk_object_unref' on the return value when you're done. */
GdamCacheBuffer  *gdam_cache_buffer_get_by_id (guint            buffer_id);
int               gdam_cache_buffer_get_id    (GdamCacheBuffer *buffer);


/* Named cache-buffers */
void              gdam_cache_buffer_set_name  (GdamCacheBuffer *buffer,
					       const char      *name);
GdamCacheBuffer* gdam_cache_buffer_peek_by_name(const char      *name);

/* Remove the cache-buffer from the global namespace */
void              gdam_cache_buffer_detach    (GdamCacheBuffer *buffer);

/* profile_mode is from gdam-protocol.h: enum GdamProtocolProfileMode. */
gint             *gdam_cache_buffer_profile   (GdamCacheBuffer *buffer,
                                               int              profile_mode,
                                               int              sample_start,
                                               int              sample_length,
                                               int              num_outputs);
int gdam_cache_buffer_profile_mode_get_n_channels (int profile_mode);

gdouble          *gdam_cache_buffer_guess_beat_times       
                                         (GdamCacheBuffer *buffer,
					  gdouble          window_size,
					  int              amplitude_threshold,
					  gdouble          amplitude_ratio,
					  gdouble          min_sample_length,
					  int             *num_beat_times);

GdamCacheBuffer*  gdam_cache_buffer_memory    (int              buffer_length,
                                               void            *buffer,
                                               GDestroyNotify   free_func,
					       gboolean         is_16bit);

GdamSample        gdam_cache_buffer_index     (GdamCacheBuffer *buffer,
                                               int              index);
int               gdam_cache_buffer_read      (GdamCacheBuffer *buffer,
                                               GdamSample      *output,
                                               int              start_index,
					       guint32          index_frac,
					       int             *end_index,
					       guint32         *end_index_frac,
                                               int              max_output,
                                               GdamFixed        rate,
                                               GdamFixed        gain,
                                               gboolean         add);

/* --- private --- */
void            gdam_cache_buffer_func_profile(GtkObject      *object,
                                               int             num_args_in,
                                               GdamArg        *arguments_in,
                                               int            *num_args_out,
                                               GdamArg       **arguments_out);

#endif
