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

#ifdef __cplusplus
extern "C" {
#endif

#include <glib.h>
#include <string.h>

#if 0

typedef gint16 GdamSampleValue;
#define GDAM_SAMPLE_BITS	16
#define GDAM_SAMPLE_OVER_BITS	0
typedef gint GdamFixedProduct;
typedef gint32 GdamSampleProduct;


#else

typedef gint32 GdamSampleValue;
#define GDAM_SAMPLE_BITS	24
#define GDAM_SAMPLE_OVER_BITS	4
typedef gint64 GdamSampleProduct;
typedef gint64 GdamFixedProduct;

#endif

/*                        struct GdamSample
 *
 * A PCM sample.  Includes left and right channels.
 */
struct _GdamSampleFloat
{
  gfloat s[2];
};
struct _GdamSampleDouble
{
  gdouble s[2];
};
typedef struct _GdamSample16
{
  gint16 s[2];
} GdamSample16;
typedef struct _GdamSample {
	GdamSampleValue s[2];
} GdamSample;


typedef gint GdamFixed;
#define GdamFixed_LOG_ONE	GDAM_SAMPLE_BITS
#define GdamFixed_ONE		(1<<GdamFixed_LOG_ONE)
#define GDAM_FIXED_MUL(a,b)			\
			(((GdamFixedProduct)(a) * (b)) >> GdamFixed_LOG_ONE)
#define GDAM_FIXED_FROM_DOUBLE(d)		\
			((GdamFixed)((d) * (GdamFixed_ONE)))
#define GDAM_FIXED_TO_DOUBLE(d)		\
			((gdouble)(d) / GdamFixed_ONE)
#define GDAM_FIXED_FROM_FLOAT(f)		\
			((GdamFixed)((f) * (GdamFixed_ONE)))
#define GDAM_FIXED_TO_FLOAT(f)		\
			((gfloat)(f) / GdamFixed_ONE)

/* Minimum/maximum sample values. */
#define GDAM_SAMPLE_LOG		(GDAM_SAMPLE_BITS - 1)
#define GDAM_SAMPLE_MAX       ((GdamSampleValue) ((1 << (GDAM_SAMPLE_LOG+GDAM_SAMPLE_OVER_BITS))-1))
#define GDAM_SAMPLE_MIN       (-(GDAM_SAMPLE_MAX))
#define GDAM_SAMPLE_ONE		(1 << GDAM_SAMPLE_LOG)

/* Used while we are using 16 bit samples.
 * Later with 32-bit sample we won't need to check all the time. */
#define GDAM_SAMPLE_NEEDS_CLIPPING	1

#if GDAM_SAMPLE_NEEDS_CLIPPING
#define GDAM_SAMPLE_CLAMP(val) CLAMP(val, GDAM_SAMPLE_MIN, GDAM_SAMPLE_MAX)
#else
#define GDAM_SAMPLE_CLAMP(val) (val)
#endif

/* Bulk sample operations. */
void gdam_sample_scale              (GdamSample*          regain,
                                     int                  num_samples,
				     GdamFixed            scale);
void gdam_sample_zero               (GdamSample*          regain,
                                     int                  num_samples);
void gdam_sample_addto              (GdamSample*          accum,
                                     const GdamSample*    term,
				     int                  length);
void gdam_sample_add_scaled         (GdamSample*          accumulator,
                                     const GdamSample*    term,
			             int                  length,
				     GdamFixed            scale);
void gdam_sample_copy_scaled        (GdamSample*          destination,
                                     const GdamSample*    source,
			             int                  length,
				     gint                 b16);
void gdam_sample_copy               (GdamSample*          destination,
                                     const GdamSample*    source,
				     int                  length);
/* the destination/source may overlap in `move's arguments */
void gdam_sample_move               (GdamSample*          destination,
                                     const GdamSample*    source,
				     int                  length);
void gdam_sample_modulate           (GdamSample*          destination,
                                     const GdamSample*    modulator,
			             int                  length);

void gdam_sample16_copy             (GdamSample16*        destination,
                                     const GdamSample16*  source,
				     int                  length);
void gdam_sample16_from_normal      (GdamSample16*        destination,
                                     const GdamSample*    source,
				     int                  length);
void gdam_sample_from_16            (GdamSample*          destination,
                                     const GdamSample16*  source,
				     int                  length);
void gdam_sample_addto_from_16      (GdamSample*          destination,
                                     const GdamSample16*  source,
				     int                  length);
void gdam_sample_addto_from_16_scaled(GdamSample*          destination,
                                      const GdamSample16*  source,
				      int                  length,
				      GdamFixed            gain);

/* Some of those are trivial, and done with #define... */
#define gdam_sample_copy(dst,src,len) memcpy(dst,src,(len)*sizeof(GdamSample))
#define gdam_sample_move(dst,src,len) memmove(dst,src,(len)*sizeof(GdamSample))
#define gdam_sample16_copy(dst,src,len) \
        memcpy(dst,src,(len)*sizeof(GdamSample16))
#define gdam_sample_zero(d,len) memset(d, 0, (len) * sizeof(GdamSample))

#define GDAM_SAMPLE_TO_FLOAT(sample_value)		\
		((float)(sample_value) / GDAM_SAMPLE_ONE)
#define GDAM_SAMPLE_FROM_FLOAT(sample_value)		\
		((int)((sample_value) * GDAM_SAMPLE_ONE))

#ifdef __cplusplus
};
#endif

#endif
