diff options
author | inmarket <andrewh@inmarket.com.au> | 2014-03-11 17:13:31 +1000 |
---|---|---|
committer | inmarket <andrewh@inmarket.com.au> | 2014-03-11 17:13:31 +1000 |
commit | ea5a1b849df6e5085a92957ad387f9e653674415 (patch) | |
tree | 72ede5ed78263a6fdba25039398b5c2a55bd1d3a /drivers | |
parent | 944c33cbff5f2cfb1c80f48193aa2161574864fd (diff) | |
download | uGFX-ea5a1b849df6e5085a92957ad387f9e653674415.tar.gz uGFX-ea5a1b849df6e5085a92957ad387f9e653674415.tar.bz2 uGFX-ea5a1b849df6e5085a92957ad387f9e653674415.zip |
Combine GAUDIN and GAUDOUT into a single GAUDIO module.
Simplify GAUDIN (now GAUDIO RECORD) api.
Update audio demo's to match.
Port Win32 driver to new audio api.
Diffstat (limited to 'drivers')
16 files changed, 359 insertions, 357 deletions
diff --git a/drivers/audio/Win32/driver.mk b/drivers/audio/Win32/driver.mk deleted file mode 100644 index 6f4ef084..00000000 --- a/drivers/audio/Win32/driver.mk +++ /dev/null @@ -1,6 +0,0 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/audio/Win32/gaudin_lld.c \ - $(GFXLIB)/drivers/audio/Win32/gaudout_lld.c - -# Required include directories -GFXINC += $(GFXLIB)/drivers/audio/Win32 diff --git a/drivers/audio/Win32/gaudin_lld.c b/drivers/audio/Win32/gaudin_lld.c deleted file mode 100644 index 2c8431cf..00000000 --- a/drivers/audio/Win32/gaudin_lld.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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/audio/Win32/gaudin_lld.c - * @brief GAUDIN - Driver file for Win32. - */ - -#include "gfx.h" - -#if GFX_USE_GAUDIN - -/* Include the driver defines */ -#include "src/gaudin/driver.h" - -#undef Red -#undef Green -#undef Blue -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <stdio.h> -#include <mmsystem.h> - -static HWAVEIN ah; -static volatile int nQueuedBuffers; -static bool_t isClosing; -static WAVEHDR *pWaveHdrs; -static HANDLE waveThread; -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); -} -*/ - -/**************************** waveProc() ******************************* - * 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. - *************************************************************************/ - -static DWORD WINAPI waveProc(LPVOID arg) { - MSG msg; - (void) arg; - - 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 closing? */ - if (isClosing) { - /* Yes. We aren't recording, so another WAVEHDR has been returned to us after recording has stopped. - * When we get all of them back, things can be cleaned up - */ - nQueuedBuffers--; - waveInUnprepareHeader(ah, (WAVEHDR *)msg.lParam, sizeof(WAVEHDR)); - } else { - /* No. 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)); - } - - break; - } - } - return 0; -} - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -void gaudin_lld_deinit(void) { - if (ah) { - isClosing = TRUE; - waveInReset(ah); - while(nQueuedBuffers) Sleep(1); - waveInClose(ah); - ah = 0; - if (pWaveHdrs) gfxFree(pWaveHdrs); - pWaveHdrs = 0; - isClosing = FALSE; - } -} - -void gaudin_lld_init(const gaudin_params *paud) { - WAVEFORMATEX wfx; - size_t spaceleft; - audin_sample_t *p; - WAVEHDR *phdr; - size_t nBuffers; - size_t sz; - - if (!waveThread) { - if (!(waveThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveProc, 0, 0, &threadID))) { - fprintf(stderr, "GAUDIN/GAUDOUT: Can't create WAVE recording thread\n"); - return; - } - CloseHandle(waveThread); - } - - gaudin_lld_deinit(); - - 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 = 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))) - nQueuedBuffers++; - else - fprintf(stderr, "GAUDIN: Buffer prepare failed\n"); - } - if (!nQueuedBuffers) - fprintf(stderr, "GAUDIN: Failed to prepare any buffers\n"); -} - -void gaudin_lld_start(void) { - waveInStart(ah); -} - -void gaudin_lld_stop(void) { - waveInStop(ah); -} - -#endif /* GFX_USE_GAUDIN */ diff --git a/drivers/audio/Win32/gaudin_lld_config.h b/drivers/audio/Win32/gaudin_lld_config.h deleted file mode 100644 index 78ddffaa..00000000 --- a/drivers/audio/Win32/gaudin_lld_config.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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/audio/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 */ -/** @} */ diff --git a/drivers/audio/Win32/readme.txt b/drivers/audio/Win32/readme.txt deleted file mode 100644 index 784f0a89..00000000 --- a/drivers/audio/Win32/readme.txt +++ /dev/null @@ -1,10 +0,0 @@ -This driver uses the Win32 audio system to provide GAUDIN and GAUDOUT channels. - -For GAUDIN - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. -For GAUDOUT - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. - -For stereo, the samples are interleaved. Remember to allocate enough space for two samples per -sample period. - -This is a simple driver that makes no changes to the mixer so set up the audio mixer using -the windows control panel audio mixer before starting recording/playback. diff --git a/drivers/audio/gadc/driver.mk b/drivers/audio/gadc/driver.mk deleted file mode 100644 index b991ede8..00000000 --- a/drivers/audio/gadc/driver.mk +++ /dev/null @@ -1,5 +0,0 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.c - -# Required include directories -GFXINC += $(GFXLIB)/drivers/audio/gadc diff --git a/drivers/gaudio/Win32/driver.mk b/drivers/gaudio/Win32/driver.mk new file mode 100644 index 00000000..1ea338d5 --- /dev/null +++ b/drivers/gaudio/Win32/driver.mk @@ -0,0 +1,6 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/gaudio/Win32/gaudio_record_lld.c \ + $(GFXLIB)/drivers/gaudio/Win32/gaudio_play_lld.c + +# Required include directories +GFXINC += $(GFXLIB)/drivers/gaudio/Win32 diff --git a/drivers/audio/Win32/gaudout_lld_config.h b/drivers/gaudio/Win32/gaudio_play_config.h index 907d44c6..4013e91f 100644 --- a/drivers/audio/Win32/gaudout_lld_config.h +++ b/drivers/gaudio/Win32/gaudio_play_config.h @@ -6,17 +6,17 @@ */ /** - * @file drivers/audio/Win32/gaudout_lld_config.h - * @brief GAUDOUT Driver config file. + * @file drivers/gaudio/Win32/gaudio_play_config.h + * @brief GAUDIO Play Driver config file. * - * @addtogroup GAUDOUT + * @addtogroup GAUDIO * @{ */ -#ifndef GAUDOUT_LLD_CONFIG_H -#define GAUDIN_LLD_CONFIG_H +#ifndef GAUDIO_PLAY_CONFIG_H +#define GAUDIO_PLAY_CONFIG_H -#if GFX_USE_GAUDOUT +#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY /*===========================================================================*/ /* Driver hardware support. */ @@ -25,39 +25,39 @@ /** * @brief The maximum sample frequency supported by this audio device */ -#define GAUDOUT_MAX_SAMPLE_FREQUENCY 44100 +#define GAUDIO_PLAY_MAX_SAMPLE_FREQUENCY 44100 /** * @brief The number of audio formats supported by this driver */ -#define GAUDOUT_NUM_FORMATS 2 +#define GAUDIO_PLAY_NUM_FORMATS 2 /** * @brief The available audio sample formats in order of preference */ -#define GAUDOUT_FORMAT1 ARRAY_DATA_16BITSIGNED -#define GAUDOUT_FORMAT2 ARRAY_DATA_8BITUNSIGNED +#define GAUDIO_PLAY_FORMAT1 ARRAY_DATA_16BITSIGNED +#define GAUDIO_PLAY_FORMAT2 ARRAY_DATA_8BITUNSIGNED /** * @brief The number of audio channels supported by this driver */ -#define GAUDOUT_NUM_CHANNELS 2 +#define GAUDIO_PLAY_NUM_CHANNELS 2 /** * @brief Whether each channel is mono or stereo */ -#define GAUDOUT_CHANNEL0_STEREO FALSE -#define GAUDOUT_CHANNEL1_STEREO TRUE +#define GAUDIO_PLAY_CHANNEL0_IS_STEREO FALSE +#define GAUDIO_PLAY_CHANNEL1_IS_STEREO TRUE /** * @brief The list of audio channel names and their uses * @{ */ -#define GAUDOUT_MONO 0 -#define GAUDOUT_STEREO 1 +#define GAUDIO_PLAY_MONO 0 +#define GAUDIO_PLAY_STEREO 1 /** @} */ -#endif /* GFX_USE_GAUDOUT */ +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ -#endif /* GAUDOUT_LLD_CONFIG_H */ +#endif /* GAUDIO_PLAY_CONFIG_H */ /** @} */ diff --git a/drivers/audio/Win32/gaudout_lld.c b/drivers/gaudio/Win32/gaudio_play_lld.c index 4fa6d605..6b4f2dab 100644 --- a/drivers/audio/Win32/gaudout_lld.c +++ b/drivers/gaudio/Win32/gaudio_play_lld.c @@ -6,16 +6,16 @@ */ /** - * @file drivers/audio/Win32/gaudout_lld.c - * @brief GAUDOUT - Driver file for Win32. + * @file drivers/gaudio/Win32/gaudio_play_lld.c + * @brief GAUDIO - Play Driver file for Win32. */ #include "gfx.h" -#if GFX_USE_GAUDOUT +#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY /* Include the driver defines */ -#include "src/gaudout/driver.h" +#include "src/gaudio/driver_play.h" #undef Red #undef Green @@ -36,20 +36,6 @@ static WAVEHDR WaveHdrs[MAX_WAVE_HEADERS]; static HANDLE waveThread; static DWORD threadID; -/* -static void PrintWaveErrorMsg(DWORD err, TCHAR * str) -{ - #define BUFFERSIZE 128 - char buffer[BUFFERSIZE]; - - fprintf(stderr, "GAUDOUT: 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); -} -*/ - /**************************** waveProc() ******************************* * We don't use CALLBACK_FUNCTION because it is restricted to calling only * a few particular Windows functions, namely some of the time functions, @@ -65,7 +51,9 @@ static bool_t senddata(WAVEHDR *pwh) { // Get the next data block to send gfxSystemLock(); - paud = gaudoutGetDataBlockI(); + paud = gaudioPlayGetDataBlockI(); + if (!paud && !nQueuedBuffers) + gaudioPlayDoneI(); gfxSystemUnlock(); if (!paud) return FALSE; @@ -77,13 +65,13 @@ static bool_t senddata(WAVEHDR *pwh) { pwh->dwFlags = 0; pwh->dwLoops = 0; if (waveOutPrepareHeader(ah, pwh, sizeof(WAVEHDR))) { - fprintf(stderr, "GAUDOUT: Failed to prepare a buffer"); + fprintf(stderr, "GAUDIO: Failed to prepare a play buffer"); exit(-1); } // Send it to windows if (waveOutWrite(ah, pwh, sizeof(WAVEHDR))) { - fprintf(stderr, "GAUDOUT: Failed to write the buffer"); + fprintf(stderr, "GAUDIO: Failed to write the play buffer"); exit(-1); } @@ -106,18 +94,25 @@ static DWORD WINAPI waveProc(LPVOID arg) { // Give the buffer back to the Audio Free List gfxSystemLock(); - gaudoutReleaseDataBlockI((GAudioData *)pwh->dwUser); + gaudioPlayReleaseDataBlockI((GAudioData *)pwh->dwUser); gfxSystemUnlock(); pwh->lpData = 0; nQueuedBuffers--; - // Try and get a new block - if ((!isRunning || !senddata(pwh)) && !nQueuedBuffers) { - gfxSystemLock(); - gaudoutDoneI(); - gfxSystemUnlock(); + // Are we stopping? + if (!isRunning) { + // Have we finished yet? + if (!nQueuedBuffers) { + gfxSystemLock(); + gaudioPlayDoneI(); + gfxSystemUnlock(); + } + break; } - break; + + // Try and get a new block + senddata(pwh); + break; } } return 0; @@ -127,17 +122,7 @@ static DWORD WINAPI waveProc(LPVOID arg) { /* External declarations. */ /*===========================================================================*/ -void gaudout_lld_deinit() { - if (ah) { - isRunning = FALSE; - waveOutReset(ah); - while(nQueuedBuffers) Sleep(1); - waveOutClose(ah); - ah = 0; - } -} - -bool_t gaudout_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { +bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { WAVEFORMATEX wfx; if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_16BITSIGNED) @@ -145,40 +130,41 @@ bool_t gaudout_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat fo if (!waveThread) { if (!(waveThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveProc, 0, 0, &threadID))) { - fprintf(stderr, "GAUDOUT: Can't create WAVE play-back thread\n"); + fprintf(stderr, "GAUDIO: Can't create WAVE play-back thread\n"); exit(-1); } CloseHandle(waveThread); } wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = channel == GAUDOUT_STEREO ? 2 : 1; + wfx.nChannels = channel == GAUDIO_PLAY_STEREO ? 2 : 1; wfx.nSamplesPerSec = frequency; wfx.nBlockAlign = wfx.nChannels * (format == ARRAY_DATA_8BITUNSIGNED ? 1 : 2); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.wBitsPerSample = (format == ARRAY_DATA_8BITUNSIGNED ? 8 : 16); wfx.cbSize = 0; + if (ah) { + waveOutClose(ah); + ah = 0; + } if (waveOutOpen(&ah, WAVE_MAPPER, &wfx, (DWORD_PTR)threadID, 0, CALLBACK_THREAD)) { - fprintf(stderr, "GAUDOUT: Can't open WAVE play-back device\n"); + fprintf(stderr, "GAUDIO: Can't open WAVE play-back device\n"); exit(-1); } return TRUE; } -bool_t gaudout_lld_set_volume(uint8_t vol) { +bool_t gaudio_play_lld_set_volume(uint8_t vol) { if (!ah) return FALSE; return waveOutSetVolume(ah, (((uint16_t)vol)<<8)|vol) != 0; } -void gaudout_lld_start(void) { +void gaudio_play_lld_start(void) { WAVEHDR *pwh; - if (!ah) - return; - isRunning = TRUE; while (nQueuedBuffers < MAX_WAVE_HEADERS) { // Find the empty one - there will always be at least one. @@ -190,10 +176,10 @@ void gaudout_lld_start(void) { } } -void gaudout_lld_stop(void) { +void gaudio_play_lld_stop(void) { isRunning = FALSE; - if (ah) - waveOutReset(ah); + waveOutReset(ah); + while(nQueuedBuffers) Sleep(1); } -#endif /* GFX_USE_GAUDOUT */ +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ diff --git a/drivers/gaudio/Win32/gaudio_record_config.h b/drivers/gaudio/Win32/gaudio_record_config.h new file mode 100644 index 00000000..4d952e1d --- /dev/null +++ b/drivers/gaudio/Win32/gaudio_record_config.h @@ -0,0 +1,63 @@ +/* + * 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/gaudio/Win32/gaudio_record_config.h + * @brief GAUDIO Record Driver config file. + * + * @addtogroup GAUDIO + * @{ + */ + +#ifndef GAUDIO_RECORD_CONFIG_H +#define GAUDIO_RECORD_CONFIG_H + +#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +/** + * @brief The maximum sample frequency supported by this audio device + */ +#define GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY 44100 + +/** + * @brief The number of audio formats supported by this driver + */ +#define GAUDIO_RECORD_NUM_FORMATS 2 + +/** + * @brief The available audio sample formats in order of preference + */ +#define GAUDIO_RECORD_FORMAT1 ARRAY_DATA_16BITSIGNED +#define GAUDIO_RECORD_FORMAT2 ARRAY_DATA_8BITUNSIGNED + +/** + * @brief The number of audio channels supported by this driver + */ +#define GAUDIO_RECORD_NUM_CHANNELS 2 + +/** + * @brief Whether each channel is mono or stereo + */ +#define GAUDIO_RECORD_CHANNEL0_IS_STEREO FALSE +#define GAUDIO_RECORD_CHANNEL1_IS_STEREO TRUE + +/** + * @brief The list of audio channels and their uses + * @{ + */ +#define GAUDIO_RECORD_MONO 0 +#define GAUDIO_RECORD_STEREO 1 +/** @} */ + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ + +#endif /* GAUDIO_RECORD_CONFIG_H */ +/** @} */ diff --git a/drivers/gaudio/Win32/gaudio_record_lld.c b/drivers/gaudio/Win32/gaudio_record_lld.c new file mode 100644 index 00000000..259707e3 --- /dev/null +++ b/drivers/gaudio/Win32/gaudio_record_lld.c @@ -0,0 +1,187 @@ +/* + * 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/gaudio/Win32/gaudio_record_lld.c + * @brief GAUDIO - Record Driver file for Win32. + */ + +#include "gfx.h" + +#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD + +/* Include the driver defines */ +#include "src/gaudio/driver_record.h" + +#undef Red +#undef Green +#undef Blue +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <stdio.h> +#include <mmsystem.h> + +#define MAX_WAVE_HEADERS 2 // Larger numbers enable more buffering which is good for ensuring + // there are no skips due to data not being available, however larger + // numbers of buffers chews buffers on the free-list. + +static HWAVEIN ah = 0; +static volatile int nQueuedBuffers; +static bool_t isRunning; +static WAVEHDR WaveHdrs[MAX_WAVE_HEADERS]; +static HANDLE waveThread; +static DWORD threadID; + +/**************************** waveProc() ******************************* + * 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. + *************************************************************************/ + +static bool_t getbuffer(WAVEHDR *pwh) { + GAudioData *paud; + + // Get the next data block to send + gfxSystemLock(); + paud = gaudioRecordGetFreeBlockI(); + if (!paud && !nQueuedBuffers) + gaudioRecordDoneI(); + gfxSystemUnlock(); + if (!paud) + return FALSE; + + // Prepare the wave header for Windows + pwh->dwUser = (DWORD_PTR)paud; + pwh->lpData = (LPSTR)(paud+1); // The data is on the end of the structure + pwh->dwBufferLength = paud->size; + pwh->dwFlags = 0; + if (waveInPrepareHeader(ah, pwh, sizeof(WAVEHDR))) { + fprintf(stderr, "GAUDIO: Failed to prepare a record buffer"); + exit(-1); + } + + // Send it to windows + if (waveInAddBuffer(ah, pwh, sizeof(WAVEHDR))) { + fprintf(stderr, "GAUDIO: Failed to add the record buffer"); + exit(-1); + } + + nQueuedBuffers++; + return TRUE; +} + +static DWORD WINAPI waveProc(LPVOID arg) { + MSG msg; + WAVEHDR *pwh; + GAudioData *paud; + (void) arg; + + while (GetMessage(&msg, 0, 0, 0)) { + switch (msg.message) { + case MM_WIM_DATA: + pwh = (WAVEHDR *)msg.lParam; + + // Windows - Let go! + waveInUnprepareHeader(ah, pwh, sizeof(WAVEHDR)); + + // Save the buffer in the audio record list + paud = (GAudioData *)pwh->dwUser; + paud->len = pwh->dwBytesRecorded; + gfxSystemLock(); + gaudioRecordSaveDataBlockI(paud); + gfxSystemUnlock(); + pwh->lpData = 0; + nQueuedBuffers--; + + // Are we stopping? + if (!isRunning) { + // Have we finished yet? + if (!nQueuedBuffers) { + gfxSystemLock(); + gaudioRecordDoneI(); + gfxSystemUnlock(); + } + break; + } + + // Try and get a new block + getbuffer(pwh); + break; + } + } + return 0; +} + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +bool_t gaudio_record_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { + WAVEFORMATEX wfx; + + if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_16BITSIGNED) + return FALSE; + + if (!waveThread) { + if (!(waveThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveProc, 0, 0, &threadID))) { + fprintf(stderr, "GAUDIO: Can't create WAVE recording thread\n"); + exit(-1); + } + CloseHandle(waveThread); + } + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = channel == GAUDIO_RECORD_STEREO ? 2 : 1; + wfx.nSamplesPerSec = frequency; + wfx.nBlockAlign = wfx.nChannels * (format == ARRAY_DATA_8BITUNSIGNED ? 1 : 2); + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + wfx.wBitsPerSample = (format == ARRAY_DATA_8BITUNSIGNED ? 8 : 16); + wfx.cbSize = 0; + + if (ah) { + waveInClose(ah); + ah = 0; + } + if (waveInOpen(&ah, WAVE_MAPPER, &wfx, (DWORD_PTR)threadID, 0, CALLBACK_THREAD)) { + fprintf(stderr, "GAUDIN: Can't open WAVE recording device\n"); + exit(-1); + } + + return TRUE; +} + +void gaudio_record_lld_start(void) { + WAVEHDR *pwh; + + if (!ah) + return; + + while (nQueuedBuffers < MAX_WAVE_HEADERS) { + // Find the empty one - there will always be at least one. + for(pwh = WaveHdrs; pwh->lpData; pwh++); + + // Grab the next audio block from the free-list + if (!getbuffer(pwh)) + break; + } + if (!isRunning) { + isRunning = TRUE; + waveInStart(ah); + } +} + +void gaudio_record_lld_stop(void) { + isRunning = FALSE; + waveInReset(ah); + while(nQueuedBuffers) Sleep(1); +} + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ diff --git a/drivers/gaudio/Win32/readme.txt b/drivers/gaudio/Win32/readme.txt new file mode 100644 index 00000000..83cb9c33 --- /dev/null +++ b/drivers/gaudio/Win32/readme.txt @@ -0,0 +1,10 @@ +This driver uses the Win32 audio system to provide GAUDIO play and record channels. + +For PLAY - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. +For RECORD - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. + +For stereo, the samples are interleaved. Remember to allocate enough space for two samples per +sample period. + +This is a simple driver that makes no changes to the mixer so set up the audio mixer using +the windows control panel audio mixer before starting recording/playback. diff --git a/drivers/gaudio/gadc/driver.mk b/drivers/gaudio/gadc/driver.mk new file mode 100644 index 00000000..4d79da25 --- /dev/null +++ b/drivers/gaudio/gadc/driver.mk @@ -0,0 +1,5 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/gaudio/gadc/gaudio_record_lld.c + +# Required include directories +GFXINC += $(GFXLIB)/drivers/gaudio/gadc diff --git a/drivers/audio/gadc/gaudin_lld_board_template.h b/drivers/gaudio/gadc/gaudio_record_board_template.h index 89cc0c12..26e87d88 100644 --- a/drivers/audio/gadc/gaudin_lld_board_template.h +++ b/drivers/gaudio/gadc/gaudio_record_board_template.h @@ -6,15 +6,15 @@ */ /** - * @file drivers/gaudin/gadc/gaudin_lld_board_template.h - * @brief GAUDIN Driver board config board file + * @file drivers/gaudio/gadc/gaudio_record_board_template.h + * @brief GAUDIO Record Driver board config board file * - * @addtogroup GAUDIN + * @addtogroup GAUDIO * @{ */ -#ifndef _GAUDIN_LLD_BOARD_H -#define _GAUDIN_LLD_BOARD_H +#ifndef _GAUDIO_RECORD_BOARD_H +#define _GAUDIO_RECORD_BOARD_H /*===========================================================================*/ /* Audio inputs on this board */ @@ -24,14 +24,14 @@ * @brief The number of audio channels supported by this driver * @note This is an example */ -#define GAUDIN_NUM_CHANNELS 1 +#define GAUDIO_RECORD_NUM_CHANNELS 1 /** * @brief The list of audio channels and their uses * @note This is an example * @{ */ -#define GAUDIN_MICROPHONE 0 +#define GAUDIO_RECORD_MICROPHONE 0 /** @} */ /** @@ -39,12 +39,12 @@ * @note This is an example * @{ */ -#ifdef GAUDIN_LLD_IMPLEMENTATION - static uint32_t gaudin_lld_physdevs[GAUDIN_NUM_CHANNELS] = { +#ifdef GAUDIO_RECORD_LLD_IMPLEMENTATION + static uint32_t gaudin_lld_physdevs[GAUDIO_RECORD_NUM_CHANNELS] = { GADC_PHYSDEV_MICROPHONE, }; #endif /** @} */ -#endif /* _GAUDIN_LLD_BOARD_H */ +#endif /* _GAUDIO_RECORD_BOARD_H */ /** @} */ diff --git a/drivers/audio/gadc/gaudin_lld_config.h b/drivers/gaudio/gadc/gaudio_record_config.h index a9fd02ae..22d8750f 100644 --- a/drivers/audio/gadc/gaudin_lld_config.h +++ b/drivers/gaudio/gadc/gaudio_record_config.h @@ -6,54 +6,54 @@ */ /** - * @file drivers/gaudin/gadc/gaudin_lld_config.h - * @brief GAUDIN Driver config file. + * @file drivers/gaudio/gadc/gaudio_record_config.h + * @brief GAUDIN Record Driver config file. * - * @addtogroup GAUDIN + * @addtogroup GAUDIO * @{ */ -#ifndef GAUDIN_LLD_CONFIG_H -#define GAUDIN_LLD_CONFIG_H +#ifndef GAUDIO_RECORD_CONFIG_H +#define GAUDIO_RECORD_CONFIG_H -#if GFX_USE_GAUDIN +#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD /*===========================================================================*/ /* Driver hardware support. */ /*===========================================================================*/ /** - * @brief The audio input sample type + * @brief The audio record sample type * @details For this driver it matches the cpu sample type */ -typedef adcsample_t audin_sample_t; +typedef adcsample_t audio_record_sample_t; /** * @brief The maximum sample frequency supported by this audio device * @details For this driver it matches the GADC maximum high speed sample rate */ -#define GAUDIN_MAX_SAMPLE_FREQUENCY GADC_MAX_HIGH_SPEED_SAMPLERATE +#define GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY GADC_MAX_HIGH_SPEED_SAMPLERATE /** * @brief The number of bits in a sample * @details For this driver it matches the cpu sample bits */ -#define GAUDIN_BITS_PER_SAMPLE GADC_BITS_PER_SAMPLE +#define GAUDIO_RECORD_BITS_PER_SAMPLE GADC_BITS_PER_SAMPLE /** * @brief The format of an audio sample * @details For this driver it matches the cpu sample format */ -#define GAUDIN_SAMPLE_FORMAT GADC_SAMPLE_FORMAT +#define GAUDIO_RECORD_SAMPLE_FORMAT GADC_SAMPLE_FORMAT /** - * For the GAUDIN driver that uses GADC - all the remaining config definitions are specific + * For the GAUDIO driver that uses GADC - all the remaining config definitions are specific * to the board. */ /* Include the user supplied board definitions */ -#include "gaudin_lld_board.h" +#include "gaudio_record_board.h" -#endif /* GFX_USE_GAUDIN */ +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ -#endif /* GAUDIN_LLD_CONFIG_H */ +#endif /* GAUDIO_RECORD_CONFIG_H */ /** @} */ diff --git a/drivers/audio/gadc/gaudin_lld.c b/drivers/gaudio/gadc/gaudio_record_lld.c index 002d9e9b..ee994dc1 100644 --- a/drivers/audio/gadc/gaudin_lld.c +++ b/drivers/gaudio/gadc/gaudio_record_lld.c @@ -6,10 +6,10 @@ */ /** - * @file drivers/gaudin/gadc/gaudin_lld.c - * @brief GAUDIN - Driver file for using the cpu ADC (via GADC). + * @file drivers/gaudio/gadc/gaudio_record_lld.c + * @brief GAUDIO - Record Driver file for using the cpu ADC (via GADC). * - * @addtogroup GAUDIN + * @addtogroup GAUDIO * * @{ */ @@ -18,20 +18,20 @@ * We are now implementing the driver - pull in our channel table * from the board definitions. */ -#define GAUDIN_LLD_IMPLEMENTATION +#define GAUDIO_RECORD_IMPLEMENTATION #include "gfx.h" -#if GFX_USE_GAUDIN +#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD /* Double check the GADC system is turned on */ #if !GFX_USE_GADC - #error "GAUDIN - The GADC driver for GAUDIN requires GFX_USE_GADC to be TRUE" + #error "GAUDIO - The GADC driver for GAUDIO requires GFX_USE_GADC to be TRUE" #endif /* Include the driver defines */ -#include "src/gaudin/driver.h" +#include "src/gaudio/driver_record.h" /*===========================================================================*/ /* External declarations. */ @@ -58,5 +58,5 @@ void gaudin_lld_stop(void) { gadcHighSpeedStop(); } -#endif /* GFX_USE_GAUDIN */ +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ /** @} */ diff --git a/drivers/audio/gadc/readme.txt b/drivers/gaudio/gadc/readme.txt index 1d3877e8..47d3f191 100644 --- a/drivers/audio/gadc/readme.txt +++ b/drivers/gaudio/gadc/readme.txt @@ -1,4 +1,4 @@ -This driver uses the generic GADC driver to provide a GAUDIN device. +This driver uses the generic GADC driver to provide a GAUDIO recording device. It supports whatever high speed device channels that your GADC driver and board supports. |