From a56e4ac7dcbf2776690c96656dbcb48b2cf2d818 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 27 Feb 2014 08:04:54 +1000 Subject: First GAUDOUT work. Still incomplete but compiling. Also moved drivers/gaudin to drivers/audio as most audio codecs support input and output in a single device. --- boards/base/Olimex-SAM7EX256-GE12/board.mk | 2 +- boards/base/Olimex-SAM7EX256-GE8/board.mk | 2 +- boards/base/Win32/board.mk | 4 +- drivers/audio/Win32/driver.mk | 6 + drivers/audio/Win32/gaudin_lld.c | 170 +++++++++++++++++++++ drivers/audio/Win32/gaudin_lld_config.h | 64 ++++++++ drivers/audio/Win32/gaudout_lld.c | 190 ++++++++++++++++++++++++ drivers/audio/Win32/gaudout_lld_config.h | 64 ++++++++ drivers/audio/Win32/readme.txt | 10 ++ drivers/audio/gadc/driver.mk | 5 + drivers/audio/gadc/gaudin_lld.c | 62 ++++++++ drivers/audio/gadc/gaudin_lld_board_template.h | 50 +++++++ drivers/audio/gadc/gaudin_lld_config.h | 59 ++++++++ drivers/audio/gadc/readme.txt | 6 + drivers/gaudin/Win32/gaudin_lld.c | 178 ---------------------- drivers/gaudin/Win32/gaudin_lld.mk | 5 - drivers/gaudin/Win32/gaudin_lld_config.h | 64 -------- drivers/gaudin/Win32/readme.txt | 9 -- drivers/gaudin/gadc/gaudin_lld.c | 62 -------- drivers/gaudin/gadc/gaudin_lld.mk | 5 - drivers/gaudin/gadc/gaudin_lld_board_template.h | 50 ------- drivers/gaudin/gadc/gaudin_lld_config.h | 59 -------- drivers/multiple/Win32/driver.mk | 2 + drivers/multiple/Win32/gdisp_lld.mk | 2 - src/gaudin/driver.h | 4 +- src/gaudin/gaudin.c | 8 +- src/gaudin/sys_defs.h | 4 +- src/gaudout/driver.h | 123 +++++++++++++++ src/gaudout/gaudout.c | 111 +++++++++++++- src/gaudout/sys_defs.h | 121 +++++++++++++++ src/gaudout/sys_rules.h | 21 +++ 31 files changed, 1074 insertions(+), 448 deletions(-) create mode 100644 drivers/audio/Win32/driver.mk create mode 100644 drivers/audio/Win32/gaudin_lld.c create mode 100644 drivers/audio/Win32/gaudin_lld_config.h create mode 100644 drivers/audio/Win32/gaudout_lld.c create mode 100644 drivers/audio/Win32/gaudout_lld_config.h create mode 100644 drivers/audio/Win32/readme.txt create mode 100644 drivers/audio/gadc/driver.mk create mode 100644 drivers/audio/gadc/gaudin_lld.c create mode 100644 drivers/audio/gadc/gaudin_lld_board_template.h create mode 100644 drivers/audio/gadc/gaudin_lld_config.h create mode 100644 drivers/audio/gadc/readme.txt delete mode 100644 drivers/gaudin/Win32/gaudin_lld.c delete mode 100644 drivers/gaudin/Win32/gaudin_lld.mk delete mode 100644 drivers/gaudin/Win32/gaudin_lld_config.h delete mode 100644 drivers/gaudin/Win32/readme.txt delete mode 100644 drivers/gaudin/gadc/gaudin_lld.c delete mode 100644 drivers/gaudin/gadc/gaudin_lld.mk delete mode 100644 drivers/gaudin/gadc/gaudin_lld_board_template.h delete mode 100644 drivers/gaudin/gadc/gaudin_lld_config.h create mode 100644 drivers/multiple/Win32/driver.mk delete mode 100644 drivers/multiple/Win32/gdisp_lld.mk create mode 100644 src/gaudout/driver.h diff --git a/boards/base/Olimex-SAM7EX256-GE12/board.mk b/boards/base/Olimex-SAM7EX256-GE12/board.mk index 662178a6..a1eae818 100644 --- a/boards/base/Olimex-SAM7EX256-GE12/board.mk +++ b/boards/base/Olimex-SAM7EX256-GE12/board.mk @@ -5,4 +5,4 @@ include $(GFXLIB)/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk include $(GFXLIB)/drivers/gadc/AT91SAM7/gadc_lld.mk include $(GFXLIB)/drivers/ginput/dial/GADC/ginput_lld.mk include $(GFXLIB)/drivers/ginput/toggle/Pal/ginput_lld.mk -include $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.mk +include $(GFXLIB)/drivers/audio/gadc/driver.mk diff --git a/boards/base/Olimex-SAM7EX256-GE8/board.mk b/boards/base/Olimex-SAM7EX256-GE8/board.mk index 6abd9a33..a60d9355 100644 --- a/boards/base/Olimex-SAM7EX256-GE8/board.mk +++ b/boards/base/Olimex-SAM7EX256-GE8/board.mk @@ -5,4 +5,4 @@ include $(GFXLIB)/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk include $(GFXLIB)/drivers/gadc/AT91SAM7/gadc_lld.mk include $(GFXLIB)/drivers/ginput/dial/GADC/ginput_lld.mk include $(GFXLIB)/drivers/ginput/toggle/Pal/ginput_lld.mk -include $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.mk +include $(GFXLIB)/drivers/audio/gadc/driver.mk diff --git a/boards/base/Win32/board.mk b/boards/base/Win32/board.mk index b3aeb7d2..5f624f3d 100644 --- a/boards/base/Win32/board.mk +++ b/boards/base/Win32/board.mk @@ -1,5 +1,5 @@ GFXINC += $(GFXLIB)/boards/base/Win32 GFXSRC += -include $(GFXLIB)/drivers/multiple/Win32/gdisp_lld.mk -include $(GFXLIB)/drivers/gaudin/Win32/gaudin_lld.mk +include $(GFXLIB)/drivers/multiple/Win32/driver.mk +include $(GFXLIB)/drivers/audio/Win32/driver.mk diff --git a/drivers/audio/Win32/driver.mk b/drivers/audio/Win32/driver.mk new file mode 100644 index 00000000..6f4ef084 --- /dev/null +++ b/drivers/audio/Win32/driver.mk @@ -0,0 +1,6 @@ +# 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 new file mode 100644 index 00000000..2c8431cf --- /dev/null +++ b/drivers/audio/Win32/gaudin_lld.c @@ -0,0 +1,170 @@ +/* + * 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 +#include +#include + +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 new file mode 100644 index 00000000..78ddffaa --- /dev/null +++ b/drivers/audio/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/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/gaudout_lld.c b/drivers/audio/Win32/gaudout_lld.c new file mode 100644 index 00000000..9581fa45 --- /dev/null +++ b/drivers/audio/Win32/gaudout_lld.c @@ -0,0 +1,190 @@ +/* + * 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/gaudout_lld.c + * @brief GAUDOUT - Driver file for Win32. + */ + +#include "gfx.h" + +#if GFX_USE_GAUDOUT + +/* Include the driver defines */ +#include "src/gaudout/driver.h" + +#undef Red +#undef Green +#undef Blue +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#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 also create higher latency. + +static HWAVEOUT ah = 0; +static volatile int nQueuedBuffers; +static bool_t isRunning; +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, + * 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 waveOutUnPrepareBuffer() which is what we need to use whenever we receive a + * MM_WOM_DONE. My callback would need to defer that job to another thread + * anyway, so instead just use CALLBACK_THREAD here instead. + *************************************************************************/ + +static bool_t senddata(WAVEHDR *pwh) { + GAudioData *paud; + + // Get the next data block to send + if (!(paud = gaudoutGetDataBlockI())) + 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->len; + pwh->dwFlags = 0; + pwh->dwLoops = 0; + if (waveOutPrepareHeader(ah, pwh, sizeof(WAVEHDR))) { + pwh->lpData = 0; + fprintf(stderr, "GAUDOUT: Failed to prepare a buffer"); + return FALSE; + } + + // Send it to windows + if (waveOutWrite(ah, pwh, sizeof(WAVEHDR))) { + pwh->lpData = 0; + fprintf(stderr, "GAUDOUT: Failed to write the buffer"); + return FALSE; + } + + nQueuedBuffers++; + return TRUE; +} + +static DWORD WINAPI waveProc(LPVOID arg) { + MSG msg; + WAVEHDR *pwh; + (void) arg; + + while (GetMessage(&msg, 0, 0, 0)) { + switch (msg.message) { + case MM_WOM_DONE: + pwh = (WAVEHDR *)msg.lParam; + + // Windows - Let go! + waveOutUnprepareHeader(ah, pwh, sizeof(WAVEHDR)); + + // Give the buffer back to the Audio Free List + gaudoutReleaseDataBlockI((GAudioData *)pwh->dwUser); + pwh->lpData = 0; + nQueuedBuffers--; + + // Try and get a new block + if (isRunning) + senddata(pwh); + break; + } + } + return 0; +} + +/*===========================================================================*/ +/* 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) { + WAVEFORMATEX wfx; + + 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"); + return FALSE; + } + CloseHandle(waveThread); + } + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = channel == GAUDOUT_STEREO ? 2 : 1; + wfx.nSamplesPerSec = frequency; + wfx.nBlockAlign = wfx.nChannels * sizeof(audout_sample_t); + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + wfx.wBitsPerSample = sizeof(audout_sample_t) * 8; + wfx.cbSize = 0; + + if (waveOutOpen(&ah, WAVE_MAPPER, &wfx, (DWORD_PTR)threadID, 0, CALLBACK_THREAD)) { + fprintf(stderr, "GAUDOUT: Can't open WAVE play-back device\n"); + return FALSE; + } + + return TRUE; +} + +bool_t gaudout_lld_set_volume(uint8_t vol) { + if (!ah) + return FALSE; + return waveOutSetVolume(ah, (((uint16_t)vol)<<8)|vol) != 0; +} + +void gaudout_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. + for(pwh = WaveHdrs; pwh->lpData; pwh++); + + // Grab the next audio block from the Audio Out Queue + if (!senddata(pwh)) + break; + } +} + +void gaudout_lld_stop(void) { + isRunning = FALSE; + if (ah) + waveOutReset(ah); +} + +#endif /* GFX_USE_GAUDOUT */ diff --git a/drivers/audio/Win32/gaudout_lld_config.h b/drivers/audio/Win32/gaudout_lld_config.h new file mode 100644 index 00000000..157f33f0 --- /dev/null +++ b/drivers/audio/Win32/gaudout_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/audio/Win32/gaudout_lld_config.h + * @brief GAUDOUT Driver config file. + * + * @addtogroup GAUDOUT + * @{ + */ + +#ifndef GAUDOUT_LLD_CONFIG_H +#define GAUDIN_LLD_CONFIG_H + +#if GFX_USE_GAUDOUT + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +/** + * @brief The audio input sample type + */ +//typedef uint8_t audout_sample_t; +typedef int16_t audout_sample_t; + +/** + * @brief The maximum sample frequency supported by this audio device + */ +#define GAUDOUT_MAX_SAMPLE_FREQUENCY 44100 + +/** + * @brief The number of bits in a sample + */ +//#define GAUDOUT_BITS_PER_SAMPLE 8 +#define GAUDOUT_BITS_PER_SAMPLE 16 + +/** + * @brief The format of an audio sample + */ +//#define GAUDOUT_SAMPLE_FORMAT ARRAY_DATA_8BITUNSIGNED +#define GAUDOUT_SAMPLE_FORMAT ARRAY_DATA_16BITSIGNED + +/** + * @brief The number of audio channels supported by this driver + */ +#define GAUDOUT_NUM_CHANNELS 2 + +/** + * @brief The list of audio channels and their uses + * @{ + */ +#define GAUDOUT_MONO 0 +#define GAUDOUT_STEREO 1 +/** @} */ + +#endif /* GFX_USE_GAUDOUT */ + +#endif /* GAUDOUT_LLD_CONFIG_H */ +/** @} */ diff --git a/drivers/audio/Win32/readme.txt b/drivers/audio/Win32/readme.txt new file mode 100644 index 00000000..784f0a89 --- /dev/null +++ b/drivers/audio/Win32/readme.txt @@ -0,0 +1,10 @@ +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 new file mode 100644 index 00000000..b991ede8 --- /dev/null +++ b/drivers/audio/gadc/driver.mk @@ -0,0 +1,5 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.c + +# Required include directories +GFXINC += $(GFXLIB)/drivers/audio/gadc diff --git a/drivers/audio/gadc/gaudin_lld.c b/drivers/audio/gadc/gaudin_lld.c new file mode 100644 index 00000000..002d9e9b --- /dev/null +++ b/drivers/audio/gadc/gaudin_lld.c @@ -0,0 +1,62 @@ +/* + * 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/gadc/gaudin_lld.c + * @brief GAUDIN - Driver file for using the cpu ADC (via GADC). + * + * @addtogroup GAUDIN + * + * @{ + */ + +/** + * We are now implementing the driver - pull in our channel table + * from the board definitions. + */ +#define GAUDIN_LLD_IMPLEMENTATION + + +#include "gfx.h" + +#if GFX_USE_GAUDIN + +/* 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" +#endif + +/* Include the driver defines */ +#include "src/gaudin/driver.h" + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +void gaudin_lld_init(const gaudin_params *paud) { + /* Setup the high speed GADC */ + gadcHighSpeedInit(gaudin_lld_physdevs[paud->channel], paud->frequency, paud->buffer, paud->bufcount, paud->samplesPerEvent); + + /* Register ourselves for ISR callbacks */ + gadcHighSpeedSetISRCallback(GAUDIN_ISR_CompleteI); + + /** + * The gadc driver handles any errors for us by restarting the transaction so there is + * no need for us to setup anything for GAUDIN_ISR_ErrorI() + */ +} + +void gaudin_lld_start(void) { + gadcHighSpeedStart(); +} + +void gaudin_lld_stop(void) { + gadcHighSpeedStop(); +} + +#endif /* GFX_USE_GAUDIN */ +/** @} */ diff --git a/drivers/audio/gadc/gaudin_lld_board_template.h b/drivers/audio/gadc/gaudin_lld_board_template.h new file mode 100644 index 00000000..89cc0c12 --- /dev/null +++ b/drivers/audio/gadc/gaudin_lld_board_template.h @@ -0,0 +1,50 @@ +/* + * 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/gadc/gaudin_lld_board_template.h + * @brief GAUDIN Driver board config board file + * + * @addtogroup GAUDIN + * @{ + */ + +#ifndef _GAUDIN_LLD_BOARD_H +#define _GAUDIN_LLD_BOARD_H + +/*===========================================================================*/ +/* Audio inputs on this board */ +/*===========================================================================*/ + +/** + * @brief The number of audio channels supported by this driver + * @note This is an example + */ +#define GAUDIN_NUM_CHANNELS 1 + +/** + * @brief The list of audio channels and their uses + * @note This is an example + * @{ + */ +#define GAUDIN_MICROPHONE 0 +/** @} */ + +/** + * @brief The audio channel to GADC physical device assignment + * @note This is an example + * @{ + */ +#ifdef GAUDIN_LLD_IMPLEMENTATION + static uint32_t gaudin_lld_physdevs[GAUDIN_NUM_CHANNELS] = { + GADC_PHYSDEV_MICROPHONE, + }; +#endif +/** @} */ + +#endif /* _GAUDIN_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/audio/gadc/gaudin_lld_config.h b/drivers/audio/gadc/gaudin_lld_config.h new file mode 100644 index 00000000..a9fd02ae --- /dev/null +++ b/drivers/audio/gadc/gaudin_lld_config.h @@ -0,0 +1,59 @@ +/* + * 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/gadc/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 + * @details For this driver it matches the cpu sample type + */ +typedef adcsample_t audin_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 + +/** + * @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 + +/** + * @brief The format of an audio sample + * @details For this driver it matches the cpu sample format + */ +#define GAUDIN_SAMPLE_FORMAT GADC_SAMPLE_FORMAT + +/** + * For the GAUDIN 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" + +#endif /* GFX_USE_GAUDIN */ + +#endif /* GAUDIN_LLD_CONFIG_H */ +/** @} */ diff --git a/drivers/audio/gadc/readme.txt b/drivers/audio/gadc/readme.txt new file mode 100644 index 00000000..1d3877e8 --- /dev/null +++ b/drivers/audio/gadc/readme.txt @@ -0,0 +1,6 @@ +This driver uses the generic GADC driver to provide a GAUDIN device. + +It supports whatever high speed device channels that your GADC driver and board supports. + +For stereo, the samples are interleaved. Remember to allocate enough space for two samples per +sample period. diff --git a/drivers/gaudin/Win32/gaudin_lld.c b/drivers/gaudin/Win32/gaudin_lld.c deleted file mode 100644 index e798f4ef..00000000 --- a/drivers/gaudin/Win32/gaudin_lld.c +++ /dev/null @@ -1,178 +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/gaudin/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 -#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 = 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 deleted file mode 100644 index 3a822971..00000000 --- a/drivers/gaudin/Win32/gaudin_lld.mk +++ /dev/null @@ -1,5 +0,0 @@ -# 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 deleted file mode 100644 index 804d2fc4..00000000 --- a/drivers/gaudin/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/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 */ -/** @} */ diff --git a/drivers/gaudin/Win32/readme.txt b/drivers/gaudin/Win32/readme.txt deleted file mode 100644 index b921c5e5..00000000 --- a/drivers/gaudin/Win32/readme.txt +++ /dev/null @@ -1,9 +0,0 @@ -This driver uses the Win32 audio system to provide a GAUDIN channel. - -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 (obviously in record mode) before starting recording. diff --git a/drivers/gaudin/gadc/gaudin_lld.c b/drivers/gaudin/gadc/gaudin_lld.c deleted file mode 100644 index 972f3dcf..00000000 --- a/drivers/gaudin/gadc/gaudin_lld.c +++ /dev/null @@ -1,62 +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/gaudin/gadc/gaudin_lld.c - * @brief GAUDIN - Driver file for using the cpu ADC (via GADC). - * - * @addtogroup GAUDIN - * - * @{ - */ - -/** - * We are now implementing the driver - pull in our channel table - * from the board definitions. - */ -#define GAUDIN_LLD_IMPLEMENTATION - - -#include "gfx.h" - -#if GFX_USE_GAUDIN - -/* 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" -#endif - -/* Include the driver defines */ -#include "src/gaudin/driver.h" - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -void gaudin_lld_init(const gaudin_params *paud) { - /* Setup the high speed GADC */ - gadcHighSpeedInit(gaudin_lld_physdevs[paud->channel], paud->frequency, paud->buffer, paud->bufcount, paud->samplesPerEvent); - - /* Register ourselves for ISR callbacks */ - gadcHighSpeedSetISRCallback(GAUDIN_ISR_CompleteI); - - /** - * The gadc driver handles any errors for us by restarting the transaction so there is - * no need for us to setup anything for GAUDIN_ISR_ErrorI() - */ -} - -void gadc_lld_start(void) { - gadcHighSpeedStart(); -} - -void gadc_lld_stop(void) { - gadcHighSpeedStop(); -} - -#endif /* GFX_USE_GAUDIN */ -/** @} */ diff --git a/drivers/gaudin/gadc/gaudin_lld.mk b/drivers/gaudin/gadc/gaudin_lld.mk deleted file mode 100644 index c969e80b..00000000 --- a/drivers/gaudin/gadc/gaudin_lld.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/gaudin/gadc diff --git a/drivers/gaudin/gadc/gaudin_lld_board_template.h b/drivers/gaudin/gadc/gaudin_lld_board_template.h deleted file mode 100644 index 89cc0c12..00000000 --- a/drivers/gaudin/gadc/gaudin_lld_board_template.h +++ /dev/null @@ -1,50 +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/gaudin/gadc/gaudin_lld_board_template.h - * @brief GAUDIN Driver board config board file - * - * @addtogroup GAUDIN - * @{ - */ - -#ifndef _GAUDIN_LLD_BOARD_H -#define _GAUDIN_LLD_BOARD_H - -/*===========================================================================*/ -/* Audio inputs on this board */ -/*===========================================================================*/ - -/** - * @brief The number of audio channels supported by this driver - * @note This is an example - */ -#define GAUDIN_NUM_CHANNELS 1 - -/** - * @brief The list of audio channels and their uses - * @note This is an example - * @{ - */ -#define GAUDIN_MICROPHONE 0 -/** @} */ - -/** - * @brief The audio channel to GADC physical device assignment - * @note This is an example - * @{ - */ -#ifdef GAUDIN_LLD_IMPLEMENTATION - static uint32_t gaudin_lld_physdevs[GAUDIN_NUM_CHANNELS] = { - GADC_PHYSDEV_MICROPHONE, - }; -#endif -/** @} */ - -#endif /* _GAUDIN_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gaudin/gadc/gaudin_lld_config.h b/drivers/gaudin/gadc/gaudin_lld_config.h deleted file mode 100644 index a9fd02ae..00000000 --- a/drivers/gaudin/gadc/gaudin_lld_config.h +++ /dev/null @@ -1,59 +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/gaudin/gadc/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 - * @details For this driver it matches the cpu sample type - */ -typedef adcsample_t audin_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 - -/** - * @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 - -/** - * @brief The format of an audio sample - * @details For this driver it matches the cpu sample format - */ -#define GAUDIN_SAMPLE_FORMAT GADC_SAMPLE_FORMAT - -/** - * For the GAUDIN 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" - -#endif /* GFX_USE_GAUDIN */ - -#endif /* GAUDIN_LLD_CONFIG_H */ -/** @} */ diff --git a/drivers/multiple/Win32/driver.mk b/drivers/multiple/Win32/driver.mk new file mode 100644 index 00000000..d9654dfe --- /dev/null +++ b/drivers/multiple/Win32/driver.mk @@ -0,0 +1,2 @@ +GFXINC += $(GFXLIB)/drivers/multiple/Win32 +GFXSRC += $(GFXLIB)/drivers/multiple/Win32/gdisp_lld_Win32.c diff --git a/drivers/multiple/Win32/gdisp_lld.mk b/drivers/multiple/Win32/gdisp_lld.mk deleted file mode 100644 index f9242380..00000000 --- a/drivers/multiple/Win32/gdisp_lld.mk +++ /dev/null @@ -1,2 +0,0 @@ -GFXINC += $(GFXLIB)/drivers/multiple/Win32 -GFXSRC += $(GFXLIB)/drivers/multiple/Win32/gdisp_lld_Win32.c diff --git a/src/gaudin/driver.h b/src/gaudin/driver.h index bd04858a..b534e2a5 100644 --- a/src/gaudin/driver.h +++ b/src/gaudin/driver.h @@ -83,14 +83,14 @@ void gaudin_lld_init(const gaudin_params *paud); * * @api */ -void gadc_lld_start(void); +void gaudin_lld_start(void); /** * @brief Stop the audio input sampling * * @api */ -void gadc_lld_stop(void); +void gaudin_lld_stop(void); #ifdef __cplusplus } diff --git a/src/gaudin/gaudin.c b/src/gaudin/gaudin.c index c9ed1c7f..2e3507ef 100644 --- a/src/gaudin/gaudin.c +++ b/src/gaudin/gaudin.c @@ -40,7 +40,7 @@ static uint16_t audFlags; while ((psl = geventGetSourceListener((GSourceHandle)(&aud), psl))) { if (!(pe = (GEventAudioIn *)geventGetEventBuffer(psl))) { // This listener is missing - save this. - psl->srcflags |= GADC_AUDIO_IN_LOSTEVENT; + psl->srcflags |= GAUDIN_LOSTEVENT; continue; } @@ -107,7 +107,7 @@ bool_t gaudinInit(uint16_t channel, uint32_t frequency, audin_sample_t *buffer, /* Stop any existing transfers */ if ((audFlags & AUDFLG_RUNNING)) - gadc_lld_stop(); + gaudin_lld_stop(); audFlags = 0; /* Initialise everything */ @@ -143,13 +143,13 @@ void gaudinSetBSem(gfxSem *pbsem, GEventAudioIn *pEvent) { void gaudinStart(void) { if (!(audFlags & AUDFLG_RUNNING)) { audFlags |= AUDFLG_RUNNING; - gadc_lld_start(); + gaudin_lld_start(); } } void gaudinStop(void) { if ((audFlags & AUDFLG_RUNNING)) { - gadc_lld_stop(); + gaudin_lld_stop(); audFlags &= ~AUDFLG_RUNNING; } } diff --git a/src/gaudin/sys_defs.h b/src/gaudin/sys_defs.h index 3f06fa6e..c65a69c1 100644 --- a/src/gaudin/sys_defs.h +++ b/src/gaudin/sys_defs.h @@ -55,7 +55,7 @@ typedef struct GEventAudioIn_t { * @brief The event flag values. * @{ */ - #define GADC_AUDIO_IN_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */ + #define GAUDIN_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */ /** @} */ /** * @brief The number of audio samples in the buffer @@ -123,7 +123,7 @@ bool_t gaudinInit(uint16_t channel, uint32_t frequency, audin_sample_t *buffer, * @note The audio input will not use the GEVENT system unless this is * called first. This saves processing time if the application does * not want to use the GEVENT sub-system for audio input. - * Once turned on it can only be turned off by calling @p gadcHighSpeedInit() again. + * Once turned on it can only be turned off by calling @p gaudinInit() again. * @note The audio input is capable of signalling via this method and a binary semaphore * at the same time. * diff --git a/src/gaudout/driver.h b/src/gaudout/driver.h new file mode 100644 index 00000000..cd9ab01b --- /dev/null +++ b/src/gaudout/driver.h @@ -0,0 +1,123 @@ +/* + * 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 src/gaudout/driver.h + * @brief GAUDOUT - Audio Output driver header file. + * + * @defgroup Driver Driver + * @ingroup GAUDOUT + * @{ + */ + +#ifndef _GAUDOUT_LLD_H +#define _GAUDOUT_LLD_H + +#include "gfx.h" + +#if GFX_USE_GAUDOUT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Get a block of audio data to play + * @return A pointer to the GAaudioData structure or NULL if none is currently available + * + * @note Defined in the high level GAUDOUT code for use by the GAUDOUT drivers. + * + * @iclass + * @notapi + */ +GAudioData *gaudoutGetDataBlockI(void); + +/** + * @brief Release a block of audio data after playing + * + * @param[in] paud The GAudioData block to be released. + * + * @note Defined in the high level GAUDOUT code for use by the GAUDOUT drivers. + * + * @iclass + * @notapi + */ +void gaudoutReleaseDataBlockI(GAudioData *paud); + +/** + * @brief Initialise the driver + * @return TRUE if the channel and frequency are valid. + * + * @param[in] channel The channel to use (see the driver for the available channels provided) + * @param[in] frequency The sample frequency to use + * + * @note The driver will always have been stopped and de-init before this is called. + * + * @api + */ +bool_t gaudout_lld_init(uint16_t channel, uint32_t frequency); + +/** + * @brief De-Initialise the driver + * + * @note The audio output will always have been stopped first by the high level layer. + * @note This may be called before a @p gaudout_lld_init() has occurred. + * + * @api + */ +void gaudout_lld_deinit(void); + +/** + * @brief Start the audio output playing + * + * @note This may be called at any stage including while the driver + * is already playing. The driver should check for data blocks + * to play using @p gaudoutGetDataBlockI(). + * + * @api + */ +void gaudout_lld_start(void); + +/** + * @brief Stop the audio output playing. + * + * @note Some drivers may only stop playing at a data block boundary. + * @note This may be called before a @p gaudout_lld_init() has occurred. + * + * @api + */ +void gaudout_lld_stop(void); + +/** + * @brief Set the output volume. + * @return TRUE if successful. + * + * @param[in] 0->255 (0 = muted) + * + * @note Some drivers may not support this. They will return FALSE. + * @note For stereo devices, both channels are set to the same volume. + * + * @api + */ +bool_t gaudout_lld_set_volume(uint8_t vol); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GAUDOUT */ + +#endif /* _GAUDOUT_LLD_H */ +/** @} */ diff --git a/src/gaudout/gaudout.c b/src/gaudout/gaudout.c index 56692453..c0d673a0 100644 --- a/src/gaudout/gaudout.c +++ b/src/gaudout/gaudout.c @@ -16,11 +16,47 @@ #if GFX_USE_GAUDOUT || defined(__DOXYGEN__) - #error "GAUDOUT: Not implemented yet" +#include "src/gaudout/driver.h" + +static gfxQueueASync playlist; +static gfxQueueGSync freelist; + +static uint16_t audFlags; + #define AUDOUTFLG_RUNNING 0x0001 + #define AUDOUTFLG_USE_EVENTS 0x0002 + +#if GFX_USE_GEVENT + static GTimer AudGTimer; + + static void AudGTimerCallback(void *param) { + (void) param; + GSourceListener *psl; + GEventADC *pe; + + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)(&aud), psl))) { + if (!(pe = (GEventAudioIn *)geventGetEventBuffer(psl))) { + // This listener is missing - save this. + psl->srcflags |= GAUDIN_LOSTEVENT; + continue; + } + + pe->type = GEVENT_AUDIO_IN; + pe->channel = aud.channel; + pe->count = lastcount; + pe->buffer = lastbuffer; + pe->flags = psl->srcflags; + psl->srcflags = 0; + geventSendEvent(psl); + } + } +#endif + void _gaudoutInit(void) { - /* ToDo */ + gfxQueueASyncInit(&playlist); + gfxQueueGSyncInit(&freelist); } void _gaudoutDeinit(void) @@ -28,6 +64,77 @@ void _gaudoutDeinit(void) /* ToDo */ } +bool_t gaudioAllocBuffers(unsigned num, size_t size) { + GAudioData *paud; + + if (num < 1) + return FALSE; + + // Round up to a multiple of 4 to prevent problems with structure alignment + size = (size + 3) & ~0x03; + + // Allocate the memory + if (!(paud = gfxAlloc((size+sizeof(GAudioData)) * num))) + return FALSE; + + // Add each of them to our free list + for(;num--; paud = (GAudioData *)((char *)(paud+1)+size)) { + paud->size = size; + gfxQueueGSyncPut(&freelist, (gfxQueueGSyncItem *)paud); + } + + return TRUE; +} + +void gaudioReleaseBuffer(GAudioData *paud) { + gfxQueueGSyncPut(&freelist, (gfxQueueGSyncItem *)paud); +} + +GAudioData *gaudioGetBuffer(delaytime_t ms) { + return (GAudioData *)gfxQueueGSyncGet(&freelist, ms); +} + +bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency) { + gaudioPlayStop(); + gaudout_lld_deinit(); + return gaudout_lld_init(channel, frequency); +} + +void gaudioPlay(GAudioData *paud) { + if (paud) + gfxQueueASyncPut(&playlist, (gfxQueueASyncItem *)paud); + gaudout_lld_start(); +} + +void gaudioPlayPause(void) { + gaudout_lld_stop(); +} + +void gaudioPlayStop(void) { + GAudioData *paud; + + gaudout_lld_stop(); + while((paud = (GAudioData *)gfxQueueASyncGet(&playlist))) + gfxQueueGSyncPut(&freelist, (gfxQueueGSyncItem *)paud); +} + +bool_t gaudioPlaySetVolume(uint8_t vol) { + return gaudout_lld_set_volume(vol); +} + +/** + * Routines provided for use by drivers. + */ + +GAudioData *gaudoutGetDataBlockI(void) { + return (GAudioData *)gfxQueueASyncGet(&playlist); +} + +void gaudoutReleaseDataBlockI(GAudioData *paud) { + gfxQueueGSyncPut(&freelist, (gfxQueueGSyncItem *)paud); +} + + #endif /* GFX_USE_GAUDOUT */ /** @} */ diff --git a/src/gaudout/sys_defs.h b/src/gaudout/sys_defs.h index f22d269c..c3745b8c 100644 --- a/src/gaudout/sys_defs.h +++ b/src/gaudout/sys_defs.h @@ -22,10 +22,26 @@ #if GFX_USE_GAUDOUT || defined(__DOXYGEN__) +/* Include the driver defines */ +#include "gaudout_lld_config.h" + + /*===========================================================================*/ /* Type definitions */ /*===========================================================================*/ +/** + * @brief Contains Audio Data Samples + * @note This structure is followed immediately by the sample data itself. + * When allocating the buffers for the sample data put this structure + * at the beginning of the buffer. + */ +typedef struct GAudioData { + gfxQueueASyncItem next; // @< Used for queuing the buffers + size_t size; // @< The size of the buffer area following this structure (in bytes) + size_t len; // @< The length of the data in the buffer area (in samples) +} GAudioData; + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ @@ -34,6 +50,111 @@ extern "C" { #endif +/** + * @brief Allocate some audio buffers and put them on the free list + * @return TRUE is it succeeded. FALSE on allocation failure. + * + * @param[in] num The number of buffers to allocate + * @param[in] size The size (in bytes) of each buffer + * + * @api + */ +bool_t gaudioAllocBuffers(unsigned num, size_t size); + +/** + * @brief Get an audio buffer from the free list + * @return A GAudioData pointer or NULL if the timeout is exceeded + * + * @params[in] ms The maximum amount of time in milliseconds to wait for a buffer if one is not available. + * + * @api + */ +GAudioData *gaudioGetBuffer(delaytime_t ms); + +/** + * @brief Release a buffer back to the free list + * + * @param[in] paud The buffer to put (back) on the free-list. + * + * @note This call should be used to return any buffers that were taken from + * the free-list once they have been finished with. It can also be used + * to put new buffers onto the free-list. Just make sure the "size" field + * of the GAudioData structure has been filled in first. + * + * @api + */ +void gaudioReleaseBuffer(GAudioData *paud); + +/** + * @brief Set the audio device to play on the specified channel and with the specified + * sample frequency. + * @return TRUE is successful, FALSE if the driver doesn't accept those parameters. + * + * @param[in] channel The audio output channel to use. + * @param[in] frequency The audio sample rate in samples per second + * + * @note Some channels are mono, and some are stereo. See your driver config file + * to determine which channels to use and whether they are stereo or not. + * + * @api + */ +bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency); + +/** + * @brief Play the specified sample data. + * @details The sample data is output to the audio channel. On completion the buffer is returned to the free-list. + * @pre @p gaudioPlayInit must have been called first to set the channel and sample frequency. + * + * @param[in] paud The audio sample buffer to play. It can be NULL (used to restart paused audio) + * + * @note Calling this will cancel any pause. + * @note Before calling this function the len field of the GAudioData structure must be + * specified. While the buffer size is specified in bytes, this length is specified in samples + * and must be even for stereo channels. + * @note For stereo channels the sample data is interleaved in the buffer. + * @note This call returns before the data has completed playing. Subject to available buffers (which + * can be obtained from the free-list), any number of buffers may be played. They will be queued + * for playing in the order they are supplied to this routine and played when previous buffers are + * complete. In this way continuous playing can be obtained without audio gaps. + * + * @api + */ +void gaudioPlay(GAudioData *paud); + +/** + * @brief Pause any currently playing sounds. + * + * @note If nothing is currently playing this routine does nothing. To restart playing call @p gaudioPlay() + * with or without a new sample buffer. + * @note Some drivers will not respond until a buffer boundary. + * + * @api + */ +void gaudioPlayPause(void); + +/** + * @brief Stop any currently playing sounds. + * + * @note This stops any playing sounds and returns any currently queued buffers back to the free-list. + * @note Some drivers will not respond until a buffer boundary. + * + * @api + */ +void gaudioPlayStop(void); + +/** + * @brief Set the output volume. + * @return TRUE if successful. + * + * @param[in] 0->255 (0 = muted) + * + * @note Some drivers may not support this. They will return FALSE. + * @note For stereo devices, both channels are set to the same volume. + * + * @api + */ +bool_t gaudioPlaySetVolume(uint8_t vol); + #ifdef __cplusplus } #endif diff --git a/src/gaudout/sys_rules.h b/src/gaudout/sys_rules.h index 50b9a442..8274e031 100644 --- a/src/gaudout/sys_rules.h +++ b/src/gaudout/sys_rules.h @@ -17,6 +17,27 @@ #define _GAUDOUT_RULES_H #if GFX_USE_GAUDOUT + #if !GFX_USE_GQUEUE + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GAUDOUT: GFX_USE_GQUEUE is required if GFX_USE_GAUDOUT is TRUE. It has been turned on for you." + #endif + #undef GFX_USE_GQUEUE + #define GFX_USE_GQUEUE TRUE + #endif + #if !GQUEUE_NEED_ASYNC + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GAUDOUT: GQUEUE_NEED_ASYNC is required if GFX_USE_GAUDOUT is TRUE. It has been turned on for you." + #endif + #undef GQUEUE_NEED_ASYNC + #define GQUEUE_NEED_ASYNC TRUE + #endif + #if !GQUEUE_NEED_GSYNC + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GAUDOUT: GQUEUE_NEED_GSYNC is required if GFX_USE_GAUDOUT is TRUE. It has been turned on for you." + #endif + #undef GQUEUE_NEED_GSYNC + #define GQUEUE_NEED_GSYNC TRUE + #endif #endif #endif /* _GAUDOUT_RULES_H */ -- cgit v1.2.3