/***************************************************************************

	sound.c

	PSP Sound thread functions.

***************************************************************************/

#include "ncdz.h"

#define SOUND_SAMPLES		PSP_AUDIO_SAMPLE_ALIGN(1024)
#define SOUND_BUFFER_SIZE	(SOUND_SAMPLES * 2)


/***************************************************************************
	Private variables
 **************************************************************************/

static volatile int sound_active;
static int sound_handle;
static SceUID sound_thread;
static int sound_volume;
static int sound_enabled;
static s16 sound_buffer[2][SOUND_BUFFER_SIZE];
static void (*sound_callback)(s16 *buffer, int length);


/***************************************************************************
	Function prototypes
 **************************************************************************/

static void default_sound_callback(s16 *buffer, int length);


/*--------------------------------------------------------
	Sound thread
 -------------------------------------------------------*/

static int SoundThread(SceSize args, void *argp)
{
	int flip = 0;

	while (sound_active)
	{
		if (bSleep)
		{
			do
			{
				sceKernelDelayThread(5000000);
			} while (bSleep);
		}

		if (sound_enabled)
		{
			sound_callback(sound_buffer[flip], SOUND_SAMPLES);
			sceAudioOutputPannedBlocking(sound_handle, sound_volume, sound_volume, (char *)sound_buffer[flip]);
		}
		else
		{
			memset(sound_buffer[flip], 0, SOUND_BUFFER_SIZE);
			sceAudioOutputPannedBlocking(sound_handle, 0, 0, (char *)sound_buffer[flip]);
		}
		flip ^= 1;
	}
	return 0;
}


/*--------------------------------------------------------
	Initialize sound
 -------------------------------------------------------*/

void sound_init(void)
{
	sound_active = 0;
	sound_thread = -1;
	sound_handle = -1;
	sound_volume = 0;
	sound_enabled = 0;

	sound_callback = default_sound_callback;
}


/*--------------------------------------------------------
	Shutdown sound
 -------------------------------------------------------*/

void sound_exit(void)
{
	sound_thread_stop();
}


/*--------------------------------------------------------
	Shutdown sound
 -------------------------------------------------------*/

void sound_set_callback(void (*callback)(s16 *buffer, int length))
{
	sound_callback = callback;
}


/*--------------------------------------------------------
	Enable / Disable sound
 -------------------------------------------------------*/

void sound_enable(int enable)
{
	sound_enabled = enable;

	if (sound_enabled)
		sound_set_volume();
	else
		sound_volume = 0;
}


/*--------------------------------------------------------
	Set sound volume
 -------------------------------------------------------*/

void sound_set_volume(void)
{
	sound_volume = PSP_AUDIO_VOLUME_MAX * (neogeo_sound_volume * 10) / 100;
}


/*--------------------------------------------------------
	Start sound thread
 -------------------------------------------------------*/

int sound_thread_start(void)
{
	sound_active = 0;
	sound_thread = -1;
	sound_handle = -1;

	sound_set_volume();

	memset(sound_buffer[0], 0, SOUND_BUFFER_SIZE);
	memset(sound_buffer[1], 0, SOUND_BUFFER_SIZE);

	sound_handle = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, SOUND_SAMPLES, PSP_AUDIO_FORMAT_STEREO);
	if (sound_handle < 0)
	{
#if JAPANESE_UI
		ui_popup("サウンド再生用オーディオチャネルを確保できません。");
#else
		ui_popup("Could not reserve audio channel for sound.");
#endif
		fatal_error = 1;
		return 0;
	}

	sound_active = 1;

	sound_thread = sceKernelCreateThread("Sound thread", SoundThread, 0x8, 0x10000, 0, NULL);
	if (sound_thread < 0)
	{
#if JAPANESE_UI
		ui_popup("サウンドスレッドを開始できません。");
#else
		ui_popup("Could not start sound thread.");
#endif
		fatal_error = 1;
		sceAudioChRelease(sound_handle);
		sound_handle = -1;
		return 0;
	}

	sceKernelStartThread(sound_thread, 0, 0);

	return 1;
}


/*--------------------------------------------------------
	Stop sound thread
 -------------------------------------------------------*/

void sound_thread_stop(void)
{
	if (sound_thread >= 0)
	{
		sound_active = 0;
		sceKernelWaitThreadEnd(sound_thread, NULL);

		sceKernelDeleteThread(sound_thread);
		sound_thread = -1;

		sceAudioChRelease(sound_handle);
		sound_handle = -1;
	}
}


/*--------------------------------------------------------
	Default sound callback
 -------------------------------------------------------*/

static void default_sound_callback(s16 *buffer, int length)
{
	memset(buffer, 0, length << 1);
}
