aboutsummaryrefslogtreecommitdiffstats
path: root/src/gaudio/gaudio.c
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2014-03-11 17:13:31 +1000
committerinmarket <andrewh@inmarket.com.au>2014-03-11 17:13:31 +1000
commitea5a1b849df6e5085a92957ad387f9e653674415 (patch)
tree72ede5ed78263a6fdba25039398b5c2a55bd1d3a /src/gaudio/gaudio.c
parent944c33cbff5f2cfb1c80f48193aa2161574864fd (diff)
downloaduGFX-ea5a1b849df6e5085a92957ad387f9e653674415.tar.gz
uGFX-ea5a1b849df6e5085a92957ad387f9e653674415.tar.bz2
uGFX-ea5a1b849df6e5085a92957ad387f9e653674415.zip
Combine GAUDIN and GAUDOUT into a single GAUDIO module.
Simplify GAUDIN (now GAUDIO RECORD) api. Update audio demo's to match. Port Win32 driver to new audio api.
Diffstat (limited to 'src/gaudio/gaudio.c')
-rw-r--r--src/gaudio/gaudio.c318
1 files changed, 318 insertions, 0 deletions
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 */
+/** @} */