#ifndef MR4TH_WAVE_H
#define MR4TH_WAVE_H

////////////////////////////////
// RIFF Format: Types

MR4TH_SYMBOL_STATIC MR4TH_READ_ONLY U32 WAVE_RIFF_ID = AsciiID4('R', 'I', 'F', 'F');

typedef struct WAVE_RiffMasterChunkHeader{
    U32 riff_id;
    U32 size;
    U32 sub_id;
} WAVE_RiffMasterChunkHeader;

typedef struct WAVE_RiffSubChunkHeader{
    U32 id;
    U32 size;
} WAVE_RiffSubChunkHeader;

MR4TH_SYMBOL_STATIC MR4TH_READ_ONLY U64 wave_riff_chunk_align = 2;

////////////////////////////////
// WAVE Format: Types

enum{
    WAVE_ID_WAVE = AsciiID4('W', 'A', 'V', 'E'),
    WAVE_ID_fmt  = AsciiID4('f', 'm', 't', ' '),
    WAVE_ID_data = AsciiID4('d', 'a', 't', 'a'),
};

typedef U32 WAVE_SpeakerFlags;
enum{
    WAVE_SpeakerFlag_FRONT_LEFT            = (1 << 0),
    WAVE_SpeakerFlag_FRONT_RIGHT           = (1 << 1),
    WAVE_SpeakerFlag_FRONT_CENTER          = (1 << 2),
    WAVE_SpeakerFlag_LOW_FREQUENCY         = (1 << 3),
    WAVE_SpeakerFlag_BACK_LEFT             = (1 << 4),
    WAVE_SpeakerFlag_BACK_RIGHT            = (1 << 5),
    WAVE_SpeakerFlag_FRONT_LEFT_OF_CENTER  = (1 << 6),
    WAVE_SpeakerFlag_FRONT_RIGHT_OF_CENTER = (1 << 7),
    WAVE_SpeakerFlag_BACK_CENTER           = (1 << 8),
    WAVE_SpeakerFlag_SIDE_LEFT             = (1 << 9),
    WAVE_SpeakerFlag_SIDE_RIGHT            = (1 << 10),
    WAVE_SpeakerFlag_TOP_CENTER            = (1 << 11),
    WAVE_SpeakerFlag_TOP_FRONT_LEFT        = (1 << 12),
    WAVE_SpeakerFlag_TOP_FRONT_CENTER      = (1 << 13),
    WAVE_SpeakerFlag_TOP_FRONT_RIGHT       = (1 << 14),
    WAVE_SpeakerFlag_TOP_BACK_LEFT         = (1 << 15),
    WAVE_SpeakerFlag_TOP_BACK_CENTER       = (1 << 16),
    WAVE_SpeakerFlag_TOP_BACK_RIGHT        = (1 << 17),
};

// "fmt " sub chunk

typedef U16 WAVE_FormatTag;
enum{
    WAVE_FormatTag_PCM = 0x0001,
    WAVE_FormatTag_IEEE_FLOAT = 0x0003,
    WAVE_FormatTag_ALAW = 0x0006,
    WAVE_FormatTag_MULAW = 0x0007,
    WAVE_FormatTag_EXTENSIBLE = 0xFFFE,
};

typedef struct WAVE_ChunkFmt{
    WAVE_FormatTag format_tag;
    U16 channel_count;
    U32 samples_per_second;
    U32 bytes_per_second;
    U16 bytes_per_sample;
    U16 bits_per_value;
} WAVE_ChunkFmt;

typedef struct WAVE_ChunkFmtExtSize{
    U16 extension_size;
} WAVE_ChunkFmtExtSize;

#pragma pack(push, 1)
typedef struct WAVE_ChunkFmtExt1{
    U16 valid_bits_per_value;
    WAVE_SpeakerFlags channel_mask;
    U8  sub_format[16];
} WAVE_ChunkFmtExt1;
#pragma pack(pop)

////////////////////////////////
// WAVE Parser: Types

typedef struct WAVE_SubChunkNode{
    struct WAVE_SubChunkNode *next;
    U32 id;
    U32 size;
    U64 off;
} WAVE_SubChunkNode;

typedef struct WAVE_SubChunkList{
    WAVE_SubChunkNode *first;
    WAVE_SubChunkNode *last;
    U64 count;
} WAVE_SubChunkList;

typedef struct WAVE_FormatData{
    WAVE_FormatTag format_tag;
    U32 channel_count;
    U32 bytes_per_sample;
    U32 samples_per_second;
    U32 byte_stride_per_value;
    U32 bits_per_value;
    U32 channel_mask;
    U8  sub_format[16];
} WAVE_FormatData;

////////////////////////////////
// WAVE Render: Types

typedef struct WAVE_RenderParams{
    SOUND_ValueKind kind;
    U32 channel_count;
    U16 samples_per_second;
} WAVE_RenderParams;

////////////////////////////////
// WAVE Parser: Functions

// low level wave format

MR4TH_SYMBOL_STATIC WAVE_SubChunkList  wave_sub_chunks_from_data(Arena *arena, String8 data);
MR4TH_SYMBOL_STATIC WAVE_SubChunkNode* wave_chunk_from_id(WAVE_SubChunkList *list, U32 id);
MR4TH_SYMBOL_STATIC WAVE_FormatData    wave_format_data_from_fmt_chunk(WAVE_SubChunkNode *node, String8 data);

// high level representation

MR4TH_SYMBOL_STATIC SOUND_Data* wave_sound_data(Arena *arena, String8 data);

////////////////////////////////
// WAVE Render: Functions

MR4TH_SYMBOL_STATIC String8 wave_render(Arena *arena, WAVE_RenderParams *params,
                                        void *sample_data, U64 size);

////////////////////////////////
// WAVE Debug: Functions

MR4TH_SYMBOL_STATIC void wave_dump(Arena *arena, String8List *out, String8 data);


#endif //MR4TH_WAVE_H
