1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/* Allow access to a raw mixing buffer */
25#include <nds.h>
26#include "SDL.h"
27#include "SDL_endian.h"
28#include "SDL_timer.h"
29#include "SDL_audio.h"
30#include "../SDL_audiomem.h"
31#include "../SDL_audio_c.h"
32#include "SDL_ndsaudio.h"
33#include "soundcommon.h"
34
35
36/* Audio driver functions */
37static int NDS_OpenAudio(_THIS, SDL_AudioSpec *spec);
38static void NDS_WaitAudio(_THIS);
39static void NDS_PlayAudio(_THIS);
40static Uint8 *NDS_GetAudioBuf(_THIS);
41static void NDS_CloseAudio(_THIS);
42
43/* Audio driver bootstrap functions */
44
45u32 framecounter = 0,soundoffset = 0;
46static SDL_AudioDevice *sdl_nds_audiodevice;
47
48//void SoundMixCallback(void *stream,u32 size)
49//{
50//	//printf("SoundMixCallback\n");
51//
52//	Uint8 *buffer;
53//
54// 	buffer = sdl_nds_audiodevice->hidden->mixbuf;
55//	memset(buffer, sdl_nds_audiodevice->spec.silence, size);
56//
57//	if (!sdl_nds_audiodevice->paused){
58//
59//
60//	//if (sdl_nds_audiodevice->convert.needed) {
61//	//	int silence;
62//
63//	//	if (sdl_nds_audiodevice->convert.src_format == AUDIO_U8 ) {
64//	//		silence = 0x80;
65//	//	} else {
66//	//		silence =  0;
67//	//	}
68//	//	memset(sdl_nds_audiodevice->convert.buf, silence, sdl_nds_audiodevice->convert.len);
69//	//	sdl_nds_audiodevice->spec.callback(sdl_nds_audiodevice->spec.userdata,
70//	//		(Uint8 *)sdl_nds_audiodevice->convert.buf,sdl_nds_audiodevice->convert.len);
71//	//	SDL_ConvertAudio(&sdl_nds_audiodevice->convert);
72//	//	memcpy(buffer, sdl_nds_audiodevice->convert.buf, sdl_nds_audiodevice->convert.len_cvt);
73//	//} else
74//	{
75//		sdl_nds_audiodevice->spec.callback(sdl_nds_audiodevice->spec.userdata, buffer, size);
76//		//memcpy((Sint16 *)stream,buffer, size);
77//	}
78//
79//	}
80//
81//	if(soundsystem->format == 8)
82//	{
83//		int i;
84//		s32 *buffer32 = (s32 *)buffer;
85//		s32 *stream32 = (s32 *)stream;
86//		for(i=0;i<size/4;i++){ *stream32++ = buffer32[i] ^ 0x80808080;}
87//		//for(i = 0; i < size; i++)
88//		//	((s8*)stream)[i]=(buffer[i]^0x80);
89//	}
90//	else
91//	{
92//		int i;
93//		for(i = 0; i < size; i++){
94//			//((short*)stream)[i] =(short)buffer[i] << 8;				// sound 8bit ---> buffer 16bit
95//			//if (buffer[i] &0x80)
96//				//((Sint16*)stream)[i] = 0xff00 | buffer[i];
97//			((Sint16*)stream)[i] = (buffer[i] - 128) << 8;
98//
99//			//else
100//			//	((Sint16*)stream)[i] = buffer[i];
101//		}
102//		//register signed char *pSrc =buffer;
103//		//register short *pDest =stream;
104//		//int x;
105//		//			for (x=size; x>0; x--)
106//		//			{
107//		//				register short temp = (((short)*pSrc)-128)<<8;
108//		//				pSrc++;
109//		//				*pDest++ = temp;
110//		//			}
111//
112//		//memcpy((Sint16 *)stream,buffer, size);
113//	}
114//}
115
116void SoundMixCallback(void *stream,u32 len)
117{
118	SDL_AudioDevice *audio = (SDL_AudioDevice *)sdl_nds_audiodevice;
119
120	/* Silence the buffer, since it's ours */
121	SDL_memset(stream, audio->spec.silence, len);
122
123	/* Only do soemthing if audio is enabled */
124	if ( ! audio->enabled )
125		return;
126
127	if ( ! audio->paused ) {
128		if ( audio->convert.needed ) {
129			//fprintf(stderr,"converting audio\n");
130			SDL_mutexP(audio->mixer_lock);
131			(*audio->spec.callback)(audio->spec.userdata,
132				(Uint8 *)audio->convert.buf,audio->convert.len);
133			SDL_mutexV(audio->mixer_lock);
134			SDL_ConvertAudio(&audio->convert);
135			SDL_memcpy(stream,audio->convert.buf,audio->convert.len_cvt);
136		} else {
137			SDL_mutexP(audio->mixer_lock);
138			(*audio->spec.callback)(audio->spec.userdata,
139						(Uint8 *)stream, len);
140			SDL_mutexV(audio->mixer_lock);
141		}
142	}
143	return;
144}
145void MixSound(void)
146{
147	int remain;
148
149	if(soundsystem->format == 8)
150	{
151		if((soundsystem->soundcursor + soundsystem->numsamples) > soundsystem->buffersize)
152		{
153			SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor],soundsystem->buffersize - soundsystem->soundcursor);
154			remain = soundsystem->numsamples - (soundsystem->buffersize - soundsystem->soundcursor);
155			SoundMixCallback(soundsystem->mixbuffer,remain);
156		}
157		else
158		{
159			SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor],soundsystem->numsamples);
160		}
161	}
162	else
163	{
164		if((soundsystem->soundcursor + soundsystem->numsamples) > (soundsystem->buffersize >> 1))
165		{
166			SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor << 1],(soundsystem->buffersize >> 1) - soundsystem->soundcursor);
167			remain = soundsystem->numsamples - ((soundsystem->buffersize >> 1) - soundsystem->soundcursor);
168			SoundMixCallback(soundsystem->mixbuffer,remain);
169		}
170		else
171		{
172			SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor << 1],soundsystem->numsamples);
173		}
174	}
175}
176
177void InterruptHandler(void)
178{
179	framecounter++;
180}
181void FiFoHandler(void)
182{
183	u32 command;
184	while ( !(REG_IPC_FIFO_CR & (IPC_FIFO_RECV_EMPTY)) )
185	{
186		command = REG_IPC_FIFO_RX;
187
188		switch(command)
189		{
190		case FIFO_NONE:
191			break;
192		case UPDATEON_ARM9:
193			REG_IME = 0;
194			MixSound();
195			REG_IME = 1;
196			SendCommandToArm7(MIXCOMPLETE_ONARM9);
197			break;
198		}
199	}
200}
201
202
203
204
205
206static int Audio_Available(void)
207{
208	return(1);
209}
210
211static void Audio_DeleteDevice(SDL_AudioDevice *device)
212{
213}
214
215static SDL_AudioDevice *Audio_CreateDevice(int devindex)
216{
217
218	SDL_AudioDevice *this;
219
220	/* Initialize all variables that we clean on shutdown */
221	this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
222	if ( this ) {
223		SDL_memset(this, 0, (sizeof *this));
224		this->hidden = (struct SDL_PrivateAudioData *)
225				SDL_malloc((sizeof *this->hidden));
226	}
227	if ( (this == NULL) || (this->hidden == NULL) ) {
228		SDL_OutOfMemory();
229		if ( this ) {
230			SDL_free(this);
231		}
232		return(0);
233	}
234	SDL_memset(this->hidden, 0, (sizeof *this->hidden));
235
236	/* Set the function pointers */
237	this->OpenAudio = NDS_OpenAudio;
238	this->WaitAudio = NDS_WaitAudio;
239	this->PlayAudio = NDS_PlayAudio;
240	this->GetAudioBuf = NDS_GetAudioBuf;
241	this->CloseAudio = NDS_CloseAudio;
242
243	this->free = Audio_DeleteDevice;
244//fprintf(stderr,"Audio_CreateDevice\n");
245	return this;
246}
247
248AudioBootStrap NDSAUD_bootstrap = {
249	"nds", "NDS audio",
250	Audio_Available, Audio_CreateDevice
251};
252
253
254void static NDS_WaitAudio(_THIS)
255{
256	//printf("NDS_WaitAudio\n");
257}
258
259static void NDS_PlayAudio(_THIS)
260{
261	//printf("playing audio\n");
262	if (this->paused)
263		return;
264
265}
266
267static Uint8 *NDS_GetAudioBuf(_THIS)
268{
269	return NULL;//(this->hidden->mixbuf);
270}
271
272static void NDS_CloseAudio(_THIS)
273{
274/*	if ( this->hidden->mixbuf != NULL ) {
275		SDL_FreeAudioMem(this->hidden->mixbuf);
276		this->hidden->mixbuf = NULL;
277	}*/
278}
279
280static int NDS_OpenAudio(_THIS, SDL_AudioSpec *spec)
281{
282	//printf("NDS_OpenAudio\n");
283	int format = 0;
284	//switch(spec->format&0xff) {
285	//case  8: spec->format = AUDIO_S8;format=8; break;
286	//case 16: spec->format = AUDIO_S16LSB;format=16; break;
287	//default:
288	//	SDL_SetError("Unsupported audio format");
289	//	return(-1);
290	//}
291	switch (spec->format&~0x1000) {
292		case AUDIO_S8:
293			/* Signed 8-bit audio supported */
294			format=8;
295			break;
296		case AUDIO_U8:
297			spec->format ^= 0x80;format=8;
298			break;
299		case AUDIO_U16:
300			/* Unsigned 16-bit audio unsupported, convert to S16 */
301			spec->format ^=0x8000;format=16;
302		case AUDIO_S16:
303			/* Signed 16-bit audio supported */
304			format=16;
305			break;
306	}
307	/* Update the fragment size as size in bytes */
308	SDL_CalculateAudioSpec(spec);
309
310	/* Allocate mixing buffer */
311	//this->hidden->mixlen = spec->size;
312	//this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
313	//if ( this->hidden->mixbuf == NULL ) {
314	//	SDL_SetError("Out of Memory");
315	//	return(-1);
316	//}
317
318	SDL_NDSAudio_mutex = 0;
319	sdl_nds_audiodevice=this;
320
321	irqInit();
322	irqSet(IRQ_VBLANK,&InterruptHandler);
323	irqSet(IRQ_FIFO_NOT_EMPTY,&FiFoHandler);
324	irqEnable(IRQ_FIFO_NOT_EMPTY);
325
326	REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR | IPC_FIFO_RECV_IRQ;
327
328
329
330	SoundSystemInit(spec->freq,spec->size,0,format);
331	SoundStartMixer();
332
333
334	return(1);
335}
336