#ifndef _Loaders_h
#define _Loaders_h

#include "TimTypes.h"
#include "kernel.h"

#define Loaders_NotThisType ((const _kernel_oserror*) 1)

#define LoadFlag_HasGlbVolumeCmd 0x00000001

struct LoaderData
{
    // Loader type info
	uint32_t        File;
	const uint8_t*  pMemory;
	uint32_t        MemSize;
	uint32_t        MemPos;
	// Decompressor
	struct
	{
		uint8_t*        pMemory;
		uint32_t        MemSize;
	} Decomp;
	// Pattern decoding trace
	struct
	{
		uint32_t    Nr;
		uint32_t    Row;
		uint32_t    Channel;
	} Pattern;
	// Pattern decoding work info
	uint8_t*        pPattern;
	uint32_t        PatternLength;
	uint32_t        HighestChannel;
	uint32_t        RowZeroSpeed;
	uint8_t*        RowStart;
	uint8_t*        RowEnd;
	uint8_t*        ChannelStart;
	uint8_t*        ChannelEffStart;
	uint32_t        LoadFlags;
	_kernel_oserror Error;
	uint8_t         Row[2048];
};

typedef const _kernel_oserror* (*FNLoader)(SongHdr* pSong);

const _kernel_oserror* Decomp_ICE(SongHdr* pSong);
const _kernel_oserror* Decomp_PP20(SongHdr* pSong);
const _kernel_oserror* Decomp_S404(SongHdr* pSong);
const _kernel_oserror* Decomp_XPKF(SongHdr* pSong);

const _kernel_oserror* Loader_669(SongHdr* pSong);
const _kernel_oserror* Loader_AMF(SongHdr* pSong);
const _kernel_oserror* Loader_AON(SongHdr* pSong);
const _kernel_oserror* Loader_Asylum(SongHdr* pSong);
const _kernel_oserror* Loader_Coconizer(SongHdr* pSong);
const _kernel_oserror* Loader_DBM(SongHdr* pSong);
const _kernel_oserror* Loader_Digi(SongHdr* pSong);
const _kernel_oserror* Loader_DMF(SongHdr* pSong);
const _kernel_oserror* Loader_DSM(SongHdr* pSong);
const _kernel_oserror* Loader_DSMF(SongHdr* pSong);
const _kernel_oserror* Loader_DSym(SongHdr* pSong);
const _kernel_oserror* Loader_DskT(SongHdr* pSong);
const _kernel_oserror* Loader_DT(SongHdr* pSong);
const _kernel_oserror* Loader_FAR(SongHdr* pSong);
const _kernel_oserror* Loader_FC(SongHdr* pSong);
const _kernel_oserror* Loader_GT2(SongHdr* pSong);
const _kernel_oserror* Loader_GTK(SongHdr* pSong);
const _kernel_oserror* Loader_IT(SongHdr* pSong);
const _kernel_oserror* Loader_IMF(SongHdr* pSong);
const _kernel_oserror* Loader_Maestro(SongHdr* pSong);
const _kernel_oserror* Loader_MDL(SongHdr* pSong);
const _kernel_oserror* Loader_MED(SongHdr* pSong);
const _kernel_oserror* Loader_MMD(SongHdr* pSong);
const _kernel_oserror* Loader_MOD(SongHdr* pSong);
const _kernel_oserror* Loader_MT2(SongHdr* pSong);
const _kernel_oserror* Loader_MTM(SongHdr* pSong);
const _kernel_oserror* Loader_MTX(SongHdr* pSong);
const _kernel_oserror* Loader_MUSX(SongHdr* pSong);
const _kernel_oserror* Loader_Oktalyzer(SongHdr* pSong);
const _kernel_oserror* Loader_PSM(SongHdr* pSong);
const _kernel_oserror* Loader_PSM254(SongHdr* pSong);
const _kernel_oserror* Loader_PTM(SongHdr* pSong);
const _kernel_oserror* Loader_S3M(SongHdr* pSong);
const _kernel_oserror* Loader_STM(SongHdr* pSong);
const _kernel_oserror* Loader_ULT(SongHdr* pSong);
const _kernel_oserror* Loader_XM(SongHdr* pSong);

typedef struct
{
	uint32_t    Channel;
	uint32_t    Note;
	uint32_t    SFx[16];  // xyy     x: 0 none, 1 cutoff, 2 resonance
	uint32_t    Zxx[128]; // xyy     yy: 255 needs param, value otherwie
} LoaderChannelData;

void convert_effect_IT(SongHdr* pSong, const LoaderChannelData* pConfig, uint32_t effect, uint32_t value);
void convert_effect_MOD(SongHdr* pSong, uint32_t channel, uint32_t effect, uint32_t value, uint32_t note);
void convert_effect_XM(SongHdr* pSong, uint32_t channel, uint32_t effect, uint32_t value, uint32_t note);
uint32_t scan_period_MOD(uint32_t period);
const _kernel_oserror* Pattern_MOD(SongHdr* pSong, uint32_t i, Pattern* pPattern, const uint32_t* pPos);

uint32_t FileLoad_GetSize(SongHdr* song);
uint32_t FileLoad_GetPos(SongHdr* song);
const _kernel_oserror* FileLoad_SetPos(SongHdr* song, int pos);
const _kernel_oserror* FileLoad_Skip(SongHdr* song, uint32_t size);
const _kernel_oserror* FileLoad_Read(SongHdr* song, void* p, int length);
const _kernel_oserror* FileLoad_ReadInt(SongHdr* song, uint32_t* pval, int length);
const _kernel_oserror* FileLoad_ReadReverseInt(SongHdr* song, uint32_t* pval, int length);
const _kernel_oserror* FileLoad_ReadByte(SongHdr* song, uint32_t* pval);
const _kernel_oserror* FileLoad_ReadSample(SongHdr* song, Sample* pSample);
const _kernel_oserror* FileLoad_ReadString(SongHdr* pSong, uint8_t** pp, uint32_t length, bool bKeepAll);

const _kernel_oserror* Loaders_Alloc(SongHdr* pSong, void** p, int length);
const _kernel_oserror* Loaders_AllocString(SongHdr* pSong, void** p, int length);
const _kernel_oserror* Loaders_Resize(SongHdr* pSong, void** p, int oldsize, int delta);
const _kernel_oserror* Loaders_Free(SongHdr* pSong, void* p);
const _kernel_oserror* ConvertHex8(uint32_t value, char* p, uint32_t size);
const _kernel_oserror* lzwd_decode(SongHdr* pSong, uint8_t* buffer, uint32_t len, int maxbits, int min_code);

const _kernel_oserror* Loaders_InvalidSong(SongHdr* pSong, int32_t Offset, const void* pParam, uint32_t value);
#ifdef __CC_NORCROFT
#pragma -v1 // hint to the compiler to check f/s/printf format
#endif
const _kernel_oserror* Loaders_Error(SongHdr* song, int32_t Offset, const char* pformat, ...);
#ifdef __CC_NORCROFT
#pragma -v0 // return to default
#endif

const _kernel_oserror* Loaders_AllocSeq(SongHdr* song, SubSong* pSubSong);
const _kernel_oserror* Loaders_AllocMapTable(SongHdr* pSong, NoteMap** pptable);

const _kernel_oserror* Loaders_CheckPattern(SongHdr* pSong, Pattern* pPattern);
const _kernel_oserror* Loaders_CheckStartedPattern(SongHdr* pSong);
const _kernel_oserror* Loaders_PreparePatterns(SongHdr* song);
const _kernel_oserror* Loaders_EmptyPattern(SongHdr* song, Pattern* pPattern);
const _kernel_oserror* Loaders_StartPattern(SongHdr* song, uint32_t index);
const _kernel_oserror* Loaders_StartRow(SongHdr* song, uint32_t index);
const _kernel_oserror* Loaders_StartChannel(SongHdr* song, uint32_t channel, uint32_t note, uint32_t inst);
const _kernel_oserror* Loaders_EndChannel(SongHdr* song);
const _kernel_oserror* Loaders_EndRow(SongHdr* song);
const _kernel_oserror* Loaders_EndPattern(SongHdr* song, Pattern* pPattern);
const _kernel_oserror* Loaders_CompletePatterns(SongHdr* song);
const _kernel_oserror* Loaders_String(SongHdr* pSong, uint8_t** ppTo, const uint8_t* pFrom, uint32_t length, bool bKeepAll);
int Loaders_strncmp(const uint8_t* p1, const uint8_t* p2, uint32_t len);

uint32_t Effect_Tremor(uint32_t offtime, uint32_t ontime);
void Pattern_AddEffect_Arpeggio(SongHdr* song, uint32_t tone1, uint32_t tone2, uint32_t type);
void Pattern_AddEffect_RetrigCounter(SongHdr* song, uint32_t delay, uint32_t effect);
void Pattern_AddEffect_Instrument(SongHdr* song, uint32_t cmd, uint32_t value);
void Pattern_AddEffect_Pitch(SongHdr* song, uint32_t cmd, uint32_t value);
void Pattern_AddEffect_NoteVolume(SongHdr* song, uint32_t cmd, uint32_t value);
void Pattern_AddEffect_ChannelVolume(SongHdr* song, uint32_t cmd, uint32_t value);
void Pattern_AddEffect_Panning(SongHdr* song, uint32_t cmd, uint32_t value);

void Pattern_AddGlbEffect_Position(SongHdr* song, uint32_t cmd, uint32_t value);
void Pattern_AddGlbEffect_Frames(SongHdr* song, uint32_t cmd, uint32_t value);
void Pattern_KeepFirstGlbEffect_Frames(SongHdr* pSong, uint32_t cmd, uint32_t val);
void Pattern_AddGlbEffect_Volume(SongHdr* song, uint32_t cmd, uint32_t value);
void Pattern_AddGlbEffect_Tempo(SongHdr* song, uint32_t cmd, uint32_t value);

// Tables with 256 input values
const uint8_t* Table_ArcSampleLogToLin(void);
const uint8_t* Table_ArcVolumeLogToLin(void);
const uint8_t* Table_MUSXVolumeLogToLin(void);

#include "FTables.h"
#endif
