#ifndef _Song_h
#define _Song_h

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

#define song_max_patterns       256
#define song_max_instruments    256
#define song_max_samples        256
#define song_max_channels        64
#define song_max_rows           512

#define song_compat_mod_vblank        0x00000001 // MOD, F is always speed
#define song_compat_mod_no_instr_swap 0x00000002 // MOD, Inst no note swaps inst
#define song_compat_mod_ultimate      0x00000004 // MOD, Ultimate STK
#define song_compat_override_cfg      0x00000008 // See SongLoad2
#define song_compat_usescalevolume    0x00000010 // See SongLoad2

#define Panning_Surround    0x180
#define Note_Min              1
#define Note_Central         64
#define Note_Max            135
#define Note_Reset          136
#define Note_Cut            255
#define Note_Off            254
#define Note_OffXM          253
#define Note_Fade           252
#define Note_CutVolume      251
#define Note_CmdMin         251

typedef enum
{ Tempo_Base_2d5Hz = 0 // MOD Tempo, x/2.5 frames per second
, Tempo_Base_20Hz  = 1 // DSym Tempo, x/20 frames per second
, Tempo_Base_4Hz   = 2 // DMF Tempo, x/4 frames per second
} Tempo_Base;

struct ChannelDefault
{
	uint32_t    Volume;  // Default channel volume [0-256]
	uint32_t    Panning; // Default panning [0-256,+ surround]
	uint32_t    Mute;    // 1 if channel is muted, 0 otherwise
};

struct Pattern
{
	uint32_t    Rows; // Number of rows in pattern [1-song_max_rows]
	uint8_t*    Ptr;  // Encoded pattern data (see Design/txt)
	uint32_t    Size; // Size of encoded pattern data in bytes
};

struct SubSong
{
	SubSong*        pNextSubSong;  // Link to next sub-song
	uint32_t        RestartPos;    // Position in sequence to loop back
	uint32_t        SeqLen;        // Number of elements in order/sequence
	int32_t*        pSeqs;         // List of pattern numbers in sequence
	uint32_t*       pTimeIndexes;  // List of start time indexes in 1/250 ms
	                               // for each position in sequence
	uint32_t*       pSecIndexes;   // List of section numbers for sequence
	uint32_t*       pSecTempos;    // List of tempo/speeds for sequence
	struct
	{
		uint32_t        Volume;    // Default volume [0-256]
		uint32_t        Tempo;     // Default tempo [MinTempo, MaxTempo]
		uint32_t        Speed;     // Default speed [MinSpeed, MaxSpeed]
		uint8_t         VibratoType;    // Default pitch vibrato type
		uint8_t         VibratoSpeed;   // Default pitch vibrato speed
		uint8_t         VibratoStrength;// Default pitch vibrato multiplier
		uint8_t         TremoloType;    // Default volume vibrato type
		uint8_t         TremoloSpeed;   // Default volume vibrato speed
		uint8_t         TremoloStrength;// Default volume vibrato multiplier
		uint8_t         PanbrelloType;  // Default panning vibrato type
		uint8_t         PanbrelloSpeed; // Default panning vibrato speed
		uint8_t         PanbrelloStrength;// Default panning vibrato multiplier
		bool            TremorOn;       // Initial tremor on/off setting
		uint8_t         Dummy;
		uint8_t         Dummy2;
		ChannelDefault  ChDef[song_max_channels];
	} Defaults;
};

// Note: string pointers maybe NULL, strings are always 0 terminated.
struct SongHdr
{
	GlobHdr*        pGlb;          // Global data (config, etc.)
	LoaderData*     pLoaderData;   // Data used by loader functions
	uint32_t        Flags;         // See Song_Flags enum
 	uint32_t        Compatibility; // Compatibility flags passed by the user
	uint8_t*        pFilename;     // String, filename used to load the song
	uint8_t*        pName;         // String, name of the song
	uint8_t*        pAuthor;       // String, author of the song
	uint8_t*        pFullType;     // String, Type + format version + livf tags
	const uint8_t*  pType;         // String, constant type returned by loader
	uint32_t        CommentsLen;   // Length of comments
	uint8_t*        pComments;     // String, comments, uses carriage returns
	uint32_t        Channels;      // Number of channels
	uint32_t        Sections;      // Number of sections in sequence
	uint32_t        Patterns;      // Number of patterns in song
	Pattern*        pPatterns;     // List of pattern definitions
	uint32_t        Instruments;   // Number of instruments in song
	Instrument*     pInstruments;  // List of instruments definitions
	uint32_t        Samples;       // Number of samples in song
	Sample*         pSamples;      // List of insamples definitions
	Sample*         pSampleDef;    // Set behaviour of samples nr > Samples
	Sample*         pSampleNoMap;  // Set behaviour of sample 0 in inst. map
	int32_t         VolumeShift;   // Shift to apply to replay volume
	uint32_t        TempoBase;     // Id of tempo base, See Tempo_Base enum
	uint32_t        MinTempo;      // Min value of tempo, ex. 32 for MOD
	uint32_t        MaxTempo;      // Max value of tempo, ex. 255 for MOD
	uint32_t        MinSpeed;      // Min value of speed, ex. 1 for MOD
	uint32_t        MaxSpeed;      // Max value of speed, ex. 31 for MOD
	uint8_t         MinPitch;      // Min value of pitch, a note number or 0
	uint8_t         MaxPitch;      // Max value of pitch, a note number or 0
	uint16_t        Version;       // Format version (! <> tracker version)
	uint32_t        MaxNotesPerChannel;// Max virtual notes per channel
	const uint8_t*  VolumeTranslation; // NULL or 256 bytes translation table
	SubSong         BaseSong;      // First sub-song
	_kernel_oserror LastError;     // Last error that occured
};

typedef enum
{
	  Song_Flag_Linear              = 0x00000001 // pitch slide in semitone frac
	, Song_Flag_Instruments         = 0x00000002 // pattern instrument number
	                                             // is instr. nr not sample nr.
	, Song_Flag_Virtual             = 0x00000004 // Info, uses virtual channels
	, Song_Flag_LinkSlideAndPorta   = 0x00000008 // Slide & porta share memory
	, Song_Flag_Corrupted           = 0x00000010 // Info, loading problems
	, Song_Flag_ITEnvelopes         = 0x00000020 // IT: [0, pos]
	                                             // XM: [0. pos -1 ]
	                                             // pos is pos of last point
	, Song_Flag_UnsupportedEffects  = 0x00000040 // Info, uses unkown effects
	, Song_Flag_Filters             = 0x00000080 // Info, uses IT filters
	, Song_Flag_PitchAsFraction     = 0x00000100 // pitch slide is frac of freq.
	, Song_Flag_RepeatRowDo0Frame   = 0x00000200 // Do frame 0 note/effect in repeats
	, Song_Flag_RepeatRowNotN0Frames= 0x00000400 // Ignore non-0 frames in repeats
	, Song_Flag_ResetsLoopsOnPatternChange
	                                = 0x00000800 // on pattern change loops must be reset
	, Song_Flag_VisibleFlags        = 0x00000fff
	// Internal info
	, Song_Flag_MoveLoopAfterLoop   = 0x00100000 // Move channel loop start
	                                             // after loop end
	                                             // when loop is completed
	, Song_Flag_CutOnHighPitch      = 0x00200000 // Cut note if >= MaxPitch
	, Song_Flag_NewNoteOnPortamento = 0x00400000 // If portamento but no note
	                                             // trigger note
	, Song_Flag_InstNoNote_Swap     = 0x00800000 // If new instr. number given
	                                             // swap sample of playing note
	, Song_Flag_InstNoNote_Ignore   = 0x01000000 // If new instr. number given
	                                             // no effect on playing note
	, Song_Flag_InstNoNote_Playing  = 0x02000000 // If new instr. number given
	                                             // reset with curr inst
	, Song_Flag_XMFadeout           = 0x04000000 // Fade without cut
	, Song_Flag_KeyoffLosesPrevNote = 0x08000000 // Key off, etc in note column
	                                             // loses memory of prev. note
	, Song_Flag_LimitTremorToRow    = 0x10000000 // Tremor, on new row, clear
	                                             // ch_flag_zero_volume so that
	                                             // rows without tremor effect
	                                             // are not affected
	, Song_Flag_SysLogged_Filename  = (~0x7fffffff)
} Song_Flags;

SubSong* Song_GetSubSong(SongHdr* pSong, uint32_t index);
const _kernel_oserror* Song_CopySubSong(SongHdr* pSong, SubSong** ppNew, const SubSong* pOld);

#endif
