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. --- src/gaudout/driver.h | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ src/gaudout/gaudout.c | 111 ++++++++++++++++++++++++++++++++++++++++++- src/gaudout/sys_defs.h | 121 +++++++++++++++++++++++++++++++++++++++++++++++ src/gaudout/sys_rules.h | 21 +++++++++ 4 files changed, 374 insertions(+), 2 deletions(-) create mode 100644 src/gaudout/driver.h (limited to 'src/gaudout') 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