Share the interpolation functions and use them in the reverb effect
[openal-soft.git] / Alc / winmm.c
blob5410105810fc2c8c66edcd8319196b400aad52ba
1 /**
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
21 #include "config.h"
23 #define _WIN32_WINNT 0x0500
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <memory.h>
28 #include <windows.h>
29 #include <mmsystem.h>
31 #include "alMain.h"
32 #include "AL/al.h"
33 #include "AL/alc.h"
36 typedef struct {
37 // MMSYSTEM Device
38 volatile ALboolean bWaveShutdown;
39 HANDLE hWaveHdrEvent;
40 HANDLE hWaveThreadEvent;
41 HANDLE hWaveThread;
42 DWORD ulWaveThreadID;
43 ALint lWaveBuffersCommitted;
44 WAVEHDR WaveBuffer[4];
46 union {
47 HWAVEIN In;
48 } hWaveHandle;
50 RingBuffer *pRing;
51 } WinMMData;
54 static ALCchar **CaptureDeviceList;
55 static ALuint NumCaptureDevices;
57 static void ProbeCaptureDevices(void)
59 ALuint i;
61 for(i = 0;i < NumCaptureDevices;i++)
62 free(CaptureDeviceList[i]);
64 NumCaptureDevices = waveInGetNumDevs();
65 CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices);
66 for(i = 0;i < NumCaptureDevices;i++)
68 WAVEINCAPS WaveInCaps;
70 CaptureDeviceList[i] = NULL;
71 if(waveInGetDevCaps(i, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
73 char name[1024];
74 ALuint count, j;
76 count = 0;
77 do {
78 if(count == 0)
79 snprintf(name, sizeof(name), "%s via WaveIn", WaveInCaps.szPname);
80 else
81 snprintf(name, sizeof(name), "%s #%d via WaveIn", WaveInCaps.szPname, count+1);
82 count++;
84 for(j = 0;j < i;j++)
86 if(strcmp(name, CaptureDeviceList[j]) == 0)
87 break;
89 } while(j != i);
91 CaptureDeviceList[i] = strdup(name);
98 WaveInProc
100 Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and
101 returns to the application (with more data)
103 static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
105 ALCdevice *pDevice = (ALCdevice*)dwInstance;
106 WinMMData *pData = pDevice->ExtraData;
108 (void)hDevice;
109 (void)dwParam2;
111 if(uMsg != WIM_DATA)
112 return;
114 // Decrement number of buffers in use
115 pData->lWaveBuffersCommitted--;
117 if(pData->bWaveShutdown == AL_FALSE)
119 // Notify Wave Processor Thread that a Wave Header has returned
120 PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1);
122 else
124 if(pData->lWaveBuffersCommitted == 0)
126 // Signal Wave Buffers Returned event
127 if(pData->hWaveHdrEvent)
128 SetEvent(pData->hWaveHdrEvent);
130 // Post 'Quit' Message to WaveIn Processor Thread
131 PostThreadMessage(pData->ulWaveThreadID,WM_QUIT,0,0);
137 CaptureThreadProc
139 Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new
140 audio data.
142 static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)
144 ALCdevice *pDevice = (ALCdevice*)lpParameter;
145 WinMMData *pData = pDevice->ExtraData;
146 LPWAVEHDR pWaveHdr;
147 ALuint FrameSize;
148 MSG msg;
150 FrameSize = aluFrameSizeFromFormat(pDevice->Format);
152 while(GetMessage(&msg, NULL, 0, 0))
154 if(msg.message != WIM_DATA || pData->bWaveShutdown)
155 continue;
157 pWaveHdr = ((LPWAVEHDR)msg.lParam);
159 WriteRingBuffer(pData->pRing, (ALubyte*)pWaveHdr->lpData,
160 pWaveHdr->dwBytesRecorded/FrameSize);
162 // Send buffer back to capture more data
163 waveInAddBuffer(pData->hWaveHandle.In,pWaveHdr,sizeof(WAVEHDR));
164 pData->lWaveBuffersCommitted++;
167 // Signal Wave Thread completed event
168 if(pData->hWaveThreadEvent)
169 SetEvent(pData->hWaveThreadEvent);
171 ExitThread(0);
173 return 0;
177 static ALCboolean WinMMOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
179 (void)device;
180 (void)deviceName;
181 return ALC_FALSE;
184 static void WinMMClosePlayback(ALCdevice *device)
186 (void)device;
189 static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
191 WAVEFORMATEX wfexCaptureFormat;
192 DWORD ulCapturedDataSize;
193 WinMMData *pData = NULL;
194 ALint lDeviceID = 0;
195 ALbyte *BufferData;
196 ALint lBufferSize;
197 MMRESULT res;
198 ALuint i;
200 if(!CaptureDeviceList)
201 ProbeCaptureDevices();
203 // Find the Device ID matching the deviceName if valid
204 if(deviceName)
206 for(i = 0;i < NumCaptureDevices;i++)
208 if(CaptureDeviceList[i] &&
209 strcmp(deviceName, CaptureDeviceList[i]) == 0)
211 lDeviceID = i;
212 break;
216 else
218 for(i = 0;i < NumCaptureDevices;i++)
220 if(CaptureDeviceList[i])
222 lDeviceID = i;
223 break;
227 if(i == NumCaptureDevices)
228 return ALC_FALSE;
230 pData = calloc(1, sizeof(*pData));
231 if(!pData)
233 alcSetError(pDevice, ALC_OUT_OF_MEMORY);
234 return ALC_FALSE;
237 memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX));
238 wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM;
239 wfexCaptureFormat.nChannels = aluChannelsFromFormat(pDevice->Format);
240 wfexCaptureFormat.wBitsPerSample = aluBytesFromFormat(pDevice->Format) * 8;
241 wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *
242 wfexCaptureFormat.nChannels / 8;
243 wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency;
244 wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *
245 wfexCaptureFormat.nBlockAlign;
246 wfexCaptureFormat.cbSize = 0;
248 if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
250 AL_PRINT("waveInOpen failed: %u\n", res);
251 goto failure;
254 pData->hWaveHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInAllHeadersReturned");
255 pData->hWaveThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInThreadDestroyed");
256 if(pData->hWaveHdrEvent == NULL || pData->hWaveThreadEvent == NULL)
258 AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
259 goto failure;
262 // Allocate circular memory buffer for the captured audio
263 ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates;
265 // Make sure circular buffer is at least 100ms in size
266 if(ulCapturedDataSize < (wfexCaptureFormat.nSamplesPerSec / 10))
267 ulCapturedDataSize = wfexCaptureFormat.nSamplesPerSec / 10;
269 pData->pRing = CreateRingBuffer(wfexCaptureFormat.nBlockAlign, ulCapturedDataSize);
270 if(!pData->pRing)
271 goto failure;
273 pData->lWaveBuffersCommitted = 0;
275 // Create 4 Buffers of 50ms each
276 lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20;
277 lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign);
279 BufferData = calloc(4, lBufferSize);
280 if(!BufferData)
281 goto failure;
283 for(i = 0;i < 4;i++)
285 memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
286 pData->WaveBuffer[i].dwBufferLength = lBufferSize;
287 pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
288 (pData->WaveBuffer[i-1].lpData +
289 pData->WaveBuffer[i-1].dwBufferLength));
290 pData->WaveBuffer[i].dwFlags = 0;
291 pData->WaveBuffer[i].dwLoops = 0;
292 waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
293 waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
294 pData->lWaveBuffersCommitted++;
297 pDevice->ExtraData = pData;
299 pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID);
300 if (pData->hWaveThread == NULL)
301 goto failure;
303 pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]);
304 return ALC_TRUE;
306 failure:
307 if(pData->hWaveThread)
308 CloseHandle(pData->hWaveThread);
310 for(i = 0;i < 4;i++)
312 if(pData->WaveBuffer[i].lpData)
314 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
315 if(i == 0)
316 free(pData->WaveBuffer[i].lpData);
320 if(pData->pRing)
321 DestroyRingBuffer(pData->pRing);
323 if(pData->hWaveThreadEvent)
324 CloseHandle(pData->hWaveThreadEvent);
325 if(pData->hWaveHdrEvent)
326 CloseHandle(pData->hWaveHdrEvent);
328 if(pData->hWaveHandle.In)
329 waveInClose(pData->hWaveHandle.In);
331 free(pData);
332 pDevice->ExtraData = NULL;
333 return ALC_FALSE;
336 static void WinMMCloseCapture(ALCdevice *pDevice)
338 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
339 int i;
341 // Call waveOutReset to shutdown wave device
342 pData->bWaveShutdown = AL_TRUE;
343 waveInReset(pData->hWaveHandle.In);
345 // Wait for signal that all Wave Buffers have returned
346 WaitForSingleObjectEx(pData->hWaveHdrEvent, 5000, FALSE);
348 // Wait for signal that Wave Thread has been destroyed
349 WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
351 CloseHandle(pData->hWaveThread);
352 pData->hWaveThread = 0;
354 // Release the wave buffers
355 for(i = 0;i < 4;i++)
357 waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
358 if(i == 0)
359 free(pData->WaveBuffer[i].lpData);
360 pData->WaveBuffer[i].lpData = NULL;
363 DestroyRingBuffer(pData->pRing);
364 pData->pRing = NULL;
366 // Close the Wave device
367 CloseHandle(pData->hWaveThreadEvent);
368 pData->hWaveThreadEvent = 0;
370 CloseHandle(pData->hWaveHdrEvent);
371 pData->hWaveHdrEvent = 0;
373 waveInClose(pData->hWaveHandle.In);
374 pData->hWaveHandle.In = 0;
376 free(pData);
377 pDevice->ExtraData = NULL;
380 static void WinMMStartCapture(ALCdevice *pDevice)
382 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
383 waveInStart(pData->hWaveHandle.In);
386 static void WinMMStopCapture(ALCdevice *pDevice)
388 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
389 waveInStop(pData->hWaveHandle.In);
392 static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
394 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
395 return RingBufferSize(pData->pRing);
398 static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
400 WinMMData *pData = (WinMMData*)pDevice->ExtraData;
402 if(WinMMAvailableSamples(pDevice) >= lSamples)
403 ReadRingBuffer(pData->pRing, pBuffer, lSamples);
404 else
405 alcSetError(pDevice, ALC_INVALID_VALUE);
409 static BackendFuncs WinMMFuncs = {
410 WinMMOpenPlayback,
411 WinMMClosePlayback,
412 NULL,
413 NULL,
414 WinMMOpenCapture,
415 WinMMCloseCapture,
416 WinMMStartCapture,
417 WinMMStopCapture,
418 WinMMCaptureSamples,
419 WinMMAvailableSamples
422 void alcWinMMInit(BackendFuncs *FuncList)
424 *FuncList = WinMMFuncs;
427 void alcWinMMDeinit()
429 ALuint lLoop;
431 for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
432 free(CaptureDeviceList[lLoop]);
433 free(CaptureDeviceList);
434 CaptureDeviceList = NULL;
436 NumCaptureDevices = 0;
439 void alcWinMMProbe(int type)
441 ALuint i;
443 if(type == CAPTURE_DEVICE_PROBE)
445 ProbeCaptureDevices();
446 for(i = 0;i < NumCaptureDevices;i++)
448 if(CaptureDeviceList[i])
449 AppendCaptureDeviceList(CaptureDeviceList[i]);