/*
 * miniJSS - Module playing routines
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2006-2012 Tecnic Software productions (TNSP)
 */
#ifndef JSSPLR_H
#define JSSPLR_H

#include "jss.h"
#include "jssmod.h"
#include "jssmix.h"

#ifdef __cplusplus
extern "C" {
#endif

// Player general constants
#define mpMinVol            (0)
#define mpMaxVol            (64)
#define mpPanCenter         (0)
//#define mpMaxFadeoutVol     (65535)
#define mpMaxFadeoutVol     (32767)


// Channel New-Data flags
#define cdfNONE             (0x000)    // Set nothing
#define cdfNewInstr         (0x001)    // Set a new instrument
#define cdfNewPitch         (0x002)    // Set a new pitch
#define cdfNewPos           (0x004)    // Set a new position
#define cdfNewVolume        (0x008)    // Set a new volume
#define cdfNewPanPos        (0x010)    // Set a new panning position
#define cdfNewGlobalVol     (0x020)    // Set a new global volume
#define cdfNewFreq          (0x040)    // New frequency
#define cdfPlay             (0x100)    // Start or restart playing sample
#define cdfStop             (0x200)    // Stop channel playing


// Player envelope data
typedef struct
{
    int frame, value;
    BOOL exec;
} JSSPlayerEnvelope;


typedef struct
{
    int pos, speed, depth, wc;
} JSSPlayerVData;


// Player channel structure
typedef struct
{
    JSSPlayerEnvelope volumeEnv, panningEnv;

    JSSPlayerVData vibrato, tremolo;
        
    BOOL    keyOff;

    JSSInstrument  *instrument;           // Instrument
    JSSExtInstrument *extInstrument;       // ExtInstrument
    int     ninstrument,
            nextInstrument,
            note,                 // Current note
            pitch,                // Pitch (NOT actual frequency!)
            freq, cfreq,
            oldPitch,
            oldNote,
            position,             // Sample position
            volume, cvolume,      // Volume
            panning,              // Panning position

            newDataFlags,         // New data flags

            fadeOutVol,

            iCAutoVib_Frame,

            iCLastFineVolumeslideUpParam,
            iCLastFineVolumeslideDownParam,
            iCLastExtraFinePortamentoUpParam,
            iCLastExtraFinePortamentoDownParam,
            iCLastFinePortamentoUpParam,
            iCLastFinePortamentoDownParam,

            iPatLoopRow,            // Pattern loop start row
            iPatLoopCount,          // Pattern loop count
        
            iLastPortaParam,        // Last portamento effect parameter
            iLastPortaToNoteParam,  // Last porta-to-note parameter
            iLastPortaToNotePitch,  // Last porta-to-note pitch
            lastPortaToNoteNote,

            iLastTremorParam,
            iTremorCount,
            iLastSampleOffset,
            iLastVolSlideParam,

            lastMultiRetrigParamX,
            lastMultiRetrigParamY,

            lastSampleOffsetParam,
            
            iSaveNDFlags;           // For notedelay-effect
} JSSPlayerChannel;


// Struct holding all player related information
typedef struct _JSSPlayer
{
    // General variables
    int     tempo,              // Current values
            speed,
            tick,
            order,
            npattern,
            row,
            globalVol,
            options;            // Playing option flags
    BOOL    isPlaying;          // Are we playing?

    int     newOrder,           // NEW order number
            newRow;             // NEW row number
    BOOL    newOrderSet,        // TRUE if new order has been set
            newRowSet;          // TRUE if new row has been set

    int     patternDelay,       // Pattern delay tick-counter
            lastPatLoopRow;     // Latest set pattern loop row (any channel)

    BOOL    jumpFlag,           // Pattern jump flag
            breakFlag;          // Pattern break flag

    // All channels for this player
//    int     nchannels;
    JSSPlayerChannel channels[jsetNChannels];


    // Module and sounddevice specific
    JSSModule *module;          // Current module in this player
    JSSPattern *pattern;        // Current pattern
    JSSMixer *device;           // Pointer to mixing device structure

#ifdef JSS_SUP_THREADS
    DMMutex *mutex;
#endif

} JSSPlayer;


/* External functions for end users
 */
int             jmpPlayOrder(JSSPlayer *, int);
int             jmpChangeOrder(JSSPlayer *, int);
int             jmpPlayPattern(JSSPlayer *, int);
void            jmpStop(JSSPlayer *);
void            jmpResume(JSSPlayer *);
void            jmpSetModule(JSSPlayer *, JSSModule *);
JSSPlayer *     jmpInit(JSSMixer *);
int             jmpClose(JSSPlayer *);
void            jmpExec(void *, void *);


/* Helper macros
 */
#define JMPMAKEPARAM(AIVAL, AVALX, AVALY) { AVALX = (((AIVAL) >> 4) & 0x0f); AVALY = ((AIVAL) & 0x0f); }
#define JMPSETNDFLAGS(IVAL) chn->newDataFlags |= IVAL
#define JMPUNSETNDFLAGS(IVAL) chn->newDataFlags &= (~(IVAL))
#define JMPGETNOTE(MNOTE, MROW, MCHAN) assert(mp); assert(mp->pattern); assert((MROW) >= 0); assert((MROW) < mp->pattern->nrows); MNOTE = &mp->pattern->data[(mp->pattern->nchannels * MROW) + (MCHAN)]
#define JMPGETEFFECT(MEFF, MIEFF) if ((MIEFF >= 0) && (MIEFF < jmpNMODEffectTable)) MEFF = jmpMODEffectTable[MIEFF]; else MEFF = 0
#define JMPGETMODFLAGS(Q, Z) ((Q->module->defFlags & (Z)) == (Z))


/* Debugging macros
 */
#if !defined(JSS_LIGHT) && defined(JSS_DEBUG)
#  define JMPDEBUG(QQ) { fprintf(stderr, "[o=%03d:p=%03d:r=%03d] (%c/%x:%x) %s\n", mp->order, mp->npattern, mp->row, effect, currNote->effect, currNote->param, QQ ); }
#else
#  define JMPDEBUG(QQ) // stub
#endif

#ifdef __cplusplus
}
#endif

#endif // JSSPLR_H
