/*
 * miniJSS - Module structure and handling routines
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2006-2009 Tecnic Software productions (TNSP)
 */
#ifndef JSSMOD_H
#define JSSMOD_H

#include "jss.h"
#include "dmres.h"

#ifdef __cplusplus
extern "C" {
#endif

// Max data size definitions
#define jsetMaxRows         (256)   // Max number of rows
#define jsetMaxPatterns     (256)   // Max patterns
#define jsetMaxTracks       (jsetMaxPatterns * jsetMaxPatterns) // Max tracks
#define jsetMaxInstruments  (512)
#define jsetMaxOrders       (260)
#define jsetNNotes          (11 * 12)
#define jsetMinNote         (0)     // Smallest note number
#define jsetMaxNote         (jsetNNotes - 1)
#define jsetMaxEnvPoints    (32)    // Max number of envelope points


// Instrument envelope flags
#define jenvfUsed           (0x01)  // Envelope is used
#define jenvfSustain        (0x02)  // Envelope has a sustain point (XM) or has sustain loop (IT)
#define jenvfLooped         (0x04)  // Envelope is looped

// Instrument vibrato waveform types
#define jvibSine            (0)
#define jvibRamp            (1)
#define jvibSquare          (2)
#define jvibRandom          (3)

// General stuff
#define jsetNoteOff         (-2)
#define jsetOrderEnd        (-1)
#define jsetOrderSkip       (-2)


// General module flags
#define jmdfAmigaPeriods    (0x0001)    // Use non-linear periods (Amiga)
#define jmdfAmigaLimits     (0x0002)    // Use Amiga-styled valuelimits
#define jmdfStereo          (0x0008)    // Use stereo output, if possible

#define jmdfFT2Replay       (0x0010)    // Use FT2 replaying bugs/features
#define jmdfST300Slides     (0x0020)    // Use Scream Tracker 3.00 slides
#define jmdfByteLStart      (0x0040)    // LStart is in BYTES instead of WORDS (MOD only)


// Module format types
enum JMDT
{
    jmdtMOD = 1,
    jmdtS3M,
    jmdtXM,
    jmdtIT
};


// Bits for sample conversion routines
#define jsampDelta          (0x01)
#define jsampFlipSign       (0x02)
#define jsampSwapEndianess  (0x04)
#define jsampSplit          (0x08)


// Internal instrument structure
typedef struct
{
    int size,               // Length in units
        loopS,              // Loop start position in units
        loopE;              // Loop end position in units
    int volume,             // Volume [jsetMinVol...jsetMaxVol]
        flags,              // Flags - see jss.h jsfXXXX
        C4BaseSpeed,        // C4BaseSpeed
        ERelNote,           // Extended: Relative note value
        EFineTune,          // Extended: Fine-tune value
        EPanning;           // Extended: Panning
#ifndef JSS_LIGHT
    char *desc;
#endif
    void *data;             // Sample data

    BOOL hasData;
    int convFlags;
} JSSInstrument;


// Envelope point structure
typedef struct
{
    int frame, value;
} JSSEnvelopePoint;


// Envelope structure
typedef struct
{
    int flags,
        npoints,
        sustain,
        loopS,
        loopE;
    JSSEnvelopePoint points[jsetMaxEnvPoints];
} JSSEnvelope;


// Extended instrument
typedef struct
{
#ifndef JSS_LIGHT
    char *desc;
#endif
    int nsamples, sNumForNotes[jsetNNotes];
    JSSEnvelope volumeEnv, panningEnv;
    int vibratoType,
        vibratoSweep,
        vibratoDepth,
        vibratoRate,
        fadeOut;
} JSSExtInstrument;


// Internal pattern structures
typedef struct
{
    int note,
        instrument,
        volume,
        effect,
        param;
} JSSNote;


typedef struct
{
    int nrows, nchannels;
    JSSNote *data;
} JSSPattern;


// Module structure
typedef struct
{
    int     moduleType;     // Type of the module
    char    *moduleName;    // Title/name
    char    *trackerName;   // Tracker software name
    int     defSpeed,       // Initial values
            defTempo,
            defFlags,
            defRestartPos,
            intVersion,     // Format's internal version
            nchannels,
            ninstruments,
            nextInstruments,
            npatterns,
            norders;

    int     defPanning[jsetNChannels];
    int     orderList[jsetMaxOrders];
    JSSPattern       *patterns[jsetMaxPatterns + 1];
    JSSInstrument    *instruments[jsetMaxInstruments];
    JSSExtInstrument *extInstruments[jsetMaxInstruments];

#ifdef JSS_SUP_THREADS
    DMMutex *mutex;
#endif

} JSSModule;


#ifdef JSS_SUP_JSSMOD

#define JSSMOD_VERSION    (0x10)

enum
{
    PATMODE_RAW_HORIZ = 1,
    PATMODE_COMP_HORIZ,
    PATMODE_RAW_VERT,
    PATMODE_COMP_VERT,
    PATMODE_RAW_ELEM,
    PATMODE_LAST    
};

/* JSSMOD typedefs
 */
typedef struct
{
    char  idMagic[2];     // "JM"
    Uint8 idVersion;      // 0x10 for 1.0, etc.
    Sint16
        norders,            // Number of orders in orderlist
        npatterns,          // Number of patterns
        nchannels,          // Number of channels
        nextInstruments,    // Number of extended instruments
        ninstruments,       // Number of sample-instruments
        defFlags,           // Flags field: see jmdf* flags
        intVersion,         // Internal version, format dependant
        defRestartPos,      // Default restart position in orderlist
        defSpeed,           // Default speed (ticks/row)
        defTempo,           // Default tempo (BPM)
        patMode;            // Pattern data format mode

    /*
    - After this, norders long orders table will follow, of type:
      Sint16 orderList[norders];
    
    - Pattern data, format depends on patMode.
    
    - Extended instruments (*)
    
    - Sample instrument headers (*)
    
    - Sample data (format depends) (*)
    
    (*) Items are optional and may have been omitted. Fields in the 
        module and other headers are used to indicate if these items exist.
    */
} JSSMODHeader;


typedef struct
{
    Uint16 frame, value;
} JSSMODEnvelopePoint;


typedef struct
{
    int flags,
        npoints,
        sustain,
        loopS,
        loopE;
    JSSMODEnvelopePoint points[jsetMaxEnvPoints];
} JSSMODEnvelope;


typedef struct
{
    Sint16 nsamples;
    Uint8 sNumForNotes[jsetNNotes];
    JSSMODEnvelope volumeEnv, panningEnv;
    Sint16 vibratoType,
            vibratoSweep,
            vibratoDepth,
            vibratoRate;
    int     fadeOut;
} JSSMODExtInstrument;


typedef struct
{
    int     size,           // Length in units
            loopS,          // Loop start position in units
            loopE;          // Loop end position in units
    Sint16 volume,         // Volume [jsetMinVol...jsetMaxVol]
            flags,          // Flags - see jss.h jsfXXXX
            C4BaseSpeed,    // C4BaseSpeed
            ERelNote,       // Extended: Relative note value
            EFineTune,      // Extended: Fine-tune value
            EPanning;       // Extended: Panning
    Uint8 convFlags,      // Conversion flags .. jsampXXXX
            hasData;        // != 0 if there is sample data
} JSSMODInstrument;


#define COMP_NOTE           (0x01)
#define COMP_INSTRUMENT     (0x02)
#define COMP_VOLUME         (0x04)
#define COMP_EFFECT         (0x08)
#define COMP_PARAM          (0x10)
#define COMP_ALL (COMP_NOTE | COMP_INSTRUMENT | COMP_VOLUME | COMP_EFFECT | COMP_PARAM)


typedef struct
{
    size_t nrows, size;
} JSSMODPattern;

#endif

#ifndef JSS_LIGHT
char*               jssASCIItoStr(char *, const char, const size_t);
BOOL                jssEncodeSample8(Uint8 *, const size_t, const int);
BOOL                jssEncodeSample16(Uint16 *, const size_t, const int);
#endif
BOOL                jssDecodeSample8(Uint8 *, const size_t, const int);
BOOL                jssDecodeSample16(Uint16 *, const size_t, const int);
int                 jssConvertModuleForPlaying(JSSModule *module);
JSSModule *         jssAllocateModule(void);
int                 jssFreeModule(JSSModule *);
JSSPattern *        jssAllocatePattern(const int, const int);
JSSInstrument *     jssAllocateInstrument(void);
JSSExtInstrument *  jssAllocateExtInstrument(void);

#ifdef JSS_SUP_XM
int        jssLoadXM(DMResource *, JSSModule **);
#endif

#ifdef JSS_SUP_JSSMOD
int        jssLoadJSSMOD(DMResource *, JSSModule **);
#endif

#ifdef __cplusplus
}
#endif

#endif // JSSMOD_H
