src/audio/mme/SDL_mmeaudio.c
author Sam Lantinga
Tue, 07 Feb 2006 12:15:46 +0000
changeset 1342 d73be99e9420
parent 1338 604d73db6802
child 1358 c71e05b4dc2e
permissions -rw-r--r--
Fixed it Hayashi Naoyuki's way. :)
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@1342
    24
#include <mme_api.h>
slouken@1342
    25
slouken@1342
    26
#include "SDL_stdlib.h"
slouken@1342
    27
#include "SDL_string.h"
slouken@1342
    28
#include "SDL_audio.h"
slouken@1342
    29
#include "SDL_mutex.h"
slouken@1342
    30
#include "SDL_timer.h"
slouken@1342
    31
#include "SDL_audio_c.h"
slouken@1342
    32
slouken@654
    33
#include "SDL_mmeaudio.h"
slouken@654
    34
slouken@654
    35
static BOOL inUse[NUM_BUFFERS];
slouken@654
    36
slouken@654
    37
/* Audio driver functions */
slouken@654
    38
static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec);
slouken@654
    39
static void MME_WaitAudio(_THIS);
slouken@654
    40
static Uint8 *MME_GetAudioBuf(_THIS);
slouken@654
    41
static void MME_PlayAudio(_THIS);
slouken@654
    42
static void MME_WaitDone(_THIS);
slouken@654
    43
static void MME_CloseAudio(_THIS);
slouken@654
    44
slouken@654
    45
/* Audio driver bootstrap functions */
slouken@654
    46
static int Audio_Available(void)
slouken@654
    47
{
slouken@654
    48
    return(1);
slouken@654
    49
}
slouken@654
    50
slouken@654
    51
static void Audio_DeleteDevice(SDL_AudioDevice *device)
slouken@654
    52
{
slouken@654
    53
    if ( device ) {
slouken@654
    54
	if ( device->hidden ) {
slouken@1336
    55
	    SDL_free(device->hidden);
slouken@654
    56
	    device->hidden = NULL;
slouken@654
    57
	}
slouken@1336
    58
	SDL_free(device);
slouken@654
    59
	device = NULL;
slouken@654
    60
    }
slouken@654
    61
}
slouken@654
    62
slouken@654
    63
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
slouken@654
    64
{
slouken@654
    65
    SDL_AudioDevice *this;
slouken@654
    66
slouken@654
    67
/* Initialize all variables that we clean on shutdown */
slouken@1336
    68
    this = SDL_malloc(sizeof(SDL_AudioDevice));
slouken@654
    69
    if ( this ) {
slouken@1336
    70
	SDL_memset(this, 0, (sizeof *this));
slouken@1336
    71
	this->hidden = SDL_malloc((sizeof *this->hidden));
slouken@654
    72
    }
slouken@654
    73
    if ( (this == NULL) || (this->hidden == NULL) ) {
slouken@654
    74
	SDL_OutOfMemory();
slouken@654
    75
	if ( this ) {
slouken@1336
    76
	    SDL_free(this);
slouken@654
    77
	}
slouken@654
    78
	return(0);
slouken@654
    79
    }
slouken@1336
    80
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
slouken@654
    81
    /* Set the function pointers */
slouken@654
    82
    this->OpenAudio       =       MME_OpenAudio;
slouken@654
    83
    this->WaitAudio       =       MME_WaitAudio;
slouken@654
    84
    this->PlayAudio       =       MME_PlayAudio;
slouken@654
    85
    this->GetAudioBuf     =     MME_GetAudioBuf;
slouken@654
    86
    this->WaitDone        =        MME_WaitDone;
slouken@654
    87
    this->CloseAudio      =      MME_CloseAudio;
slouken@654
    88
    this->free            =  Audio_DeleteDevice;
slouken@654
    89
slouken@654
    90
    return this;
slouken@654
    91
}
slouken@654
    92
slouken@654
    93
AudioBootStrap MMEAUDIO_bootstrap = {
slouken@654
    94
    "waveout", "Tru64 MME WaveOut",
slouken@654
    95
    Audio_Available, Audio_CreateDevice
slouken@654
    96
};
slouken@654
    97
slouken@654
    98
static void SetMMerror(char *function, MMRESULT code)
slouken@654
    99
{
slouken@654
   100
    int len;
slouken@654
   101
    char errbuf[MAXERRORLENGTH];
slouken@654
   102
slouken@1338
   103
    SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
slouken@1336
   104
    len = SDL_strlen(errbuf);
slouken@654
   105
    waveOutGetErrorText(code, errbuf+len, MAXERRORLENGTH-len);
slouken@654
   106
    SDL_SetError("%s",errbuf);
slouken@654
   107
}
slouken@654
   108
slouken@654
   109
static void CALLBACK MME_CALLBACK(HWAVEOUT hwo,
slouken@654
   110
				  UINT uMsg,
slouken@654
   111
				  DWORD dwInstance,
slouken@654
   112
				  LPARAM dwParam1,
slouken@654
   113
				  LPARAM dwParam2)
slouken@654
   114
{
slouken@654
   115
    WAVEHDR *wp = (WAVEHDR *) dwParam1;
slouken@654
   116
slouken@654
   117
    if ( uMsg == WOM_DONE )
slouken@654
   118
	inUse[wp->dwUser] = FALSE;
slouken@654
   119
}
slouken@654
   120
slouken@654
   121
static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec)
slouken@654
   122
{
slouken@654
   123
    MMRESULT result;
slouken@654
   124
    int i;
slouken@654
   125
slouken@654
   126
    mixbuf = NULL;
slouken@654
   127
slouken@654
   128
    /* Set basic WAVE format parameters */
slouken@654
   129
    shm = mmeAllocMem(sizeof(*shm));
slouken@654
   130
    if ( shm == NULL ) {
slouken@654
   131
	SDL_SetError("Out of memory: shm");
slouken@654
   132
	return(-1);
slouken@654
   133
    }
slouken@654
   134
    shm->sound = 0;
slouken@654
   135
    shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;
slouken@654
   136
slouken@654
   137
    /* Determine the audio parameters from the AudioSpec */
slouken@654
   138
    switch ( spec->format & 0xFF ) {
slouken@654
   139
	case 8:
slouken@654
   140
	    /* Unsigned 8 bit audio data */
slouken@654
   141
	    spec->format = AUDIO_U8;
slouken@654
   142
	    shm->wFmt.wBitsPerSample = 8;
slouken@654
   143
	    break;
slouken@654
   144
	case 16:
slouken@654
   145
	    /* Signed 16 bit audio data */
slouken@654
   146
	    spec->format = AUDIO_S16;
slouken@654
   147
	    shm->wFmt.wBitsPerSample = 16;
slouken@654
   148
	    break;
slouken@654
   149
	    default:
slouken@654
   150
	    SDL_SetError("Unsupported audio format");
slouken@654
   151
	    return(-1);
slouken@654
   152
    }
slouken@654
   153
slouken@654
   154
    shm->wFmt.wf.nChannels = spec->channels;
slouken@654
   155
    shm->wFmt.wf.nSamplesPerSec = spec->freq;
slouken@654
   156
    shm->wFmt.wf.nBlockAlign =
slouken@654
   157
	shm->wFmt.wf.nChannels * shm->wFmt.wBitsPerSample / 8;
slouken@654
   158
    shm->wFmt.wf.nAvgBytesPerSec =
slouken@654
   159
	shm->wFmt.wf.nSamplesPerSec * shm->wFmt.wf.nBlockAlign;
slouken@654
   160
slouken@654
   161
    /* Check the buffer size -- minimum of 1/4 second (word aligned) */
slouken@654
   162
    if ( spec->samples < (spec->freq/4) )
slouken@654
   163
	spec->samples = ((spec->freq/4)+3)&~3;
slouken@654
   164
slouken@654
   165
    /* Update the fragment size as size in bytes */
slouken@654
   166
    SDL_CalculateAudioSpec(spec);
slouken@654
   167
slouken@654
   168
    /* Open the audio device */
slouken@654
   169
    result = waveOutOpen(&(shm->sound),
slouken@654
   170
			 WAVE_MAPPER,
slouken@654
   171
			 &(shm->wFmt.wf),
slouken@654
   172
			 MME_CALLBACK,
slouken@654
   173
			 NULL,
slouken@654
   174
			 (CALLBACK_FUNCTION|WAVE_OPEN_SHAREABLE));
slouken@654
   175
    if ( result != MMSYSERR_NOERROR ) {
slouken@654
   176
	    SetMMerror("waveOutOpen()", result);
slouken@654
   177
	    return(-1);
slouken@654
   178
    }
slouken@654
   179
slouken@654
   180
    /* Create the sound buffers */
slouken@654
   181
    mixbuf = (Uint8 *)mmeAllocBuffer(NUM_BUFFERS * (spec->size));
slouken@654
   182
    if ( mixbuf == NULL ) {
slouken@654
   183
	SDL_SetError("Out of memory: mixbuf");
slouken@654
   184
	return(-1);
slouken@654
   185
    }
slouken@654
   186
slouken@654
   187
    for (i = 0; i < NUM_BUFFERS; i++) {
slouken@654
   188
	shm->wHdr[i].lpData         = &mixbuf[i * (spec->size)];
slouken@654
   189
	shm->wHdr[i].dwBufferLength = spec->size;
slouken@654
   190
	shm->wHdr[i].dwFlags        = 0;
slouken@654
   191
	shm->wHdr[i].dwUser         = i;
slouken@654
   192
	shm->wHdr[i].dwLoops        = 0;       /* loop control counter */
slouken@654
   193
	shm->wHdr[i].lpNext         = NULL;    /* reserved for driver */
slouken@654
   194
	shm->wHdr[i].reserved       = 0;
slouken@654
   195
	inUse[i] = FALSE;
slouken@654
   196
    }
slouken@654
   197
    next_buffer = 0;
slouken@654
   198
    return 0;
slouken@654
   199
}
slouken@654
   200
slouken@654
   201
static void MME_WaitAudio(_THIS)
slouken@654
   202
{
slouken@755
   203
    while ( inUse[next_buffer] ) {
slouken@755
   204
	mmeWaitForCallbacks();
slouken@755
   205
	mmeProcessCallbacks();
slouken@755
   206
    }
slouken@654
   207
}
slouken@654
   208
slouken@654
   209
static Uint8 *MME_GetAudioBuf(_THIS)
slouken@654
   210
{
slouken@654
   211
    Uint8 *retval;
slouken@654
   212
slouken@654
   213
    inUse[next_buffer] = TRUE;
slouken@654
   214
    retval = (Uint8 *)(shm->wHdr[next_buffer].lpData);
slouken@654
   215
    return retval;
slouken@654
   216
}
slouken@654
   217
slouken@654
   218
static void MME_PlayAudio(_THIS)
slouken@654
   219
{
slouken@654
   220
    /* Queue it up */
slouken@654
   221
    waveOutWrite(shm->sound, &(shm->wHdr[next_buffer]), sizeof(WAVEHDR));
slouken@654
   222
    next_buffer = (next_buffer+1)%NUM_BUFFERS;
slouken@654
   223
}
slouken@654
   224
slouken@654
   225
static void MME_WaitDone(_THIS)
slouken@654
   226
{
slouken@654
   227
    MMRESULT result;
slouken@654
   228
    int i;
slouken@654
   229
slouken@654
   230
    if ( shm->sound ) {
slouken@755
   231
	for (i = 0; i < NUM_BUFFERS; i++)
slouken@755
   232
	    while ( inUse[i] ) {
slouken@755
   233
		mmeWaitForCallbacks();
slouken@755
   234
		mmeProcessCallbacks();
slouken@755
   235
	    }
slouken@654
   236
	result = waveOutReset(shm->sound);
slouken@654
   237
	if ( result != MMSYSERR_NOERROR )
slouken@654
   238
	    SetMMerror("waveOutReset()", result);
slouken@755
   239
	mmeProcessCallbacks();
slouken@654
   240
    }
slouken@654
   241
}
slouken@654
   242
slouken@654
   243
static void MME_CloseAudio(_THIS)
slouken@654
   244
{
slouken@654
   245
    MMRESULT result;
slouken@654
   246
slouken@654
   247
    if ( mixbuf ) {
slouken@654
   248
	result = mmeFreeBuffer(mixbuf);
slouken@654
   249
	if (result != MMSYSERR_NOERROR )
slouken@654
   250
	    SetMMerror("mmeFreeBuffer", result);
slouken@654
   251
	mixbuf = NULL;
slouken@654
   252
    }
slouken@654
   253
slouken@654
   254
    if ( shm ) {
slouken@654
   255
	if ( shm->sound ) {
slouken@654
   256
	    result = waveOutClose(shm->sound);
slouken@654
   257
	    if (result != MMSYSERR_NOERROR )
slouken@654
   258
		SetMMerror("waveOutClose()", result);
slouken@755
   259
	    mmeProcessCallbacks();
slouken@654
   260
	}
slouken@654
   261
	result = mmeFreeMem(shm);
slouken@654
   262
	if (result != MMSYSERR_NOERROR )
slouken@654
   263
	    SetMMerror("mmeFreeMem()", result);
slouken@654
   264
	shm = NULL;
slouken@654
   265
    }
slouken@654
   266
}
slouken@654
   267