// Copyright (c) 2023 Alex Diener. All rights reserved.

#include "audioplayer/MusicAudioStream.h"
#include "audiosynth/MusicSequence.h"
#include "binaryserialization/BinaryDeserializationContext.h"
#include "PROJECT_NAME/Globals.h"
#include "PROJECT_NAME/Music.h"
#include "PROJECT_NAME/SharedDefinitions.h"

#define MUSIC_FADE_OUT_DURATION 0.5
#define MUSIC_CROSSFADE_DURATION 0.25
#define MUSIC_FADE_IN_DURATION 0.5
#define MUSIC_PAUSE_FADE_OUT_DURATION 0.0625
#define MUSIC_PAUSE_FADE_IN_DURATION 0.0625

static struct {
	const void * embedData;
	unsigned int embedSize;
} embeddedMusic[MUSIC_COUNT];

void initMusic(void) {
	#define DEFINE_MUSIC(music_id, embed_suffix, load_priority, category) { \
		extern const char EMBEDDATA_##embed_suffix[]; \
		extern unsigned int EMBEDSIZE_##embed_suffix; \
		embeddedMusic[music_id].embedData = EMBEDDATA_##embed_suffix; \
		embeddedMusic[music_id].embedSize = EMBEDSIZE_##embed_suffix; \
		AudioManager_registerMusic(music_id, category, load_priority); \
	}
	#include "PROJECT_NAME/Music_list.h"
	#undef DEFINE_MUSIC
}

PCMAudio * loadMusic(MusicID musicID, AudioFrameIndex * outLoopDuration) {
	BinaryDeserializationContext * deserializationContext;
	deserializationContext = BinaryDeserializationContext_createWithBytes(embeddedMusic[musicID].embedData, embeddedMusic[musicID].embedSize);
	MusicSequence * musicSequence = MusicSequence_deserialize(deserializationContext);
	BinaryDeserializationContext_dispose(deserializationContext);
	double loopDuration = MusicSequence_getLoopDuration(musicSequence);
	AudioSequence * audioSequence = MusicSequence_createAudioSequence(musicSequence);
	MusicSequence_dispose(musicSequence);
	PCMAudio * audio = AudioSequence_composite(audioSequence, 2, 1, g_audioSampleRate, 1.0f, true);
	AudioSequence_dispose(audioSequence);
	*outLoopDuration = loopDuration * g_audioSampleRate;
	return audio;
}

void playMusic(MusicID musicID, bool resume) {
	AudioManager_playMusic(musicID, 0, true, resume, true, MUSIC_FADE_OUT_DURATION, MUSIC_CROSSFADE_DURATION, MUSIC_FADE_IN_DURATION);
}

void pauseMusic(void) {
	AudioManager_pauseMusic(0, MUSIC_PAUSE_FADE_OUT_DURATION);
}

void unpauseMusic(void) {
	AudioManager_unpauseMusic(0, MUSIC_PAUSE_FADE_IN_DURATION);
}

void stopMusic(void) {
	AudioManager_stopMusic(0, MUSIC_FADE_OUT_DURATION);
}
