/*
 * miniJSS - Mixing device and channel handling
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2006-2012 Tecnic Software productions (TNSP)
 */
#ifndef JSSMIX_H
#define JSSMIX_H
#include "jss.h"


#ifdef __cplusplus
extern "C" {
#endif

//#define DBG(...) do { fprintf(stderr, __VA_ARGS__); } while (0)
#define DBG(...) do { /* stub */ } while (0)


// Mixing limits
#define JVM_LIMIT_16_POS    (32767)
#define JVM_LIMIT_16_NEG    (-32767)
#define JVM_ADD_16          (32768)


#define JMIXER_ADDBUF_TYPE Sint32


// A channel data structure
typedef struct
{
    DMFixedPoint
            chSize,         // Length of sample in UNITS
            chLoopS,        // Loop start in UNITS
            chLoopE,        // Loop end in UNITS

            chPos,          // Current position in sample, 32:32 fixpoint
            chDeltaO,       // Delta in 32:32 UNSIGNED! (chDirection)
            chVolume,       // Volume
            chDeltaV,
            chPanning,      // Panning
            chDeltaP;
    int     chVolumeD,
            chPanningD;

    int     chFreq;         // Frequency of sampel in Hz

    void    *chData;        // Pointer to data

    BOOL    chPlaying,      // TRUE = playing
            chMute,         // TRUE = muted
            chDirection;    // TRUE = playing forwards, FALSE = backwards

    int     chFlags;        // Flags

    JMIXER_ADDBUF_TYPE chPrevR[5], chPrevL[5];
} JSSChannel;


// Channel table
typedef int JSSChannelTable[jsetNChannels];


// Virtual software mixer "device" structure
typedef struct _JSSMixer JSSMixer;

struct _JSSMixer
{
    int             outFormat,
                    outChannels,
                    outFreq,
                    globalVol;
    JSSChannel      channels[jsetNChannels];
    
    int             addBufSize;
    JMIXER_ADDBUF_TYPE *addBuffer;

    // Callback handling
    int             cbFreq, cbCounter;
    void            *cbData;
    void            (*cbFunction)(void *, void *);

    // Mixing routine pointers
    int    (*jvmMixChannel_FW)(JSSMixer *, JSSChannel *, JMIXER_ADDBUF_TYPE *, const int, const DMFixedPoint);
    int    (*jvmMixChannel_BW)(JSSMixer *, JSSChannel *, JMIXER_ADDBUF_TYPE *, const int, const DMFixedPoint);
    void   (*jvmPostProcess)(JMIXER_ADDBUF_TYPE *, void *, const int);

    // Device locking
#ifdef JSS_SUP_THREADS
    DMMutex *mutex;
#endif
};


/* Enums
 */
enum {
    JMIX_AUTO = 0,
    JMIX_C,
    JMIX_MMX,
    JMIX_SSE
};


/* Main routines
 */
JSSMixer *  jvmInit(const int outFormat, const int outChannels, const int outFreq, const int mixerID);
int         jvmClose(JSSMixer *mixer);

int         jvmSetCallback(JSSMixer *mixer, void (*cbFunction)(void *, void *), void *cbData);
void        jvmRemoveCallback(JSSMixer *mixer);
int         jvmSetCallbackFreq(JSSMixer *mixer, const int cbFreq);
Sint32      jvmGetLastCBBufPos(JSSMixer *mixer, const int cbHandle);
Sint32      jvmGetNextCBBufPos(JSSMixer *mixer, const int cbHandle);

int         jvmGetSampleSize(JSSMixer *mixer);
int         jvmGetSampleRes(JSSMixer *mixer);

void        jvmRenderAudio(JSSMixer *mixer, void *mixBuffer, const int mixLength);


/*
int         jvmAddCallback(JSSMixer *mixer, void (*cbFunction)(JSSMixer *, void *));
int         jvmRemoveCallback(JSSMixer *mixer, int cbHandle);
int         jvmSetCallbackFreq(JSSMixer *mixer, int cbHandle, int cbFreq);

int         jvmAllocChannels(JSSMixer *mixer, int nChannels);
int         jvmFreeChannels(JSSMixer *mixer, int iHandle);
int         jvmGetChannelTable(JSSMixer *mixer, int iHandle, JSSChannelTable *pTable);
*/


/* Channel manipulation routines
 */
void        jvmPlay(JSSMixer *mixer, const int channel);
void        jvmStop(JSSMixer *mixer, const int channel);
void        jvmReset(JSSMixer * mixer, const int channel);

void        jvmSetSample(JSSMixer *mixer, const int channel,
            void *data, const Sint32 size, const Sint32 loopS,
            const Sint32 loopE, const int flags);

void        jvmSetFreq(JSSMixer *mixer, const int channel, const int freq);
int         jvmGetFreq(JSSMixer *mixer, const int channel);

void        jvmSetVolume(JSSMixer *mixer, const int channel, const int volume);
void        jvmSetVolumeRamp(JSSMixer * mixer, const int channel, const int start, const int end, const int len);
int         jvmGetVolume(JSSMixer *mixer, const int channel);

void        jvmSetPos(JSSMixer *mixer, const int channel, const Sint32 pos);
Sint32      jvmGetPos(JSSMixer *mixer, const int channel);

void        jvmSetPan(JSSMixer *mixer, const int channel, const int panning);
void        jvmSetPanRamp(JSSMixer * mixer, const int channel, const int start, const int end, const int len);
int         jvmGetPan(JSSMixer *mixer, const int channel);

void        jvmMute(JSSMixer *mixer, const int channel, const BOOL mute);
BOOL        jvmGetMute(JSSMixer *mixer, const int channel);

void        jvmClear(JSSMixer *mixer, const int channel);
void        jvmClearChannels(JSSMixer *mixer);

void        jvmSetGlobalVol(JSSMixer *mixer, const int volume);
int         jvmGetGlobalVol(JSSMixer *mixer);


#ifdef __cplusplus
}
#endif

#endif // JSSMIX_H
