From ea5a1b849df6e5085a92957ad387f9e653674415 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 11 Mar 2014 17:13:31 +1000 Subject: 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. --- src/gaudio/driver_play.h | 126 +++++++++++++++++ src/gaudio/driver_record.h | 108 ++++++++++++++ src/gaudio/gaudio.c | 318 ++++++++++++++++++++++++++++++++++++++++++ src/gaudio/sys_defs.h | 340 +++++++++++++++++++++++++++++++++++++++++++++ src/gaudio/sys_make.mk | 1 + src/gaudio/sys_options.h | 44 ++++++ src/gaudio/sys_rules.h | 54 +++++++ 7 files changed, 991 insertions(+) create mode 100644 src/gaudio/driver_play.h create mode 100644 src/gaudio/driver_record.h create mode 100644 src/gaudio/gaudio.c create mode 100644 src/gaudio/sys_defs.h create mode 100644 src/gaudio/sys_make.mk create mode 100644 src/gaudio/sys_options.h create mode 100644 src/gaudio/sys_rules.h (limited to 'src/gaudio') diff --git a/src/gaudio/driver_play.h b/src/gaudio/driver_play.h new file mode 100644 index 00000000..72ad4747 --- /dev/null +++ b/src/gaudio/driver_play.h @@ -0,0 +1,126 @@ +/* + * 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/gaudio/driver_play.h + * @brief GAUDIO - Audio play driver header file. + * + * @defgroup Driver Driver + * @ingroup GAUDIO + * @{ + */ + +#ifndef _GAUDIO_PLAY_LLD_H +#define _GAUDIO_PLAY_LLD_H + +#include "gfx.h" + +#if (GFX_USE_GAUDIO && GAUDIO_NEED_PLAY) || 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 GAUDIO code for use by the GAUDIO play drivers. + * + * @iclass + * @notapi + */ +GAudioData *gaudioPlayGetDataBlockI(void); + +/** + * @brief Release a block of audio data to the free list + * + * @param[in] paud The GAudioData block to be released. + * + * @note Defined in the high level GAUDIO code for use by the GAUDIO play drivers. + * + * @iclass + * @notapi + */ +void gaudioPlayReleaseDataBlockI(GAudioData *paud); + +/** + * @brief Signal that all playing has now stopped + * + * @note Defined in the high level GAUDIO code for use by the GAUDIO play drivers. + * + * @iclass + * @notapi + */ +void gaudioPlayDoneI(void); + +/** + * @brief Initialise the play driver + * @return TRUE if the channel, frequency and format 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 + * @param[in] format The sample format + * + * @note The driver will always have been stopped and de-init before this is called. + * + * @api + */ +bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format); + +/** + * @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 gaudioPlayGetDataBlockI(). + * + * @api + */ +void gaudio_play_lld_start(void); + +/** + * @brief Stop the audio output playing. + * + * @note Some drivers may only stop playing at a data block boundary. + * @note It is possible but unlikely for it to be called when playing has already stopped. + * @note It should not return until all active buffers (currently in use by the driver) + * have been returned to the free-list and @p gaudioPlayDoneI() has been called. + * + * @api + */ +void gaudio_play_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 gaudio_play_lld_set_volume(uint8_t vol); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ + +#endif /* _GAUDIO_PLAY_LLD_H */ +/** @} */ diff --git a/src/gaudio/driver_record.h b/src/gaudio/driver_record.h new file mode 100644 index 00000000..252cae5c --- /dev/null +++ b/src/gaudio/driver_record.h @@ -0,0 +1,108 @@ +/* + * 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/gaudio/driver_record.h + * @brief GAUDIO - Audio Recording driver header file. + * + * @defgroup Driver Driver + * @ingroup GAUDIO + * @{ + */ + +#ifndef _GAUDIO_RECORD_LLD_H +#define _GAUDIO_RECORD_LLD_H + +#include "gfx.h" + +#if (GFX_USE_GAUDIO && GAUDIO_NEED_RECORD) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +/** + * @brief Get a free block of audio data that we can record into + * @return A pointer to the GAaudioData structure or NULL if none is currently available + * + * @note Defined in the high level GAUDIO code for use by the GAUDIO record drivers. + * + * @iclass + * @notapi + */ +GAudioData *gaudioRecordGetFreeBlockI(void); + +/** + * @brief Save a block of recorded audio data ready for the application + * + * @param[in] paud The GAudioData block with data. + * + * @note Defined in the high level GAUDIO code for use by the GAUDIO record drivers. + * + * @iclass + * @notapi + */ +void gaudioRecordSaveDataBlockI(GAudioData *paud); + +/** + * @brief Signal that all recording has now stopped + * + * @note Defined in the high level GAUDIO code for use by the GAUDIO record drivers. + * + * @iclass + * @notapi + */ +void gaudioRecordDoneI(void); + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialise the record driver + * @return TRUE if the channel, frequency and format 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 + * @param[in] format The sample format + * + * @note The driver will always have been stopped and de-init before this is called. + * + * @api + */ +bool_t gaudio_record_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format); + +/** + * @brief Start the audio recording + * + * @api + */ +void gaudio_record_lld_start(void); + +/** + * @brief Stop the audio recording. + * + * @note Some drivers may only stop recording at a data block boundary. + * @note This routine should not return until any currently active buffers have been + * saved (even if with zero length) and @p gaudioRecordDoneI() has been called. + * + * @api + */ +void gaudio_record_lld_stop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ + +#endif /* _GAUDIO_RECORD_LLD_H */ +/** @} */ diff --git a/src/gaudio/gaudio.c b/src/gaudio/gaudio.c new file mode 100644 index 00000000..a83dcd85 --- /dev/null +++ b/src/gaudio/gaudio.c @@ -0,0 +1,318 @@ +/* + * 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/gaudio/gaudio.c + * @brief GAUDIO sub-system code. + * + * @addtogroup GAUDIO + * @{ + */ +#include "gfx.h" + +#if GFX_USE_GAUDIO + +static gfxQueueGSync freeList; + +#if GAUDIO_NEED_PLAY + #include "src/gaudio/driver_play.h" + + static gfxQueueASync playList; + static gfxSem playComplete; + static uint16_t playFlags; + #define PLAYFLG_USEEVENTS 0x0001 + #define PLAYFLG_PLAYING 0x0002 + #define PLAYFLG_ISINIT 0x0004 + #if GFX_USE_GEVENT + static GTimer playTimer; + static void PlayTimerCallback(void *param); + #endif +#endif + +#if GAUDIO_NEED_RECORD + #include "src/gaudio/driver_record.h" + + static gfxQueueGSync recordList; + static uint16_t recordFlags; + #define RECORDFLG_USEEVENTS 0x0001 + #define RECORDFLG_RECORDING 0x0002 + #define RECORDFLG_STALLED 0x0004 + #define RECORDFLG_ISINIT 0x0008 + #if GFX_USE_GEVENT + static GTimer recordTimer; + static void RecordTimerCallback(void *param); + #endif +#endif + + +void _gaudioInit(void) +{ + gfxQueueGSyncInit(&freeList); + #if GAUDIO_NEED_PLAY + gfxQueueASyncInit(&playList); + #if GFX_USE_GEVENT + gtimerInit(&playTimer); + #endif + gfxSemInit(&playComplete, 0, 0); + #endif + #if GAUDIO_NEED_RECORD + gfxQueueGSyncInit(&recordList); + #if GFX_USE_GEVENT + gtimerInit(&recordTimer); + #endif + #endif +} + +void _gaudioDeinit(void) +{ + #if GAUDIO_NEED_PLAY + #if GFX_USE_GEVENT + gtimerDeinit(&playTimer); + #endif + gfxSemDestroy(&playComplete); + #endif + #if GAUDIO_NEED_RECORD + #if GFX_USE_GEVENT + gtimerDeinit(&recordTimer); + #endif + #endif +} + +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); +} + +#if GAUDIO_NEED_PLAY + + bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { + gaudioPlayStop(); + playFlags &= ~PLAYFLG_ISINIT; + if (!gaudio_play_lld_init(channel, frequency, format)) + return FALSE; + playFlags |= PLAYFLG_ISINIT; + return TRUE; + } + + void gaudioPlay(GAudioData *paud) { + if (!(playFlags & PLAYFLG_ISINIT)) { + // Oops - init failed - return it directly to the free-list + if (paud) { + gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud); + gfxYield(); // Make sure we get no endless cpu hogging loops + } + return; + } + + if (paud) + gfxQueueASyncPut(&playList, (gfxQueueASyncItem *)paud); + playFlags |= PLAYFLG_PLAYING; + gaudio_play_lld_start(); + } + + void gaudioPlayPause(void) { + if ((playFlags & (PLAYFLG_ISINIT|PLAYFLG_PLAYING)) == (PLAYFLG_ISINIT|PLAYFLG_PLAYING)) + gaudio_play_lld_stop(); + } + + void gaudioPlayStop(void) { + GAudioData *paud; + + if (playFlags & PLAYFLG_PLAYING) + gaudio_play_lld_stop(); + while((paud = (GAudioData *)gfxQueueASyncGet(&playList))) + gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud); + } + + bool_t gaudioPlaySetVolume(uint8_t vol) { + return gaudio_play_lld_set_volume(vol); + } + + bool_t gaudioPlayWait(delaytime_t ms) { + if (!(playFlags & PLAYFLG_PLAYING)) + return TRUE; + return gfxSemWait(&playComplete, ms); + } + + #if GFX_USE_GEVENT + static void PlayTimerCallback(void *param) { + (void) param; + GSourceListener *psl; + GEventAudioPlay *pe; + + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)&playTimer, psl))) { + if (!(pe = (GEventAudioPlay *)geventGetEventBuffer(psl))) { + // This listener is missing - save this. + psl->srcflags |= GAUDIO_PLAY_LOSTEVENT; + continue; + } + + pe->type = GEVENT_AUDIO_PLAY; + pe->flags = psl->srcflags; + psl->srcflags = 0; + if ((playFlags & PLAYFLG_PLAYING)) + pe->flags |= GAUDIO_PLAY_PLAYING; + if (!gfxQueueGSyncIsEmpty(&freeList)) + pe->flags |= GAUDIO_PLAY_FREEBLOCK; + geventSendEvent(psl); + } + } + + GSourceHandle gaudioPlayGetSource(void) { + if (!gtimerIsActive(&playTimer)) + gtimerStart(&playTimer, PlayTimerCallback, 0, TRUE, TIME_INFINITE); + playFlags |= PLAYFLG_USEEVENTS; + return (GSourceHandle)&playTimer; + } + #endif + + /** + * Routines provided for use by drivers. + */ + + GAudioData *gaudioPlayGetDataBlockI(void) { + return (GAudioData *)gfxQueueASyncGetI(&playList); + } + + void gaudioPlayReleaseDataBlockI(GAudioData *paud) { + gfxQueueGSyncPutI(&freeList, (gfxQueueGSyncItem *)paud); + #if GFX_USE_GEVENT + if (playFlags & PLAYFLG_USEEVENTS) + gtimerJabI(&playTimer); + #endif + } + + void gaudioPlayDoneI(void) { + playFlags &= ~PLAYFLG_PLAYING; + #if GFX_USE_GEVENT + if (playFlags & PLAYFLG_USEEVENTS) + gtimerJabI(&playTimer); + #endif + gfxSemSignalI(&playComplete); // This should really be gfxSemSignalAllI(&playComplete); + } +#endif + +#if GAUDIO_NEED_RECORD + bool_t gaudioRecordInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { + gaudioRecordStop(); + recordFlags &= ~RECORDFLG_ISINIT; + if (!gaudio_record_lld_init(channel, frequency, format)) + return FALSE; + recordFlags |= RECORDFLG_ISINIT; + return TRUE; + } + + void gaudioRecordStart(void) { + if (!(recordFlags & RECORDFLG_ISINIT)) + return; // Oops - init failed + + recordFlags |= RECORDFLG_RECORDING; + recordFlags &= ~RECORDFLG_STALLED; + gaudio_record_lld_start(); + } + + void gaudioRecordStop(void) { + GAudioData *paud; + + if ((recordFlags & (RECORDFLG_RECORDING|RECORDFLG_STALLED)) == RECORDFLG_RECORDING) + gaudio_record_lld_stop(); + recordFlags &= ~(RECORDFLG_RECORDING|RECORDFLG_STALLED); + while((paud = (GAudioData *)gfxQueueGSyncGet(&recordList, TIME_IMMEDIATE))) + gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud); + } + + GAudioData *gaudioRecordGetData(delaytime_t ms) { + return (GAudioData *)gfxQueueGSyncGet(&recordList, ms); + } + + #if GFX_USE_GEVENT + static void RecordTimerCallback(void *param) { + (void) param; + GSourceListener *psl; + GEventAudioRecord *pe; + + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)&recordTimer, psl))) { + if (!(pe = (GEventAudioRecord *)geventGetEventBuffer(psl))) { + // This listener is missing - save this. + psl->srcflags |= GAUDIO_RECORD_LOSTEVENT; + continue; + } + pe->type = GEVENT_AUDIO_RECORD; + pe->flags = psl->srcflags; + psl->srcflags = 0; + if ((recordFlags & RECORDFLG_RECORDING)) + pe->flags |= GAUDIO_RECORD_RECORDING; + if ((recordFlags & RECORDFLG_STALLED)) + pe->flags |= GAUDIO_RECORD_STALL; + if (!gfxQueueGSyncIsEmpty(&recordList)) + pe->flags |= GAUDIO_RECORD_GOTBLOCK; + geventSendEvent(psl); + } + } + + GSourceHandle gaudioRecordGetSource(void) { + if (!gtimerIsActive(&recordTimer)) + gtimerStart(&recordTimer, RecordTimerCallback, 0, TRUE, TIME_INFINITE); + recordFlags |= RECORDFLG_USEEVENTS; + return (GSourceHandle)&recordTimer; + } + #endif + + /** + * Routines provided for use by drivers. + */ + + GAudioData *gaudioRecordGetFreeBlockI(void) { + return (GAudioData *)gfxQueueGSyncGetI(&freeList); + } + + void gaudioRecordSaveDataBlockI(GAudioData *paud) { + gfxQueueGSyncPutI(&recordList, (gfxQueueGSyncItem *)paud); + #if GFX_USE_GEVENT + if (recordFlags & RECORDFLG_USEEVENTS) + gtimerJabI(&recordTimer); + #endif + } + + void gaudioRecordDoneI(void) { + recordFlags |= RECORDFLG_STALLED; + #if GFX_USE_GEVENT + if (recordFlags & RECORDFLG_USEEVENTS) + gtimerJabI(&recordTimer); + #endif + } +#endif + +#endif /* GFX_USE_GAUDIO */ +/** @} */ diff --git a/src/gaudio/sys_defs.h b/src/gaudio/sys_defs.h new file mode 100644 index 00000000..a9a951b7 --- /dev/null +++ b/src/gaudio/sys_defs.h @@ -0,0 +1,340 @@ +/* + * 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/gaudio/sys_defs.h + * + * @addtogroup GAUDIO + * + * @brief Module to handle audio recording and play-back + * + * @{ + */ + +#ifndef _GAUDIO_H +#define _GAUDIO_H + +#include "gfx.h" + +#if GFX_USE_GAUDIO || defined(__DOXYGEN__) + +/* Include the driver defines */ +#if GAUDIO_NEED_PLAY + #include "gaudio_play_config.h" +#endif +#if GAUDIO_NEED_RECORD + #include "gaudio_record_config.h" +#endif + +/*===========================================================================*/ +/* 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 bytes) +} GAudioData; + + +// Event types for GAUDIO +#define GEVENT_AUDIO_PLAY (GEVENT_GAUDIO_FIRST+0) +#define GEVENT_AUDIO_RECORD (GEVENT_GAUDIO_FIRST+1) + +#if GFX_USE_GEVENT || defined(__DOXYGEN__) + /** + * @brief The Audio play event structure. + * @{ + */ + typedef struct GEventAudioPlay_t { + /** + * @brief The type of this event (GEVENT_AUDIO_PLAY) + */ + GEventType type; + /** + * @brief The event flags + */ + uint16_t flags; + /** + * @brief The event flag values. + * @{ + */ + #define GAUDIO_PLAY_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_PLAY event was lost */ + #define GAUDIO_PLAY_PLAYING 0x0002 /**< @brief The audio out system is currently playing */ + #define GAUDIO_PLAY_FREEBLOCK 0x0004 /**< @brief An audio buffer has been freed */ + /** @} */ + } GEventAudioPlay; + /** @} */ + + /** + * @brief The Audio record event structure. + * @{ + */ + typedef struct GEventAudioRecord_t { + /** + * @brief The type of this event (GEVENT_AUDIO_RECORD) + */ + GEventType type; + /** + * @brief The event flags + */ + uint16_t flags; + /** + * @brief The event flag values. + * @{ + */ + #define GAUDIO_RECORD_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */ + #define GAUDIO_RECORD_RECORDING 0x0002 /**< @brief The audio recording system is currently recording */ + #define GAUDIO_RECORD_GOTBLOCK 0x0004 /**< @brief An audio buffer is ready for processing */ + #define GAUDIO_RECORD_STALL 0x0008 /**< @brief The recording process has stalled due to no free buffers */ + /** @} */ + } GEventAudioRecord; + /** @} */ +#endif + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +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); + +#if GAUDIO_NEED_PLAY || defined(__DOXYGEN__) + /** + * @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. Can be set from 0 to GAUDIO_PLAY_NUM_CHANNELS - 1 + * @param[in] frequency The audio sample rate in samples per second + * @param[in] format The audio sample format + * + * @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. + * @note Only one channel can be playing at a time. Calling this will stop any + * currently playing channel. + * + * @api + */ + bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format); + + /** + * @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 (in bytes). + * @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); + + #if GFX_USE_GEVENT || defined(__DOXYGEN__) + /** + * @brief Turn on sending results to the GEVENT sub-system. + * @details Returns a GSourceHandle to listen for GEVENT_AUDIO_OUT events. + * + * @note The audio output 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 output. + * Once turned on it can only be turned off by calling @p gaudioPlayInit() again. + * @note The audio output is capable of signaling via this method and other methods + * at the same time. + * + * @return The GSourceHandle + * + * @api + */ + GSourceHandle gaudioPlayGetSource(void); + #endif + + /** + * @brief Wait for any currently playing sounds to complete + * @return TRUE if there is now nothing playing or FALSE if the timeout is exceeded + * + * @params[in] ms The maximum amount of time in milliseconds to wait for playing to complete. + * + * @api + */ + bool_t gaudioPlayWait(delaytime_t ms); +#endif + +#if GAUDIO_NEED_RECORD || defined(__DOXYGEN__) + /** + * @brief Initialise (but not start) the Audio Recording sub-system. + * @details Returns FALSE for an invalid channel or other invalid parameter. + * + * @param[in] channel The channel to convert. Can be set from 0 to GAUDIO_RECORD_NUM_CHANNELS - 1 + * @param[in] frequency The sample frequency + * @param[in] format The audio sample format requested + * + * @note Only one channel is active at a time. If an audio input is running it will be stopped. + * The Event subsystem is disconnected from the audio subsystem and any binary semaphore + * event is forgotten. + * @note Some channels may be stereo channels which return twice as much sample data with + * the left and right channel data interleaved. Other channels may be mono channels. + * Where stereo channels exist the low level driver may also + * offer the left and right channels separately. + * @note Due to a bug in Chibi-OS each buffer on the free-list must contain an even number of + * samples and for stereo devices it must hold a number of samples that is evenly divisible by 4. + * This requirement applies only to ChibiOS where the audio driver uses + * a ChibiOS hal driver like the cpu ADC driver. This applies even it is used indirectly via + * the uGFX GADC driver. + * @note The number of samples for stereo devices will be double the number of conversions. + * Make sure you allocate your buffers large enough. Each channel is then interleaved + * into the provided buffer. + * + * @return FALSE if invalid channel or parameter + * + * @api + */ + bool_t gaudioRecordInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format); + + /** + * @brief Start the audio recording. + * @pre It must have been initialised first with @p gaudioRecordInit() + * + * @api + */ + void gaudioRecordStart(void); + + /** + * @brief Stop the audio recording. + * + * @note All audio recording data that has not yet been retrieved is automatically + * returned to the free-list. + * @api + */ + void gaudioRecordStop(void); + + /** + * @brief Get a filled audio buffer from the recording 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 data if some is not currently available. + * + * @note After processing the audio data, your application must return the buffer to the free-list so that + * it can be used to record more audio into. This can be done via the play list using @p gaudioPlay() or + * directly using @p gaudioReleaseBuffer(). + * @api + */ + GAudioData *gaudioRecordGetData(delaytime_t ms); + + #if GFX_USE_GEVENT || defined(__DOXYGEN__) + /** + * @brief Turn on sending results to the GEVENT sub-system. + * @details Returns a GSourceHandle to listen for GEVENT_AUDIO_RECORD events. + * + * @note Audio recording 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 recording. + * Once turned on it can only be turned off by calling @p gaudioRecordInit() again. + * @note The audio input is capable of signaling via this and other methods + * at the same time. + * + * @return The GSourceHandle + * + * @api + */ + GSourceHandle gaudioRecordGetSource(void); + #endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GAUDIO */ + +#endif /* _GAUDIO_H */ +/** @} */ + diff --git a/src/gaudio/sys_make.mk b/src/gaudio/sys_make.mk new file mode 100644 index 00000000..438892c0 --- /dev/null +++ b/src/gaudio/sys_make.mk @@ -0,0 +1 @@ +GFXSRC += $(GFXLIB)/src/gaudio/gaudio.c diff --git a/src/gaudio/sys_options.h b/src/gaudio/sys_options.h new file mode 100644 index 00000000..1363d703 --- /dev/null +++ b/src/gaudio/sys_options.h @@ -0,0 +1,44 @@ +/* + * 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/gaudio/sys_options.h + * @brief GAUDIO - Audio subsystem options header file. + * + * @addtogroup GAUDIO + * @{ + */ + +#ifndef _GAUDIO_OPTIONS_H +#define _GAUDOUT_OPTIONS_H + +/** + * @name GAUDIO Functionality to be included + * @{ + */ + /** + * @brief Audio Play capability is needed + */ + #ifndef GAUDIO_NEED_PLAY + #define GAUDIO_NEED_PLAY FALSE + #endif + /** + * @brief Audio Recording capability is needed + */ + #ifndef GAUDIO_NEED_RECORD + #define GAUDIO_NEED_RECORD FALSE + #endif +/** + * @} + * + * @name GAUDIO Optional Sizing Parameters + * @{ + */ +/** @} */ + +#endif /* _GAUDIO_OPTIONS_H */ +/** @} */ diff --git a/src/gaudio/sys_rules.h b/src/gaudio/sys_rules.h new file mode 100644 index 00000000..a3f0dffc --- /dev/null +++ b/src/gaudio/sys_rules.h @@ -0,0 +1,54 @@ +/* + * 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/gaudio/sys_rules.h + * @brief GAUDIO safety rules header file. + * + * @addtogroup GAUDIO + * @{ + */ + +#ifndef _GAUDIO_RULES_H +#define _GAUDIO_RULES_H + +#if GFX_USE_GAUDIO + #if !GAUDIO_NEED_PLAY && !GAUDIO_NEED_RECORD + #error "GAUDIO: GAUDIO_NEED_PLAY and/or GAUDIO_NEED_RECORD is required if GFX_USE_GAUDIO is TRUE" + #endif + #if !GFX_USE_GQUEUE + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GAUDIO: GFX_USE_GQUEUE is required if GFX_USE_GAUDIO 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 "GAUDIO: GQUEUE_NEED_ASYNC is required if GFX_USE_GAUDIO 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 "GAUDIO: GQUEUE_NEED_GSYNC is required if GFX_USE_GAUDIO is TRUE. It has been turned on for you." + #endif + #undef GQUEUE_NEED_GSYNC + #define GQUEUE_NEED_GSYNC TRUE + #endif + #if GFX_USE_GEVENT && !GFX_USE_GTIMER + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GAUDIO: GFX_USE_GTIMER is required if GFX_USE_GAUDIO and GFX_USE_GEVENT are TRUE. It has been turned on for you." + #endif + #undef GFX_USE_GTIMER + #define GFX_USE_GTIMER TRUE + #endif +#endif + +#endif /* _GAUDIO_RULES_H */ +/** @} */ -- cgit v1.2.3