From d8bde70ab6bdf8d05d84e1a0622e39d65b5ae895 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sun, 22 Dec 2013 21:38:57 +1000 Subject: Add Win32 GAUDIN driver. --- drivers/gaudin/Win32/gaudin_lld.c | 178 +++++++++++++++++++++++++++++++ drivers/gaudin/Win32/gaudin_lld.mk | 5 + drivers/gaudin/Win32/gaudin_lld_config.h | 64 +++++++++++ 3 files changed, 247 insertions(+) create mode 100644 drivers/gaudin/Win32/gaudin_lld.c create mode 100644 drivers/gaudin/Win32/gaudin_lld.mk create mode 100644 drivers/gaudin/Win32/gaudin_lld_config.h (limited to 'drivers/gaudin/Win32') diff --git a/drivers/gaudin/Win32/gaudin_lld.c b/drivers/gaudin/Win32/gaudin_lld.c new file mode 100644 index 00000000..665c89f7 --- /dev/null +++ b/drivers/gaudin/Win32/gaudin_lld.c @@ -0,0 +1,178 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gaudin/Win32/gaudin_lld.c + * @brief GAUDIN - Driver file for Win32. + */ + +#include "gfx.h" + +#if GFX_USE_GAUDIN + +/* Include the driver defines */ +#include "gaudin/lld/gaudin_lld.h" + +#undef Red +#undef Green +#undef Blue +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +static HWAVEIN ah; +static volatile int nUsedBuffers; +static WAVEHDR *pWaveHdrs; +static HANDLE waveInThread; +static DWORD threadID; + +/* +static void PrintWaveErrorMsg(DWORD err, TCHAR * str) +{ + #define BUFFERSIZE 128 + char buffer[BUFFERSIZE]; + + fprintf(stderr, "GAUDIN: ERROR 0x%08X: %s\r\n", err, str); + if (mciGetErrorString(err, &buffer[0], sizeof(buffer))) + fprintf(stderr, "%s\r\n", &buffer[0]); + else + fprintf(stderr, "0x%08X returned!\r\n", err); +} +*/ + +/**************************** waveInProc() ******************************* + * We don't use CALLBACK_FUNCTION because it is restricted to calling only + * a few particular Windows functions, namely some of the time functions, + * and a few of the Low Level MIDI API. If you violate this rule, your app can + * hang inside of the callback). One of the Windows API that a callback can't + * call is waveInAddBuffer() which is what we need to use whenever we receive a + * MM_WIM_DATA. My callback would need to defer that job to another thread + * anyway, so instead just use CALLBACK_THREAD here instead. + *************************************************************************/ + +DWORD WINAPI waveInProc(LPVOID arg) { + MSG msg; + bool_t isRecording; + (void) arg; + + isRecording = FALSE; + while (GetMessage(&msg, 0, 0, 0)) { + switch (msg.message) { + case MM_WIM_DATA: + GAUDIN_ISR_CompleteI((audin_sample_t *)((WAVEHDR *)msg.lParam)->lpData, ((WAVEHDR *)msg.lParam)->dwBytesRecorded/sizeof(audin_sample_t)); + + /* Are we still recording? */ + if (isRecording) { + /* Yes. Now we need to requeue this buffer so the driver can use it for another block of audio + * data. NOTE: We shouldn't need to waveInPrepareHeader() a WAVEHDR that has already been prepared once. + * Note: We are assuming here that both the application can still access the buffer while + * it is on the queue. + */ + waveInAddBuffer(ah, (WAVEHDR *)msg.lParam, sizeof(WAVEHDR)); + + } else { + /* We aren't recording, so another WAVEHDR has been returned to us after recording has stopped. + * When we get all of them back, DoneAll will be equal to how many WAVEHDRs we queued + */ + nUsedBuffers--; + waveInUnprepareHeader(ah, (WAVEHDR *)msg.lParam, sizeof(WAVEHDR)); + } + + break; + + case MM_WIM_OPEN: + isRecording = TRUE; + break; + + case MM_WIM_CLOSE: + isRecording = FALSE; + break; + } + } + return 0; +} + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +void gaudin_lld_init(const gaudin_params *paud) { +// uint16_t channel; +// uint32_t frequency; +// audin_sample_t *buffer; +// size_t bufcount; +// size_t samplesPerEvent; + WAVEFORMATEX wfx; + size_t spaceleft; + audin_sample_t *p; + WAVEHDR *phdr; + size_t nBuffers; + size_t sz; + + if (!waveInThread) { + if (!(waveInThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveInProc, 0, 0, &threadID))) { + fprintf(stderr, "GAUDIN: Can't create WAVE recording thread\n"); + return; + } + CloseHandle(waveInThread); + } + + nUsedBuffers = 0; + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = paud->channel == GAUDIN_STEREO ? 2 : 1; + wfx.nSamplesPerSec = paud->frequency; + wfx.nBlockAlign = wfx.nChannels * sizeof(audin_sample_t); + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + wfx.wBitsPerSample = sizeof(audin_sample_t) * 8; + wfx.cbSize = 0; + + if (waveInOpen(&ah, WAVE_MAPPER, &wfx, (DWORD_PTR)threadID, (DWORD_PTR)paud, CALLBACK_THREAD)) { + fprintf(stderr, "GAUDIN: Can't open WAVE recording device\n"); + return; + } + + /* We need to allocate a wave header for each buffer */ + nBuffers = (paud->bufcount + paud->samplesPerEvent - 1) / paud->samplesPerEvent; + if (!(pWaveHdrs = (WAVEHDR *)gfxAlloc(nBuffers * sizeof(WAVEHDR)))) { + fprintf(stderr, "GAUDIN: Buffer header allocation failed\n"); + return; + } + + /* Prepare each buffer and send to the wavein device */ + spaceleft = paud->bufcount; + for(p = paud->buffer, phdr = pWaveHdrs, spaceleft = paud->bufcount; spaceleft; p += sz, phdr++, spaceleft -= sz) { + sz = spaceleft > paud->samplesPerEvent ? paud->samplesPerEvent : spaceleft; + phdr->dwBufferLength = sz * sizeof(audin_sample_t); + phdr->lpData = (LPSTR)p; + phdr->dwFlags = 0; + if (!waveInPrepareHeader(ah, phdr, sizeof(WAVEHDR)) + && !waveInAddBuffer(ah, phdr, sizeof(WAVEHDR))) + nUsedBuffers++; + else + fprintf(stderr, "GAUDIN: Buffer prepare failed\n"); + } + if (!nUsedBuffers) + fprintf(stderr, "GAUDIN: Failed to prepare any buffers\n"); +} + +void gadc_lld_start(void) { + if (nUsedBuffers) + waveInStart(ah); +} + +void gadc_lld_stop(void) { + waveInReset(ah); + while(nUsedBuffers) Sleep(1); + if (pWaveHdrs) { + gfxFree(pWaveHdrs); + pWaveHdrs = 0; + } +} + +#endif /* GFX_USE_GAUDIN */ diff --git a/drivers/gaudin/Win32/gaudin_lld.mk b/drivers/gaudin/Win32/gaudin_lld.mk new file mode 100644 index 00000000..3a822971 --- /dev/null +++ b/drivers/gaudin/Win32/gaudin_lld.mk @@ -0,0 +1,5 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/gaudin/Win32/gaudin_lld.c + +# Required include directories +GFXINC += $(GFXLIB)/drivers/gaudin/Win32 diff --git a/drivers/gaudin/Win32/gaudin_lld_config.h b/drivers/gaudin/Win32/gaudin_lld_config.h new file mode 100644 index 00000000..804d2fc4 --- /dev/null +++ b/drivers/gaudin/Win32/gaudin_lld_config.h @@ -0,0 +1,64 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/multiple/Win32/gaudin_lld_config.h + * @brief GAUDIN Driver config file. + * + * @addtogroup GAUDIN + * @{ + */ + +#ifndef GAUDIN_LLD_CONFIG_H +#define GAUDIN_LLD_CONFIG_H + +#if GFX_USE_GAUDIN + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +/** + * @brief The audio input sample type + */ +//typedef uint8_t audin_sample_t; +typedef int16_t audin_sample_t; + +/** + * @brief The maximum sample frequency supported by this audio device + */ +#define GAUDIN_MAX_SAMPLE_FREQUENCY 44100 + +/** + * @brief The number of bits in a sample + */ +//#define GAUDIN_BITS_PER_SAMPLE 8 +#define GAUDIN_BITS_PER_SAMPLE 16 + +/** + * @brief The format of an audio sample + */ +//#define GAUDIN_SAMPLE_FORMAT ARRAY_DATA_8BITUNSIGNED +#define GAUDIN_SAMPLE_FORMAT ARRAY_DATA_16BITSIGNED + +/** + * @brief The number of audio channels supported by this driver + */ +#define GAUDIN_NUM_CHANNELS 2 + +/** + * @brief The list of audio channels and their uses + * @{ + */ +#define GAUDIN_MONO 0 +#define GAUDIN_STEREO 1 +/** @} */ + +#endif /* GFX_USE_GAUDIN */ + +#endif /* GAUDIN_LLD_CONFIG_H */ +/** @} */ -- cgit v1.2.3