diff --git a/boards/base/Olimex-SAM7EX256-GE12/board.mk b/boards/base/Olimex-SAM7EX256-GE12/board.mk index a1eae818..2ef53142 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/audio/gadc/driver.mk +include $(GFXLIB)/drivers/gaudio/gadc/driver.mk diff --git a/boards/base/Olimex-SAM7EX256-GE12/readme.txt b/boards/base/Olimex-SAM7EX256-GE12/readme.txt index ebf1497a..83e32ee8 100644 --- a/boards/base/Olimex-SAM7EX256-GE12/readme.txt +++ b/boards/base/Olimex-SAM7EX256-GE12/readme.txt @@ -6,7 +6,7 @@ On this board uGFX currently supports: - GADC via the AT91SAM7 driver - GINPUT-dials via the GADC driver - GINPUT-toggles via the Pal driver - - GAUDIN via the GADC driver + - GAUDIO recording via the GADC driver Note there are two variants of this board - one with the GE8 display and one with the GE12 display. This one is for the GE12 display. diff --git a/boards/base/Olimex-SAM7EX256-GE8/board.mk b/boards/base/Olimex-SAM7EX256-GE8/board.mk index a60d9355..249cfc2d 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/audio/gadc/driver.mk +include $(GFXLIB)/drivers/gaudio/gadc/driver.mk diff --git a/boards/base/Olimex-SAM7EX256-GE8/gaudin_lld_board.h b/boards/base/Olimex-SAM7EX256-GE8/gaudio_record_board.h similarity index 55% rename from boards/base/Olimex-SAM7EX256-GE8/gaudin_lld_board.h rename to boards/base/Olimex-SAM7EX256-GE8/gaudio_record_board.h index 632f0659..cdea5e06 100644 --- a/boards/base/Olimex-SAM7EX256-GE8/gaudin_lld_board.h +++ b/boards/base/Olimex-SAM7EX256-GE8/gaudio_record_board.h @@ -6,28 +6,28 @@ */ /** - * @file boards/base/Olimex-SAM7EX256-GE8/gaudin_lld_board.h - * @brief GAUDIN Driver board config file for the Olimex SAM7EX256 board + * @file boards/base/Olimex-SAM7EX256-GE8/gaudio_record_board.h + * @brief GAUDIO Record Driver board config file for the Olimex SAM7EX256 board */ -#ifndef _GAUDIN_LLD_BOARD_H -#define _GAUDIN_LLD_BOARD_H +#ifndef _GAUDIO_RECORD_BOARD_H +#define _GAUDIO_RECORD_BOARD_H /*===========================================================================*/ /* Audio inputs on this board */ /*===========================================================================*/ -#define GAUDIN_NUM_CHANNELS 1 +#define GAUDIO_RECORD_NUM_CHANNELS 1 /** * The list of audio channels and their uses */ -#define GAUDIN_MICROPHONE 0 +#define GAUDIO_RECORD_MICROPHONE 0 -#ifdef GAUDIN_LLD_IMPLEMENTATION - static uint32_t gaudin_lld_physdevs[GAUDIN_NUM_CHANNELS] = { +#ifdef GAUDIO_RECORD_IMPLEMENTATION + static uint32_t gaudin_lld_physdevs[GAUDIO_RECORD_NUM_CHANNELS] = { GADC_PHYSDEV_MICROPHONE, }; #endif -#endif /* _GAUDIN_LLD_BOARD_H */ +#endif /* _GAUDIO_RECORD_BOARD_H */ diff --git a/boards/base/Olimex-SAM7EX256-GE8/readme.txt b/boards/base/Olimex-SAM7EX256-GE8/readme.txt index 01b3f8b4..f613dee3 100644 --- a/boards/base/Olimex-SAM7EX256-GE8/readme.txt +++ b/boards/base/Olimex-SAM7EX256-GE8/readme.txt @@ -6,7 +6,7 @@ On this board uGFX currently supports: - GADC via the AT91SAM7 driver - GINPUT-dials via the GADC driver - GINPUT-toggles via the Pal driver - - GAUDIN via the GADC driver + - GAUDIO recording via the GADC driver Note there are two variants of this board - one with the GE8 display and one with the GE12 display. This one is for the GE8 display. diff --git a/boards/base/Win32/board.mk b/boards/base/Win32/board.mk index 5f624f3d..69d09100 100644 --- a/boards/base/Win32/board.mk +++ b/boards/base/Win32/board.mk @@ -2,4 +2,4 @@ GFXINC += $(GFXLIB)/boards/base/Win32 GFXSRC += include $(GFXLIB)/drivers/multiple/Win32/driver.mk -include $(GFXLIB)/drivers/audio/Win32/driver.mk +include $(GFXLIB)/drivers/gaudio/Win32/driver.mk diff --git a/demos/modules/audio/oscilloscope/demo.mk b/demos/modules/gaudio/oscilloscope/demo.mk similarity index 57% rename from demos/modules/audio/oscilloscope/demo.mk rename to demos/modules/gaudio/oscilloscope/demo.mk index ffdf6980..47b28f5f 100644 --- a/demos/modules/audio/oscilloscope/demo.mk +++ b/demos/modules/gaudio/oscilloscope/demo.mk @@ -1,3 +1,3 @@ -DEMODIR = $(GFXLIB)/demos/modules/audio/oscilloscope +DEMODIR = $(GFXLIB)/demos/modules/gaudio/oscilloscope GFXINC += $(DEMODIR) GFXSRC += $(DEMODIR)/main.c $(DEMODIR)/gwinosc.c diff --git a/demos/modules/audio/oscilloscope/gfxconf.h b/demos/modules/gaudio/oscilloscope/gfxconf.h similarity index 95% rename from demos/modules/audio/oscilloscope/gfxconf.h rename to demos/modules/gaudio/oscilloscope/gfxconf.h index 8733268d..2caa1da9 100644 --- a/demos/modules/audio/oscilloscope/gfxconf.h +++ b/demos/modules/gaudio/oscilloscope/gfxconf.h @@ -46,11 +46,14 @@ #define GFX_USE_GWIN TRUE #define GFX_USE_GTIMER TRUE //#define GFX_USE_GADC TRUE -#define GFX_USE_GAUDIN TRUE +#define GFX_USE_GAUDIO TRUE /* Features for the GDISP sub-system. */ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_MULTITHREAD TRUE +/* Features for the GAUDIO sub-system */ +#define GAUDIO_NEED_RECORD TRUE + #endif /* _GFXCONF_H */ diff --git a/demos/modules/audio/oscilloscope/gwinosc.c b/demos/modules/gaudio/oscilloscope/gwinosc.c similarity index 61% rename from demos/modules/audio/oscilloscope/gwinosc.c rename to demos/modules/gaudio/oscilloscope/gwinosc.c index 43ef1385..21a83760 100644 --- a/demos/modules/audio/oscilloscope/gwinosc.c +++ b/demos/modules/gaudio/oscilloscope/gwinosc.c @@ -32,8 +32,8 @@ * * This GWIN superset implements a simple audio oscilloscope using the GAUDIN module. * - * It makes many assumptions, the most fundamental of which is that the audio device - * produces unsigned integer samples. + * It makes many assumptions, the most fundamental of which is that the audio data + * should be scaled to SCOPE_Y_BITS. * * The GMISC module with GMISC_NEED_ARRAYOPS could be used to process the samples more * correctly if we were really building something generic. @@ -45,22 +45,15 @@ /* Include internal GWIN routines so we can build our own superset class */ #include "src/gwin/class_gwin.h" -/* The size of our dynamically allocated audio buffer */ -#define AUDIOBUFSZ 64*2 - /* How many flat-line sample before we trigger */ #define FLATLINE_SAMPLES 8 static void _destroy(GHandle gh) { - gaudinStop(); + gaudioRecordStop(); if (((GScopeObject *)gh)->lastscopetrace) { gfxFree(((GScopeObject *)gh)->lastscopetrace); ((GScopeObject *)gh)->lastscopetrace = 0; } - if (((GScopeObject *)gh)->audiobuf) { - gfxFree(((GScopeObject *)gh)->audiobuf); - ((GScopeObject *)gh)->audiobuf = 0; - } } static const gwinVMT scopeVMT = { @@ -71,127 +64,136 @@ static const gwinVMT scopeVMT = { 0, // The after-clear routine }; -GHandle gwinGScopeCreate(GDisplay *g, GScopeObject *gs, GWindowInit *pInit, uint16_t channel, uint32_t frequency) { +GHandle gwinGScopeCreate(GDisplay *g, GScopeObject *gs, GWindowInit *pInit, uint16_t channel, uint32_t frequency, ArrayDataFormat format) { + /* Make sure the audio parameters are valid first */ + if (!gaudioRecordInit(channel, frequency, format)) + return 0; + /* Initialise the base class GWIN */ if (!(gs = (GScopeObject *)_gwindowCreate(g, &gs->g, pInit, &scopeVMT, 0))) return 0; /* Initialise the scope object members and allocate memory for buffers */ - gfxSemInit(&gs->bsem, 0, 1); + gs->format = format; gs->nextx = 0; if (!(gs->lastscopetrace = (coord_t *)gfxAlloc(gs->g.width * sizeof(coord_t)))) return 0; - if (!(gs->audiobuf = (audin_sample_t *)gfxAlloc(AUDIOBUFSZ * sizeof(audin_sample_t)))) - return 0; -#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP - gs->lasty = gs->g.height/2; -#elif TRIGGER_METHOD == TRIGGER_MINVALUE - gs->lasty = gs->g.height/2; - gs->scopemin = 0; -#endif - - /* Start the GADC high speed converter */ - gaudinInit(channel, frequency, gs->audiobuf, AUDIOBUFSZ, AUDIOBUFSZ/2); - gaudinSetBSem(&gs->bsem, &gs->myEvent); - gaudinStart(); + #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + gs->lasty = gs->g.height/2; + #elif TRIGGER_METHOD == TRIGGER_MINVALUE + gs->lasty = gs->g.height/2; + gs->scopemin = 0; + #endif + /* Set visibility */ gwinSetVisible((GHandle)gs, pInit->show); + + /* Start the audio recording */ + gaudioRecordStart(); + return (GHandle)gs; } void gwinScopeWaitForTrace(GHandle gh) { #define gs ((GScopeObject *)(gh)) + GAudioData *paud; int i; coord_t x, y; coord_t yoffset; - audin_sample_t *pa; + uint8_t *pa8; + uint16_t *pa16; coord_t *pc; -#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP - bool_t rdytrigger; - int flsamples; -#elif TRIGGER_METHOD == TRIGGER_MINVALUE - bool_t rdytrigger; - int flsamples; - coord_t scopemin; -#endif + uint8_t shr; + + #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + bool_t rdytrigger; + int flsamples; + #elif TRIGGER_METHOD == TRIGGER_MINVALUE + bool_t rdytrigger; + int flsamples; + coord_t scopemin; + #endif if (gh->vmt != &scopeVMT) return; /* Wait for a set of audio conversions */ - gfxSemWait(&gs->bsem, TIME_INFINITE); + paud = gaudioRecordGetData(TIME_INFINITE); /* Ensure we are drawing in the right area */ #if GDISP_NEED_CLIP gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif + shr = 16 - gfxSampleFormatBits(gs->format); yoffset = gh->height/2; - if (!(GAUDIN_SAMPLE_FORMAT & 1)) + if (!gfxSampleFormatIsSigned(gs->format)) yoffset += (1<nextx; pc = gs->lastscopetrace+x; - pa = gs->myEvent.buffer; -#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP - rdytrigger = FALSE; - flsamples = 0; -#elif TRIGGER_METHOD == TRIGGER_MINVALUE - rdytrigger = FALSE; - flsamples = 0; - scopemin = 0; -#endif + pa8 = (uint8_t *)(paud+1); + pa16 = (uint16_t *)(paud+1); - for(i = gs->myEvent.count; i; i--) { + #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + rdytrigger = FALSE; + flsamples = 0; + #elif TRIGGER_METHOD == TRIGGER_MINVALUE + rdytrigger = FALSE; + flsamples = 0; + scopemin = 0; + #endif + + for(i = paud->len/(gfxSampleFormatBits(gs->format)/8); i; i--) { /* Calculate the new scope value - re-scale using simple shifts for efficiency, re-center and y-invert */ - #if GAUDIN_BITS_PER_SAMPLE > SCOPE_Y_BITS - y = yoffset - (*pa++ >> (GAUDIN_BITS_PER_SAMPLE - SCOPE_Y_BITS)); - #else - y = yoffset - (*pa++ << (SCOPE_Y_BITS - GAUDIN_BITS_PER_SAMPLE)); - #endif + if (gs->format <= 8) + y = yoffset - (((coord_t)(*pa8++ ) << shr) >> (16-SCOPE_Y_BITS)); + else + y = yoffset - (((coord_t)(*pa16++) << shr) >> (16-SCOPE_Y_BITS)); -#if TRIGGER_METHOD == TRIGGER_MINVALUE - /* Calculate the scopemin ready for the next trace */ - if (y > scopemin) - scopemin = y; -#endif + #if TRIGGER_METHOD == TRIGGER_MINVALUE + /* Calculate the scopemin ready for the next trace */ + if (y > scopemin) + scopemin = y; + #endif /* Have we reached the end of a scope trace? */ if (x >= gh->width) { -#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP || TRIGGER_METHOD == TRIGGER_MINVALUE - /* Handle triggering - we trigger on the next sample minimum (y value maximum) or a flat-line */ + #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP || TRIGGER_METHOD == TRIGGER_MINVALUE + /* Handle triggering - we trigger on the next sample minimum (y value maximum) or a flat-line */ - #if TRIGGER_METHOD == TRIGGER_MINVALUE - /* Arm when we reach the sample minimum (y value maximum) of the previous trace */ - if (!rdytrigger && y >= gs->scopemin) - rdytrigger = TRUE; - #endif - - if (y == gs->lasty) { - /* Trigger if we get too many flat-line samples regardless of the armed state */ - if (++flsamples < FLATLINE_SAMPLES) - continue; - flsamples = 0; - } else if (y > gs->lasty) { - gs->lasty = y; - flsamples = 0; - #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP - /* Arm the trigger when samples fall (y increases) ie. negative slope */ - rdytrigger = TRUE; + #if TRIGGER_METHOD == TRIGGER_MINVALUE + /* Arm when we reach the sample minimum (y value maximum) of the previous trace */ + if (!rdytrigger && y >= gs->scopemin) + rdytrigger = TRUE; #endif - continue; - } else { - /* If the trigger is armed, Trigger when samples increases (y decreases) ie. positive slope */ - gs->lasty = y; - flsamples = 0; - if (!rdytrigger) - continue; - } - /* Ready for a the next trigger cycle */ - rdytrigger = FALSE; -#endif + if (y == gs->lasty) { + /* Trigger if we get too many flat-line samples regardless of the armed state */ + if (++flsamples < FLATLINE_SAMPLES) + continue; + flsamples = 0; + } else if (y > gs->lasty) { + gs->lasty = y; + flsamples = 0; + #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + /* Arm the trigger when samples fall (y increases) ie. negative slope */ + rdytrigger = TRUE; + #endif + continue; + } else { + /* If the trigger is armed, Trigger when samples increases (y decreases) ie. positive slope */ + gs->lasty = y; + flsamples = 0; + if (!rdytrigger) + continue; + } + + /* Ready for a the next trigger cycle */ + rdytrigger = FALSE; + #endif /* Prepare for a scope trace */ x = 0; @@ -214,5 +216,6 @@ void gwinScopeWaitForTrace(GHandle gh) { gs->scopemin = scopemin; #endif + gaudioReleaseBuffer(paud); #undef gs } diff --git a/demos/modules/audio/oscilloscope/gwinosc.h b/demos/modules/gaudio/oscilloscope/gwinosc.h similarity index 92% rename from demos/modules/audio/oscilloscope/gwinosc.h rename to demos/modules/gaudio/oscilloscope/gwinosc.h index 0efb403c..5a5c5034 100644 --- a/demos/modules/audio/oscilloscope/gwinosc.h +++ b/demos/modules/gaudio/oscilloscope/gwinosc.h @@ -64,9 +64,7 @@ typedef struct GScopeObject_t { GWindowObject g; // Base Class coord_t *lastscopetrace; // To store last scope trace - gfxSem bsem; // We get signalled on this - audin_sample_t *audiobuf; // To store audio samples - GEventAudioIn myEvent; // Information on received samples + ArrayDataFormat format; // The sample format coord_t nextx; // Where we are up to #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP coord_t lasty; // The last y value - used for trigger slope detection @@ -83,8 +81,8 @@ extern "C" { /** * Create a scope window. */ - GHandle gwinGScopeCreate(GDisplay *g, GScopeObject *gs, GWindowInit *pInit, uint16_t channel, uint32_t frequency); - #define gwinScopeCreate(gs,pI,ch,f) gwinGScopeCreate(GDISP,gs,pI,ch,f) + GHandle gwinGScopeCreate(GDisplay *g, GScopeObject *gs, GWindowInit *pInit, uint16_t channel, uint32_t frequency, ArrayDataFormat format); + #define gwinScopeCreate(gs,pI,ch,f,fmt) gwinGScopeCreate(GDISP,gs,pI,ch,f,fmt) /** * Wait for a scope trace to be ready and then draw it. diff --git a/demos/modules/audio/oscilloscope/main.c b/demos/modules/gaudio/oscilloscope/main.c similarity index 84% rename from demos/modules/audio/oscilloscope/main.c rename to demos/modules/gaudio/oscilloscope/main.c index 32418450..b44b5a02 100644 --- a/demos/modules/audio/oscilloscope/main.c +++ b/demos/modules/gaudio/oscilloscope/main.c @@ -39,8 +39,9 @@ #include "gwinosc.h" /* Specify our timing parameters */ -#define MY_AUDIO_FREQUENCY 4000 /* 4khz */ -#define MY_AUDIO_CHANNEL 0 /* Use channel 0 */ +#define MY_AUDIO_FREQUENCY 8000 /* 8khz. If this is too much try 4000 (4khz) */ +#define MY_AUDIO_CHANNEL 0 /* Use channel 0 - must be a mono channel */ +#define MY_AUDIO_FORMAT GAUDIO_RECORD_FORMAT1 /* The default format */ /* Data */ static GScopeObject gScopeWindow; @@ -54,6 +55,11 @@ int main(void) { gfxInit(); + // Allocate audio buffers - 4 x 128 byte buffers. + // You may need to increase this for slower cpu's. + // You may be able to decrease this for low latency operating systems. + gaudioAllocBuffers(4, 128); + /* Get the screen dimensions */ swidth = gdispGetWidth(); sheight = gdispGetHeight(); @@ -65,7 +71,7 @@ int main(void) { wi.show = TRUE; wi.x = wi.y = 0; wi.width = swidth; wi.height = sheight; - ghScope = gwinScopeCreate(&gScopeWindow, &wi, MY_AUDIO_CHANNEL, MY_AUDIO_FREQUENCY); + ghScope = gwinScopeCreate(&gScopeWindow, &wi, MY_AUDIO_CHANNEL, MY_AUDIO_FREQUENCY, MY_AUDIO_FORMAT); } gwinSetBgColor(ghScope, White); gwinSetColor(ghScope, Red); diff --git a/demos/modules/audio/oscilloscope/results_264x264.jpg b/demos/modules/gaudio/oscilloscope/results_264x264.jpg similarity index 100% rename from demos/modules/audio/oscilloscope/results_264x264.jpg rename to demos/modules/gaudio/oscilloscope/results_264x264.jpg diff --git a/demos/modules/audio/play-wave/allwrong.wav b/demos/modules/gaudio/play-wave/allwrong.wav similarity index 100% rename from demos/modules/audio/play-wave/allwrong.wav rename to demos/modules/gaudio/play-wave/allwrong.wav diff --git a/demos/modules/audio/play-wave/demo.mk b/demos/modules/gaudio/play-wave/demo.mk similarity index 50% rename from demos/modules/audio/play-wave/demo.mk rename to demos/modules/gaudio/play-wave/demo.mk index 242e57b5..cd6f941f 100644 --- a/demos/modules/audio/play-wave/demo.mk +++ b/demos/modules/gaudio/play-wave/demo.mk @@ -1,3 +1,3 @@ -DEMODIR = $(GFXLIB)/demos/modules/audio/play-wave +DEMODIR = $(GFXLIB)/demos/modules/gaudio/play-wave GFXINC += $(DEMODIR) GFXSRC += $(DEMODIR)/main.c diff --git a/demos/modules/audio/play-wave/gfxconf.h b/demos/modules/gaudio/play-wave/gfxconf.h similarity index 95% rename from demos/modules/audio/play-wave/gfxconf.h rename to demos/modules/gaudio/play-wave/gfxconf.h index 1480b919..a9bb6252 100644 --- a/demos/modules/audio/play-wave/gfxconf.h +++ b/demos/modules/gaudio/play-wave/gfxconf.h @@ -43,7 +43,7 @@ /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE -#define GFX_USE_GAUDOUT TRUE +#define GFX_USE_GAUDIO TRUE #define GFX_USE_GFILE TRUE /* Features for the GDISP sub-system. */ @@ -53,6 +53,9 @@ /* GDISP fonts to include */ #define GDISP_INCLUDE_FONT_UI2 TRUE +/* Features for the GAUDIO sub-system */ +#define GAUDIO_NEED_PLAY TRUE + /* Features for the GFILE sub-system */ #define GFILE_NEED_ROMFS TRUE diff --git a/demos/modules/audio/play-wave/main.c b/demos/modules/gaudio/play-wave/main.c similarity index 93% rename from demos/modules/audio/play-wave/main.c rename to demos/modules/gaudio/play-wave/main.c index e8cab254..f15ec7a1 100644 --- a/demos/modules/audio/play-wave/main.c +++ b/demos/modules/gaudio/play-wave/main.c @@ -34,8 +34,8 @@ #include "gfx.h" /* Specify our timing parameters */ -#define MY_AUDIO_CHANNEL 0 /* Use channel 0 */ -#define MY_AUDIO_CHANNEL_IS_STEREO GAUDOUT_CHANNEL0_STEREO /* Is it stereo? */ +#define MY_AUDIO_CHANNEL 0 /* Use channel 0 */ +#define MY_AUDIO_CHANNEL_IS_STEREO GAUDOUT_CHANNEL0_IS_STEREO /* Is it stereo? */ // Storage for the wave header static char whdr[32]; @@ -61,7 +61,9 @@ int main(void) { // Any font will do font = gdispOpenFont("*"); - // Allocate audio buffers - 4 x 512 byte buffers. You may need to increase this for slower cpu's. + // Allocate audio buffers - 4 x 512 byte buffers. + // You may need to increase this for slower cpu's. + // You may be able to decrease this for low latency operating systems. if (!gaudioAllocBuffers(4, 512)) { errmsg = "Err: No Memory"; goto theend; @@ -179,8 +181,8 @@ int main(void) { } gfileClose(f); - // Wait 3 seconds for the play to finish - FIX THIS - gfxSleepMilliseconds(3000); + // Wait for the play to finish + gaudioPlayWait(TIME_INFINITE); gdispDrawString(0, gdispGetHeight()/2+10, "Done", font, Green); // The end diff --git a/demos/modules/audio/play-wave/romfs_allwrong.h b/demos/modules/gaudio/play-wave/romfs_allwrong.h similarity index 99% rename from demos/modules/audio/play-wave/romfs_allwrong.h rename to demos/modules/gaudio/play-wave/romfs_allwrong.h index a374bde3..adc74fc7 100644 --- a/demos/modules/audio/play-wave/romfs_allwrong.h +++ b/demos/modules/gaudio/play-wave/romfs_allwrong.h @@ -1,7 +1,7 @@ /** * This file was generated from "allwrong.wav" using... * - * file2c -bcs allwrong.wav romfs_allwrong.h + * file2c -dcs allwrong.wav romfs_allwrong.h * */ static const char allwrong[] = { diff --git a/demos/modules/audio/play-wave/romfs_files.h b/demos/modules/gaudio/play-wave/romfs_files.h similarity index 100% rename from demos/modules/audio/play-wave/romfs_files.h rename to demos/modules/gaudio/play-wave/romfs_files.h diff --git a/drivers/audio/Win32/driver.mk b/drivers/audio/Win32/driver.mk deleted file mode 100644 index 6f4ef084..00000000 --- a/drivers/audio/Win32/driver.mk +++ /dev/null @@ -1,6 +0,0 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/audio/Win32/gaudin_lld.c \ - $(GFXLIB)/drivers/audio/Win32/gaudout_lld.c - -# Required include directories -GFXINC += $(GFXLIB)/drivers/audio/Win32 diff --git a/drivers/audio/Win32/gaudin_lld.c b/drivers/audio/Win32/gaudin_lld.c deleted file mode 100644 index 2c8431cf..00000000 --- a/drivers/audio/Win32/gaudin_lld.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/audio/Win32/gaudin_lld.c - * @brief GAUDIN - Driver file for Win32. - */ - -#include "gfx.h" - -#if GFX_USE_GAUDIN - -/* Include the driver defines */ -#include "src/gaudin/driver.h" - -#undef Red -#undef Green -#undef Blue -#define WIN32_LEAN_AND_MEAN -#include -#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 deleted file mode 100644 index 78ddffaa..00000000 --- a/drivers/audio/Win32/gaudin_lld_config.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/audio/Win32/gaudin_lld_config.h - * @brief GAUDIN Driver config file. - * - * @addtogroup GAUDIN - * @{ - */ - -#ifndef GAUDIN_LLD_CONFIG_H -#define GAUDIN_LLD_CONFIG_H - -#if GFX_USE_GAUDIN - -/*===========================================================================*/ -/* Driver hardware support. */ -/*===========================================================================*/ - -/** - * @brief The audio input sample type - */ -//typedef uint8_t audin_sample_t; -typedef int16_t audin_sample_t; - -/** - * @brief The maximum sample frequency supported by this audio device - */ -#define GAUDIN_MAX_SAMPLE_FREQUENCY 44100 - -/** - * @brief The number of bits in a sample - */ -//#define GAUDIN_BITS_PER_SAMPLE 8 -#define GAUDIN_BITS_PER_SAMPLE 16 - -/** - * @brief The format of an audio sample - */ -//#define GAUDIN_SAMPLE_FORMAT ARRAY_DATA_8BITUNSIGNED -#define GAUDIN_SAMPLE_FORMAT ARRAY_DATA_16BITSIGNED - -/** - * @brief The number of audio channels supported by this driver - */ -#define GAUDIN_NUM_CHANNELS 2 - -/** - * @brief The list of audio channels and their uses - * @{ - */ -#define GAUDIN_MONO 0 -#define GAUDIN_STEREO 1 -/** @} */ - -#endif /* GFX_USE_GAUDIN */ - -#endif /* GAUDIN_LLD_CONFIG_H */ -/** @} */ diff --git a/drivers/audio/Win32/readme.txt b/drivers/audio/Win32/readme.txt deleted file mode 100644 index 784f0a89..00000000 --- a/drivers/audio/Win32/readme.txt +++ /dev/null @@ -1,10 +0,0 @@ -This driver uses the Win32 audio system to provide GAUDIN and GAUDOUT channels. - -For GAUDIN - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. -For GAUDOUT - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. - -For stereo, the samples are interleaved. Remember to allocate enough space for two samples per -sample period. - -This is a simple driver that makes no changes to the mixer so set up the audio mixer using -the windows control panel audio mixer before starting recording/playback. diff --git a/drivers/audio/gadc/driver.mk b/drivers/audio/gadc/driver.mk deleted file mode 100644 index b991ede8..00000000 --- a/drivers/audio/gadc/driver.mk +++ /dev/null @@ -1,5 +0,0 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.c - -# Required include directories -GFXINC += $(GFXLIB)/drivers/audio/gadc diff --git a/drivers/gaudio/Win32/driver.mk b/drivers/gaudio/Win32/driver.mk new file mode 100644 index 00000000..1ea338d5 --- /dev/null +++ b/drivers/gaudio/Win32/driver.mk @@ -0,0 +1,6 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/gaudio/Win32/gaudio_record_lld.c \ + $(GFXLIB)/drivers/gaudio/Win32/gaudio_play_lld.c + +# Required include directories +GFXINC += $(GFXLIB)/drivers/gaudio/Win32 diff --git a/drivers/audio/Win32/gaudout_lld_config.h b/drivers/gaudio/Win32/gaudio_play_config.h similarity index 56% rename from drivers/audio/Win32/gaudout_lld_config.h rename to drivers/gaudio/Win32/gaudio_play_config.h index 907d44c6..4013e91f 100644 --- a/drivers/audio/Win32/gaudout_lld_config.h +++ b/drivers/gaudio/Win32/gaudio_play_config.h @@ -6,17 +6,17 @@ */ /** - * @file drivers/audio/Win32/gaudout_lld_config.h - * @brief GAUDOUT Driver config file. + * @file drivers/gaudio/Win32/gaudio_play_config.h + * @brief GAUDIO Play Driver config file. * - * @addtogroup GAUDOUT + * @addtogroup GAUDIO * @{ */ -#ifndef GAUDOUT_LLD_CONFIG_H -#define GAUDIN_LLD_CONFIG_H +#ifndef GAUDIO_PLAY_CONFIG_H +#define GAUDIO_PLAY_CONFIG_H -#if GFX_USE_GAUDOUT +#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY /*===========================================================================*/ /* Driver hardware support. */ @@ -25,39 +25,39 @@ /** * @brief The maximum sample frequency supported by this audio device */ -#define GAUDOUT_MAX_SAMPLE_FREQUENCY 44100 +#define GAUDIO_PLAY_MAX_SAMPLE_FREQUENCY 44100 /** * @brief The number of audio formats supported by this driver */ -#define GAUDOUT_NUM_FORMATS 2 +#define GAUDIO_PLAY_NUM_FORMATS 2 /** * @brief The available audio sample formats in order of preference */ -#define GAUDOUT_FORMAT1 ARRAY_DATA_16BITSIGNED -#define GAUDOUT_FORMAT2 ARRAY_DATA_8BITUNSIGNED +#define GAUDIO_PLAY_FORMAT1 ARRAY_DATA_16BITSIGNED +#define GAUDIO_PLAY_FORMAT2 ARRAY_DATA_8BITUNSIGNED /** * @brief The number of audio channels supported by this driver */ -#define GAUDOUT_NUM_CHANNELS 2 +#define GAUDIO_PLAY_NUM_CHANNELS 2 /** * @brief Whether each channel is mono or stereo */ -#define GAUDOUT_CHANNEL0_STEREO FALSE -#define GAUDOUT_CHANNEL1_STEREO TRUE +#define GAUDIO_PLAY_CHANNEL0_IS_STEREO FALSE +#define GAUDIO_PLAY_CHANNEL1_IS_STEREO TRUE /** * @brief The list of audio channel names and their uses * @{ */ -#define GAUDOUT_MONO 0 -#define GAUDOUT_STEREO 1 +#define GAUDIO_PLAY_MONO 0 +#define GAUDIO_PLAY_STEREO 1 /** @} */ -#endif /* GFX_USE_GAUDOUT */ +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ -#endif /* GAUDOUT_LLD_CONFIG_H */ +#endif /* GAUDIO_PLAY_CONFIG_H */ /** @} */ diff --git a/drivers/audio/Win32/gaudout_lld.c b/drivers/gaudio/Win32/gaudio_play_lld.c similarity index 73% rename from drivers/audio/Win32/gaudout_lld.c rename to drivers/gaudio/Win32/gaudio_play_lld.c index 4fa6d605..6b4f2dab 100644 --- a/drivers/audio/Win32/gaudout_lld.c +++ b/drivers/gaudio/Win32/gaudio_play_lld.c @@ -6,16 +6,16 @@ */ /** - * @file drivers/audio/Win32/gaudout_lld.c - * @brief GAUDOUT - Driver file for Win32. + * @file drivers/gaudio/Win32/gaudio_play_lld.c + * @brief GAUDIO - Play Driver file for Win32. */ #include "gfx.h" -#if GFX_USE_GAUDOUT +#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY /* Include the driver defines */ -#include "src/gaudout/driver.h" +#include "src/gaudio/driver_play.h" #undef Red #undef Green @@ -36,20 +36,6 @@ static WAVEHDR WaveHdrs[MAX_WAVE_HEADERS]; static HANDLE waveThread; static DWORD threadID; -/* -static void PrintWaveErrorMsg(DWORD err, TCHAR * str) -{ - #define BUFFERSIZE 128 - char buffer[BUFFERSIZE]; - - fprintf(stderr, "GAUDOUT: ERROR 0x%08X: %s\r\n", err, str); - if (mciGetErrorString(err, &buffer[0], sizeof(buffer))) - fprintf(stderr, "%s\r\n", &buffer[0]); - else - fprintf(stderr, "0x%08X returned!\r\n", err); -} -*/ - /**************************** waveProc() ******************************* * We don't use CALLBACK_FUNCTION because it is restricted to calling only * a few particular Windows functions, namely some of the time functions, @@ -65,7 +51,9 @@ static bool_t senddata(WAVEHDR *pwh) { // Get the next data block to send gfxSystemLock(); - paud = gaudoutGetDataBlockI(); + paud = gaudioPlayGetDataBlockI(); + if (!paud && !nQueuedBuffers) + gaudioPlayDoneI(); gfxSystemUnlock(); if (!paud) return FALSE; @@ -77,13 +65,13 @@ static bool_t senddata(WAVEHDR *pwh) { pwh->dwFlags = 0; pwh->dwLoops = 0; if (waveOutPrepareHeader(ah, pwh, sizeof(WAVEHDR))) { - fprintf(stderr, "GAUDOUT: Failed to prepare a buffer"); + fprintf(stderr, "GAUDIO: Failed to prepare a play buffer"); exit(-1); } // Send it to windows if (waveOutWrite(ah, pwh, sizeof(WAVEHDR))) { - fprintf(stderr, "GAUDOUT: Failed to write the buffer"); + fprintf(stderr, "GAUDIO: Failed to write the play buffer"); exit(-1); } @@ -106,18 +94,25 @@ static DWORD WINAPI waveProc(LPVOID arg) { // Give the buffer back to the Audio Free List gfxSystemLock(); - gaudoutReleaseDataBlockI((GAudioData *)pwh->dwUser); + gaudioPlayReleaseDataBlockI((GAudioData *)pwh->dwUser); gfxSystemUnlock(); pwh->lpData = 0; nQueuedBuffers--; - // Try and get a new block - if ((!isRunning || !senddata(pwh)) && !nQueuedBuffers) { - gfxSystemLock(); - gaudoutDoneI(); - gfxSystemUnlock(); + // Are we stopping? + if (!isRunning) { + // Have we finished yet? + if (!nQueuedBuffers) { + gfxSystemLock(); + gaudioPlayDoneI(); + gfxSystemUnlock(); + } + break; } - break; + + // Try and get a new block + senddata(pwh); + break; } } return 0; @@ -127,17 +122,7 @@ static DWORD WINAPI waveProc(LPVOID arg) { /* External declarations. */ /*===========================================================================*/ -void gaudout_lld_deinit() { - if (ah) { - isRunning = FALSE; - waveOutReset(ah); - while(nQueuedBuffers) Sleep(1); - waveOutClose(ah); - ah = 0; - } -} - -bool_t gaudout_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { +bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { WAVEFORMATEX wfx; if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_16BITSIGNED) @@ -145,40 +130,41 @@ bool_t gaudout_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat fo if (!waveThread) { if (!(waveThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveProc, 0, 0, &threadID))) { - fprintf(stderr, "GAUDOUT: Can't create WAVE play-back thread\n"); + fprintf(stderr, "GAUDIO: Can't create WAVE play-back thread\n"); exit(-1); } CloseHandle(waveThread); } wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = channel == GAUDOUT_STEREO ? 2 : 1; + wfx.nChannels = channel == GAUDIO_PLAY_STEREO ? 2 : 1; wfx.nSamplesPerSec = frequency; wfx.nBlockAlign = wfx.nChannels * (format == ARRAY_DATA_8BITUNSIGNED ? 1 : 2); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.wBitsPerSample = (format == ARRAY_DATA_8BITUNSIGNED ? 8 : 16); wfx.cbSize = 0; + if (ah) { + waveOutClose(ah); + ah = 0; + } if (waveOutOpen(&ah, WAVE_MAPPER, &wfx, (DWORD_PTR)threadID, 0, CALLBACK_THREAD)) { - fprintf(stderr, "GAUDOUT: Can't open WAVE play-back device\n"); + fprintf(stderr, "GAUDIO: Can't open WAVE play-back device\n"); exit(-1); } return TRUE; } -bool_t gaudout_lld_set_volume(uint8_t vol) { +bool_t gaudio_play_lld_set_volume(uint8_t vol) { if (!ah) return FALSE; return waveOutSetVolume(ah, (((uint16_t)vol)<<8)|vol) != 0; } -void gaudout_lld_start(void) { +void gaudio_play_lld_start(void) { WAVEHDR *pwh; - if (!ah) - return; - isRunning = TRUE; while (nQueuedBuffers < MAX_WAVE_HEADERS) { // Find the empty one - there will always be at least one. @@ -190,10 +176,10 @@ void gaudout_lld_start(void) { } } -void gaudout_lld_stop(void) { +void gaudio_play_lld_stop(void) { isRunning = FALSE; - if (ah) - waveOutReset(ah); + waveOutReset(ah); + while(nQueuedBuffers) Sleep(1); } -#endif /* GFX_USE_GAUDOUT */ +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ diff --git a/drivers/gaudio/Win32/gaudio_record_config.h b/drivers/gaudio/Win32/gaudio_record_config.h new file mode 100644 index 00000000..4d952e1d --- /dev/null +++ b/drivers/gaudio/Win32/gaudio_record_config.h @@ -0,0 +1,63 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gaudio/Win32/gaudio_record_config.h + * @brief GAUDIO Record Driver config file. + * + * @addtogroup GAUDIO + * @{ + */ + +#ifndef GAUDIO_RECORD_CONFIG_H +#define GAUDIO_RECORD_CONFIG_H + +#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +/** + * @brief The maximum sample frequency supported by this audio device + */ +#define GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY 44100 + +/** + * @brief The number of audio formats supported by this driver + */ +#define GAUDIO_RECORD_NUM_FORMATS 2 + +/** + * @brief The available audio sample formats in order of preference + */ +#define GAUDIO_RECORD_FORMAT1 ARRAY_DATA_16BITSIGNED +#define GAUDIO_RECORD_FORMAT2 ARRAY_DATA_8BITUNSIGNED + +/** + * @brief The number of audio channels supported by this driver + */ +#define GAUDIO_RECORD_NUM_CHANNELS 2 + +/** + * @brief Whether each channel is mono or stereo + */ +#define GAUDIO_RECORD_CHANNEL0_IS_STEREO FALSE +#define GAUDIO_RECORD_CHANNEL1_IS_STEREO TRUE + +/** + * @brief The list of audio channels and their uses + * @{ + */ +#define GAUDIO_RECORD_MONO 0 +#define GAUDIO_RECORD_STEREO 1 +/** @} */ + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ + +#endif /* GAUDIO_RECORD_CONFIG_H */ +/** @} */ diff --git a/drivers/gaudio/Win32/gaudio_record_lld.c b/drivers/gaudio/Win32/gaudio_record_lld.c new file mode 100644 index 00000000..259707e3 --- /dev/null +++ b/drivers/gaudio/Win32/gaudio_record_lld.c @@ -0,0 +1,187 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gaudio/Win32/gaudio_record_lld.c + * @brief GAUDIO - Record Driver file for Win32. + */ + +#include "gfx.h" + +#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD + +/* Include the driver defines */ +#include "src/gaudio/driver_record.h" + +#undef Red +#undef Green +#undef Blue +#define WIN32_LEAN_AND_MEAN +#include +#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 chews buffers on the free-list. + +static HWAVEIN ah = 0; +static volatile int nQueuedBuffers; +static bool_t isRunning; +static WAVEHDR WaveHdrs[MAX_WAVE_HEADERS]; +static HANDLE waveThread; +static DWORD threadID; + +/**************************** waveProc() ******************************* + * We don't use CALLBACK_FUNCTION because it is restricted to calling only + * a few particular Windows functions, namely some of the time functions, + * and a few of the Low Level MIDI API. If you violate this rule, your app can + * hang inside of the callback). One of the Windows API that a callback can't + * call is waveInAddBuffer() which is what we need to use whenever we receive a + * MM_WIM_DATA. My callback would need to defer that job to another thread + * anyway, so instead just use CALLBACK_THREAD here instead. + *************************************************************************/ + +static bool_t getbuffer(WAVEHDR *pwh) { + GAudioData *paud; + + // Get the next data block to send + gfxSystemLock(); + paud = gaudioRecordGetFreeBlockI(); + if (!paud && !nQueuedBuffers) + gaudioRecordDoneI(); + gfxSystemUnlock(); + if (!paud) + return FALSE; + + // Prepare the wave header for Windows + pwh->dwUser = (DWORD_PTR)paud; + pwh->lpData = (LPSTR)(paud+1); // The data is on the end of the structure + pwh->dwBufferLength = paud->size; + pwh->dwFlags = 0; + if (waveInPrepareHeader(ah, pwh, sizeof(WAVEHDR))) { + fprintf(stderr, "GAUDIO: Failed to prepare a record buffer"); + exit(-1); + } + + // Send it to windows + if (waveInAddBuffer(ah, pwh, sizeof(WAVEHDR))) { + fprintf(stderr, "GAUDIO: Failed to add the record buffer"); + exit(-1); + } + + nQueuedBuffers++; + return TRUE; +} + +static DWORD WINAPI waveProc(LPVOID arg) { + MSG msg; + WAVEHDR *pwh; + GAudioData *paud; + (void) arg; + + while (GetMessage(&msg, 0, 0, 0)) { + switch (msg.message) { + case MM_WIM_DATA: + pwh = (WAVEHDR *)msg.lParam; + + // Windows - Let go! + waveInUnprepareHeader(ah, pwh, sizeof(WAVEHDR)); + + // Save the buffer in the audio record list + paud = (GAudioData *)pwh->dwUser; + paud->len = pwh->dwBytesRecorded; + gfxSystemLock(); + gaudioRecordSaveDataBlockI(paud); + gfxSystemUnlock(); + pwh->lpData = 0; + nQueuedBuffers--; + + // Are we stopping? + if (!isRunning) { + // Have we finished yet? + if (!nQueuedBuffers) { + gfxSystemLock(); + gaudioRecordDoneI(); + gfxSystemUnlock(); + } + break; + } + + // Try and get a new block + getbuffer(pwh); + break; + } + } + return 0; +} + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +bool_t gaudio_record_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { + WAVEFORMATEX wfx; + + if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_16BITSIGNED) + return FALSE; + + if (!waveThread) { + if (!(waveThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveProc, 0, 0, &threadID))) { + fprintf(stderr, "GAUDIO: Can't create WAVE recording thread\n"); + exit(-1); + } + CloseHandle(waveThread); + } + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = channel == GAUDIO_RECORD_STEREO ? 2 : 1; + wfx.nSamplesPerSec = frequency; + wfx.nBlockAlign = wfx.nChannels * (format == ARRAY_DATA_8BITUNSIGNED ? 1 : 2); + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + wfx.wBitsPerSample = (format == ARRAY_DATA_8BITUNSIGNED ? 8 : 16); + wfx.cbSize = 0; + + if (ah) { + waveInClose(ah); + ah = 0; + } + if (waveInOpen(&ah, WAVE_MAPPER, &wfx, (DWORD_PTR)threadID, 0, CALLBACK_THREAD)) { + fprintf(stderr, "GAUDIN: Can't open WAVE recording device\n"); + exit(-1); + } + + return TRUE; +} + +void gaudio_record_lld_start(void) { + WAVEHDR *pwh; + + if (!ah) + return; + + while (nQueuedBuffers < MAX_WAVE_HEADERS) { + // Find the empty one - there will always be at least one. + for(pwh = WaveHdrs; pwh->lpData; pwh++); + + // Grab the next audio block from the free-list + if (!getbuffer(pwh)) + break; + } + if (!isRunning) { + isRunning = TRUE; + waveInStart(ah); + } +} + +void gaudio_record_lld_stop(void) { + isRunning = FALSE; + waveInReset(ah); + while(nQueuedBuffers) Sleep(1); +} + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ diff --git a/drivers/gaudio/Win32/readme.txt b/drivers/gaudio/Win32/readme.txt new file mode 100644 index 00000000..83cb9c33 --- /dev/null +++ b/drivers/gaudio/Win32/readme.txt @@ -0,0 +1,10 @@ +This driver uses the Win32 audio system to provide GAUDIO play and record channels. + +For PLAY - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. +For RECORD - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. + +For stereo, the samples are interleaved. Remember to allocate enough space for two samples per +sample period. + +This is a simple driver that makes no changes to the mixer so set up the audio mixer using +the windows control panel audio mixer before starting recording/playback. diff --git a/drivers/gaudio/gadc/driver.mk b/drivers/gaudio/gadc/driver.mk new file mode 100644 index 00000000..4d79da25 --- /dev/null +++ b/drivers/gaudio/gadc/driver.mk @@ -0,0 +1,5 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/gaudio/gadc/gaudio_record_lld.c + +# Required include directories +GFXINC += $(GFXLIB)/drivers/gaudio/gadc diff --git a/drivers/audio/gadc/gaudin_lld_board_template.h b/drivers/gaudio/gadc/gaudio_record_board_template.h similarity index 66% rename from drivers/audio/gadc/gaudin_lld_board_template.h rename to drivers/gaudio/gadc/gaudio_record_board_template.h index 89cc0c12..26e87d88 100644 --- a/drivers/audio/gadc/gaudin_lld_board_template.h +++ b/drivers/gaudio/gadc/gaudio_record_board_template.h @@ -6,15 +6,15 @@ */ /** - * @file drivers/gaudin/gadc/gaudin_lld_board_template.h - * @brief GAUDIN Driver board config board file + * @file drivers/gaudio/gadc/gaudio_record_board_template.h + * @brief GAUDIO Record Driver board config board file * - * @addtogroup GAUDIN + * @addtogroup GAUDIO * @{ */ -#ifndef _GAUDIN_LLD_BOARD_H -#define _GAUDIN_LLD_BOARD_H +#ifndef _GAUDIO_RECORD_BOARD_H +#define _GAUDIO_RECORD_BOARD_H /*===========================================================================*/ /* Audio inputs on this board */ @@ -24,14 +24,14 @@ * @brief The number of audio channels supported by this driver * @note This is an example */ -#define GAUDIN_NUM_CHANNELS 1 +#define GAUDIO_RECORD_NUM_CHANNELS 1 /** * @brief The list of audio channels and their uses * @note This is an example * @{ */ -#define GAUDIN_MICROPHONE 0 +#define GAUDIO_RECORD_MICROPHONE 0 /** @} */ /** @@ -39,12 +39,12 @@ * @note This is an example * @{ */ -#ifdef GAUDIN_LLD_IMPLEMENTATION - static uint32_t gaudin_lld_physdevs[GAUDIN_NUM_CHANNELS] = { +#ifdef GAUDIO_RECORD_LLD_IMPLEMENTATION + static uint32_t gaudin_lld_physdevs[GAUDIO_RECORD_NUM_CHANNELS] = { GADC_PHYSDEV_MICROPHONE, }; #endif /** @} */ -#endif /* _GAUDIN_LLD_BOARD_H */ +#endif /* _GAUDIO_RECORD_BOARD_H */ /** @} */ diff --git a/drivers/audio/gadc/gaudin_lld_config.h b/drivers/gaudio/gadc/gaudio_record_config.h similarity index 59% rename from drivers/audio/gadc/gaudin_lld_config.h rename to drivers/gaudio/gadc/gaudio_record_config.h index a9fd02ae..22d8750f 100644 --- a/drivers/audio/gadc/gaudin_lld_config.h +++ b/drivers/gaudio/gadc/gaudio_record_config.h @@ -6,54 +6,54 @@ */ /** - * @file drivers/gaudin/gadc/gaudin_lld_config.h - * @brief GAUDIN Driver config file. + * @file drivers/gaudio/gadc/gaudio_record_config.h + * @brief GAUDIN Record Driver config file. * - * @addtogroup GAUDIN + * @addtogroup GAUDIO * @{ */ -#ifndef GAUDIN_LLD_CONFIG_H -#define GAUDIN_LLD_CONFIG_H +#ifndef GAUDIO_RECORD_CONFIG_H +#define GAUDIO_RECORD_CONFIG_H -#if GFX_USE_GAUDIN +#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD /*===========================================================================*/ /* Driver hardware support. */ /*===========================================================================*/ /** - * @brief The audio input sample type + * @brief The audio record sample type * @details For this driver it matches the cpu sample type */ -typedef adcsample_t audin_sample_t; +typedef adcsample_t audio_record_sample_t; /** * @brief The maximum sample frequency supported by this audio device * @details For this driver it matches the GADC maximum high speed sample rate */ -#define GAUDIN_MAX_SAMPLE_FREQUENCY GADC_MAX_HIGH_SPEED_SAMPLERATE +#define GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY GADC_MAX_HIGH_SPEED_SAMPLERATE /** * @brief The number of bits in a sample * @details For this driver it matches the cpu sample bits */ -#define GAUDIN_BITS_PER_SAMPLE GADC_BITS_PER_SAMPLE +#define GAUDIO_RECORD_BITS_PER_SAMPLE GADC_BITS_PER_SAMPLE /** * @brief The format of an audio sample * @details For this driver it matches the cpu sample format */ -#define GAUDIN_SAMPLE_FORMAT GADC_SAMPLE_FORMAT +#define GAUDIO_RECORD_SAMPLE_FORMAT GADC_SAMPLE_FORMAT /** - * For the GAUDIN driver that uses GADC - all the remaining config definitions are specific + * For the GAUDIO driver that uses GADC - all the remaining config definitions are specific * to the board. */ /* Include the user supplied board definitions */ -#include "gaudin_lld_board.h" +#include "gaudio_record_board.h" -#endif /* GFX_USE_GAUDIN */ +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ -#endif /* GAUDIN_LLD_CONFIG_H */ +#endif /* GAUDIO_RECORD_CONFIG_H */ /** @} */ diff --git a/drivers/audio/gadc/gaudin_lld.c b/drivers/gaudio/gadc/gaudio_record_lld.c similarity index 77% rename from drivers/audio/gadc/gaudin_lld.c rename to drivers/gaudio/gadc/gaudio_record_lld.c index 002d9e9b..ee994dc1 100644 --- a/drivers/audio/gadc/gaudin_lld.c +++ b/drivers/gaudio/gadc/gaudio_record_lld.c @@ -6,10 +6,10 @@ */ /** - * @file drivers/gaudin/gadc/gaudin_lld.c - * @brief GAUDIN - Driver file for using the cpu ADC (via GADC). + * @file drivers/gaudio/gadc/gaudio_record_lld.c + * @brief GAUDIO - Record Driver file for using the cpu ADC (via GADC). * - * @addtogroup GAUDIN + * @addtogroup GAUDIO * * @{ */ @@ -18,20 +18,20 @@ * We are now implementing the driver - pull in our channel table * from the board definitions. */ -#define GAUDIN_LLD_IMPLEMENTATION +#define GAUDIO_RECORD_IMPLEMENTATION #include "gfx.h" -#if GFX_USE_GAUDIN +#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD /* Double check the GADC system is turned on */ #if !GFX_USE_GADC - #error "GAUDIN - The GADC driver for GAUDIN requires GFX_USE_GADC to be TRUE" + #error "GAUDIO - The GADC driver for GAUDIO requires GFX_USE_GADC to be TRUE" #endif /* Include the driver defines */ -#include "src/gaudin/driver.h" +#include "src/gaudio/driver_record.h" /*===========================================================================*/ /* External declarations. */ @@ -58,5 +58,5 @@ void gaudin_lld_stop(void) { gadcHighSpeedStop(); } -#endif /* GFX_USE_GAUDIN */ +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ /** @} */ diff --git a/drivers/audio/gadc/readme.txt b/drivers/gaudio/gadc/readme.txt similarity index 71% rename from drivers/audio/gadc/readme.txt rename to drivers/gaudio/gadc/readme.txt index 1d3877e8..47d3f191 100644 --- a/drivers/audio/gadc/readme.txt +++ b/drivers/gaudio/gadc/readme.txt @@ -1,4 +1,4 @@ -This driver uses the generic GADC driver to provide a GAUDIN device. +This driver uses the generic GADC driver to provide a GAUDIO recording device. It supports whatever high speed device channels that your GADC driver and board supports. diff --git a/gfx.h b/gfx.h index 77aba969..de6047fc 100644 --- a/gfx.h +++ b/gfx.h @@ -62,7 +62,7 @@ * @brief GFX Graphics Display Basic API * @details Defaults to FALSE * @note Also add the specific hardware driver to your makefile. - * Eg. include $(GFXLIB)/drivers/gdisp/Nokia6610/gdisp_lld.mk + * Eg. include $(GFXLIB)/drivers/gdisp/Nokia6610/driver.mk */ #ifndef GFX_USE_GDISP #define GFX_USE_GDISP FALSE @@ -106,9 +106,9 @@ * @details Defaults to FALSE * @note Also add the specific hardware drivers to your makefile. * Eg. - * include $(GFXLIB)/drivers/ginput/toggle/Pal/ginput_lld.mk + * include $(GFXLIB)/drivers/ginput/toggle/Pal/driver.mk * and... - * include $(GFXLIB)/drivers/ginput/touch/MCU/ginput_lld.mk + * include $(GFXLIB)/drivers/ginput/touch/MCU/driver.mk */ #ifndef GFX_USE_GINPUT #define GFX_USE_GINPUT FALSE @@ -121,24 +121,14 @@ #define GFX_USE_GADC FALSE #endif /** - * @brief GFX Audio Input Device API + * @brief GFX Audio API * @details Defaults to FALSE * @note Also add the specific hardware drivers to your makefile. * Eg. - * include $(GFXLIB)/drivers/gaudin/GADC/gaudin_lld.mk + * include $(GFXLIB)/drivers/gaudio/GADC/driver.mk */ - #ifndef GFX_USE_GAUDIN - #define GFX_USE_GAUDIN FALSE - #endif - /** - * @brief GFX Audio Output Device API - * @details Defaults to FALSE - * @note Also add the specific hardware drivers to your makefile. - * Eg. - * include $(GFXLIB)/drivers/gaudout/PWM/gaudout_lld.mk - */ - #ifndef GFX_USE_GAUDOUT - #define GFX_USE_GAUDOUT FALSE + #ifndef GFX_USE_GAUDIO + #define GFX_USE_GAUDIO FALSE #endif /** * @brief GFX Miscellaneous Routines API @@ -173,8 +163,7 @@ #include "src/gwin/sys_options.h" #include "src/ginput/sys_options.h" #include "src/gadc/sys_options.h" -#include "src/gaudin/sys_options.h" -#include "src/gaudout/sys_options.h" +#include "src/gaudio/sys_options.h" /** * Interdependency safety checks on the sub-systems. @@ -187,8 +176,7 @@ #include "src/gwin/sys_rules.h" #include "src/ginput/sys_rules.h" #include "src/gdisp/sys_rules.h" -#include "src/gaudout/sys_rules.h" -#include "src/gaudin/sys_rules.h" +#include "src/gaudio/sys_rules.h" #include "src/gadc/sys_rules.h" #include "src/gevent/sys_rules.h" #include "src/gtimer/sys_rules.h" @@ -210,8 +198,7 @@ #include "src/gwin/sys_defs.h" #include "src/ginput/sys_defs.h" #include "src/gadc/sys_defs.h" -#include "src/gaudin/sys_defs.h" -#include "src/gaudout/sys_defs.h" +#include "src/gaudio/sys_defs.h" #ifdef __cplusplus extern "C" { @@ -231,7 +218,7 @@ extern "C" { /** * @brief The one call to end it all * - * @note This will deinitialise each sub-system that has been turned on. + * @note This will de-initialise each sub-system that has been turned on. * * @api */ diff --git a/gfx.mk b/gfx.mk index 8ac6e36b..8a2faa2b 100644 --- a/gfx.mk +++ b/gfx.mk @@ -9,7 +9,6 @@ include $(GFXLIB)/src/gtimer/sys_make.mk include $(GFXLIB)/src/gwin/sys_make.mk include $(GFXLIB)/src/ginput/sys_make.mk include $(GFXLIB)/src/gadc/sys_make.mk -include $(GFXLIB)/src/gaudin/sys_make.mk -include $(GFXLIB)/src/gaudout/sys_make.mk +include $(GFXLIB)/src/gaudio/sys_make.mk include $(GFXLIB)/src/gmisc/sys_make.mk include $(GFXLIB)/src/gfile/sys_make.mk diff --git a/gfxconf.example.h b/gfxconf.example.h index 79d932e8..99f5e569 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -218,15 +218,11 @@ /////////////////////////////////////////////////////////////////////////// -// GAUDIN // +// GAUDIO // /////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GAUDIN FALSE - - -/////////////////////////////////////////////////////////////////////////// -// GAUDOUT // -/////////////////////////////////////////////////////////////////////////// -#define GFX_USE_GAUDOUT FALSE +#define GFX_USE_GAUDIO FALSE + #define GAUDIO_NEED_PLAY FALSE + #define GAUDIO_NEED_RECORD FALSE /////////////////////////////////////////////////////////////////////////// @@ -243,4 +239,3 @@ #endif /* _GFXCONF_H */ - diff --git a/src/gaudin/driver.h b/src/gaudin/driver.h deleted file mode 100644 index b534e2a5..00000000 --- a/src/gaudin/driver.h +++ /dev/null @@ -1,102 +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 src/gaudin/driver.h - * @brief GAUDIN - Audio Input driver header file. - * - * @defgroup Driver Driver - * @ingroup GAUDIN - * @{ - */ - -#ifndef _GAUDIN_LLD_H -#define _GAUDIN_LLD_H - -#include "gfx.h" - -#if GFX_USE_GAUDIN || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Type definitions */ -/*===========================================================================*/ - -/** - * @brief The structure passed to start a audio conversion - * @note We use the structure instead of parameters purely to save - * interrupt stack space which is very limited in some platforms. - * @{ - */ -typedef struct gaudin_params_t { - uint16_t channel; - uint32_t frequency; - audin_sample_t *buffer; - size_t bufcount; - size_t samplesPerEvent; - } gaudin_params; -/** @} */ - -/** - * @brief These routines are the callbacks that the driver uses. - * @details Defined in the high level GAUDIN code. - * - * @iclass - * @notapi - * - * @{ - */ - -/** - * @param[in] buffer The buffer - * @param[in] n The amount of samples - * */ -extern void GAUDIN_ISR_CompleteI(audin_sample_t *buffer, size_t n); - -extern void GAUDIN_ISR_ErrorI(void); -/** - * @} - */ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Initialise the driver - * - * @param[in] paud Initialisation parameters - * - * @api - */ -void gaudin_lld_init(const gaudin_params *paud); - -/** - * @brief Start the audio input sampling - * - * @api - */ -void gaudin_lld_start(void); - -/** - * @brief Stop the audio input sampling - * - * @api - */ -void gaudin_lld_stop(void); - -#ifdef __cplusplus -} -#endif - -#endif /* GFX_USE_GADC */ - -#endif /* _GADC_LLD_H */ -/** @} */ diff --git a/src/gaudin/gaudin.c b/src/gaudin/gaudin.c deleted file mode 100644 index 2e3507ef..00000000 --- a/src/gaudin/gaudin.c +++ /dev/null @@ -1,158 +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 src/gaudin/gaudin.c - * @brief GAUDIN sub-system code. - * - * @addtogroup GAUDIN - * @{ - */ -#include "gfx.h" - -#if GFX_USE_GAUDIN - -/* Include the driver defines */ -#include "src/gaudin/driver.h" - -static gaudin_params aud; -static gfxSem *paudSem; -static GEventAudioIn *paudEvent; -static audin_sample_t *lastbuffer; -static size_t lastcount; -static uint16_t audFlags; - #define AUDFLG_RUNNING 0x0001 - #define AUDFLG_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 GAUDIN_ISR_CompleteI(audin_sample_t *buffer, size_t n) { - /* Save the details */ - lastcount = n; - lastbuffer = buffer; - - /* Signal the user with the data */ - if (paudEvent) { - #if GFX_USE_GEVENT - paudEvent->type = GEVENT_AUDIO_IN; - #endif - paudEvent->channel = aud.channel; - paudEvent->count = lastcount; - paudEvent->buffer = lastbuffer; - paudEvent->flags = 0; - } - - /* Our two signalling mechanisms */ - if (paudSem) - gfxSemSignalI(paudSem); - - #if GFX_USE_GEVENT - if (audFlags & AUDFLG_USE_EVENTS) - gtimerJabI(&AudGTimer); - #endif -} - -void GAUDIN_ISR_ErrorI(void) { - /* Ignore any errors for now */ -} - -void _gaudinInit(void) -{ - #if GFX_USE_GEVENT - gtimerInit(&AudGTimer); - #endif -} - -void _gaudinDeinit(void) -{ - // Commented stuff still ToDo - #if GFX_USE_GEVENT - gtimerDeinit(&AudGTimer); - #endif -} - -bool_t gaudinInit(uint16_t channel, uint32_t frequency, audin_sample_t *buffer, size_t bufcount, size_t samplesPerEvent) { - /* Check the channel is valid */ - if (channel >= GAUDIN_NUM_CHANNELS || frequency > GAUDIN_MAX_SAMPLE_FREQUENCY) - return FALSE; - - /* Stop any existing transfers */ - if ((audFlags & AUDFLG_RUNNING)) - gaudin_lld_stop(); - audFlags = 0; - - /* Initialise everything */ - aud.channel = channel; - aud.frequency = frequency; - aud.buffer = buffer; - aud.bufcount = bufcount; - aud.samplesPerEvent = samplesPerEvent; - paudSem = 0; - paudEvent = 0; - - /* Set up the low level driver */ - gaudin_lld_init(&aud); - return TRUE; -} - -#if GFX_USE_GEVENT - GSourceHandle gaudinGetSource(void) { - if (!gtimerIsActive(&AudGTimer)) - gtimerStart(&AudGTimer, AudGTimerCallback, 0, TRUE, TIME_INFINITE); - audFlags |= AUDFLG_USE_EVENTS; - return (GSourceHandle)&aud; - } -#endif - -void gaudinSetBSem(gfxSem *pbsem, GEventAudioIn *pEvent) { - gfxSystemLock(); - paudSem = pbsem; - paudEvent = pEvent; - gfxSystemUnlock(); -} - -void gaudinStart(void) { - if (!(audFlags & AUDFLG_RUNNING)) { - audFlags |= AUDFLG_RUNNING; - gaudin_lld_start(); - } -} - -void gaudinStop(void) { - if ((audFlags & AUDFLG_RUNNING)) { - gaudin_lld_stop(); - audFlags &= ~AUDFLG_RUNNING; - } -} - -#endif /* GFX_USE_GAUDIN */ -/** @} */ diff --git a/src/gaudin/sys_defs.h b/src/gaudin/sys_defs.h deleted file mode 100644 index c65a69c1..00000000 --- a/src/gaudin/sys_defs.h +++ /dev/null @@ -1,174 +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 src/gaudin/sys_defs.h - * - * @addtogroup GAUDIN - * - * @brief Module to read audio inputs - * - * @{ - */ - -#ifndef _GAUDIN_H -#define _GAUDIN_H - -#include "gfx.h" - -#if GFX_USE_GAUDIN || defined(__DOXYGEN__) - -/* Include the driver defines */ -#include "gaudin_lld_config.h" - -/*===========================================================================*/ -/* Type definitions */ -/*===========================================================================*/ - -// Event types for GAUDIN -#define GEVENT_AUDIO_IN (GEVENT_GAUDIN_FIRST+0) - -/** - * @brief The Audio Input event structure. - * @{ - */ -typedef struct GEventAudioIn_t { - #if GFX_USE_GEVENT || defined(__DOXYGEN__) - /** - * @brief The type of this event (GEVENT_AUDIO_IN) - */ - GEventType type; - #endif - /** - * @brief The current channel - */ - uint16_t channel; - /** - * @brief The event flags - */ - uint16_t flags; - /** - * @brief The event flag values. - * @{ - */ - #define GAUDIN_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */ - /** @} */ - /** - * @brief The number of audio samples in the buffer - */ - size_t count; - /** - * @brief The buffer containing the audio samples - */ - audin_sample_t *buffer; -} GEventAudioIn; -/** @} */ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Initialise (but not start) the Audio Input Subsystem. - * @details Returns FALSE for an invalid channel or other invalid parameter. - * - * @param[in] channel The channel to convert. Can be set from 0 to GAUDIN_NUM_CHANNELS - 1. - * @param[in] frequency The sample frequency - * @param[in] buffer The static buffer to put the samples into. - * @param[in] bufcount The total number of conversions that will fit in the buffer. - * @param[in] samplesPerEvent The number of conversions to do before returning an event. - * - * @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 it would be common for the low level driver to also - * offer the left and right channels separately. - * @note Due to a bug in Chibi-OS countPerEvent must be even if using the GADC low level audio driver. - * If bufcount is not evenly divisable by countPerEvent, the remainder must also be even. - * This requirement may not apply to other GAUDIN drivers. - * @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. Note 'bufcount' and 'countPerEvent' parameters describe the - * number of conversions not the number of samples. - * @note The buffer is circular. When the end of the buffer is reached it will start - * putting data into the beginning of the buffer again. - * @note The event listener must process the event (and the data in it) before the - * next event occurs. If not, the following event will be lost. - * @note If bufcount is evenly divisable by countPerEvent, then every event will return - * countPerEvent conversions. If bufcount is not evenly divisable, it will return - * a block of samples containing less than countPerEvent samples when it reaches the - * end of the buffer. - * - * @return FALSE if invalid channel or parameter - * - * @api - */ -bool_t gaudinInit(uint16_t channel, uint32_t frequency, audin_sample_t *buffer, size_t bufcount, size_t samplesPerEvent); - -#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_IN events. - * - * @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 gaudinInit() again. - * @note The audio input is capable of signalling via this method and a binary semaphore - * at the same time. - * - * @return The GSourceHandle - * - * @api - */ - GSourceHandle gaudinGetSource(void); -#endif - -/** - * @brief Allow retrieving of results from the audio input using a Binary Semaphore and a static event buffer. - * - * @param[in] pbsem The semaphore is signaled when data is available. - * @param[in] pEvent The static event buffer to place the result information. - * - * @note Passing a NULL for pbsem or pEvent will turn off signalling via this method. - * @note The audio input is capable of signalling via this method and the GEVENT - * sub-system at the same time. - * - * @api - */ -void gaudinSetBSem(gfxSem *pbsem, GEventAudioIn *pEvent); - -/** - * @brief Start the audio input conversions. - * @pre It must have been initialised first with @p gaudinInit() - * - * @api - */ -void gaudinStart(void); - -/** - * @brief Stop the audio input conversions. - * - * @api - */ -void gaudinStop(void); - -#ifdef __cplusplus -} -#endif - -#endif /* GFX_USE_GAUDIN */ - -#endif /* _GAUDIN_H */ -/** @} */ - diff --git a/src/gaudin/sys_make.mk b/src/gaudin/sys_make.mk deleted file mode 100644 index 16bb33b7..00000000 --- a/src/gaudin/sys_make.mk +++ /dev/null @@ -1 +0,0 @@ -GFXSRC += $(GFXLIB)/src/gaudin/gaudin.c diff --git a/src/gaudin/sys_options.h b/src/gaudin/sys_options.h deleted file mode 100644 index 305a6f8d..00000000 --- a/src/gaudin/sys_options.h +++ /dev/null @@ -1,32 +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 src/gaudin/sys_options.h - * @brief GAUDIN - Audio Input subsystem options header file. - * - * @addtogroup GAUDIN - * @{ - */ - -#ifndef _GAUDIN_OPTIONS_H -#define _GAUDIN_OPTIONS_H - -/** - * @name GAUDIN Functionality to be included - * @{ - */ -/** - * @} - * - * @name GAUDIN Optional Sizing Parameters - * @{ - */ -/** @} */ - -#endif /* _GAUDIN_OPTIONS_H */ -/** @} */ diff --git a/src/gaudin/sys_rules.h b/src/gaudin/sys_rules.h deleted file mode 100644 index 21d2552f..00000000 --- a/src/gaudin/sys_rules.h +++ /dev/null @@ -1,30 +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 src/gaudin/sys_rules.h - * @brief GAUDIN safety rules header file. - * - * @addtogroup GAUDIN - * @{ - */ - -#ifndef _GAUDIN_RULES_H -#define _GAUDIN_RULES_H - -#if GFX_USE_GAUDIN - #if GFX_USE_GEVENT && !GFX_USE_GTIMER - #if GFX_DISPLAY_RULE_WARNINGS - #warning "GAUDIN: GFX_USE_GTIMER is required if GFX_USE_GAUDIN 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 /* _GAUDIN_RULES_H */ -/** @} */ diff --git a/src/gaudout/driver.h b/src/gaudio/driver_play.h similarity index 60% rename from src/gaudout/driver.h rename to src/gaudio/driver_play.h index bd00d06d..72ad4747 100644 --- a/src/gaudout/driver.h +++ b/src/gaudio/driver_play.h @@ -6,20 +6,20 @@ */ /** - * @file src/gaudout/driver.h - * @brief GAUDOUT - Audio Output driver header file. + * @file src/gaudio/driver_play.h + * @brief GAUDIO - Audio play driver header file. * * @defgroup Driver Driver - * @ingroup GAUDOUT + * @ingroup GAUDIO * @{ */ -#ifndef _GAUDOUT_LLD_H -#define _GAUDOUT_LLD_H +#ifndef _GAUDIO_PLAY_LLD_H +#define _GAUDIO_PLAY_LLD_H #include "gfx.h" -#if GFX_USE_GAUDOUT || defined(__DOXYGEN__) +#if (GFX_USE_GAUDIO && GAUDIO_NEED_PLAY) || defined(__DOXYGEN__) /*===========================================================================*/ /* Type definitions */ @@ -37,38 +37,38 @@ extern "C" { * @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. + * @note Defined in the high level GAUDIO code for use by the GAUDIO play drivers. * * @iclass * @notapi */ -GAudioData *gaudoutGetDataBlockI(void); +GAudioData *gaudioPlayGetDataBlockI(void); /** - * @brief Release a block of audio data after playing + * @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 GAUDOUT code for use by the GAUDOUT drivers. + * @note Defined in the high level GAUDIO code for use by the GAUDIO play drivers. * * @iclass * @notapi */ -void gaudoutReleaseDataBlockI(GAudioData *paud); +void gaudioPlayReleaseDataBlockI(GAudioData *paud); /** * @brief Signal that all playing has now stopped * - * @note Defined in the high level GAUDOUT code for use by the GAUDOUT drivers. + * @note Defined in the high level GAUDIO code for use by the GAUDIO play drivers. * * @iclass * @notapi */ -void gaudoutDoneI(void); +void gaudioPlayDoneI(void); /** - * @brief Initialise the driver - * @return TRUE if the channel and frequency are valid. + * @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 @@ -78,38 +78,30 @@ void gaudoutDoneI(void); * * @api */ -bool_t gaudout_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format); - -/** - * @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); +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 gaudoutGetDataBlockI(). + * to play using @p gaudioPlayGetDataBlockI(). * * @api */ -void gaudout_lld_start(void); +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 This may be called before a @p gaudout_lld_init() has occurred. + * @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 gaudout_lld_stop(void); +void gaudio_play_lld_stop(void); /** * @brief Set the output volume. @@ -122,13 +114,13 @@ void gaudout_lld_stop(void); * * @api */ -bool_t gaudout_lld_set_volume(uint8_t vol); +bool_t gaudio_play_lld_set_volume(uint8_t vol); #ifdef __cplusplus } #endif -#endif /* GFX_USE_GAUDOUT */ +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ -#endif /* _GAUDOUT_LLD_H */ +#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 */ +/** @} */ diff --git a/src/gaudout/gaudout.c b/src/gaudout/gaudout.c deleted file mode 100644 index 00b01e91..00000000 --- a/src/gaudout/gaudout.c +++ /dev/null @@ -1,169 +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 src/gaudout/gaudout.c - * @brief GAUDOUT sub-system code. - * - * @addtogroup GAUDOUT - * @{ - */ -#include "gfx.h" - -#if GFX_USE_GAUDOUT || defined(__DOXYGEN__) - -#include "src/gaudout/driver.h" - -static gfxQueueASync playlist; -static gfxQueueGSync freelist; - -static uint16_t PlayFlags; - #define PLAYFLG_USEEVENTS 0x0001 - #define PLAYFLG_PLAYING 0x0002 - -#if GFX_USE_GEVENT - static GTimer PlayTimer; - - static void PlayTimerCallback(void *param) { - (void) param; - GSourceListener *psl; - GEventAudioOut *pe; - - psl = 0; - while ((psl = geventGetSourceListener((GSourceHandle)(&aud), psl))) { - if (!(pe = (GEventAudioOut *)geventGetEventBuffer(psl))) { - // This listener is missing - save this. - psl->srcflags |= GAUDOUT_LOSTEVENT; - continue; - } - - pe->type = GEVENT_AUDIO_OUT; - pe->flags = psl->srcflags; - psl->srcflags = 0; - if ((PlayFlags & PLAYFLG_PLAYING)) - pe->flags |= GAUDOUT_PLAYING; - if (!gfxQueueGSyncIsEmpty(&freelist)) - pe->flags |= GAUDOUT_FREEBLOCK; - geventSendEvent(psl); - } - } -#endif - - -void _gaudoutInit(void) -{ - gfxQueueASyncInit(&playlist); - gfxQueueGSyncInit(&freelist); - #if GFX_USE_GEVENT - gtimerInit(&PlayTimer); - #endif -} - -void _gaudoutDeinit(void) -{ - /* ToDo */ - #if GFX_USE_GEVENT - gtimerDeinit(&PlayTimer); - #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); -} - -bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { - gaudioPlayStop(); - gaudout_lld_deinit(); - return gaudout_lld_init(channel, frequency, format); -} - -void gaudioPlay(GAudioData *paud) { - if (paud) - gfxQueueASyncPut(&playlist, (gfxQueueASyncItem *)paud); - PlayFlags |= PLAYFLG_PLAYING; - 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); - PlayFlags &= ~PLAYFLG_PLAYING; -} - -bool_t gaudioPlaySetVolume(uint8_t vol) { - return gaudout_lld_set_volume(vol); -} - -#if GFX_USE_GEVENT || defined(__DOXYGEN__) - GSourceHandle gaudioPlayGetSource(void) { - if (!gtimerIsActive(&PlayTimer)) - gtimerStart(&PlayTimer, PlayTimerCallback, 0, TRUE, TIME_INFINITE); - PlayFlags |= PLAYFLG_USEEVENTS; - return (GSourceHandle)&PlayFlags; - } -#endif - -/** - * Routines provided for use by drivers. - */ - -GAudioData *gaudoutGetDataBlockI(void) { - return (GAudioData *)gfxQueueASyncGetI(&playlist); -} - -void gaudoutReleaseDataBlockI(GAudioData *paud) { - gfxQueueGSyncPutI(&freelist, (gfxQueueGSyncItem *)paud); - #if GFX_USE_GEVENT - if (PlayFlags & PLAYFLG_USEEVENTS) - gtimerJabI(&PlayTimer); - #endif -} - -void gaudoutDoneI(void) { - PlayFlags &= ~PLAYFLG_PLAYING; - #if GFX_USE_GEVENT - if (PlayFlags & PLAYFLG_USEEVENTS) - gtimerJabI(&PlayTimer); - #endif -} - -#endif /* GFX_USE_GAUDOUT */ -/** @} */ - diff --git a/src/gaudout/sys_defs.h b/src/gaudout/sys_defs.h deleted file mode 100644 index 75cda243..00000000 --- a/src/gaudout/sys_defs.h +++ /dev/null @@ -1,217 +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 src/gaudout/sys_defs.h - * - * @addtogroup GAUDOUT - * - * @brief Module to output audio data (under development) - * - * @{ - */ - -#ifndef _GAUDOUT_H -#define _GAUDOUT_H - -#include "gfx.h" - -#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 bytes) -} GAudioData; - - -// Event types for GAUDOUT -#define GEVENT_AUDIO_OUT (GEVENT_GAUDOUT_FIRST+0) - -/** - * @brief The Audio output event structure. - * @{ - */ -typedef struct GEventAudioOut_t { - #if GFX_USE_GEVENT || defined(__DOXYGEN__) - /** - * @brief The type of this event (GEVENT_AUDIO_OUT) - */ - GEventType type; - #endif - /** - * @brief The event flags - */ - uint16_t flags; - /** - * @brief The event flag values. - * @{ - */ - #define GAUDOUT_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_OUT event was lost */ - #define GAUDOUT_PLAYING 0x0002 /**< @brief The audio out system is currently playing */ - #define GAUDOUT_FREEBLOCK 0x0004 /**< @brief An audio buffer has been freed */ - /** @} */ -} GEventAudioOut; -/** @} */ - -/*===========================================================================*/ -/* 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); - -/** - * @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 - * @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 signalling via this method and other methods - * at the same time. - * - * @return The GSourceHandle - * - * @api - */ - GSourceHandle gaudioPlayGetSource(void); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* GFX_USE_GAUDOUT */ - -#endif /* _GAUDOUT_H */ -/** @} */ - diff --git a/src/gaudout/sys_make.mk b/src/gaudout/sys_make.mk deleted file mode 100644 index 14f5bac3..00000000 --- a/src/gaudout/sys_make.mk +++ /dev/null @@ -1 +0,0 @@ -GFXSRC += $(GFXLIB)/src/gaudout/gaudout.c diff --git a/src/gaudout/sys_options.h b/src/gaudout/sys_options.h deleted file mode 100644 index 929bb42a..00000000 --- a/src/gaudout/sys_options.h +++ /dev/null @@ -1,32 +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 src/gaudout/sys_options.h - * @brief GAUDOUT - Audio Output subsystem options header file. - * - * @addtogroup GAUDOUT - * @{ - */ - -#ifndef _GAUDOUT_OPTIONS_H -#define _GAUDOUT_OPTIONS_H - -/** - * @name GAUDOUT Functionality to be included - * @{ - */ -/** - * @} - * - * @name GAUDOUT Optional Sizing Parameters - * @{ - */ -/** @} */ - -#endif /* _GAUDOUT_OPTIONS_H */ -/** @} */ diff --git a/src/gaudout/sys_rules.h b/src/gaudout/sys_rules.h deleted file mode 100644 index 8274e031..00000000 --- a/src/gaudout/sys_rules.h +++ /dev/null @@ -1,44 +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 src/gaudout/sys_rules.h - * @brief GAUDOUT safety rules header file. - * - * @addtogroup GAUDOUT - * @{ - */ - -#ifndef _GAUDOUT_RULES_H -#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 */ -/** @} */ diff --git a/src/gevent/sys_defs.h b/src/gevent/sys_defs.h index 0e656145..c50dc5ae 100644 --- a/src/gevent/sys_defs.h +++ b/src/gevent/sys_defs.h @@ -38,8 +38,7 @@ typedef uint16_t GEventType; #define GEVENT_GINPUT_FIRST 0x0100 // GINPUT events range from 0x0100 to 0x01FF #define GEVENT_GWIN_FIRST 0x0200 // GWIN events range from 0x0200 to 0x02FF #define GEVENT_GADC_FIRST 0x0300 // GADC events range from 0x0300 to 0x033F - #define GEVENT_GAUDIN_FIRST 0x0340 // GAUDIN events range from 0x0340 to 0x037F - #define GEVENT_GAUDOUT_FIRST 0x0380 // GAUDOUT events range from 0x0380 to 0x03BF + #define GEVENT_GAUDIO_FIRST 0x0340 // GAUDIO events range from 0x0340 to 0x037F #define GEVENT_USER_FIRST 0x8000 // Any application defined events start at 0x8000 // This object can be typecast to any GEventXxxxx type to allow any sub-system (or the application) to create events. diff --git a/src/gfx.c b/src/gfx.c index d01d3b1f..8e92fc29 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -44,13 +44,9 @@ extern void _gosDeinit(void); extern void _gadcInit(void); extern void _gadcDeinit(void); #endif -#if GFX_USE_GAUDIN - extern void _gaudinInit(void); - extern void _gaudinDeinit(void); -#endif -#if GFX_USE_GAUDOUT - extern void _gaudoutInit(void); - extern void _gaudoutDeinit(void); +#if GFX_USE_GAUDIO + extern void _gaudioInit(void); + extern void _gaudioDeinit(void); #endif #if GFX_USE_GMISC extern void _gmiscInit(void); @@ -88,11 +84,8 @@ void gfxInit(void) #if GFX_USE_GADC _gadcInit(); #endif - #if GFX_USE_GAUDIN - _gaudinInit(); - #endif - #if GFX_USE_GAUDOUT - _gaudoutInit(); + #if GFX_USE_GAUDIO + _gaudioInit(); #endif } @@ -103,11 +96,8 @@ void gfxDeinit(void) initDone = FALSE; // We deinitialise the opposite way as we initialised - #if GFX_USE_GAUDOUT - _gaudoutDeinit(); - #endif #if GFX_USE_GAUDIN - _gaudinDeinit(); + _gaudioDeinit(); #endif #if GFX_USE_GADC _gadcDeinit();