2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
37 #ifndef DSSPEAKER_7POINT1
38 #define DSSPEAKER_7POINT1 7
41 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
44 // DirectSound Playback Device
46 LPDIRECTSOUNDBUFFER DSpbuffer
;
47 LPDIRECTSOUNDBUFFER DSsbuffer
;
54 static ALCchar
*DeviceList
[16];
57 static ALuint
DSoundProc(ALvoid
*ptr
)
59 ALCdevice
*pDevice
= (ALCdevice
*)ptr
;
60 DSoundData
*pData
= (DSoundData
*)pDevice
->ExtraData
;
63 VOID
*WritePtr1
, *WritePtr2
;
64 DWORD WriteCnt1
, WriteCnt2
;
69 BufferSize
= pDevice
->UpdateFreq
*pDevice
->FrameSize
;
71 while(!pData
->killNow
)
73 // Get current play and write cursors
74 IDirectSoundBuffer_GetCurrentPosition(pData
->DSsbuffer
, &PlayCursor
, NULL
);
75 avail
= (PlayCursor
-LastCursor
+BufferSize
) % BufferSize
;
86 err
= IDirectSoundBuffer_Lock(pData
->DSsbuffer
, LastCursor
, avail
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
88 // If the buffer is lost, restore it, play and lock
89 if(err
== DSERR_BUFFERLOST
)
91 err
= IDirectSoundBuffer_Restore(pData
->DSsbuffer
);
93 err
= IDirectSoundBuffer_Play(pData
->DSsbuffer
, 0, 0, DSBPLAY_LOOPING
);
95 err
= IDirectSoundBuffer_Lock(pData
->DSsbuffer
, LastCursor
, avail
, &WritePtr1
, &WriteCnt1
, &WritePtr2
, &WriteCnt2
, 0);
98 // Successfully locked the output buffer
101 // If we have an active context, mix data directly into output buffer otherwise fill with silence
102 SuspendContext(NULL
);
103 aluMixData(pDevice
->Context
, WritePtr1
, WriteCnt1
, pDevice
->Format
);
104 aluMixData(pDevice
->Context
, WritePtr2
, WriteCnt2
, pDevice
->Format
);
105 ProcessContext(NULL
);
107 // Unlock output buffer only when successfully locked
108 IDirectSoundBuffer_Unlock(pData
->DSsbuffer
, WritePtr1
, WriteCnt1
, WritePtr2
, WriteCnt2
);
111 AL_PRINT("Buffer lock error: %#lx\n", err
);
113 // Update old write cursor location
114 LastCursor
+= WriteCnt1
+WriteCnt2
;
115 LastCursor
%= BufferSize
;
121 static ALCboolean
DSoundOpenPlayback(ALCdevice
*device
, const ALCchar
*deviceName
)
123 DSBUFFERDESC DSBDescription
;
124 DSoundData
*pData
= NULL
;
125 WAVEFORMATEXTENSIBLE OutputType
;
132 for(i
= 0;DeviceList
[i
];i
++)
134 if(strcmp(deviceName
, DeviceList
[i
]) == 0)
136 device
->szDeviceName
= DeviceList
[i
];
144 device
->szDeviceName
= DeviceList
[0];
146 memset(&OutputType
, 0, sizeof(OutputType
));
148 //Initialise requested device
150 pData
= calloc(1, sizeof(DSoundData
));
153 SetALCError(ALC_OUT_OF_MEMORY
);
160 //DirectSound Init code
161 hr
= CoCreateInstance(&CLSID_DirectSound
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IDirectSound
, (LPVOID
*)&pData
->lpDS
);
163 hr
= IDirectSound_Initialize(pData
->lpDS
, NULL
);
165 hr
= IDirectSound_SetCooperativeLevel(pData
->lpDS
, GetForegroundWindow(), DSSCL_PRIORITY
);
168 hr
= IDirectSound_GetSpeakerConfig(pData
->lpDS
, &speakers
);
171 speakers
= DSSPEAKER_CONFIG(speakers
);
172 if(speakers
== DSSPEAKER_MONO
)
174 if(aluBytesFromFormat(device
->Format
) == 1)
175 device
->Format
= AL_FORMAT_MONO8
;
177 device
->Format
= AL_FORMAT_MONO16
;
179 else if(speakers
== DSSPEAKER_STEREO
)
181 if(aluBytesFromFormat(device
->Format
) == 1)
182 device
->Format
= AL_FORMAT_STEREO8
;
184 device
->Format
= AL_FORMAT_STEREO16
;
186 else if(speakers
== DSSPEAKER_QUAD
)
188 if(aluBytesFromFormat(device
->Format
) == 1)
189 device
->Format
= AL_FORMAT_QUAD8
;
191 device
->Format
= AL_FORMAT_QUAD16
;
192 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
193 SPEAKER_FRONT_RIGHT
|
197 else if(speakers
== DSSPEAKER_5POINT1
)
199 if(aluBytesFromFormat(device
->Format
) == 1)
200 device
->Format
= AL_FORMAT_51CHN8
;
202 device
->Format
= AL_FORMAT_51CHN16
;
203 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
204 SPEAKER_FRONT_RIGHT
|
205 SPEAKER_FRONT_CENTER
|
206 SPEAKER_LOW_FREQUENCY
|
210 else if(speakers
== DSSPEAKER_7POINT1
)
212 if(aluBytesFromFormat(device
->Format
) == 1)
213 device
->Format
= AL_FORMAT_71CHN8
;
215 device
->Format
= AL_FORMAT_71CHN16
;
216 OutputType
.dwChannelMask
= SPEAKER_FRONT_LEFT
|
217 SPEAKER_FRONT_RIGHT
|
218 SPEAKER_FRONT_CENTER
|
219 SPEAKER_LOW_FREQUENCY
|
225 device
->FrameSize
= aluBytesFromFormat(device
->Format
) *
226 aluChannelsFromFormat(device
->Format
);
228 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_PCM
;
229 OutputType
.Format
.nChannels
= aluChannelsFromFormat(device
->Format
);
230 OutputType
.Format
.wBitsPerSample
= aluBytesFromFormat(device
->Format
) * 8;
231 OutputType
.Format
.nBlockAlign
= OutputType
.Format
.nChannels
*OutputType
.Format
.wBitsPerSample
/8;
232 OutputType
.Format
.nSamplesPerSec
= device
->Frequency
;
233 OutputType
.Format
.nAvgBytesPerSec
= OutputType
.Format
.nSamplesPerSec
*OutputType
.Format
.nBlockAlign
;
234 OutputType
.Format
.cbSize
= 0;
237 if(OutputType
.Format
.nChannels
> 2)
239 OutputType
.Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
240 OutputType
.Samples
.wValidBitsPerSample
= OutputType
.Format
.wBitsPerSample
;
241 OutputType
.Format
.cbSize
= 22;
242 OutputType
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
248 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
249 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
250 DSBDescription
.dwFlags
=DSBCAPS_PRIMARYBUFFER
;
251 hr
= IDirectSound_CreateSoundBuffer(pData
->lpDS
, &DSBDescription
, &pData
->DSpbuffer
, NULL
);
254 hr
= IDirectSoundBuffer_SetFormat(pData
->DSpbuffer
,&OutputType
.Format
);
259 memset(&DSBDescription
,0,sizeof(DSBUFFERDESC
));
260 DSBDescription
.dwSize
=sizeof(DSBUFFERDESC
);
261 DSBDescription
.dwFlags
=DSBCAPS_GLOBALFOCUS
|DSBCAPS_GETCURRENTPOSITION2
;
262 DSBDescription
.dwBufferBytes
=device
->UpdateFreq
* device
->FrameSize
;
263 DSBDescription
.lpwfxFormat
=&OutputType
.Format
;
264 hr
= IDirectSound_CreateSoundBuffer(pData
->lpDS
, &DSBDescription
, &pData
->DSsbuffer
, NULL
);
268 hr
= IDirectSoundBuffer_Play(pData
->DSsbuffer
, 0, 0, DSBPLAY_LOOPING
);
270 device
->ExtraData
= pData
;
271 pData
->thread
= StartThread(DSoundProc
, device
);
277 if (pData
->DSsbuffer
)
278 IDirectSoundBuffer_Release(pData
->DSsbuffer
);
279 if (pData
->DSpbuffer
)
280 IDirectSoundBuffer_Release(pData
->DSpbuffer
);
282 IDirectSound_Release(pData
->lpDS
);
291 static void DSoundClosePlayback(ALCdevice
*device
)
293 DSoundData
*pData
= device
->ExtraData
;
296 StopThread(pData
->thread
);
298 IDirectSoundBuffer_Release(pData
->DSsbuffer
);
299 if (pData
->DSpbuffer
)
300 IDirectSoundBuffer_Release(pData
->DSpbuffer
);
301 IDirectSound_Release(pData
->lpDS
);
307 device
->ExtraData
= NULL
;
311 static ALCboolean
DSoundOpenCapture(ALCdevice
*pDevice
, const ALCchar
*deviceName
, ALCuint frequency
, ALCenum format
, ALCsizei SampleSize
)
321 static void DSoundCloseCapture(ALCdevice
*pDevice
)
326 static void DSoundStartCapture(ALCdevice
*pDevice
)
331 static void DSoundStopCapture(ALCdevice
*pDevice
)
336 static void DSoundCaptureSamples(ALCdevice
*pDevice
, ALCvoid
*pBuffer
, ALCuint lSamples
)
343 static ALCuint
DSoundAvailableSamples(ALCdevice
*pDevice
)
350 BackendFuncs DSoundFuncs
= {
357 DSoundCaptureSamples
,
358 DSoundAvailableSamples
361 void alcDSoundInit(BackendFuncs
*FuncList
)
363 *FuncList
= DSoundFuncs
;
365 DeviceList
[0] = AppendDeviceList("DirectSound Software");
366 AppendAllDeviceList(DeviceList
[0]);