src/audio/mme/SDL_mmeaudio.c
author Sam Lantinga
Mon, 06 Feb 2006 08:28:51 +0000
changeset 1330 450721ad5436
parent 769 b8d311d90021
child 1336 3692456e7b0f
permissions -rw-r--r--
It's now possible to build SDL without any C runtime at all on Windows,
using Visual C++ 2005
slouken@654
     1
/*
slouken@654
     2
    SDL - Simple DirectMedia Layer
slouken@769
     3
    Copyright (C) 1997-2004 Sam Lantinga
slouken@654
     4
slouken@654
     5
    This library is free software; you can redistribute it and/or
slouken@654
     6
    modify it under the terms of the GNU Library General Public
slouken@654
     7
    License as published by the Free Software Foundation; either
slouken@654
     8
    version 2 of the License, or (at your option) any later version.
slouken@654
     9
slouken@654
    10
    This library is distributed in the hope that it will be useful,
slouken@654
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@654
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@654
    13
    Library General Public License for more details.
slouken@654
    14
slouken@654
    15
    You should have received a copy of the GNU Library General Public
slouken@654
    16
    License along with this library; if not, write to the Free
slouken@654
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@654
    18
slouken@654
    19
    Sam Lantinga
slouken@654
    20
    slouken@libsdl.org
slouken@654
    21
*/
slouken@654
    22
slouken@654
    23
/* Tru64 UNIX MME support */
slouken@654
    24
#include "SDL_mmeaudio.h"
slouken@654
    25
slouken@654
    26
static BOOL inUse[NUM_BUFFERS];
slouken@654
    27
slouken@654
    28
/* Audio driver functions */
slouken@654
    29
static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec);
slouken@654
    30
static void MME_WaitAudio(_THIS);
slouken@654
    31
static Uint8 *MME_GetAudioBuf(_THIS);
slouken@654
    32
static void MME_PlayAudio(_THIS);
slouken@654
    33
static void MME_WaitDone(_THIS);
slouken@654
    34
static void MME_CloseAudio(_THIS);
slouken@654
    35
slouken@654
    36
/* Audio driver bootstrap functions */
slouken@654
    37
static int Audio_Available(void)
slouken@654
    38
{
slouken@654
    39
    return(1);
slouken@654
    40
}
slouken@654
    41
slouken@654
    42
static void Audio_DeleteDevice(SDL_AudioDevice *device)
slouken@654
    43
{
slouken@654
    44
    if ( device ) {
slouken@654
    45
	if ( device->hidden ) {
slouken@654
    46
	    free(device->hidden);
slouken@654
    47
	    device->hidden = NULL;
slouken@654
    48
	}
slouken@654
    49
	free(device);
slouken@654
    50
	device = NULL;
slouken@654
    51
    }
slouken@654
    52
}
slouken@654
    53
slouken@654
    54
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
slouken@654
    55
{
slouken@654
    56
    SDL_AudioDevice *this;
slouken@654
    57
slouken@654
    58
/* Initialize all variables that we clean on shutdown */
slouken@654
    59
    this = malloc(sizeof(SDL_AudioDevice));
slouken@654
    60
    if ( this ) {
slouken@654
    61
	memset(this, 0, (sizeof *this));
slouken@654
    62
	this->hidden = malloc((sizeof *this->hidden));
slouken@654
    63
    }
slouken@654
    64
    if ( (this == NULL) || (this->hidden == NULL) ) {
slouken@654
    65
	SDL_OutOfMemory();
slouken@654
    66
	if ( this ) {
slouken@654
    67
	    free(this);
slouken@654
    68
	}
slouken@654
    69
	return(0);
slouken@654
    70
    }
slouken@654
    71
    memset(this->hidden, 0, (sizeof *this->hidden));
slouken@654
    72
    /* Set the function pointers */
slouken@654
    73
    this->OpenAudio       =       MME_OpenAudio;
slouken@654
    74
    this->WaitAudio       =       MME_WaitAudio;
slouken@654
    75
    this->PlayAudio       =       MME_PlayAudio;
slouken@654
    76
    this->GetAudioBuf     =     MME_GetAudioBuf;
slouken@654
    77
    this->WaitDone        =        MME_WaitDone;
slouken@654
    78
    this->CloseAudio      =      MME_CloseAudio;
slouken@654
    79
    this->free            =  Audio_DeleteDevice;
slouken@654
    80
slouken@654
    81
    return this;
slouken@654
    82
}
slouken@654
    83
slouken@654
    84
AudioBootStrap MMEAUDIO_bootstrap = {
slouken@654
    85
    "waveout", "Tru64 MME WaveOut",
slouken@654
    86
    Audio_Available, Audio_CreateDevice
slouken@654
    87
};
slouken@654
    88
slouken@654
    89
static void SetMMerror(char *function, MMRESULT code)
slouken@654
    90
{
slouken@654
    91
    int len;
slouken@654
    92
    char errbuf[MAXERRORLENGTH];
slouken@654
    93
slouken@654
    94
    sprintf(errbuf, "%s: ", function);
slouken@654
    95
    len = strlen(errbuf);
slouken@654
    96
    waveOutGetErrorText(code, errbuf+len, MAXERRORLENGTH-len);
slouken@654
    97
    SDL_SetError("%s",errbuf);
slouken@654
    98
}
slouken@654
    99
slouken@654
   100
static void CALLBACK MME_CALLBACK(HWAVEOUT hwo,
slouken@654
   101
				  UINT uMsg,
slouken@654
   102
				  DWORD dwInstance,
slouken@654
   103
				  LPARAM dwParam1,
slouken@654
   104
				  LPARAM dwParam2)
slouken@654
   105
{
slouken@654
   106
    WAVEHDR *wp = (WAVEHDR *) dwParam1;
slouken@654
   107
slouken@654
   108
    if ( uMsg == WOM_DONE )
slouken@654
   109
	inUse[wp->dwUser] = FALSE;
slouken@654
   110
}
slouken@654
   111
slouken@654
   112
static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec)
slouken@654
   113
{
slouken@654
   114
    MMRESULT result;
slouken@654
   115
    int i;
slouken@654
   116
slouken@654
   117
    mixbuf = NULL;
slouken@654
   118
slouken@654
   119
    /* Set basic WAVE format parameters */
slouken@654
   120
    shm = mmeAllocMem(sizeof(*shm));
slouken@654
   121
    if ( shm == NULL ) {
slouken@654
   122
	SDL_SetError("Out of memory: shm");
slouken@654
   123
	return(-1);
slouken@654
   124
    }
slouken@654
   125
    shm->sound = 0;
slouken@654
   126
    shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;
slouken@654
   127
slouken@654
   128
    /* Determine the audio parameters from the AudioSpec */
slouken@654
   129
    switch ( spec->format & 0xFF ) {
slouken@654
   130
	case 8:
slouken@654
   131
	    /* Unsigned 8 bit audio data */
slouken@654
   132
	    spec->format = AUDIO_U8;
slouken@654
   133
	    shm->wFmt.wBitsPerSample = 8;
slouken@654
   134
	    break;
slouken@654
   135
	case 16:
slouken@654
   136
	    /* Signed 16 bit audio data */
slouken@654
   137
	    spec->format = AUDIO_S16;
slouken@654
   138
	    shm->wFmt.wBitsPerSample = 16;
slouken@654
   139
	    break;
slouken@654
   140
	    default:
slouken@654
   141
	    SDL_SetError("Unsupported audio format");
slouken@654
   142
	    return(-1);
slouken@654
   143
    }
slouken@654
   144
slouken@654
   145
    shm->wFmt.wf.nChannels = spec->channels;
slouken@654
   146
    shm->wFmt.wf.nSamplesPerSec = spec->freq;
slouken@654
   147
    shm->wFmt.wf.nBlockAlign =
slouken@654
   148
	shm->wFmt.wf.nChannels * shm->wFmt.wBitsPerSample / 8;
slouken@654
   149
    shm->wFmt.wf.nAvgBytesPerSec =
slouken@654
   150
	shm->wFmt.wf.nSamplesPerSec * shm->wFmt.wf.nBlockAlign;
slouken@654
   151
slouken@654
   152
    /* Check the buffer size -- minimum of 1/4 second (word aligned) */
slouken@654
   153
    if ( spec->samples < (spec->freq/4) )
slouken@654
   154
	spec->samples = ((spec->freq/4)+3)&~3;
slouken@654
   155
slouken@654
   156
    /* Update the fragment size as size in bytes */
slouken@654
   157
    SDL_CalculateAudioSpec(spec);
slouken@654
   158
slouken@654
   159
    /* Open the audio device */
slouken@654
   160
    result = waveOutOpen(&(shm->sound),
slouken@654
   161
			 WAVE_MAPPER,
slouken@654
   162
			 &(shm->wFmt.wf),
slouken@654
   163
			 MME_CALLBACK,
slouken@654
   164
			 NULL,
slouken@654
   165
			 (CALLBACK_FUNCTION|WAVE_OPEN_SHAREABLE));
slouken@654
   166
    if ( result != MMSYSERR_NOERROR ) {
slouken@654
   167
	    SetMMerror("waveOutOpen()", result);
slouken@654
   168
	    return(-1);
slouken@654
   169
    }
slouken@654
   170
slouken@654
   171
    /* Create the sound buffers */
slouken@654
   172
    mixbuf = (Uint8 *)mmeAllocBuffer(NUM_BUFFERS * (spec->size));
slouken@654
   173
    if ( mixbuf == NULL ) {
slouken@654
   174
	SDL_SetError("Out of memory: mixbuf");
slouken@654
   175
	return(-1);
slouken@654
   176
    }
slouken@654
   177
slouken@654
   178
    for (i = 0; i < NUM_BUFFERS; i++) {
slouken@654
   179
	shm->wHdr[i].lpData         = &mixbuf[i * (spec->size)];
slouken@654
   180
	shm->wHdr[i].dwBufferLength = spec->size;
slouken@654
   181
	shm->wHdr[i].dwFlags        = 0;
slouken@654
   182
	shm->wHdr[i].dwUser         = i;
slouken@654
   183
	shm->wHdr[i].dwLoops        = 0;       /* loop control counter */
slouken@654
   184
	shm->wHdr[i].lpNext         = NULL;    /* reserved for driver */
slouken@654
   185
	shm->wHdr[i].reserved       = 0;
slouken@654
   186
	inUse[i] = FALSE;
slouken@654
   187
    }
slouken@654
   188
    next_buffer = 0;
slouken@654
   189
    return 0;
slouken@654
   190
}
slouken@654
   191
slouken@654
   192
static void MME_WaitAudio(_THIS)
slouken@654
   193
{
slouken@755
   194
    while ( inUse[next_buffer] ) {
slouken@755
   195
	mmeWaitForCallbacks();
slouken@755
   196
	mmeProcessCallbacks();
slouken@755
   197
    }
slouken@654
   198
}
slouken@654
   199
slouken@654
   200
static Uint8 *MME_GetAudioBuf(_THIS)
slouken@654
   201
{
slouken@654
   202
    Uint8 *retval;
slouken@654
   203
slouken@654
   204
    inUse[next_buffer] = TRUE;
slouken@654
   205
    retval = (Uint8 *)(shm->wHdr[next_buffer].lpData);
slouken@654
   206
    return retval;
slouken@654
   207
}
slouken@654
   208
slouken@654
   209
static void MME_PlayAudio(_THIS)
slouken@654
   210
{
slouken@654
   211
    /* Queue it up */
slouken@654
   212
    waveOutWrite(shm->sound, &(shm->wHdr[next_buffer]), sizeof(WAVEHDR));
slouken@654
   213
    next_buffer = (next_buffer+1)%NUM_BUFFERS;
slouken@654
   214
}
slouken@654
   215
slouken@654
   216
static void MME_WaitDone(_THIS)
slouken@654
   217
{
slouken@654
   218
    MMRESULT result;
slouken@654
   219
    int i;
slouken@654
   220
slouken@654
   221
    if ( shm->sound ) {
slouken@755
   222
	for (i = 0; i < NUM_BUFFERS; i++)
slouken@755
   223
	    while ( inUse[i] ) {
slouken@755
   224
		mmeWaitForCallbacks();
slouken@755
   225
		mmeProcessCallbacks();
slouken@755
   226
	    }
slouken@654
   227
	result = waveOutReset(shm->sound);
slouken@654
   228
	if ( result != MMSYSERR_NOERROR )
slouken@654
   229
	    SetMMerror("waveOutReset()", result);
slouken@755
   230
	mmeProcessCallbacks();
slouken@654
   231
    }
slouken@654
   232
}
slouken@654
   233
slouken@654
   234
static void MME_CloseAudio(_THIS)
slouken@654
   235
{
slouken@654
   236
    MMRESULT result;
slouken@654
   237
slouken@654
   238
    if ( mixbuf ) {
slouken@654
   239
	result = mmeFreeBuffer(mixbuf);
slouken@654
   240
	if (result != MMSYSERR_NOERROR )
slouken@654
   241
	    SetMMerror("mmeFreeBuffer", result);
slouken@654
   242
	mixbuf = NULL;
slouken@654
   243
    }
slouken@654
   244
slouken@654
   245
    if ( shm ) {
slouken@654
   246
	if ( shm->sound ) {
slouken@654
   247
	    result = waveOutClose(shm->sound);
slouken@654
   248
	    if (result != MMSYSERR_NOERROR )
slouken@654
   249
		SetMMerror("waveOutClose()", result);
slouken@755
   250
	    mmeProcessCallbacks();
slouken@654
   251
	}
slouken@654
   252
	result = mmeFreeMem(shm);
slouken@654
   253
	if (result != MMSYSERR_NOERROR )
slouken@654
   254
	    SetMMerror("mmeFreeMem()", result);
slouken@654
   255
	shm = NULL;
slouken@654
   256
    }
slouken@654
   257
}
slouken@654
   258