symbian-qemu-0.9.1-12/libsdl-trunk/src/audio/windib/SDL_dibaudio.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2     SDL - Simple DirectMedia Layer
       
     3     Copyright (C) 1997-2006 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 
       
    26 #define WIN32_LEAN_AND_MEAN
       
    27 #include <windows.h>
       
    28 #include <mmsystem.h>
       
    29 
       
    30 #include "SDL_timer.h"
       
    31 #include "SDL_audio.h"
       
    32 #include "../SDL_audio_c.h"
       
    33 #include "SDL_dibaudio.h"
       
    34 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
       
    35 #include "win_ce_semaphore.h"
       
    36 #endif
       
    37 
       
    38 
       
    39 /* Audio driver functions */
       
    40 static int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec);
       
    41 static void DIB_ThreadInit(_THIS);
       
    42 static void DIB_WaitAudio(_THIS);
       
    43 static Uint8 *DIB_GetAudioBuf(_THIS);
       
    44 static void DIB_PlayAudio(_THIS);
       
    45 static void DIB_WaitDone(_THIS);
       
    46 static void DIB_CloseAudio(_THIS);
       
    47 
       
    48 /* Audio driver bootstrap functions */
       
    49 
       
    50 static int Audio_Available(void)
       
    51 {
       
    52 	return(1);
       
    53 }
       
    54 
       
    55 static void Audio_DeleteDevice(SDL_AudioDevice *device)
       
    56 {
       
    57 	SDL_free(device->hidden);
       
    58 	SDL_free(device);
       
    59 }
       
    60 
       
    61 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
       
    62 {
       
    63 	SDL_AudioDevice *this;
       
    64 
       
    65 	/* Initialize all variables that we clean on shutdown */
       
    66 	this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
       
    67 	if ( this ) {
       
    68 		SDL_memset(this, 0, (sizeof *this));
       
    69 		this->hidden = (struct SDL_PrivateAudioData *)
       
    70 				SDL_malloc((sizeof *this->hidden));
       
    71 	}
       
    72 	if ( (this == NULL) || (this->hidden == NULL) ) {
       
    73 		SDL_OutOfMemory();
       
    74 		if ( this ) {
       
    75 			SDL_free(this);
       
    76 		}
       
    77 		return(0);
       
    78 	}
       
    79 	SDL_memset(this->hidden, 0, (sizeof *this->hidden));
       
    80 
       
    81 	/* Set the function pointers */
       
    82 	this->OpenAudio = DIB_OpenAudio;
       
    83 	this->ThreadInit = DIB_ThreadInit;
       
    84 	this->WaitAudio = DIB_WaitAudio;
       
    85 	this->PlayAudio = DIB_PlayAudio;
       
    86 	this->GetAudioBuf = DIB_GetAudioBuf;
       
    87 	this->WaitDone = DIB_WaitDone;
       
    88 	this->CloseAudio = DIB_CloseAudio;
       
    89 
       
    90 	this->free = Audio_DeleteDevice;
       
    91 
       
    92 	return this;
       
    93 }
       
    94 
       
    95 AudioBootStrap WAVEOUT_bootstrap = {
       
    96 	"waveout", "Win95/98/NT/2000 WaveOut",
       
    97 	Audio_Available, Audio_CreateDevice
       
    98 };
       
    99 
       
   100 
       
   101 /* The Win32 callback for filling the WAVE device */
       
   102 static void CALLBACK FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
       
   103 						DWORD dwParam1, DWORD dwParam2)
       
   104 {
       
   105 	SDL_AudioDevice *this = (SDL_AudioDevice *)dwInstance;
       
   106 
       
   107 	/* Only service "buffer done playing" messages */
       
   108 	if ( uMsg != WOM_DONE )
       
   109 		return;
       
   110 
       
   111 	/* Signal that we are done playing a buffer */
       
   112 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
       
   113 	ReleaseSemaphoreCE(audio_sem, 1, NULL);
       
   114 #else
       
   115 	ReleaseSemaphore(audio_sem, 1, NULL);
       
   116 #endif
       
   117 }
       
   118 
       
   119 static void SetMMerror(char *function, MMRESULT code)
       
   120 {
       
   121 	size_t len;
       
   122 	char errbuf[MAXERRORLENGTH];
       
   123 #ifdef _WIN32_WCE
       
   124 	wchar_t werrbuf[MAXERRORLENGTH];
       
   125 #endif
       
   126 
       
   127 	SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
       
   128 	len = SDL_strlen(errbuf);
       
   129 
       
   130 #ifdef _WIN32_WCE
       
   131 	/* UNICODE version */
       
   132 	waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH-len);
       
   133 	WideCharToMultiByte(CP_ACP,0,werrbuf,-1,errbuf+len,MAXERRORLENGTH-len,NULL,NULL);
       
   134 #else
       
   135 	waveOutGetErrorText(code, errbuf+len, (UINT)(MAXERRORLENGTH-len));
       
   136 #endif
       
   137 
       
   138 	SDL_SetError("%s",errbuf);
       
   139 }
       
   140 
       
   141 /* Set high priority for the audio thread */
       
   142 static void DIB_ThreadInit(_THIS)
       
   143 {
       
   144 	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
       
   145 }
       
   146 
       
   147 void DIB_WaitAudio(_THIS)
       
   148 {
       
   149 	/* Wait for an audio chunk to finish */
       
   150 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
       
   151 	WaitForSemaphoreCE(audio_sem, INFINITE);
       
   152 #else
       
   153 	WaitForSingleObject(audio_sem, INFINITE);
       
   154 #endif
       
   155 }
       
   156 
       
   157 Uint8 *DIB_GetAudioBuf(_THIS)
       
   158 {
       
   159         Uint8 *retval;
       
   160 
       
   161 	retval = (Uint8 *)(wavebuf[next_buffer].lpData);
       
   162 	return retval;
       
   163 }
       
   164 
       
   165 void DIB_PlayAudio(_THIS)
       
   166 {
       
   167 	/* Queue it up */
       
   168 	waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0]));
       
   169 	next_buffer = (next_buffer+1)%NUM_BUFFERS;
       
   170 }
       
   171 
       
   172 void DIB_WaitDone(_THIS)
       
   173 {
       
   174 	int i, left;
       
   175 
       
   176 	do {
       
   177 		left = NUM_BUFFERS;
       
   178 		for ( i=0; i<NUM_BUFFERS; ++i ) {
       
   179 			if ( wavebuf[i].dwFlags & WHDR_DONE ) {
       
   180 				--left;
       
   181 			}
       
   182 		}
       
   183 		if ( left > 0 ) {
       
   184 			SDL_Delay(100);
       
   185 		}
       
   186 	} while ( left > 0 );
       
   187 }
       
   188 
       
   189 void DIB_CloseAudio(_THIS)
       
   190 {
       
   191 	int i;
       
   192 
       
   193 	/* Close up audio */
       
   194 	if ( audio_sem ) {
       
   195 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
       
   196 		CloseSynchHandle(audio_sem);
       
   197 #else
       
   198 		CloseHandle(audio_sem);
       
   199 #endif
       
   200 	}
       
   201 	if ( sound ) {
       
   202 		waveOutClose(sound);
       
   203 	}
       
   204 
       
   205 	/* Clean up mixing buffers */
       
   206 	for ( i=0; i<NUM_BUFFERS; ++i ) {
       
   207 		if ( wavebuf[i].dwUser != 0xFFFF ) {
       
   208 			waveOutUnprepareHeader(sound, &wavebuf[i],
       
   209 						sizeof(wavebuf[i]));
       
   210 			wavebuf[i].dwUser = 0xFFFF;
       
   211 		}
       
   212 	}
       
   213 	/* Free raw mixing buffer */
       
   214 	if ( mixbuf != NULL ) {
       
   215 		SDL_free(mixbuf);
       
   216 		mixbuf = NULL;
       
   217 	}
       
   218 }
       
   219 
       
   220 int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec)
       
   221 {
       
   222 	MMRESULT result;
       
   223 	int i;
       
   224 	WAVEFORMATEX waveformat;
       
   225 
       
   226 	/* Initialize the wavebuf structures for closing */
       
   227 	sound = NULL;
       
   228 	audio_sem = NULL;
       
   229 	for ( i = 0; i < NUM_BUFFERS; ++i )
       
   230 		wavebuf[i].dwUser = 0xFFFF;
       
   231 	mixbuf = NULL;
       
   232 
       
   233 	/* Set basic WAVE format parameters */
       
   234 	SDL_memset(&waveformat, 0, sizeof(waveformat));
       
   235 	waveformat.wFormatTag = WAVE_FORMAT_PCM;
       
   236 
       
   237 	/* Determine the audio parameters from the AudioSpec */
       
   238 	switch ( spec->format & 0xFF ) {
       
   239 		case 8:
       
   240 			/* Unsigned 8 bit audio data */
       
   241 			spec->format = AUDIO_U8;
       
   242 			waveformat.wBitsPerSample = 8;
       
   243 			break;
       
   244 		case 16:
       
   245 			/* Signed 16 bit audio data */
       
   246 			spec->format = AUDIO_S16;
       
   247 			waveformat.wBitsPerSample = 16;
       
   248 			break;
       
   249 		default:
       
   250 			SDL_SetError("Unsupported audio format");
       
   251 			return(-1);
       
   252 	}
       
   253 	waveformat.nChannels = spec->channels;
       
   254 	waveformat.nSamplesPerSec = spec->freq;
       
   255 	waveformat.nBlockAlign =
       
   256 		waveformat.nChannels * (waveformat.wBitsPerSample/8);
       
   257 	waveformat.nAvgBytesPerSec = 
       
   258 		waveformat.nSamplesPerSec * waveformat.nBlockAlign;
       
   259 
       
   260 	/* Check the buffer size -- minimum of 1/4 second (word aligned) */
       
   261 	if ( spec->samples < (spec->freq/4) )
       
   262 		spec->samples = ((spec->freq/4)+3)&~3;
       
   263 
       
   264 	/* Update the fragment size as size in bytes */
       
   265 	SDL_CalculateAudioSpec(spec);
       
   266 
       
   267 	/* Open the audio device */
       
   268 	result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat,
       
   269 			(DWORD_PTR)FillSound, (DWORD_PTR)this, CALLBACK_FUNCTION);
       
   270 	if ( result != MMSYSERR_NOERROR ) {
       
   271 		SetMMerror("waveOutOpen()", result);
       
   272 		return(-1);
       
   273 	}
       
   274 
       
   275 #ifdef SOUND_DEBUG
       
   276 	/* Check the sound device we retrieved */
       
   277 	{
       
   278 		WAVEOUTCAPS caps;
       
   279 
       
   280 		result = waveOutGetDevCaps((UINT)sound, &caps, sizeof(caps));
       
   281 		if ( result != MMSYSERR_NOERROR ) {
       
   282 			SetMMerror("waveOutGetDevCaps()", result);
       
   283 			return(-1);
       
   284 		}
       
   285 		printf("Audio device: %s\n", caps.szPname);
       
   286 	}
       
   287 #endif
       
   288 
       
   289 	/* Create the audio buffer semaphore */
       
   290 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
       
   291 	audio_sem = CreateSemaphoreCE(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
       
   292 #else
       
   293 	audio_sem = CreateSemaphore(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
       
   294 #endif
       
   295 	if ( audio_sem == NULL ) {
       
   296 		SDL_SetError("Couldn't create semaphore");
       
   297 		return(-1);
       
   298 	}
       
   299 
       
   300 	/* Create the sound buffers */
       
   301 	mixbuf = (Uint8 *)SDL_malloc(NUM_BUFFERS*spec->size);
       
   302 	if ( mixbuf == NULL ) {
       
   303 		SDL_SetError("Out of memory");
       
   304 		return(-1);
       
   305 	}
       
   306 	for ( i = 0; i < NUM_BUFFERS; ++i ) {
       
   307 		SDL_memset(&wavebuf[i], 0, sizeof(wavebuf[i]));
       
   308 		wavebuf[i].lpData = (LPSTR) &mixbuf[i*spec->size];
       
   309 		wavebuf[i].dwBufferLength = spec->size;
       
   310 		wavebuf[i].dwFlags = WHDR_DONE;
       
   311 		result = waveOutPrepareHeader(sound, &wavebuf[i],
       
   312 							sizeof(wavebuf[i]));
       
   313 		if ( result != MMSYSERR_NOERROR ) {
       
   314 			SetMMerror("waveOutPrepareHeader()", result);
       
   315 			return(-1);
       
   316 		}
       
   317 	}
       
   318 
       
   319 	/* Ready to go! */
       
   320 	next_buffer = 0;
       
   321 	return(0);
       
   322 }