From c5a86757bd8309027d50f82d8947250c8e1197e6 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 21 Nov 2015 19:27:08 +1000 Subject: Make all include paths in ugfx relative. The only include path now needed is for drivers (in particular GDISP drivers) --- drivers/gaudio/Win32/driver.mk | 6 +- drivers/gaudio/Win32/gaudio_play_Win32.c | 183 +++++++++++++++ drivers/gaudio/Win32/gaudio_play_lld.c | 183 --------------- drivers/gaudio/Win32/gaudio_record_Win32.c | 185 +++++++++++++++ drivers/gaudio/Win32/gaudio_record_lld.c | 185 --------------- drivers/gaudio/gadc/driver.mk | 5 +- drivers/gaudio/gadc/gaudio_record_gadc.c | 55 +++++ drivers/gaudio/gadc/gaudio_record_lld.c | 55 ----- drivers/gaudio/pwm/driver.mk | 5 +- drivers/gaudio/pwm/gaudio_play_lld.c | 117 ---------- drivers/gaudio/pwm/gaudio_play_pwm.c | 117 ++++++++++ drivers/gaudio/vs1053/driver.mk | 7 +- drivers/gaudio/vs1053/gaudio_play_lld.c | 361 ----------------------------- drivers/gaudio/vs1053/gaudio_play_vs1053.c | 361 +++++++++++++++++++++++++++++ 14 files changed, 906 insertions(+), 919 deletions(-) create mode 100644 drivers/gaudio/Win32/gaudio_play_Win32.c delete mode 100644 drivers/gaudio/Win32/gaudio_play_lld.c create mode 100644 drivers/gaudio/Win32/gaudio_record_Win32.c delete mode 100644 drivers/gaudio/Win32/gaudio_record_lld.c create mode 100644 drivers/gaudio/gadc/gaudio_record_gadc.c delete mode 100644 drivers/gaudio/gadc/gaudio_record_lld.c delete mode 100644 drivers/gaudio/pwm/gaudio_play_lld.c create mode 100644 drivers/gaudio/pwm/gaudio_play_pwm.c delete mode 100644 drivers/gaudio/vs1053/gaudio_play_lld.c create mode 100644 drivers/gaudio/vs1053/gaudio_play_vs1053.c (limited to 'drivers/gaudio') diff --git a/drivers/gaudio/Win32/driver.mk b/drivers/gaudio/Win32/driver.mk index f959279f..aa3ed3ab 100644 --- a/drivers/gaudio/Win32/driver.mk +++ b/drivers/gaudio/Win32/driver.mk @@ -1,6 +1,4 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gaudio/Win32/gaudio_record_lld.c \ - $(GFXLIB)/drivers/gaudio/Win32/gaudio_play_lld.c - GFXINC += $(GFXLIB)/drivers/gaudio/Win32 +GFXSRC += $(GFXLIB)/drivers/gaudio/Win32/gaudio_record_Win32.c \ + $(GFXLIB)/drivers/gaudio/Win32/gaudio_play_Win32.c GFXLIBS += winmm diff --git a/drivers/gaudio/Win32/gaudio_play_Win32.c b/drivers/gaudio/Win32/gaudio_play_Win32.c new file mode 100644 index 00000000..baafd4ce --- /dev/null +++ b/drivers/gaudio/Win32/gaudio_play_Win32.c @@ -0,0 +1,183 @@ +/* + * 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 + */ + +// We need to include stdio.h below. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts +#define GFILE_NEED_STDIO_MUST_BE_OFF + +#include "gfx.h" + +#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY + +/* Include the driver defines */ +#include "../../../src/gaudio/gaudio_driver_play.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 also create higher latency. + +static HWAVEOUT 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 waveOutUnPrepareBuffer() which is what we need to use whenever we receive a + * MM_WOM_DONE. My callback would need to defer that job to another thread + * anyway, so instead just use CALLBACK_THREAD here instead. + *************************************************************************/ + +static bool_t senddata(WAVEHDR *pwh) { + GDataBuffer *paud; + + // Get the next data block to send + gfxSystemLock(); + paud = gaudioPlayGetDataBlockI(); + if (!paud && !nQueuedBuffers) + gaudioPlayDoneI(); + 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->len; + pwh->dwFlags = 0; + pwh->dwLoops = 0; + if (waveOutPrepareHeader(ah, pwh, sizeof(WAVEHDR))) { + fprintf(stderr, "GAUDIO: Failed to prepare a play buffer"); + exit(-1); + } + + // Send it to windows + if (waveOutWrite(ah, pwh, sizeof(WAVEHDR))) { + fprintf(stderr, "GAUDIO: Failed to write the play buffer"); + exit(-1); + } + + nQueuedBuffers++; + return TRUE; +} + +static DWORD WINAPI waveProc(LPVOID arg) { + MSG msg; + WAVEHDR *pwh; + (void) arg; + + while (GetMessage(&msg, 0, 0, 0)) { + switch (msg.message) { + case MM_WOM_DONE: + pwh = (WAVEHDR *)msg.lParam; + + // Windows - Let go! + waveOutUnprepareHeader(ah, pwh, sizeof(WAVEHDR)); + + // Give the buffer back to the Audio Free List + gfxSystemLock(); + gaudioPlayReleaseDataBlockI((GDataBuffer *)pwh->dwUser); + gfxSystemUnlock(); + pwh->lpData = 0; + nQueuedBuffers--; + + // Are we stopping? + if (!isRunning) { + // Have we finished yet? + if (!nQueuedBuffers) { + gfxSystemLock(); + gaudioPlayDoneI(); + gfxSystemUnlock(); + } + break; + } + + // Try and get a new block + senddata(pwh); + break; + } + } + return 0; +} + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +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) + return FALSE; + + if (!waveThread) { + if (!(waveThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveProc, 0, 0, &threadID))) { + fprintf(stderr, "GAUDIO: Can't create WAVE play-back thread\n"); + exit(-1); + } + CloseHandle(waveThread); + } + + wfx.wFormatTag = WAVE_FORMAT_PCM; + 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, "GAUDIO: Can't open WAVE play-back device\n"); + exit(-1); + } + + return TRUE; +} + +bool_t gaudio_play_lld_set_volume(uint8_t vol) { + if (!ah) + return FALSE; + return waveOutSetVolume(ah, (((uint16_t)vol)<<8)|vol) != 0; +} + +void gaudio_play_lld_start(void) { + WAVEHDR *pwh; + + isRunning = TRUE; + 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 Audio Out Queue + if (!senddata(pwh)) + break; + } +} + +void gaudio_play_lld_stop(void) { + isRunning = FALSE; + waveOutReset(ah); + while(nQueuedBuffers) Sleep(1); +} + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ diff --git a/drivers/gaudio/Win32/gaudio_play_lld.c b/drivers/gaudio/Win32/gaudio_play_lld.c deleted file mode 100644 index 03d9acea..00000000 --- a/drivers/gaudio/Win32/gaudio_play_lld.c +++ /dev/null @@ -1,183 +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 - */ - -// We need to include stdio.h below. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts -#define GFILE_NEED_STDIO_MUST_BE_OFF - -#include "gfx.h" - -#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY - -/* Include the driver defines */ -#include "src/gaudio/gaudio_driver_play.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 also create higher latency. - -static HWAVEOUT 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 waveOutUnPrepareBuffer() which is what we need to use whenever we receive a - * MM_WOM_DONE. My callback would need to defer that job to another thread - * anyway, so instead just use CALLBACK_THREAD here instead. - *************************************************************************/ - -static bool_t senddata(WAVEHDR *pwh) { - GDataBuffer *paud; - - // Get the next data block to send - gfxSystemLock(); - paud = gaudioPlayGetDataBlockI(); - if (!paud && !nQueuedBuffers) - gaudioPlayDoneI(); - 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->len; - pwh->dwFlags = 0; - pwh->dwLoops = 0; - if (waveOutPrepareHeader(ah, pwh, sizeof(WAVEHDR))) { - fprintf(stderr, "GAUDIO: Failed to prepare a play buffer"); - exit(-1); - } - - // Send it to windows - if (waveOutWrite(ah, pwh, sizeof(WAVEHDR))) { - fprintf(stderr, "GAUDIO: Failed to write the play buffer"); - exit(-1); - } - - nQueuedBuffers++; - return TRUE; -} - -static DWORD WINAPI waveProc(LPVOID arg) { - MSG msg; - WAVEHDR *pwh; - (void) arg; - - while (GetMessage(&msg, 0, 0, 0)) { - switch (msg.message) { - case MM_WOM_DONE: - pwh = (WAVEHDR *)msg.lParam; - - // Windows - Let go! - waveOutUnprepareHeader(ah, pwh, sizeof(WAVEHDR)); - - // Give the buffer back to the Audio Free List - gfxSystemLock(); - gaudioPlayReleaseDataBlockI((GDataBuffer *)pwh->dwUser); - gfxSystemUnlock(); - pwh->lpData = 0; - nQueuedBuffers--; - - // Are we stopping? - if (!isRunning) { - // Have we finished yet? - if (!nQueuedBuffers) { - gfxSystemLock(); - gaudioPlayDoneI(); - gfxSystemUnlock(); - } - break; - } - - // Try and get a new block - senddata(pwh); - break; - } - } - return 0; -} - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -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) - return FALSE; - - if (!waveThread) { - if (!(waveThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveProc, 0, 0, &threadID))) { - fprintf(stderr, "GAUDIO: Can't create WAVE play-back thread\n"); - exit(-1); - } - CloseHandle(waveThread); - } - - wfx.wFormatTag = WAVE_FORMAT_PCM; - 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, "GAUDIO: Can't open WAVE play-back device\n"); - exit(-1); - } - - return TRUE; -} - -bool_t gaudio_play_lld_set_volume(uint8_t vol) { - if (!ah) - return FALSE; - return waveOutSetVolume(ah, (((uint16_t)vol)<<8)|vol) != 0; -} - -void gaudio_play_lld_start(void) { - WAVEHDR *pwh; - - isRunning = TRUE; - 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 Audio Out Queue - if (!senddata(pwh)) - break; - } -} - -void gaudio_play_lld_stop(void) { - isRunning = FALSE; - waveOutReset(ah); - while(nQueuedBuffers) Sleep(1); -} - -#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ diff --git a/drivers/gaudio/Win32/gaudio_record_Win32.c b/drivers/gaudio/Win32/gaudio_record_Win32.c new file mode 100644 index 00000000..e3e122d8 --- /dev/null +++ b/drivers/gaudio/Win32/gaudio_record_Win32.c @@ -0,0 +1,185 @@ +/* + * 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 + */ + +// We need to include stdio.h below. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts +#define GFILE_NEED_STDIO_MUST_BE_OFF + +#include "gfx.h" + +#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD + +/* Include the driver defines */ +#include "../../../src/gaudio/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) { + GDataBuffer *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; + GDataBuffer *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 = (GDataBuffer *)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/gaudio_record_lld.c b/drivers/gaudio/Win32/gaudio_record_lld.c deleted file mode 100644 index dd1a201a..00000000 --- a/drivers/gaudio/Win32/gaudio_record_lld.c +++ /dev/null @@ -1,185 +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 - */ - -// We need to include stdio.h below. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts -#define GFILE_NEED_STDIO_MUST_BE_OFF - -#include "gfx.h" - -#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD - -/* Include the driver defines */ -#include "src/gaudio/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) { - GDataBuffer *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; - GDataBuffer *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 = (GDataBuffer *)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/gadc/driver.mk b/drivers/gaudio/gadc/driver.mk index b5a2768a..f9d2db03 100644 --- a/drivers/gaudio/gadc/driver.mk +++ b/drivers/gaudio/gadc/driver.mk @@ -1,8 +1,5 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gaudio/gadc/gaudio_record_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gaudio/gadc +GFXSRC += $(GFXLIB)/drivers/gaudio/gadc/gaudio_record_gadc.c # Make sure the GADC sub-system is turned on GFXDEFS += -DGFX_USE_GADC=GAUDIO_NEED_RECORD diff --git a/drivers/gaudio/gadc/gaudio_record_gadc.c b/drivers/gaudio/gadc/gaudio_record_gadc.c new file mode 100644 index 00000000..a35d070b --- /dev/null +++ b/drivers/gaudio/gadc/gaudio_record_gadc.c @@ -0,0 +1,55 @@ +/* + * 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 + */ + +#define GAUDIO_RECORD_IMPLEMENTATION +#include "gfx.h" + +#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD + +/* Double check the GADC system is turned on */ +#if !GFX_USE_GADC + #error "GAUDIO - The GADC driver for GAUDIO requires GFX_USE_GADC to be TRUE" +#endif + +/* Include the driver defines */ +#include "../../../src/gaudio/gaudio_driver_record.h" + +static void gadcCallbackI(void) { + GDataBuffer *pd; + + pd = gadcHighSpeedGetDataI(); + if (pd) + gaudioRecordSaveDataBlockI(pd); +} + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +bool_t gaudio_record_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { + /* Check the parameters */ + if (channel >= GAUDIO_RECORD_NUM_CHANNELS || frequency > GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY || format != GAUDIO_RECORD_FORMAT1) + return FALSE; + + /* Setup the high speed GADC */ + gadcHighSpeedInit(gaudio_gadc_physdevs[channel], frequency); + + /* Register ourselves for ISR callbacks */ + gadcHighSpeedSetISRCallback(gadcCallbackI); + + return TRUE; +} + +void gaudio_record_lld_start(void) { + gadcHighSpeedStart(); +} + +void gaudio_record_lld_stop(void) { + gadcHighSpeedStop(); +} + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ diff --git a/drivers/gaudio/gadc/gaudio_record_lld.c b/drivers/gaudio/gadc/gaudio_record_lld.c deleted file mode 100644 index 6495309a..00000000 --- a/drivers/gaudio/gadc/gaudio_record_lld.c +++ /dev/null @@ -1,55 +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 - */ - -#define GAUDIO_RECORD_IMPLEMENTATION -#include "gfx.h" - -#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD - -/* Double check the GADC system is turned on */ -#if !GFX_USE_GADC - #error "GAUDIO - The GADC driver for GAUDIO requires GFX_USE_GADC to be TRUE" -#endif - -/* Include the driver defines */ -#include "src/gaudio/gaudio_driver_record.h" - -static void gadcCallbackI(void) { - GDataBuffer *pd; - - pd = gadcHighSpeedGetDataI(); - if (pd) - gaudioRecordSaveDataBlockI(pd); -} - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -bool_t gaudio_record_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { - /* Check the parameters */ - if (channel >= GAUDIO_RECORD_NUM_CHANNELS || frequency > GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY || format != GAUDIO_RECORD_FORMAT1) - return FALSE; - - /* Setup the high speed GADC */ - gadcHighSpeedInit(gaudio_gadc_physdevs[channel], frequency); - - /* Register ourselves for ISR callbacks */ - gadcHighSpeedSetISRCallback(gadcCallbackI); - - return TRUE; -} - -void gaudio_record_lld_start(void) { - gadcHighSpeedStart(); -} - -void gaudio_record_lld_stop(void) { - gadcHighSpeedStop(); -} - -#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ diff --git a/drivers/gaudio/pwm/driver.mk b/drivers/gaudio/pwm/driver.mk index 52f752aa..32f74c28 100644 --- a/drivers/gaudio/pwm/driver.mk +++ b/drivers/gaudio/pwm/driver.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gaudio/pwm/gaudio_play_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gaudio/pwm +GFXSRC += $(GFXLIB)/drivers/gaudio/pwm/gaudio_play_pwm.c diff --git a/drivers/gaudio/pwm/gaudio_play_lld.c b/drivers/gaudio/pwm/gaudio_play_lld.c deleted file mode 100644 index d4d85c33..00000000 --- a/drivers/gaudio/pwm/gaudio_play_lld.c +++ /dev/null @@ -1,117 +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 - */ - -#include "gfx.h" - -#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY - -/* Include the driver defines */ -#include "src/gaudio/gaudio_driver_play.h" - -/* Forward definition */ -static void gaudio_play_pwm_timer_callbackI(void); - -/* Include the board interface */ -#include "gaudio_play_board.h" - -static GDataBuffer *pplay; -static ArrayDataFormat playfmt; -static size_t playlen; -static uint8_t *pdata; - -static void gaudio_play_pwm_timer_callbackI(void) { - if (pplay) { - - // Get the next value from the current data buffer - if (gfxSampleFormatBits(playfmt) > 8) { - gaudio_play_pwm_setI(*(uint16_t *)pdata); - pdata += 2; - } else { - gaudio_play_pwm_setI(*pdata); - pdata++; - } - - // Are we done yet - if (--playlen) - return; - gaudioPlayReleaseDataBlockI(pplay); - - // Get a new data buffer - if (!(pplay = gaudioPlayGetDataBlockI())) { - // All is done - gaudioPlayDoneI(); - return; - } - - } else { - // Get a new data buffer - if (!(pplay = gaudioPlayGetDataBlockI())) - return; - } - - // Set up ready for the new buffer - playlen = pplay->len; - if (gfxSampleFormatBits(playfmt) > 8) - playlen >>= 1; - pdata = (uint8_t *)(pplay+1); -} - - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { - (void) channel; - - if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_10BITUNSIGNED) - return FALSE; - - playfmt = format; - return gaudio_play_pwm_setup(frequency, format); -} - -bool_t gaudio_play_lld_set_volume(uint8_t vol) { - (void) vol; - return FALSE; -} - -void gaudio_play_lld_start(void) { - - gfxSystemLock(); - // Get a new data buffer - if (pplay || !(pplay = gaudioPlayGetDataBlockI())) { - gfxSystemUnlock(); // Nothing to do - return; - } - - // Set up ready for the new buffer - playlen = pplay->len; - if (gfxSampleFormatBits(playfmt) > 8) - playlen >>= 1; - pdata = (uint8_t *)(pplay+1); - gfxSystemUnlock(); - - // Start the playing - gaudio_play_pwm_start(); -} - -void gaudio_play_lld_stop(void) { - // Stop everything - gaudio_play_pwm_stop(); - - // We may need to clean up the remaining buffer. - gfxSystemLock(); - if (pplay) { - gaudioPlayReleaseDataBlockI(pplay); - pplay = 0; - gaudioPlayDoneI(); - } - gfxSystemUnlock(); -} - -#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ diff --git a/drivers/gaudio/pwm/gaudio_play_pwm.c b/drivers/gaudio/pwm/gaudio_play_pwm.c new file mode 100644 index 00000000..91d7a835 --- /dev/null +++ b/drivers/gaudio/pwm/gaudio_play_pwm.c @@ -0,0 +1,117 @@ +/* + * 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 + */ + +#include "gfx.h" + +#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY + +/* Include the driver defines */ +#include "../../../src/gaudio/gaudio_driver_play.h" + +/* Forward definition */ +static void gaudio_play_pwm_timer_callbackI(void); + +/* Include the board interface */ +#include "gaudio_play_board.h" + +static GDataBuffer *pplay; +static ArrayDataFormat playfmt; +static size_t playlen; +static uint8_t *pdata; + +static void gaudio_play_pwm_timer_callbackI(void) { + if (pplay) { + + // Get the next value from the current data buffer + if (gfxSampleFormatBits(playfmt) > 8) { + gaudio_play_pwm_setI(*(uint16_t *)pdata); + pdata += 2; + } else { + gaudio_play_pwm_setI(*pdata); + pdata++; + } + + // Are we done yet + if (--playlen) + return; + gaudioPlayReleaseDataBlockI(pplay); + + // Get a new data buffer + if (!(pplay = gaudioPlayGetDataBlockI())) { + // All is done + gaudioPlayDoneI(); + return; + } + + } else { + // Get a new data buffer + if (!(pplay = gaudioPlayGetDataBlockI())) + return; + } + + // Set up ready for the new buffer + playlen = pplay->len; + if (gfxSampleFormatBits(playfmt) > 8) + playlen >>= 1; + pdata = (uint8_t *)(pplay+1); +} + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { + (void) channel; + + if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_10BITUNSIGNED) + return FALSE; + + playfmt = format; + return gaudio_play_pwm_setup(frequency, format); +} + +bool_t gaudio_play_lld_set_volume(uint8_t vol) { + (void) vol; + return FALSE; +} + +void gaudio_play_lld_start(void) { + + gfxSystemLock(); + // Get a new data buffer + if (pplay || !(pplay = gaudioPlayGetDataBlockI())) { + gfxSystemUnlock(); // Nothing to do + return; + } + + // Set up ready for the new buffer + playlen = pplay->len; + if (gfxSampleFormatBits(playfmt) > 8) + playlen >>= 1; + pdata = (uint8_t *)(pplay+1); + gfxSystemUnlock(); + + // Start the playing + gaudio_play_pwm_start(); +} + +void gaudio_play_lld_stop(void) { + // Stop everything + gaudio_play_pwm_stop(); + + // We may need to clean up the remaining buffer. + gfxSystemLock(); + if (pplay) { + gaudioPlayReleaseDataBlockI(pplay); + pplay = 0; + gaudioPlayDoneI(); + } + gfxSystemUnlock(); +} + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ diff --git a/drivers/gaudio/vs1053/driver.mk b/drivers/gaudio/vs1053/driver.mk index faf92852..3dfb3b3d 100644 --- a/drivers/gaudio/vs1053/driver.mk +++ b/drivers/gaudio/vs1053/driver.mk @@ -1,7 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gaudio/vs1053/gaudio_play_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gaudio/vs1053 - -#GFXDEFS += -DGFX_USE_GTIMER=GFX_USE_GAUDIO +GFXSRC += $(GFXLIB)/drivers/gaudio/vs1053/gaudio_play_vs1053.c diff --git a/drivers/gaudio/vs1053/gaudio_play_lld.c b/drivers/gaudio/vs1053/gaudio_play_lld.c deleted file mode 100644 index 24c5a176..00000000 --- a/drivers/gaudio/vs1053/gaudio_play_lld.c +++ /dev/null @@ -1,361 +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 - */ - -#include "gfx.h" - -#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY - -/* Include the driver defines */ -#include "src/gaudio/gaudio_driver_play.h" - -/* Include the vs1053 registers */ -#include "drivers/gaudio/vs1053/vs1053.h" - -/* Include the board interface */ -#include "gaudio_play_board.h" - -// Override-able parameters -#ifndef VS1053_CLK - #define VS1053_CLK 12288000 -#endif -#ifndef VS1053_FIRMWARE_PATCH - #define VS1053_FIRMWARE_PATCH FALSE -#endif -#ifndef VS1053_POLL_RATE - #define VS1053_POLL_RATE 5 -#endif - -// Load the patch file if desired. New format patches only. -#if VS1053_FIRMWARE_PATCH - #define SKIP_PLUGIN_VARNAME - static const uint16_t plugin[] = { /* Compressed plugin */ - #include "vs1053_patch.plg" - }; -#endif - -// Set various stuff based on the clock -#if VS1053_CLK >= 16192000 - #define SCI_MODE_STARTUP (SCI_MODE_DEFAULTS|SM_CLK_RANGE) - #define VS1053_CLKI (VS1053_CLK/2) -#else - #define SCI_MODE_STARTUP (SCI_MODE_DEFAULTS) - #define VS1053_CLKI (VS1053_CLK) -#endif -#if VS1053_CLKI > 13000000 || VS1053_CLKI < 12000000 - #error "GAUDIO(vs1053): VS1053_CLK is out of range" -#endif -#if VS1053_CLKI == 12288000 - #define SC_FREQ_ADJUST 0x0000 -#else - #define SC_FREQ_ADJUST ((VS1053_CLKI-8000000)/4000) -#endif -#define VS1053_MAX_SAMPLE_RATE (VS1053_CLKI/256) -#if VS1053_CLKI > 1228800 - #define SC_CLOCK_MODE (SC_MULT_3|SC_ADD_1|SC_FREQ_ADJUST) -#else - #define SC_CLOCK_MODE (SC_MULT_3_5|SC_ADD_1|SC_FREQ_ADJUST) -#endif - -// Our static variables -static bool_t vs1053_isinit; -static GTimer playTimer; - -// Some common macro's -#define waitforready() while(!board_dreq()) gfxSleepMilliseconds(5) - -static void cmd_write(uint16_t addr, uint16_t data) { - char buf[4]; - buf[0] = 2; - buf[1] = (char)addr; - buf[2] = (char)(data >> 8); - buf[3] = (char)data; - - waitforready(); - board_startcmdwrite(); - board_spiwrite(buf, 4); - board_endcmdwrite(); -} - -#if VS1053_CLK > 12288000 - static GFXINLINE void cmd_writenodreq(uint16_t addr, uint16_t data) { - uint8_t buf[4]; - - // This is the same as cmd_write() except for it doesn't wait for dreq first - buf[0] = 2; - buf[1] = (uint8_t)addr; - buf[2] = (uint8_t)(data >> 8); - buf[3] = (uint8_t)data; - - board_startcmdwrite(); - board_spiwrite(buf, 4); - board_endcmdwrite(); - } -#endif - -static uint16_t cmd_read(uint16_t addr) { - uint8_t buf[2]; - - buf[0] = 3; - buf[1] = (char)addr; - - board_startcmdread(); - board_spiwrite(buf, 2); - board_spiread(buf, 2); - board_endcmdread(); - return (((uint16_t)buf[0])<<8)|buf[1]; -} - -static void data_write(const uint8_t *data, unsigned len) { - board_startdatawrite(); - board_spiwrite(data, len); - board_enddatawrite(); -} - -#if VS1053_FIRMWARE_PATCH - static void LoadUserCode(void) { - int i; - uint16_t addr, n, val; - - for(i=0; i 12288000 - cmd_writenodreq(SCI_MODE, SCI_MODE_STARTUP); // Set super-clock before dreq - #endif - - // Set up registers - cmd_write(SCI_MODE, SCI_MODE_STARTUP); // Set mode - cmd_write(SCI_CLOCKF, SC_CLOCK_MODE); // Set clocks - board_init_end(); // Clocks are now set up - cmd_write(SCI_BASS, 0x0000); // No treble or bass boost - cmd_write(SCI_VOL, VOL_MAX); // Maximum volume - - // Load any firmware - #if VS1053_FIRMWARE_PATCH - LoadUserCode(); - - // Reset mode just in case - cmd_write(SCI_MODE, SCI_MODE_STARTUP); - #endif -} - -static void vs1053_soft_reset(void) { - cmd_write(SCI_MODE, cmd_read(SCI_MODE)|SM_RESET); - gfxSleepMilliseconds(1); // Wait for at least 2uS - waitforready(); - - // Reload any firmware - #if VS1053_FIRMWARE_PATCH - LoadUserCode(); - - // Reset mode just in case - cmd_write(SCI_MODE, SCI_MODE_STARTUP); - #endif -} - -static uint16_t vs1053_getendbyte(void) { - cmd_write(SCI_WRAMADDR, WRAMADDR_EXTRAPARAMS+4); - return cmd_read(SCI_WRAM); -} - -static GTimer playTimer; -static GDataBuffer *pplay; -static size_t playlen; -static uint8_t *pdata; - -static void FeedData(void *param) { - unsigned len; - (void) param; - - // While there is data space - while (board_dreq()) { - - // Send up to 32 bytes - len = playlen; - if (len > 32) len = 32; - data_write(pdata, len); - pdata += len; - playlen -= len; - - // Have we finished the buffer - while (!playlen) { - gfxSystemLock(); - gaudioPlayReleaseDataBlockI(pplay); - - // Get a new data buffer - if (!(pplay = gaudioPlayGetDataBlockI())) { - // We should really only do the play-done when the audio - // has really finished playing. Unfortunately there seems - // to be no documented way of determining this. - gaudioPlayDoneI(); - gfxSystemUnlock(); - gtimerStop(&playTimer); - return; - } - - // Set up ready for the new buffer - playlen = pplay->len; - pdata = (uint8_t *)(pplay+1); - gfxSystemUnlock(); - } - } -} - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { - uint32_t brate; - uint32_t bps; - uint8_t buf[4]; - static const uint8_t hdr1[] = { - 'R', 'I', 'F', 'F', - 0xFF, 0xFF, 0xFF, 0xFF, - 'W', 'A', 'V', 'E', - 'f', 'm', 't', ' ', - 16, 0, 0, 0, - 0x01, 0x00, - }; - static const uint8_t hdr2[] = { - 'd', 'a', 't', 'a', - 0xFF, 0xFF, 0xFF, 0xFF, - }; - - if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_16BITSIGNED && format != ARRAY_DATA_UNKNOWN) - return FALSE; - if (frequency > VS1053_MAX_SAMPLE_RATE) - return FALSE; - - // Reset the chip if needed - if (!vs1053_isinit) { - vs1053_hard_reset(); - vs1053_isinit = TRUE; - } - - // Setup - if (format == ARRAY_DATA_8BITUNSIGNED || format == ARRAY_DATA_16BITSIGNED) { - bps = (gfxSampleFormatBits(format)+7)/8; - if (channel == GAUDIO_PLAY_STEREO) - bps *= 2; - brate = frequency * bps; - - // Write the RIFF header - waitforready(); - data_write(hdr1, sizeof(hdr1)); - buf[0] = channel == GAUDIO_PLAY_STEREO ? 2 : 1; buf[1] = 0; data_write(buf, 2); - buf[0] = frequency; buf[1] = frequency>>8; buf[2] = frequency>>16; buf[3] = frequency>>24; data_write(buf, 4); - buf[0] = brate; buf[1] = brate>>8; buf[2] = brate>>16; buf[3] = brate>>24; data_write(buf, 4); - waitforready(); // 32 bytes max before checking - buf[0] = bps; buf[1] = 0; data_write(buf, 2); - buf[0] = gfxSampleFormatBits(format); buf[1] = 0; data_write(buf, 2); - data_write(hdr2, sizeof(hdr2)); - } - return TRUE; -} - -bool_t gaudio_play_lld_set_volume(uint8_t vol) { - uint16_t tmp; - - // Volume is 0xFE -> 0x00. Adjust vol to match - vol = ~vol; - if (vol > 0xFE) - vol = 0xFE; - - tmp = 0; - tmp |= (( vol << VOL_LEFT_SHIFT ) & VOL_LEFT_MASK ); - tmp |= (( vol << VOL_RIGHT_SHIFT ) & VOL_RIGHT_MASK ); - - cmd_write(SCI_VOL, tmp); - - return TRUE; -} - -void gaudio_play_lld_start(void) { - - gfxSystemLock(); - // Get a new data buffer - if (pplay || !(pplay = gaudioPlayGetDataBlockI())) { - gfxSystemUnlock(); // Nothing to do - return; - } - - // Set up ready for the new buffer - playlen = pplay->len; - pdata = (uint8_t *)(pplay+1); - gfxSystemUnlock(); - - // Start the playing by starting the timer and executing FeedData immediately just to get things started - // We really should set the timer to be equivalent to half the available data but that is just too hard to calculate. - gtimerStart(&playTimer, FeedData, 0, TRUE, VS1053_POLL_RATE); - FeedData(0); -} - -void gaudio_play_lld_stop(void) { - uint8_t ch; - unsigned i; - - // Stop the timer interrupt - gtimerStop(&playTimer); - - // We may need to clean up the remaining buffer. - gfxSystemLock(); - if (pplay) { - gaudioPlayReleaseDataBlockI(pplay); - pplay = 0; - gaudioPlayDoneI(); - } - gfxSystemUnlock(); - - // Set CANCEL - cmd_write(SCI_MODE, cmd_read(SCI_MODE)|SM_CANCEL); - - // Write up to 2048 bytes of data - ch = 0; - for(i = 0; i < 2048; i++) { - if (!(i & 0x1F)) { - waitforready(); - if (!(cmd_read(SCI_MODE) & SM_CANCEL)) - break; - } - data_write(&ch, 1); - } - - // Make sure the cancel worked - waitforready(); - if ((cmd_read(SCI_MODE) & SM_CANCEL)) - vs1053_soft_reset(); - - // Send the terminating data - ch = vs1053_getendbyte(); - for(i = 0; i < 2052; i++) { - if (!(i & 0x1F)) - waitforready(); - data_write(&ch, 1); - } -} - -#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ diff --git a/drivers/gaudio/vs1053/gaudio_play_vs1053.c b/drivers/gaudio/vs1053/gaudio_play_vs1053.c new file mode 100644 index 00000000..2aab288c --- /dev/null +++ b/drivers/gaudio/vs1053/gaudio_play_vs1053.c @@ -0,0 +1,361 @@ +/* + * 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 + */ + +#include "gfx.h" + +#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY + +/* Include the driver defines */ +#include "../../../src/gaudio/gaudio_driver_play.h" + +/* Include the vs1053 registers */ +#include "vs1053.h" + +/* Include the board interface */ +#include "gaudio_play_board.h" + +// Override-able parameters +#ifndef VS1053_CLK + #define VS1053_CLK 12288000 +#endif +#ifndef VS1053_FIRMWARE_PATCH + #define VS1053_FIRMWARE_PATCH FALSE +#endif +#ifndef VS1053_POLL_RATE + #define VS1053_POLL_RATE 5 +#endif + +// Load the patch file if desired. New format patches only. +#if VS1053_FIRMWARE_PATCH + #define SKIP_PLUGIN_VARNAME + static const uint16_t plugin[] = { /* Compressed plugin */ + #include "vs1053_patch.plg" + }; +#endif + +// Set various stuff based on the clock +#if VS1053_CLK >= 16192000 + #define SCI_MODE_STARTUP (SCI_MODE_DEFAULTS|SM_CLK_RANGE) + #define VS1053_CLKI (VS1053_CLK/2) +#else + #define SCI_MODE_STARTUP (SCI_MODE_DEFAULTS) + #define VS1053_CLKI (VS1053_CLK) +#endif +#if VS1053_CLKI > 13000000 || VS1053_CLKI < 12000000 + #error "GAUDIO(vs1053): VS1053_CLK is out of range" +#endif +#if VS1053_CLKI == 12288000 + #define SC_FREQ_ADJUST 0x0000 +#else + #define SC_FREQ_ADJUST ((VS1053_CLKI-8000000)/4000) +#endif +#define VS1053_MAX_SAMPLE_RATE (VS1053_CLKI/256) +#if VS1053_CLKI > 1228800 + #define SC_CLOCK_MODE (SC_MULT_3|SC_ADD_1|SC_FREQ_ADJUST) +#else + #define SC_CLOCK_MODE (SC_MULT_3_5|SC_ADD_1|SC_FREQ_ADJUST) +#endif + +// Our static variables +static bool_t vs1053_isinit; +static GTimer playTimer; + +// Some common macro's +#define waitforready() while(!board_dreq()) gfxSleepMilliseconds(5) + +static void cmd_write(uint16_t addr, uint16_t data) { + char buf[4]; + buf[0] = 2; + buf[1] = (char)addr; + buf[2] = (char)(data >> 8); + buf[3] = (char)data; + + waitforready(); + board_startcmdwrite(); + board_spiwrite(buf, 4); + board_endcmdwrite(); +} + +#if VS1053_CLK > 12288000 + static GFXINLINE void cmd_writenodreq(uint16_t addr, uint16_t data) { + uint8_t buf[4]; + + // This is the same as cmd_write() except for it doesn't wait for dreq first + buf[0] = 2; + buf[1] = (uint8_t)addr; + buf[2] = (uint8_t)(data >> 8); + buf[3] = (uint8_t)data; + + board_startcmdwrite(); + board_spiwrite(buf, 4); + board_endcmdwrite(); + } +#endif + +static uint16_t cmd_read(uint16_t addr) { + uint8_t buf[2]; + + buf[0] = 3; + buf[1] = (char)addr; + + board_startcmdread(); + board_spiwrite(buf, 2); + board_spiread(buf, 2); + board_endcmdread(); + return (((uint16_t)buf[0])<<8)|buf[1]; +} + +static void data_write(const uint8_t *data, unsigned len) { + board_startdatawrite(); + board_spiwrite(data, len); + board_enddatawrite(); +} + +#if VS1053_FIRMWARE_PATCH + static void LoadUserCode(void) { + int i; + uint16_t addr, n, val; + + for(i=0; i 12288000 + cmd_writenodreq(SCI_MODE, SCI_MODE_STARTUP); // Set super-clock before dreq + #endif + + // Set up registers + cmd_write(SCI_MODE, SCI_MODE_STARTUP); // Set mode + cmd_write(SCI_CLOCKF, SC_CLOCK_MODE); // Set clocks + board_init_end(); // Clocks are now set up + cmd_write(SCI_BASS, 0x0000); // No treble or bass boost + cmd_write(SCI_VOL, VOL_MAX); // Maximum volume + + // Load any firmware + #if VS1053_FIRMWARE_PATCH + LoadUserCode(); + + // Reset mode just in case + cmd_write(SCI_MODE, SCI_MODE_STARTUP); + #endif +} + +static void vs1053_soft_reset(void) { + cmd_write(SCI_MODE, cmd_read(SCI_MODE)|SM_RESET); + gfxSleepMilliseconds(1); // Wait for at least 2uS + waitforready(); + + // Reload any firmware + #if VS1053_FIRMWARE_PATCH + LoadUserCode(); + + // Reset mode just in case + cmd_write(SCI_MODE, SCI_MODE_STARTUP); + #endif +} + +static uint16_t vs1053_getendbyte(void) { + cmd_write(SCI_WRAMADDR, WRAMADDR_EXTRAPARAMS+4); + return cmd_read(SCI_WRAM); +} + +static GTimer playTimer; +static GDataBuffer *pplay; +static size_t playlen; +static uint8_t *pdata; + +static void FeedData(void *param) { + unsigned len; + (void) param; + + // While there is data space + while (board_dreq()) { + + // Send up to 32 bytes + len = playlen; + if (len > 32) len = 32; + data_write(pdata, len); + pdata += len; + playlen -= len; + + // Have we finished the buffer + while (!playlen) { + gfxSystemLock(); + gaudioPlayReleaseDataBlockI(pplay); + + // Get a new data buffer + if (!(pplay = gaudioPlayGetDataBlockI())) { + // We should really only do the play-done when the audio + // has really finished playing. Unfortunately there seems + // to be no documented way of determining this. + gaudioPlayDoneI(); + gfxSystemUnlock(); + gtimerStop(&playTimer); + return; + } + + // Set up ready for the new buffer + playlen = pplay->len; + pdata = (uint8_t *)(pplay+1); + gfxSystemUnlock(); + } + } +} + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { + uint32_t brate; + uint32_t bps; + uint8_t buf[4]; + static const uint8_t hdr1[] = { + 'R', 'I', 'F', 'F', + 0xFF, 0xFF, 0xFF, 0xFF, + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, + 0x01, 0x00, + }; + static const uint8_t hdr2[] = { + 'd', 'a', 't', 'a', + 0xFF, 0xFF, 0xFF, 0xFF, + }; + + if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_16BITSIGNED && format != ARRAY_DATA_UNKNOWN) + return FALSE; + if (frequency > VS1053_MAX_SAMPLE_RATE) + return FALSE; + + // Reset the chip if needed + if (!vs1053_isinit) { + vs1053_hard_reset(); + vs1053_isinit = TRUE; + } + + // Setup + if (format == ARRAY_DATA_8BITUNSIGNED || format == ARRAY_DATA_16BITSIGNED) { + bps = (gfxSampleFormatBits(format)+7)/8; + if (channel == GAUDIO_PLAY_STEREO) + bps *= 2; + brate = frequency * bps; + + // Write the RIFF header + waitforready(); + data_write(hdr1, sizeof(hdr1)); + buf[0] = channel == GAUDIO_PLAY_STEREO ? 2 : 1; buf[1] = 0; data_write(buf, 2); + buf[0] = frequency; buf[1] = frequency>>8; buf[2] = frequency>>16; buf[3] = frequency>>24; data_write(buf, 4); + buf[0] = brate; buf[1] = brate>>8; buf[2] = brate>>16; buf[3] = brate>>24; data_write(buf, 4); + waitforready(); // 32 bytes max before checking + buf[0] = bps; buf[1] = 0; data_write(buf, 2); + buf[0] = gfxSampleFormatBits(format); buf[1] = 0; data_write(buf, 2); + data_write(hdr2, sizeof(hdr2)); + } + return TRUE; +} + +bool_t gaudio_play_lld_set_volume(uint8_t vol) { + uint16_t tmp; + + // Volume is 0xFE -> 0x00. Adjust vol to match + vol = ~vol; + if (vol > 0xFE) + vol = 0xFE; + + tmp = 0; + tmp |= (( vol << VOL_LEFT_SHIFT ) & VOL_LEFT_MASK ); + tmp |= (( vol << VOL_RIGHT_SHIFT ) & VOL_RIGHT_MASK ); + + cmd_write(SCI_VOL, tmp); + + return TRUE; +} + +void gaudio_play_lld_start(void) { + + gfxSystemLock(); + // Get a new data buffer + if (pplay || !(pplay = gaudioPlayGetDataBlockI())) { + gfxSystemUnlock(); // Nothing to do + return; + } + + // Set up ready for the new buffer + playlen = pplay->len; + pdata = (uint8_t *)(pplay+1); + gfxSystemUnlock(); + + // Start the playing by starting the timer and executing FeedData immediately just to get things started + // We really should set the timer to be equivalent to half the available data but that is just too hard to calculate. + gtimerStart(&playTimer, FeedData, 0, TRUE, VS1053_POLL_RATE); + FeedData(0); +} + +void gaudio_play_lld_stop(void) { + uint8_t ch; + unsigned i; + + // Stop the timer interrupt + gtimerStop(&playTimer); + + // We may need to clean up the remaining buffer. + gfxSystemLock(); + if (pplay) { + gaudioPlayReleaseDataBlockI(pplay); + pplay = 0; + gaudioPlayDoneI(); + } + gfxSystemUnlock(); + + // Set CANCEL + cmd_write(SCI_MODE, cmd_read(SCI_MODE)|SM_CANCEL); + + // Write up to 2048 bytes of data + ch = 0; + for(i = 0; i < 2048; i++) { + if (!(i & 0x1F)) { + waitforready(); + if (!(cmd_read(SCI_MODE) & SM_CANCEL)) + break; + } + data_write(&ch, 1); + } + + // Make sure the cancel worked + waitforready(); + if ((cmd_read(SCI_MODE) & SM_CANCEL)) + vs1053_soft_reset(); + + // Send the terminating data + ch = vs1053_getendbyte(); + for(i = 0; i < 2052; i++) { + if (!(i & 0x1F)) + waitforready(); + data_write(&ch, 1); + } +} + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ -- cgit v1.2.3