Mercurial > fife-parpg
diff ext/openal-soft/Alc/dsound.c @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ext/openal-soft/Alc/dsound.c Sun Jun 29 18:44:17 2008 +0000 @@ -0,0 +1,395 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#define INITGUID +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> + +#include <dsound.h> +#include <mmreg.h> + +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + +#ifndef DSSPEAKER_7POINT1 +#define DSSPEAKER_7POINT1 7 +#endif + +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// Since DSound doesn't report the fragment size, just assume 4 fragments +#define DS_FRAGS 4 + +typedef struct { + // DirectSound Playback Device + LPDIRECTSOUND lpDS; + LPDIRECTSOUNDBUFFER DSpbuffer; + LPDIRECTSOUNDBUFFER DSsbuffer; + + int killNow; + ALvoid *thread; +} DSoundData; + + +typedef struct { + ALCchar *name; + GUID guid; +} DevMap; +static DevMap DeviceList[16]; + + +static ALuint DSoundProc(ALvoid *ptr) +{ + ALCdevice *pDevice = (ALCdevice*)ptr; + DSoundData *pData = (DSoundData*)pDevice->ExtraData; + DWORD LastCursor = 0; + DWORD PlayCursor; + VOID *WritePtr1, *WritePtr2; + DWORD WriteCnt1, WriteCnt2; + DWORD BufferSize; + DWORD avail; + HRESULT err; + + BufferSize = pDevice->UpdateSize * DS_FRAGS * + aluBytesFromFormat(pDevice->Format) * + aluChannelsFromFormat(pDevice->Format); + + while(!pData->killNow) + { + // Get current play and write cursors + IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL); + avail = (PlayCursor-LastCursor+BufferSize) % BufferSize; + + if(avail == 0) + { + Sleep(1); + continue; + } + + // Lock output buffer + WriteCnt1 = 0; + WriteCnt2 = 0; + err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); + + // If the buffer is lost, restore it, play and lock + if(err == DSERR_BUFFERLOST) + { + err = IDirectSoundBuffer_Restore(pData->DSsbuffer); + if(SUCCEEDED(err)) + err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); + if(SUCCEEDED(err)) + err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); + } + + // Successfully locked the output buffer + if(SUCCEEDED(err)) + { + // If we have an active context, mix data directly into output buffer otherwise fill with silence + SuspendContext(NULL); + aluMixData(pDevice->Context, WritePtr1, WriteCnt1, pDevice->Format); + aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format); + ProcessContext(NULL); + + // Unlock output buffer only when successfully locked + IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); + } + else + AL_PRINT("Buffer lock error: %#lx\n", err); + + // Update old write cursor location + LastCursor += WriteCnt1+WriteCnt2; + LastCursor %= BufferSize; + } + + return 0; +} + +static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName) +{ + DSBUFFERDESC DSBDescription; + DSoundData *pData = NULL; + WAVEFORMATEXTENSIBLE OutputType; + DWORD frameSize = 0; + LPGUID guid = NULL; + DWORD speakers; + HRESULT hr; + + if(deviceName) + { + int i; + for(i = 0;DeviceList[i].name;i++) + { + if(strcmp(deviceName, DeviceList[i].name) == 0) + { + device->szDeviceName = DeviceList[i].name; + if(i > 0) + guid = &DeviceList[i].guid; + break; + } + } + if(!DeviceList[i].name) + return ALC_FALSE; + } + else + device->szDeviceName = DeviceList[0].name; + + memset(&OutputType, 0, sizeof(OutputType)); + + //Initialise requested device + + pData = calloc(1, sizeof(DSoundData)); + if(!pData) + { + SetALCError(ALC_OUT_OF_MEMORY); + return ALC_FALSE; + } + + //DirectSound Init code + hr = DirectSoundCreate(guid, &pData->lpDS, NULL); + if(SUCCEEDED(hr)) + hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY); + + if(SUCCEEDED(hr)) + hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers); + if(SUCCEEDED(hr)) + { + speakers = DSSPEAKER_CONFIG(speakers); + if(speakers == DSSPEAKER_MONO) + { + if(aluBytesFromFormat(device->Format) == 1) + device->Format = AL_FORMAT_MONO8; + else + device->Format = AL_FORMAT_MONO16; + } + else if(speakers == DSSPEAKER_STEREO) + { + if(aluBytesFromFormat(device->Format) == 1) + device->Format = AL_FORMAT_STEREO8; + else + device->Format = AL_FORMAT_STEREO16; + } + else if(speakers == DSSPEAKER_QUAD) + { + if(aluBytesFromFormat(device->Format) == 1) + device->Format = AL_FORMAT_QUAD8; + else + device->Format = AL_FORMAT_QUAD16; + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + } + else if(speakers == DSSPEAKER_5POINT1) + { + if(aluBytesFromFormat(device->Format) == 1) + device->Format = AL_FORMAT_51CHN8; + else + device->Format = AL_FORMAT_51CHN16; + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + } + else if(speakers == DSSPEAKER_7POINT1) + { + if(aluBytesFromFormat(device->Format) == 1) + device->Format = AL_FORMAT_71CHN8; + else + device->Format = AL_FORMAT_71CHN16; + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + } + frameSize = aluBytesFromFormat(device->Format) * + aluChannelsFromFormat(device->Format); + + OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; + OutputType.Format.nChannels = aluChannelsFromFormat(device->Format); + OutputType.Format.wBitsPerSample = aluBytesFromFormat(device->Format) * 8; + OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; + OutputType.Format.nSamplesPerSec = device->Frequency; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; + OutputType.Format.cbSize = 0; + + device->UpdateSize /= DS_FRAGS; + } + + if(OutputType.Format.nChannels > 2) + { + OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + OutputType.Format.cbSize = 22; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + else + { + if(SUCCEEDED(hr)) + { + memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); + DSBDescription.dwSize=sizeof(DSBUFFERDESC); + DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER; + hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL); + } + if(SUCCEEDED(hr)) + hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format); + } + + if(SUCCEEDED(hr)) + { + memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); + DSBDescription.dwSize=sizeof(DSBUFFERDESC); + DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2; + DSBDescription.dwBufferBytes=device->UpdateSize * DS_FRAGS * frameSize; + DSBDescription.lpwfxFormat=&OutputType.Format; + hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL); + } + + if(SUCCEEDED(hr)) + hr = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); + + device->ExtraData = pData; + pData->thread = StartThread(DSoundProc, device); + if(!pData->thread) + hr = E_FAIL; + + if(FAILED(hr)) + { + if (pData->DSsbuffer) + IDirectSoundBuffer_Release(pData->DSsbuffer); + if (pData->DSpbuffer) + IDirectSoundBuffer_Release(pData->DSpbuffer); + if (pData->lpDS) + IDirectSound_Release(pData->lpDS); + + free(pData); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void DSoundClosePlayback(ALCdevice *device) +{ + DSoundData *pData = device->ExtraData; + + pData->killNow = 1; + StopThread(pData->thread); + + IDirectSoundBuffer_Release(pData->DSsbuffer); + if (pData->DSpbuffer) + IDirectSoundBuffer_Release(pData->DSpbuffer); + IDirectSound_Release(pData->lpDS); + + free(pData); + device->ExtraData = NULL; +} + + +static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) +{ + (void)pDevice; + (void)deviceName; + (void)frequency; + (void)format; + (void)SampleSize; + return ALC_FALSE; +} + +static void DSoundCloseCapture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void DSoundStartCapture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void DSoundStopCapture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) +{ + (void)pDevice; + (void)pBuffer; + (void)lSamples; +} + +static ALCuint DSoundAvailableSamples(ALCdevice *pDevice) +{ + (void)pDevice; + return 0; +} + + +BackendFuncs DSoundFuncs = { + DSoundOpenPlayback, + DSoundClosePlayback, + DSoundOpenCapture, + DSoundCloseCapture, + DSoundStartCapture, + DSoundStopCapture, + DSoundCaptureSamples, + DSoundAvailableSamples +}; + +static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data) +{ + size_t *iter = data; + (void)drvname; + + if(guid) + { + char str[128]; + snprintf(str, sizeof(str), "DirectSound Software on %s", desc); + DeviceList[*iter].name = AppendAllDeviceList(str); + DeviceList[*iter].guid = *guid; + (*iter)++; + } + else + DeviceList[0].name = AppendDeviceList("DirectSound Software"); + + return TRUE; +} + +void alcDSoundInit(BackendFuncs *FuncList) +{ + size_t iter = 1; + HRESULT hr; + + *FuncList = DSoundFuncs; + + hr = DirectSoundEnumerate(DSoundEnumDevices, &iter); + if(FAILED(hr)) + AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); +}