diff --git a/drivers/audio/Win32/gaudout_lld.c b/drivers/audio/Win32/gaudout_lld.c index fd70c80b..4fa6d605 100644 --- a/drivers/audio/Win32/gaudout_lld.c +++ b/drivers/audio/Win32/gaudout_lld.c @@ -77,16 +77,14 @@ static bool_t senddata(WAVEHDR *pwh) { pwh->dwFlags = 0; pwh->dwLoops = 0; if (waveOutPrepareHeader(ah, pwh, sizeof(WAVEHDR))) { - pwh->lpData = 0; fprintf(stderr, "GAUDOUT: Failed to prepare a buffer"); - return FALSE; + exit(-1); } // Send it to windows if (waveOutWrite(ah, pwh, sizeof(WAVEHDR))) { - pwh->lpData = 0; fprintf(stderr, "GAUDOUT: Failed to write the buffer"); - return FALSE; + exit(-1); } nQueuedBuffers++; @@ -114,8 +112,11 @@ static DWORD WINAPI waveProc(LPVOID arg) { nQueuedBuffers--; // Try and get a new block - if (isRunning) - senddata(pwh); + if ((!isRunning || !senddata(pwh)) && !nQueuedBuffers) { + gfxSystemLock(); + gaudoutDoneI(); + gfxSystemUnlock(); + } break; } } @@ -145,7 +146,7 @@ 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"); - return FALSE; + exit(-1); } CloseHandle(waveThread); } @@ -160,7 +161,7 @@ bool_t gaudout_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat fo if (waveOutOpen(&ah, WAVE_MAPPER, &wfx, (DWORD_PTR)threadID, 0, CALLBACK_THREAD)) { fprintf(stderr, "GAUDOUT: Can't open WAVE play-back device\n"); - return FALSE; + exit(-1); } return TRUE; diff --git a/drivers/audio/Win32/gaudout_lld_config.h b/drivers/audio/Win32/gaudout_lld_config.h index 157f33f0..0fb90508 100644 --- a/drivers/audio/Win32/gaudout_lld_config.h +++ b/drivers/audio/Win32/gaudout_lld_config.h @@ -22,28 +22,21 @@ /* Driver hardware support. */ /*===========================================================================*/ -/** - * @brief The audio input sample type - */ -//typedef uint8_t audout_sample_t; -typedef int16_t audout_sample_t; - /** * @brief The maximum sample frequency supported by this audio device */ -#define GAUDOUT_MAX_SAMPLE_FREQUENCY 44100 +#define GAUDOUT_MAX_SAMPLE_FREQUENCY 44100 /** - * @brief The number of bits in a sample + * @brief The number of audio formats supported by this driver */ -//#define GAUDOUT_BITS_PER_SAMPLE 8 -#define GAUDOUT_BITS_PER_SAMPLE 16 +#define GAUDOUT_NUM_FORMATS 2 /** - * @brief The format of an audio sample + * @brief The available audio sample formats in order of preference */ -//#define GAUDOUT_SAMPLE_FORMAT ARRAY_DATA_8BITUNSIGNED -#define GAUDOUT_SAMPLE_FORMAT ARRAY_DATA_16BITSIGNED +#define GAUDOUT_FORMAT1 ARRAY_DATA_16BITSIGNED +#define GAUDOUT_FORMAT2 ARRAY_DATA_8BITUNSIGNED /** * @brief The number of audio channels supported by this driver diff --git a/src/gaudout/driver.h b/src/gaudout/driver.h index 8e72dff4..bd00d06d 100644 --- a/src/gaudout/driver.h +++ b/src/gaudout/driver.h @@ -56,6 +56,16 @@ GAudioData *gaudoutGetDataBlockI(void); */ void gaudoutReleaseDataBlockI(GAudioData *paud); +/** + * @brief Signal that all playing has now stopped + * + * @note Defined in the high level GAUDOUT code for use by the GAUDOUT drivers. + * + * @iclass + * @notapi + */ +void gaudoutDoneI(void); + /** * @brief Initialise the driver * @return TRUE if the channel and frequency are valid. diff --git a/src/gaudout/gaudout.c b/src/gaudout/gaudout.c index 275677c8..00b01e91 100644 --- a/src/gaudout/gaudout.c +++ b/src/gaudout/gaudout.c @@ -21,32 +21,33 @@ static gfxQueueASync playlist; static gfxQueueGSync freelist; -static uint16_t audFlags; - #define AUDOUTFLG_RUNNING 0x0001 - #define AUDOUTFLG_USE_EVENTS 0x0002 +static uint16_t PlayFlags; + #define PLAYFLG_USEEVENTS 0x0001 + #define PLAYFLG_PLAYING 0x0002 #if GFX_USE_GEVENT - static GTimer AudGTimer; + static GTimer PlayTimer; - static void AudGTimerCallback(void *param) { + static void PlayTimerCallback(void *param) { (void) param; GSourceListener *psl; - GEventADC *pe; + GEventAudioOut *pe; psl = 0; while ((psl = geventGetSourceListener((GSourceHandle)(&aud), psl))) { - if (!(pe = (GEventAudioIn *)geventGetEventBuffer(psl))) { + if (!(pe = (GEventAudioOut *)geventGetEventBuffer(psl))) { // This listener is missing - save this. - psl->srcflags |= GAUDIN_LOSTEVENT; + psl->srcflags |= GAUDOUT_LOSTEVENT; continue; } - pe->type = GEVENT_AUDIO_IN; - pe->channel = aud.channel; - pe->count = lastcount; - pe->buffer = lastbuffer; + 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); } } @@ -57,11 +58,17 @@ 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) { @@ -103,6 +110,7 @@ bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat form void gaudioPlay(GAudioData *paud) { if (paud) gfxQueueASyncPut(&playlist, (gfxQueueASyncItem *)paud); + PlayFlags |= PLAYFLG_PLAYING; gaudout_lld_start(); } @@ -116,12 +124,22 @@ void gaudioPlayStop(void) { 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. */ @@ -132,8 +150,19 @@ GAudioData *gaudoutGetDataBlockI(void) { 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 index 4f09678b..75cda243 100644 --- a/src/gaudout/sys_defs.h +++ b/src/gaudout/sys_defs.h @@ -42,6 +42,36 @@ typedef struct GAudioData { 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. */ /*===========================================================================*/ @@ -96,6 +126,8 @@ void gaudioReleaseBuffer(GAudioData *paud); * * @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 */ @@ -155,6 +187,25 @@ void gaudioPlayStop(void); */ 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