示例#1
0
static void
MME_CloseDevice(_THIS)
{
    if (this->hidden != NULL) {
        MMRESULT result;

        if (this->hidden->mixbuf) {
            result = mmeFreeBuffer(this->hidden->mixbuf);
            if (result != MMSYSERR_NOERROR)
                SetMMerror("mmeFreeBuffer", result);
            this->hidden->mixbuf = NULL;
        }

        if (this->hidden->shm) {
            if (this->hidden->shm->sound) {
                result = waveOutClose(this->hidden->shm->sound);
                if (result != MMSYSERR_NOERROR)
                    SetMMerror("waveOutClose()", result);
                mmeProcessCallbacks();
            }
            result = mmeFreeMem(this->hidden->shm);
            if (result != MMSYSERR_NOERROR)
                SetMMerror("mmeFreeMem()", result);
            this->hidden->shm = NULL;
        }

        SDL_free(this->hidden);
        this->hidden = NULL;
    }
}
示例#2
0
static void MME_CloseAudio(_THIS)
{
    MMRESULT result;

    if ( mixbuf ) {
	result = mmeFreeBuffer(mixbuf);
	if (result != MMSYSERR_NOERROR )
	    SetMMerror("mmeFreeBuffer", result);
	mixbuf = NULL;
    }

    if ( shm ) {
	if ( shm->sound ) {
	    result = waveOutClose(shm->sound);
	    if (result != MMSYSERR_NOERROR )
		SetMMerror("waveOutClose()", result);
	    mmeProcessCallbacks();
	}
	result = mmeFreeMem(shm);
	if (result != MMSYSERR_NOERROR )
	    SetMMerror("mmeFreeMem()", result);
	shm = NULL;
    }
}
示例#3
0
static void MME_WaitDone(_THIS)
{
    MMRESULT result;
    int i;

    if ( shm->sound ) {
	for (i = 0; i < NUM_BUFFERS; i++)
	    while ( inUse[i] ) {
		mmeWaitForCallbacks();
		mmeProcessCallbacks();
	    }
	result = waveOutReset(shm->sound);
	if ( result != MMSYSERR_NOERROR )
	    SetMMerror("waveOutReset()", result);
	mmeProcessCallbacks();
    }
}
示例#4
0
int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
	MMRESULT result;
	int i;
	WAVEFORMATEX waveformat;

	/* Initialize the wavebuf structures for closing */
	sound = NULL;
	audio_sem = NULL;
	for ( i = 0; i < NUM_BUFFERS; ++i )
		wavebuf[i].dwUser = 0xFFFF;
	mixbuf = NULL;

	/* Set basic WAVE format parameters */
	SDL_memset(&waveformat, 0, sizeof(waveformat));
	waveformat.wFormatTag = WAVE_FORMAT_PCM;

	/* Determine the audio parameters from the AudioSpec */
	switch ( spec->format & 0xFF ) {
		case 8:
			/* Unsigned 8 bit audio data */
			spec->format = AUDIO_U8;
			waveformat.wBitsPerSample = 8;
			break;
		case 16:
			/* Signed 16 bit audio data */
			spec->format = AUDIO_S16;
			waveformat.wBitsPerSample = 16;
			break;
		default:
			SDL_SetError("Unsupported audio format");
			return(-1);
	}
	waveformat.nChannels = spec->channels;
	waveformat.nSamplesPerSec = spec->freq;
	waveformat.nBlockAlign =
		waveformat.nChannels * (waveformat.wBitsPerSample/8);
	waveformat.nAvgBytesPerSec = 
		waveformat.nSamplesPerSec * waveformat.nBlockAlign;

	/* Check the buffer size -- minimum of 1/4 second (word aligned) */
	if ( spec->samples < (spec->freq/4) )
		spec->samples = ((spec->freq/4)+3)&~3;

	/* Update the fragment size as size in bytes */
	SDL_CalculateAudioSpec(spec);

	/* Open the audio device */
	result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat,
			(DWORD_PTR)FillSound, (DWORD_PTR)this, CALLBACK_FUNCTION);
	if ( result != MMSYSERR_NOERROR ) {
		SetMMerror("waveOutOpen()", result);
		return(-1);
	}

#ifdef SOUND_DEBUG
	/* Check the sound device we retrieved */
	{
		WAVEOUTCAPS caps;

		result = waveOutGetDevCaps((UINT)sound, &caps, sizeof(caps));
		if ( result != MMSYSERR_NOERROR ) {
			SetMMerror("waveOutGetDevCaps()", result);
			return(-1);
		}
		printf("Audio device: %s\n", caps.szPname);
	}
#endif

	/* Create the audio buffer semaphore */
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
	audio_sem = CreateSemaphoreCE(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
#else
	audio_sem = CreateSemaphore(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
#endif
	if ( audio_sem == NULL ) {
		SDL_SetError("Couldn't create semaphore");
		return(-1);
	}

	/* Create the sound buffers */
	mixbuf = (Uint8 *)SDL_malloc(NUM_BUFFERS*spec->size);
	if ( mixbuf == NULL ) {
		SDL_SetError("Out of memory");
		return(-1);
	}
	for ( i = 0; i < NUM_BUFFERS; ++i ) {
		SDL_memset(&wavebuf[i], 0, sizeof(wavebuf[i]));
		wavebuf[i].lpData = (LPSTR) &mixbuf[i*spec->size];
		wavebuf[i].dwBufferLength = spec->size;
		wavebuf[i].dwFlags = WHDR_DONE;
		result = waveOutPrepareHeader(sound, &wavebuf[i],
							sizeof(wavebuf[i]));
		if ( result != MMSYSERR_NOERROR ) {
			SetMMerror("waveOutPrepareHeader()", result);
			return(-1);
		}
	}

	/* Ready to go! */
	next_buffer = 0;
	return(0);
}
示例#5
0
static int
WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
    SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
    int valid_datatype = 0;
    MMRESULT result;
    WAVEFORMATEX waveformat;
    UINT devId = WAVE_MAPPER;  /* WAVE_MAPPER == choose system's default */
    UINT i;

    if (handle != NULL) {  /* specific device requested? */
        /* -1 because we increment the original value to avoid NULL. */
        const size_t val = ((size_t) handle) - 1;
        devId = (UINT) val;
    }

    /* Initialize all variables that we clean on shutdown */
    this->hidden = (struct SDL_PrivateAudioData *)
        SDL_malloc((sizeof *this->hidden));
    if (this->hidden == NULL) {
        return SDL_OutOfMemory();
    }
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));

    /* Initialize the wavebuf structures for closing */
    for (i = 0; i < NUM_BUFFERS; ++i)
        this->hidden->wavebuf[i].dwUser = 0xFFFF;

    if (this->spec.channels > 2)
        this->spec.channels = 2;        /* !!! FIXME: is this right? */

    while ((!valid_datatype) && (test_format)) {
        switch (test_format) {
        case AUDIO_U8:
        case AUDIO_S16:
        case AUDIO_S32:
        case AUDIO_F32:
            this->spec.format = test_format;
            if (PrepWaveFormat(this, devId, &waveformat, iscapture)) {
                valid_datatype = 1;
            } else {
                test_format = SDL_NextAudioFormat();
            }
            break;

        default:
            test_format = SDL_NextAudioFormat();
            break;
        }
    }

    if (!valid_datatype) {
        WINMM_CloseDevice(this);
        return SDL_SetError("Unsupported audio format");
    }

    /* Update the fragment size as size in bytes */
    SDL_CalculateAudioSpec(&this->spec);

    /* Open the audio device */
    if (iscapture) {
        result = waveInOpen(&this->hidden->hin, devId, &waveformat,
                             (DWORD_PTR) CaptureSound, (DWORD_PTR) this,
                             CALLBACK_FUNCTION);
    } else {
        result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
                             (DWORD_PTR) FillSound, (DWORD_PTR) this,
                             CALLBACK_FUNCTION);
    }

    if (result != MMSYSERR_NOERROR) {
        WINMM_CloseDevice(this);
        return SetMMerror("waveOutOpen()", result);
    }
#ifdef SOUND_DEBUG
    /* Check the sound device we retrieved */
    {
        WAVEOUTCAPS caps;

        result = waveOutGetDevCaps((UINT) this->hidden->hout,
                                   &caps, sizeof(caps));
        if (result != MMSYSERR_NOERROR) {
            WINMM_CloseDevice(this);
            return SetMMerror("waveOutGetDevCaps()", result);
        }
        printf("Audio device: %s\n", caps.szPname);
    }
#endif

    /* Create the audio buffer semaphore */
    this->hidden->audio_sem =
        CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
    if (this->hidden->audio_sem == NULL) {
        WINMM_CloseDevice(this);
        return SDL_SetError("Couldn't create semaphore");
    }

    /* Create the sound buffers */
    this->hidden->mixbuf =
        (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
    if (this->hidden->mixbuf == NULL) {
        WINMM_CloseDevice(this);
        return SDL_OutOfMemory();
    }
    for (i = 0; i < NUM_BUFFERS; ++i) {
        SDL_memset(&this->hidden->wavebuf[i], 0,
                   sizeof(this->hidden->wavebuf[i]));
        this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
        this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
        this->hidden->wavebuf[i].lpData =
            (LPSTR) & this->hidden->mixbuf[i * this->spec.size];
        result = waveOutPrepareHeader(this->hidden->hout,
                                      &this->hidden->wavebuf[i],
                                      sizeof(this->hidden->wavebuf[i]));
        if (result != MMSYSERR_NOERROR) {
            WINMM_CloseDevice(this);
            return SetMMerror("waveOutPrepareHeader()", result);
        }
    }

    return 0;                   /* Ready to go! */
}
/* Function to update the state of a joystick - called as a device poll.
 * This function shouldn't update the joystick structure directly,
 * but instead should call SDL_PrivateJoystick*() to deliver events
 * and update joystick device state.
 */
void
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
{
    MMRESULT result;
    int i;
    DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
        JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
    };
    DWORD pos[MAX_AXES];
    struct _transaxis *transaxis;
    int value, change;
    JOYINFOEX joyinfo;

    joyinfo.dwSize = sizeof(joyinfo);
    joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
    if (!joystick->hats) {
        joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS);
    }
    result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
    if (result != JOYERR_NOERROR) {
        SetMMerror("joyGetPosEx", result);
        return;
    }

    /* joystick motion events */
    pos[0] = joyinfo.dwXpos;
    pos[1] = joyinfo.dwYpos;
    pos[2] = joyinfo.dwZpos;
    pos[3] = joyinfo.dwRpos;
    pos[4] = joyinfo.dwUpos;
    pos[5] = joyinfo.dwVpos;

    transaxis = joystick->hwdata->transaxis;
    for (i = 0; i < joystick->naxes; i++) {
        if (joyinfo.dwFlags & flags[i]) {
            value =
                (int) (((float) pos[i] +
                        transaxis[i].offset) * transaxis[i].scale);
            change = (value - joystick->axes[i]);
            if ((change < -JOY_AXIS_THRESHOLD)
                || (change > JOY_AXIS_THRESHOLD)) {
                SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
            }
        }
    }

    /* joystick button events */
    if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
        for (i = 0; i < joystick->nbuttons; ++i) {
            if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
                if (!joystick->buttons[i]) {
                    SDL_PrivateJoystickButton(joystick, (Uint8) i,
                                              SDL_PRESSED);
                }
            } else {
                if (joystick->buttons[i]) {
                    SDL_PrivateJoystickButton(joystick, (Uint8) i,
                                              SDL_RELEASED);
                }
            }
        }
    }

    /* joystick hat events */
    if (joyinfo.dwFlags & JOY_RETURNPOV) {
        Uint8 pos;

        pos = TranslatePOV(joyinfo.dwPOV);
        if (pos != joystick->hats[0]) {
            SDL_PrivateJoystickHat(joystick, 0, pos);
        }
    }
}
示例#7
0
static int
MME_OpenDevice(_THIS, const char *devname, int iscapture)
{
    int valid_format = 0;
    MMRESULT result;
    Uint8 *mixbuf = NULL;
    int i;

    /* Initialize all variables that we clean on shutdown */
    this->hidden = (struct SDL_PrivateAudioData *)
        SDL_malloc((sizeof *this->hidden));
    if (this->hidden == NULL) {
        SDL_OutOfMemory();
        return 0;
    }
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));

    /* Set basic WAVE format parameters */
    this->hidden->shm = mmeAllocMem(sizeof(*this->hidden->shm));
    if (this->hidden->shm == NULL) {
        MME_CloseDevice(this);
        SDL_OutOfMemory();
        return 0;
    }

    SDL_memset(this->hidden->shm, '\0', sizeof(*this->hidden->shm));
    this->hidden->shm->sound = 0;
    this->hidden->shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;

    /* Determine the audio parameters from the AudioSpec */
    /* Try for a closest match on audio format */
    for (test_format = SDL_FirstAudioFormat(this->spec.format);
         !valid_format && test_format;) {
        valid_format = 1;
        switch (test_format) {
        case AUDIO_U8:
        case AUDIO_S16:
        case AUDIO_S32:
            break;
        default:
            valid_format = 0;
            test_format = SDL_NextAudioFormat();
        }
    }

    if (!valid_format) {
        MME_CloseDevice(this);
        SDL_SetError("Unsupported audio format");
        return 0;
    }

    this->spec.format = test_format;
    this->hidden->shm->wFmt.wBitsPerSample = SDL_AUDIO_BITSIZE(test_format);

    /* !!! FIXME: Can this handle more than stereo? */
    this->hidden->shm->wFmt.wf.nChannels = this->spec.channels;
    this->hidden->shm->wFmt.wf.nSamplesPerSec = this->spec.freq;
    this->hidden->shm->wFmt.wf.nBlockAlign =
        this->hidden->shm->wFmt.wf.nChannels *
        this->hidden->shm->wFmt.wBitsPerSample / 8;
    this->hidden->shm->wFmt.wf.nAvgBytesPerSec =
        this->hidden->shm->wFmt.wf.nSamplesPerSec *
        this->hidden->shm->wFmt.wf.nBlockAlign;

    /* Check the buffer size -- minimum of 1/4 second (word aligned) */
    if (this->spec.samples < (this->spec.freq / 4))
        this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;

    /* Update the fragment size as size in bytes */
    SDL_CalculateAudioSpec(&this->spec);

    /* Open the audio device */
    result = waveOutOpen(&(this->hidden->shm->sound),
                         WAVE_MAPPER,
                         &(this->hidden->shm->wFmt.wf),
                         MME_Callback,
                         NULL, (CALLBACK_FUNCTION | WAVE_OPEN_SHAREABLE));
    if (result != MMSYSERR_NOERROR) {
        MME_CloseDevice(this);
        SetMMerror("waveOutOpen()", result);
        return 0;
    }

    /* Create the sound buffers */
    mixbuf = (Uint8 *) mmeAllocBuffer(NUM_BUFFERS * (this->spec.size));
    if (mixbuf == NULL) {
        MME_CloseDevice(this);
        SDL_OutOfMemory();
        return 0;
    }
    this->hidden->mixbuf = mixbuf;

    for (i = 0; i < NUM_BUFFERS; i++) {
        this->hidden->shm->wHdr[i].lpData = &mixbuf[i * (this->spec.size)];
        this->hidden->shm->wHdr[i].dwBufferLength = this->spec.size;
        this->hidden->shm->wHdr[i].dwFlags = 0;
        this->hidden->shm->wHdr[i].dwUser = i;
        this->hidden->shm->wHdr[i].dwLoops = 0; /* loop control counter */
        this->hidden->shm->wHdr[i].lpNext = NULL;       /* reserved for driver */
        this->hidden->shm->wHdr[i].reserved = 0;
        inUse[i] = FALSE;
    }
    this->hidden->next_buffer = 0;

    return 1;
}
示例#8
0
static int
WINMM_OpenDevice(_THIS, const char *devname, int iscapture)
{
    SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
    int valid_datatype = 0;
    MMRESULT result;
    WAVEFORMATEX waveformat;
    UINT_PTR devId = WAVE_MAPPER;  /* WAVE_MAPPER == choose system's default */
    char *utf8 = NULL;
    int i;

    if (devname != NULL) {  /* specific device requested? */
        if (iscapture) {
            const int devcount = (int) waveInGetNumDevs();
            WAVEINCAPS caps;
            for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) {
                result = waveInGetDevCaps(i, &caps, sizeof (caps));
                if (result != MMSYSERR_NOERROR)
                    continue;
                else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL)
                    continue;
                else if (SDL_strcmp(devname, utf8) == 0)
                    devId = (UINT_PTR) i;
                SDL_free(utf8);
            }
        } else {
            const int devcount = (int) waveOutGetNumDevs();
            WAVEOUTCAPS caps;
            for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) {
                result = waveOutGetDevCaps(i, &caps, sizeof (caps));
                if (result != MMSYSERR_NOERROR)
                    continue;
                else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL)
                    continue;
                else if (SDL_strcmp(devname, utf8) == 0)
                    devId = (UINT_PTR) i;
                SDL_free(utf8);
            }
        }

        if (devId == WAVE_MAPPER) {
            SDL_SetError("Requested device not found");
            return 0;
        }
    }

    /* Initialize all variables that we clean on shutdown */
    this->hidden = (struct SDL_PrivateAudioData *)
        SDL_malloc((sizeof *this->hidden));
    if (this->hidden == NULL) {
        SDL_OutOfMemory();
        return 0;
    }
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));

    /* Initialize the wavebuf structures for closing */
    for (i = 0; i < NUM_BUFFERS; ++i)
        this->hidden->wavebuf[i].dwUser = 0xFFFF;

    while ((!valid_datatype) && (test_format)) {
        valid_datatype = 1;
        this->spec.format = test_format;
        switch (test_format) {
        case AUDIO_U8:
        case AUDIO_S16:
        case AUDIO_S32:
            break;              /* valid. */

        default:
            valid_datatype = 0;
            test_format = SDL_NextAudioFormat();
            break;
        }
    }

    if (!valid_datatype) {
        WINMM_CloseDevice(this);
        SDL_SetError("Unsupported audio format");
        return 0;
    }

    /* Set basic WAVE format parameters */
    SDL_memset(&waveformat, '\0', sizeof(waveformat));
    waveformat.wFormatTag = WAVE_FORMAT_PCM;
    waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);

    if (this->spec.channels > 2)
        this->spec.channels = 2;        /* !!! FIXME: is this right? */

    waveformat.nChannels = this->spec.channels;
    waveformat.nSamplesPerSec = this->spec.freq;
    waveformat.nBlockAlign =
        waveformat.nChannels * (waveformat.wBitsPerSample / 8);
    waveformat.nAvgBytesPerSec =
        waveformat.nSamplesPerSec * waveformat.nBlockAlign;

    /* Check the buffer size -- minimum of 1/4 second (word aligned) */
    if (this->spec.samples < (this->spec.freq / 4))
        this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;

    /* Update the fragment size as size in bytes */
    SDL_CalculateAudioSpec(&this->spec);

    /* Open the audio device */
    if (iscapture) {
        result = waveInOpen(&this->hidden->hin, devId, &waveformat,
                             (DWORD_PTR) CaptureSound, (DWORD_PTR) this,
                             CALLBACK_FUNCTION);
    } else {
        result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
                             (DWORD_PTR) FillSound, (DWORD_PTR) this,
                             CALLBACK_FUNCTION);
    }

    if (result != MMSYSERR_NOERROR) {
        WINMM_CloseDevice(this);
        SetMMerror("waveOutOpen()", result);
        return 0;
    }
#ifdef SOUND_DEBUG
    /* Check the sound device we retrieved */
    {
        WAVEOUTCAPS caps;

        result = waveOutGetDevCaps((UINT) this->hidden->hout,
                                   &caps, sizeof(caps));
        if (result != MMSYSERR_NOERROR) {
            WINMM_CloseDevice(this);
            SetMMerror("waveOutGetDevCaps()", result);
            return 0;
        }
        printf("Audio device: %s\n", caps.szPname);
    }
#endif

    /* Create the audio buffer semaphore */
    this->hidden->audio_sem =
        CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
    if (this->hidden->audio_sem == NULL) {
        WINMM_CloseDevice(this);
        SDL_SetError("Couldn't create semaphore");
        return 0;
    }

    /* Create the sound buffers */
    this->hidden->mixbuf =
        (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
    if (this->hidden->mixbuf == NULL) {
        WINMM_CloseDevice(this);
        SDL_OutOfMemory();
        return 0;
    }
    for (i = 0; i < NUM_BUFFERS; ++i) {
        SDL_memset(&this->hidden->wavebuf[i], 0,
                   sizeof(this->hidden->wavebuf[i]));
        this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
        this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
        this->hidden->wavebuf[i].lpData =
            (LPSTR) & this->hidden->mixbuf[i * this->spec.size];
        result = waveOutPrepareHeader(this->hidden->hout,
                                      &this->hidden->wavebuf[i],
                                      sizeof(this->hidden->wavebuf[i]));
        if (result != MMSYSERR_NOERROR) {
            WINMM_CloseDevice(this);
            SetMMerror("waveOutPrepareHeader()", result);
            return 0;
        }
    }

    return 1;                   /* Ready to go! */
}
示例#9
0
static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
    MMRESULT result;
    int i;

    mixbuf = NULL;

    /* Set basic WAVE format parameters */
    shm = mmeAllocMem(sizeof(*shm));
    if ( shm == NULL ) {
	SDL_SetError("Out of memory: shm");
	return(-1);
    }
    shm->sound = 0;
    shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;

    /* Determine the audio parameters from the AudioSpec */
    switch ( spec->format & 0xFF ) {
	case 8:
	    /* Unsigned 8 bit audio data */
	    spec->format = AUDIO_U8;
	    shm->wFmt.wBitsPerSample = 8;
	    break;
	case 16:
	    /* Signed 16 bit audio data */
	    spec->format = AUDIO_S16;
	    shm->wFmt.wBitsPerSample = 16;
	    break;
	    default:
	    SDL_SetError("Unsupported audio format");
	    return(-1);
    }

    shm->wFmt.wf.nChannels = spec->channels;
    shm->wFmt.wf.nSamplesPerSec = spec->freq;
    shm->wFmt.wf.nBlockAlign =
	shm->wFmt.wf.nChannels * shm->wFmt.wBitsPerSample / 8;
    shm->wFmt.wf.nAvgBytesPerSec =
	shm->wFmt.wf.nSamplesPerSec * shm->wFmt.wf.nBlockAlign;

    /* Check the buffer size -- minimum of 1/4 second (word aligned) */
    if ( spec->samples < (spec->freq/4) )
	spec->samples = ((spec->freq/4)+3)&~3;

    /* Update the fragment size as size in bytes */
    SDL_CalculateAudioSpec(spec);

    /* Open the audio device */
    result = waveOutOpen(&(shm->sound),
			 WAVE_MAPPER,
			 &(shm->wFmt.wf),
			 MME_CALLBACK,
			 NULL,
			 (CALLBACK_FUNCTION|WAVE_OPEN_SHAREABLE));
    if ( result != MMSYSERR_NOERROR ) {
	    SetMMerror("waveOutOpen()", result);
	    return(-1);
    }

    /* Create the sound buffers */
    mixbuf = (Uint8 *)mmeAllocBuffer(NUM_BUFFERS * (spec->size));
    if ( mixbuf == NULL ) {
	SDL_SetError("Out of memory: mixbuf");
	return(-1);
    }

    for (i = 0; i < NUM_BUFFERS; i++) {
	shm->wHdr[i].lpData         = &mixbuf[i * (spec->size)];
	shm->wHdr[i].dwBufferLength = spec->size;
	shm->wHdr[i].dwFlags        = 0;
	shm->wHdr[i].dwUser         = i;
	shm->wHdr[i].dwLoops        = 0;       /* loop control counter */
	shm->wHdr[i].lpNext         = NULL;    /* reserved for driver */
	shm->wHdr[i].reserved       = 0;
	inUse[i] = FALSE;
    }
    next_buffer = 0;
    return 0;
}