aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--boards/base/Olimex-SAM7EX256-GE12/board.mk2
-rw-r--r--boards/base/Olimex-SAM7EX256-GE8/board.mk2
-rw-r--r--boards/base/Win32/board.mk4
-rw-r--r--drivers/audio/Win32/driver.mk6
-rw-r--r--drivers/audio/Win32/gaudin_lld.c (renamed from drivers/gaudin/Win32/gaudin_lld.c)86
-rw-r--r--drivers/audio/Win32/gaudin_lld_config.h (renamed from drivers/gaudin/Win32/gaudin_lld_config.h)2
-rw-r--r--drivers/audio/Win32/gaudout_lld.c190
-rw-r--r--drivers/audio/Win32/gaudout_lld_config.h64
-rw-r--r--drivers/audio/Win32/readme.txt10
-rw-r--r--drivers/audio/gadc/driver.mk (renamed from drivers/gaudin/gadc/gaudin_lld.mk)2
-rw-r--r--drivers/audio/gadc/gaudin_lld.c (renamed from drivers/gaudin/gadc/gaudin_lld.c)4
-rw-r--r--drivers/audio/gadc/gaudin_lld_board_template.h (renamed from drivers/gaudin/gadc/gaudin_lld_board_template.h)0
-rw-r--r--drivers/audio/gadc/gaudin_lld_config.h (renamed from drivers/gaudin/gadc/gaudin_lld_config.h)0
-rw-r--r--drivers/audio/gadc/readme.txt6
-rw-r--r--drivers/gaudin/Win32/gaudin_lld.mk5
-rw-r--r--drivers/gaudin/Win32/readme.txt9
-rw-r--r--drivers/multiple/Win32/driver.mk (renamed from drivers/multiple/Win32/gdisp_lld.mk)4
-rw-r--r--src/gaudin/driver.h4
-rw-r--r--src/gaudin/gaudin.c8
-rw-r--r--src/gaudin/sys_defs.h4
-rw-r--r--src/gaudout/driver.h123
-rw-r--r--src/gaudout/gaudout.c111
-rw-r--r--src/gaudout/sys_defs.h121
-rw-r--r--src/gaudout/sys_rules.h21
24 files changed, 707 insertions, 81 deletions
diff --git a/boards/base/Olimex-SAM7EX256-GE12/board.mk b/boards/base/Olimex-SAM7EX256-GE12/board.mk
index 662178a6..a1eae818 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/gaudin/gadc/gaudin_lld.mk
+include $(GFXLIB)/drivers/audio/gadc/driver.mk
diff --git a/boards/base/Olimex-SAM7EX256-GE8/board.mk b/boards/base/Olimex-SAM7EX256-GE8/board.mk
index 6abd9a33..a60d9355 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/gaudin/gadc/gaudin_lld.mk
+include $(GFXLIB)/drivers/audio/gadc/driver.mk
diff --git a/boards/base/Win32/board.mk b/boards/base/Win32/board.mk
index b3aeb7d2..5f624f3d 100644
--- a/boards/base/Win32/board.mk
+++ b/boards/base/Win32/board.mk
@@ -1,5 +1,5 @@
GFXINC += $(GFXLIB)/boards/base/Win32
GFXSRC +=
-include $(GFXLIB)/drivers/multiple/Win32/gdisp_lld.mk
-include $(GFXLIB)/drivers/gaudin/Win32/gaudin_lld.mk
+include $(GFXLIB)/drivers/multiple/Win32/driver.mk
+include $(GFXLIB)/drivers/audio/Win32/driver.mk
diff --git a/drivers/audio/Win32/driver.mk b/drivers/audio/Win32/driver.mk
new file mode 100644
index 00000000..6f4ef084
--- /dev/null
+++ b/drivers/audio/Win32/driver.mk
@@ -0,0 +1,6 @@
+# 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/gaudin/Win32/gaudin_lld.c b/drivers/audio/Win32/gaudin_lld.c
index e798f4ef..2c8431cf 100644
--- a/drivers/gaudin/Win32/gaudin_lld.c
+++ b/drivers/audio/Win32/gaudin_lld.c
@@ -6,7 +6,7 @@
*/
/**
- * @file drivers/gaudin/Win32/gaudin_lld.c
+ * @file drivers/audio/Win32/gaudin_lld.c
* @brief GAUDIN - Driver file for Win32.
*/
@@ -26,9 +26,10 @@
#include <mmsystem.h>
static HWAVEIN ah;
-static volatile int nUsedBuffers;
+static volatile int nQueuedBuffers;
+static bool_t isClosing;
static WAVEHDR *pWaveHdrs;
-static HANDLE waveInThread;
+static HANDLE waveThread;
static DWORD threadID;
/*
@@ -45,7 +46,7 @@ static void PrintWaveErrorMsg(DWORD err, TCHAR * str)
}
*/
-/**************************** waveInProc() *******************************
+/**************************** 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
@@ -55,43 +56,32 @@ static void PrintWaveErrorMsg(DWORD err, TCHAR * str)
* anyway, so instead just use CALLBACK_THREAD here instead.
*************************************************************************/
-DWORD WINAPI waveInProc(LPVOID arg) {
+static DWORD WINAPI waveProc(LPVOID arg) {
MSG msg;
- bool_t isRecording;
(void) arg;
- isRecording = FALSE;
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 still recording? */
- if (isRecording) {
- /* Yes. Now we need to requeue this buffer so the driver can use it for another block of audio
+ /* 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));
-
- } else {
- /* We aren't recording, so another WAVEHDR has been returned to us after recording has stopped.
- * When we get all of them back, DoneAll will be equal to how many WAVEHDRs we queued
- */
- nUsedBuffers--;
- waveInUnprepareHeader(ah, (WAVEHDR *)msg.lParam, sizeof(WAVEHDR));
}
break;
-
- case MM_WIM_OPEN:
- isRecording = TRUE;
- break;
-
- case MM_WIM_CLOSE:
- isRecording = FALSE;
- break;
}
}
return 0;
@@ -101,12 +91,20 @@ DWORD WINAPI waveInProc(LPVOID arg) {
/* 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) {
-// uint16_t channel;
-// uint32_t frequency;
-// audin_sample_t *buffer;
-// size_t bufcount;
-// size_t samplesPerEvent;
WAVEFORMATEX wfx;
size_t spaceleft;
audin_sample_t *p;
@@ -114,15 +112,15 @@ void gaudin_lld_init(const gaudin_params *paud) {
size_t nBuffers;
size_t sz;
- if (!waveInThread) {
- if (!(waveInThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveInProc, 0, 0, &threadID))) {
- fprintf(stderr, "GAUDIN: Can't create WAVE recording thread\n");
+ 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(waveInThread);
+ CloseHandle(waveThread);
}
- nUsedBuffers = 0;
+ gaudin_lld_deinit();
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = paud->channel == GAUDIN_STEREO ? 2 : 1;
@@ -153,26 +151,20 @@ void gaudin_lld_init(const gaudin_params *paud) {
phdr->dwFlags = 0;
if (!waveInPrepareHeader(ah, phdr, sizeof(WAVEHDR))
&& !waveInAddBuffer(ah, phdr, sizeof(WAVEHDR)))
- nUsedBuffers++;
+ nQueuedBuffers++;
else
fprintf(stderr, "GAUDIN: Buffer prepare failed\n");
}
- if (!nUsedBuffers)
+ if (!nQueuedBuffers)
fprintf(stderr, "GAUDIN: Failed to prepare any buffers\n");
}
-void gadc_lld_start(void) {
- if (nUsedBuffers)
- waveInStart(ah);
+void gaudin_lld_start(void) {
+ waveInStart(ah);
}
-void gadc_lld_stop(void) {
- waveInReset(ah);
- while(nUsedBuffers) Sleep(1);
- if (pWaveHdrs) {
- gfxFree(pWaveHdrs);
- pWaveHdrs = 0;
- }
+void gaudin_lld_stop(void) {
+ waveInStop(ah);
}
#endif /* GFX_USE_GAUDIN */
diff --git a/drivers/gaudin/Win32/gaudin_lld_config.h b/drivers/audio/Win32/gaudin_lld_config.h
index 804d2fc4..78ddffaa 100644
--- a/drivers/gaudin/Win32/gaudin_lld_config.h
+++ b/drivers/audio/Win32/gaudin_lld_config.h
@@ -6,7 +6,7 @@
*/
/**
- * @file drivers/multiple/Win32/gaudin_lld_config.h
+ * @file drivers/audio/Win32/gaudin_lld_config.h
* @brief GAUDIN Driver config file.
*
* @addtogroup GAUDIN
diff --git a/drivers/audio/Win32/gaudout_lld.c b/drivers/audio/Win32/gaudout_lld.c
new file mode 100644
index 00000000..9581fa45
--- /dev/null
+++ b/drivers/audio/Win32/gaudout_lld.c
@@ -0,0 +1,190 @@
+/*
+ * 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/gaudout_lld.c
+ * @brief GAUDOUT - Driver file for Win32.
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GAUDOUT
+
+/* Include the driver defines */
+#include "src/gaudout/driver.h"
+
+#undef Red
+#undef Green
+#undef Blue
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdio.h>
+#include <mmsystem.h>
+
+#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;
+
+/*
+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,
+ * 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) {
+ GAudioData *paud;
+
+ // Get the next data block to send
+ if (!(paud = gaudoutGetDataBlockI()))
+ 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))) {
+ pwh->lpData = 0;
+ fprintf(stderr, "GAUDOUT: Failed to prepare a buffer");
+ return FALSE;
+ }
+
+ // Send it to windows
+ if (waveOutWrite(ah, pwh, sizeof(WAVEHDR))) {
+ pwh->lpData = 0;
+ fprintf(stderr, "GAUDOUT: Failed to write the buffer");
+ return FALSE;
+ }
+
+ 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
+ gaudoutReleaseDataBlockI((GAudioData *)pwh->dwUser);
+ pwh->lpData = 0;
+ nQueuedBuffers--;
+
+ // Try and get a new block
+ if (isRunning)
+ senddata(pwh);
+ break;
+ }
+ }
+ return 0;
+}
+
+/*===========================================================================*/
+/* 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) {
+ WAVEFORMATEX wfx;
+
+ 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;
+ }
+ CloseHandle(waveThread);
+ }
+
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = channel == GAUDOUT_STEREO ? 2 : 1;
+ wfx.nSamplesPerSec = frequency;
+ wfx.nBlockAlign = wfx.nChannels * sizeof(audout_sample_t);
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+ wfx.wBitsPerSample = sizeof(audout_sample_t) * 8;
+ wfx.cbSize = 0;
+
+ 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;
+ }
+
+ return TRUE;
+}
+
+bool_t gaudout_lld_set_volume(uint8_t vol) {
+ if (!ah)
+ return FALSE;
+ return waveOutSetVolume(ah, (((uint16_t)vol)<<8)|vol) != 0;
+}
+
+void gaudout_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.
+ for(pwh = WaveHdrs; pwh->lpData; pwh++);
+
+ // Grab the next audio block from the Audio Out Queue
+ if (!senddata(pwh))
+ break;
+ }
+}
+
+void gaudout_lld_stop(void) {
+ isRunning = FALSE;
+ if (ah)
+ waveOutReset(ah);
+}
+
+#endif /* GFX_USE_GAUDOUT */
diff --git a/drivers/audio/Win32/gaudout_lld_config.h b/drivers/audio/Win32/gaudout_lld_config.h
new file mode 100644
index 00000000..157f33f0
--- /dev/null
+++ b/drivers/audio/Win32/gaudout_lld_config.h
@@ -0,0 +1,64 @@
+/*
+ * 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/gaudout_lld_config.h
+ * @brief GAUDOUT Driver config file.
+ *
+ * @addtogroup GAUDOUT
+ * @{
+ */
+
+#ifndef GAUDOUT_LLD_CONFIG_H
+#define GAUDIN_LLD_CONFIG_H
+
+#if GFX_USE_GAUDOUT
+
+/*===========================================================================*/
+/* 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
+
+/**
+ * @brief The number of bits in a sample
+ */
+//#define GAUDOUT_BITS_PER_SAMPLE 8
+#define GAUDOUT_BITS_PER_SAMPLE 16
+
+/**
+ * @brief The format of an audio sample
+ */
+//#define GAUDOUT_SAMPLE_FORMAT ARRAY_DATA_8BITUNSIGNED
+#define GAUDOUT_SAMPLE_FORMAT ARRAY_DATA_16BITSIGNED
+
+/**
+ * @brief The number of audio channels supported by this driver
+ */
+#define GAUDOUT_NUM_CHANNELS 2
+
+/**
+ * @brief The list of audio channels and their uses
+ * @{
+ */
+#define GAUDOUT_MONO 0
+#define GAUDOUT_STEREO 1
+/** @} */
+
+#endif /* GFX_USE_GAUDOUT */
+
+#endif /* GAUDOUT_LLD_CONFIG_H */
+/** @} */
diff --git a/drivers/audio/Win32/readme.txt b/drivers/audio/Win32/readme.txt
new file mode 100644
index 00000000..784f0a89
--- /dev/null
+++ b/drivers/audio/Win32/readme.txt
@@ -0,0 +1,10 @@
+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/gaudin/gadc/gaudin_lld.mk b/drivers/audio/gadc/driver.mk
index c969e80b..b991ede8 100644
--- a/drivers/gaudin/gadc/gaudin_lld.mk
+++ b/drivers/audio/gadc/driver.mk
@@ -2,4 +2,4 @@
GFXSRC += $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.c
# Required include directories
-GFXINC += $(GFXLIB)/drivers/gaudin/gadc
+GFXINC += $(GFXLIB)/drivers/audio/gadc
diff --git a/drivers/gaudin/gadc/gaudin_lld.c b/drivers/audio/gadc/gaudin_lld.c
index 972f3dcf..002d9e9b 100644
--- a/drivers/gaudin/gadc/gaudin_lld.c
+++ b/drivers/audio/gadc/gaudin_lld.c
@@ -50,11 +50,11 @@ void gaudin_lld_init(const gaudin_params *paud) {
*/
}
-void gadc_lld_start(void) {
+void gaudin_lld_start(void) {
gadcHighSpeedStart();
}
-void gadc_lld_stop(void) {
+void gaudin_lld_stop(void) {
gadcHighSpeedStop();
}
diff --git a/drivers/gaudin/gadc/gaudin_lld_board_template.h b/drivers/audio/gadc/gaudin_lld_board_template.h
index 89cc0c12..89cc0c12 100644
--- a/drivers/gaudin/gadc/gaudin_lld_board_template.h
+++ b/drivers/audio/gadc/gaudin_lld_board_template.h
diff --git a/drivers/gaudin/gadc/gaudin_lld_config.h b/drivers/audio/gadc/gaudin_lld_config.h
index a9fd02ae..a9fd02ae 100644
--- a/drivers/gaudin/gadc/gaudin_lld_config.h
+++ b/drivers/audio/gadc/gaudin_lld_config.h
diff --git a/drivers/audio/gadc/readme.txt b/drivers/audio/gadc/readme.txt
new file mode 100644
index 00000000..1d3877e8
--- /dev/null
+++ b/drivers/audio/gadc/readme.txt
@@ -0,0 +1,6 @@
+This driver uses the generic GADC driver to provide a GAUDIN device.
+
+It supports whatever high speed device channels that your GADC driver and board supports.
+
+For stereo, the samples are interleaved. Remember to allocate enough space for two samples per
+sample period.
diff --git a/drivers/gaudin/Win32/gaudin_lld.mk b/drivers/gaudin/Win32/gaudin_lld.mk
deleted file mode 100644
index 3a822971..00000000
--- a/drivers/gaudin/Win32/gaudin_lld.mk
+++ /dev/null
@@ -1,5 +0,0 @@
-# List the required driver.
-GFXSRC += $(GFXLIB)/drivers/gaudin/Win32/gaudin_lld.c
-
-# Required include directories
-GFXINC += $(GFXLIB)/drivers/gaudin/Win32
diff --git a/drivers/gaudin/Win32/readme.txt b/drivers/gaudin/Win32/readme.txt
deleted file mode 100644
index b921c5e5..00000000
--- a/drivers/gaudin/Win32/readme.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This driver uses the Win32 audio system to provide a GAUDIN channel.
-
-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 (obviously in record mode) before starting recording.
diff --git a/drivers/multiple/Win32/gdisp_lld.mk b/drivers/multiple/Win32/driver.mk
index f9242380..d9654dfe 100644
--- a/drivers/multiple/Win32/gdisp_lld.mk
+++ b/drivers/multiple/Win32/driver.mk
@@ -1,2 +1,2 @@
-GFXINC += $(GFXLIB)/drivers/multiple/Win32
-GFXSRC += $(GFXLIB)/drivers/multiple/Win32/gdisp_lld_Win32.c
+GFXINC += $(GFXLIB)/drivers/multiple/Win32
+GFXSRC += $(GFXLIB)/drivers/multiple/Win32/gdisp_lld_Win32.c
diff --git a/src/gaudin/driver.h b/src/gaudin/driver.h
index bd04858a..b534e2a5 100644
--- a/src/gaudin/driver.h
+++ b/src/gaudin/driver.h
@@ -83,14 +83,14 @@ void gaudin_lld_init(const gaudin_params *paud);
*
* @api
*/
-void gadc_lld_start(void);
+void gaudin_lld_start(void);
/**
* @brief Stop the audio input sampling
*
* @api
*/
-void gadc_lld_stop(void);
+void gaudin_lld_stop(void);
#ifdef __cplusplus
}
diff --git a/src/gaudin/gaudin.c b/src/gaudin/gaudin.c
index c9ed1c7f..2e3507ef 100644
--- a/src/gaudin/gaudin.c
+++ b/src/gaudin/gaudin.c
@@ -40,7 +40,7 @@ static uint16_t audFlags;
while ((psl = geventGetSourceListener((GSourceHandle)(&aud), psl))) {
if (!(pe = (GEventAudioIn *)geventGetEventBuffer(psl))) {
// This listener is missing - save this.
- psl->srcflags |= GADC_AUDIO_IN_LOSTEVENT;
+ psl->srcflags |= GAUDIN_LOSTEVENT;
continue;
}
@@ -107,7 +107,7 @@ bool_t gaudinInit(uint16_t channel, uint32_t frequency, audin_sample_t *buffer,
/* Stop any existing transfers */
if ((audFlags & AUDFLG_RUNNING))
- gadc_lld_stop();
+ gaudin_lld_stop();
audFlags = 0;
/* Initialise everything */
@@ -143,13 +143,13 @@ void gaudinSetBSem(gfxSem *pbsem, GEventAudioIn *pEvent) {
void gaudinStart(void) {
if (!(audFlags & AUDFLG_RUNNING)) {
audFlags |= AUDFLG_RUNNING;
- gadc_lld_start();
+ gaudin_lld_start();
}
}
void gaudinStop(void) {
if ((audFlags & AUDFLG_RUNNING)) {
- gadc_lld_stop();
+ gaudin_lld_stop();
audFlags &= ~AUDFLG_RUNNING;
}
}
diff --git a/src/gaudin/sys_defs.h b/src/gaudin/sys_defs.h
index 3f06fa6e..c65a69c1 100644
--- a/src/gaudin/sys_defs.h
+++ b/src/gaudin/sys_defs.h
@@ -55,7 +55,7 @@ typedef struct GEventAudioIn_t {
* @brief The event flag values.
* @{
*/
- #define GADC_AUDIO_IN_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */
+ #define GAUDIN_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */
/** @} */
/**
* @brief The number of audio samples in the buffer
@@ -123,7 +123,7 @@ bool_t gaudinInit(uint16_t channel, uint32_t frequency, audin_sample_t *buffer,
* @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 gadcHighSpeedInit() again.
+ * 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.
*
diff --git a/src/gaudout/driver.h b/src/gaudout/driver.h
new file mode 100644
index 00000000..cd9ab01b
--- /dev/null
+++ b/src/gaudout/driver.h
@@ -0,0 +1,123 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file src/gaudout/driver.h
+ * @brief GAUDOUT - Audio Output driver header file.
+ *
+ * @defgroup Driver Driver
+ * @ingroup GAUDOUT
+ * @{
+ */
+
+#ifndef _GAUDOUT_LLD_H
+#define _GAUDOUT_LLD_H
+
+#include "gfx.h"
+
+#if GFX_USE_GAUDOUT || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Get a block of audio data to play
+ * @return A pointer to the GAaudioData structure or NULL if none is currently available
+ *
+ * @note Defined in the high level GAUDOUT code for use by the GAUDOUT drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+GAudioData *gaudoutGetDataBlockI(void);
+
+/**
+ * @brief Release a block of audio data after playing
+ *
+ * @param[in] paud The GAudioData block to be released.
+ *
+ * @note Defined in the high level GAUDOUT code for use by the GAUDOUT drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+void gaudoutReleaseDataBlockI(GAudioData *paud);
+
+/**
+ * @brief Initialise the driver
+ * @return TRUE if the channel and frequency are valid.
+ *
+ * @param[in] channel The channel to use (see the driver for the available channels provided)
+ * @param[in] frequency The sample frequency to use
+ *
+ * @note The driver will always have been stopped and de-init before this is called.
+ *
+ * @api
+ */
+bool_t gaudout_lld_init(uint16_t channel, uint32_t frequency);
+
+/**
+ * @brief De-Initialise the driver
+ *
+ * @note The audio output will always have been stopped first by the high level layer.
+ * @note This may be called before a @p gaudout_lld_init() has occurred.
+ *
+ * @api
+ */
+void gaudout_lld_deinit(void);
+
+/**
+ * @brief Start the audio output playing
+ *
+ * @note This may be called at any stage including while the driver
+ * is already playing. The driver should check for data blocks
+ * to play using @p gaudoutGetDataBlockI().
+ *
+ * @api
+ */
+void gaudout_lld_start(void);
+
+/**
+ * @brief Stop the audio output playing.
+ *
+ * @note Some drivers may only stop playing at a data block boundary.
+ * @note This may be called before a @p gaudout_lld_init() has occurred.
+ *
+ * @api
+ */
+void gaudout_lld_stop(void);
+
+/**
+ * @brief Set the output volume.
+ * @return TRUE if successful.
+ *
+ * @param[in] 0->255 (0 = muted)
+ *
+ * @note Some drivers may not support this. They will return FALSE.
+ * @note For stereo devices, both channels are set to the same volume.
+ *
+ * @api
+ */
+bool_t gaudout_lld_set_volume(uint8_t vol);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GAUDOUT */
+
+#endif /* _GAUDOUT_LLD_H */
+/** @} */
diff --git a/src/gaudout/gaudout.c b/src/gaudout/gaudout.c
index 56692453..c0d673a0 100644
--- a/src/gaudout/gaudout.c
+++ b/src/gaudout/gaudout.c
@@ -16,11 +16,47 @@
#if GFX_USE_GAUDOUT || defined(__DOXYGEN__)
- #error "GAUDOUT: Not implemented yet"
+#include "src/gaudout/driver.h"
+
+static gfxQueueASync playlist;
+static gfxQueueGSync freelist;
+
+static uint16_t audFlags;
+ #define AUDOUTFLG_RUNNING 0x0001
+ #define AUDOUTFLG_USE_EVENTS 0x0002
+
+#if GFX_USE_GEVENT
+ static GTimer AudGTimer;
+
+ static void AudGTimerCallback(void *param) {
+ (void) param;
+ GSourceListener *psl;
+ GEventADC *pe;
+
+ psl = 0;
+ while ((psl = geventGetSourceListener((GSourceHandle)(&aud), psl))) {
+ if (!(pe = (GEventAudioIn *)geventGetEventBuffer(psl))) {
+ // This listener is missing - save this.
+ psl->srcflags |= GAUDIN_LOSTEVENT;
+ continue;
+ }
+
+ pe->type = GEVENT_AUDIO_IN;
+ pe->channel = aud.channel;
+ pe->count = lastcount;
+ pe->buffer = lastbuffer;
+ pe->flags = psl->srcflags;
+ psl->srcflags = 0;
+ geventSendEvent(psl);
+ }
+ }
+#endif
+
void _gaudoutInit(void)
{
- /* ToDo */
+ gfxQueueASyncInit(&playlist);
+ gfxQueueGSyncInit(&freelist);
}
void _gaudoutDeinit(void)
@@ -28,6 +64,77 @@ void _gaudoutDeinit(void)
/* ToDo */
}
+bool_t gaudioAllocBuffers(unsigned num, size_t size) {
+ GAudioData *paud;
+
+ if (num < 1)
+ return FALSE;
+
+ // Round up to a multiple of 4 to prevent problems with structure alignment
+ size = (size + 3) & ~0x03;
+
+ // Allocate the memory
+ if (!(paud = gfxAlloc((size+sizeof(GAudioData)) * num)))
+ return FALSE;
+
+ // Add each of them to our free list
+ for(;num--; paud = (GAudioData *)((char *)(paud+1)+size)) {
+ paud->size = size;
+ gfxQueueGSyncPut(&freelist, (gfxQueueGSyncItem *)paud);
+ }
+
+ return TRUE;
+}
+
+void gaudioReleaseBuffer(GAudioData *paud) {
+ gfxQueueGSyncPut(&freelist, (gfxQueueGSyncItem *)paud);
+}
+
+GAudioData *gaudioGetBuffer(delaytime_t ms) {
+ return (GAudioData *)gfxQueueGSyncGet(&freelist, ms);
+}
+
+bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency) {
+ gaudioPlayStop();
+ gaudout_lld_deinit();
+ return gaudout_lld_init(channel, frequency);
+}
+
+void gaudioPlay(GAudioData *paud) {
+ if (paud)
+ gfxQueueASyncPut(&playlist, (gfxQueueASyncItem *)paud);
+ gaudout_lld_start();
+}
+
+void gaudioPlayPause(void) {
+ gaudout_lld_stop();
+}
+
+void gaudioPlayStop(void) {
+ GAudioData *paud;
+
+ gaudout_lld_stop();
+ while((paud = (GAudioData *)gfxQueueASyncGet(&playlist)))
+ gfxQueueGSyncPut(&freelist, (gfxQueueGSyncItem *)paud);
+}
+
+bool_t gaudioPlaySetVolume(uint8_t vol) {
+ return gaudout_lld_set_volume(vol);
+}
+
+/**
+ * Routines provided for use by drivers.
+ */
+
+GAudioData *gaudoutGetDataBlockI(void) {
+ return (GAudioData *)gfxQueueASyncGet(&playlist);
+}
+
+void gaudoutReleaseDataBlockI(GAudioData *paud) {
+ gfxQueueGSyncPut(&freelist, (gfxQueueGSyncItem *)paud);
+}
+
+
#endif /* GFX_USE_GAUDOUT */
/** @} */
diff --git a/src/gaudout/sys_defs.h b/src/gaudout/sys_defs.h
index f22d269c..c3745b8c 100644
--- a/src/gaudout/sys_defs.h
+++ b/src/gaudout/sys_defs.h
@@ -22,10 +22,26 @@
#if GFX_USE_GAUDOUT || defined(__DOXYGEN__)
+/* Include the driver defines */
+#include "gaudout_lld_config.h"
+
+
/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
+/**
+ * @brief Contains Audio Data Samples
+ * @note This structure is followed immediately by the sample data itself.
+ * When allocating the buffers for the sample data put this structure
+ * at the beginning of the buffer.
+ */
+typedef struct GAudioData {
+ gfxQueueASyncItem next; // @< Used for queuing the buffers
+ size_t size; // @< The size of the buffer area following this structure (in bytes)
+ size_t len; // @< The length of the data in the buffer area (in samples)
+} GAudioData;
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@@ -34,6 +50,111 @@
extern "C" {
#endif
+/**
+ * @brief Allocate some audio buffers and put them on the free list
+ * @return TRUE is it succeeded. FALSE on allocation failure.
+ *
+ * @param[in] num The number of buffers to allocate
+ * @param[in] size The size (in bytes) of each buffer
+ *
+ * @api
+ */
+bool_t gaudioAllocBuffers(unsigned num, size_t size);
+
+/**
+ * @brief Get an audio buffer from the free list
+ * @return A GAudioData pointer or NULL if the timeout is exceeded
+ *
+ * @params[in] ms The maximum amount of time in milliseconds to wait for a buffer if one is not available.
+ *
+ * @api
+ */
+GAudioData *gaudioGetBuffer(delaytime_t ms);
+
+/**
+ * @brief Release a buffer back to the free list
+ *
+ * @param[in] paud The buffer to put (back) on the free-list.
+ *
+ * @note This call should be used to return any buffers that were taken from
+ * the free-list once they have been finished with. It can also be used
+ * to put new buffers onto the free-list. Just make sure the "size" field
+ * of the GAudioData structure has been filled in first.
+ *
+ * @api
+ */
+void gaudioReleaseBuffer(GAudioData *paud);
+
+/**
+ * @brief Set the audio device to play on the specified channel and with the specified
+ * sample frequency.
+ * @return TRUE is successful, FALSE if the driver doesn't accept those parameters.
+ *
+ * @param[in] channel The audio output channel to use.
+ * @param[in] frequency The audio sample rate in samples per second
+ *
+ * @note Some channels are mono, and some are stereo. See your driver config file
+ * to determine which channels to use and whether they are stereo or not.
+ *
+ * @api
+ */
+bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency);
+
+/**
+ * @brief Play the specified sample data.
+ * @details The sample data is output to the audio channel. On completion the buffer is returned to the free-list.
+ * @pre @p gaudioPlayInit must have been called first to set the channel and sample frequency.
+ *
+ * @param[in] paud The audio sample buffer to play. It can be NULL (used to restart paused audio)
+ *
+ * @note Calling this will cancel any pause.
+ * @note Before calling this function the len field of the GAudioData structure must be
+ * specified. While the buffer size is specified in bytes, this length is specified in samples
+ * and must be even for stereo channels.
+ * @note For stereo channels the sample data is interleaved in the buffer.
+ * @note This call returns before the data has completed playing. Subject to available buffers (which
+ * can be obtained from the free-list), any number of buffers may be played. They will be queued
+ * for playing in the order they are supplied to this routine and played when previous buffers are
+ * complete. In this way continuous playing can be obtained without audio gaps.
+ *
+ * @api
+ */
+void gaudioPlay(GAudioData *paud);
+
+/**
+ * @brief Pause any currently playing sounds.
+ *
+ * @note If nothing is currently playing this routine does nothing. To restart playing call @p gaudioPlay()
+ * with or without a new sample buffer.
+ * @note Some drivers will not respond until a buffer boundary.
+ *
+ * @api
+ */
+void gaudioPlayPause(void);
+
+/**
+ * @brief Stop any currently playing sounds.
+ *
+ * @note This stops any playing sounds and returns any currently queued buffers back to the free-list.
+ * @note Some drivers will not respond until a buffer boundary.
+ *
+ * @api
+ */
+void gaudioPlayStop(void);
+
+/**
+ * @brief Set the output volume.
+ * @return TRUE if successful.
+ *
+ * @param[in] 0->255 (0 = muted)
+ *
+ * @note Some drivers may not support this. They will return FALSE.
+ * @note For stereo devices, both channels are set to the same volume.
+ *
+ * @api
+ */
+bool_t gaudioPlaySetVolume(uint8_t vol);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/gaudout/sys_rules.h b/src/gaudout/sys_rules.h
index 50b9a442..8274e031 100644
--- a/src/gaudout/sys_rules.h
+++ b/src/gaudout/sys_rules.h
@@ -17,6 +17,27 @@
#define _GAUDOUT_RULES_H
#if GFX_USE_GAUDOUT
+ #if !GFX_USE_GQUEUE
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GAUDOUT: GFX_USE_GQUEUE is required if GFX_USE_GAUDOUT is TRUE. It has been turned on for you."
+ #endif
+ #undef GFX_USE_GQUEUE
+ #define GFX_USE_GQUEUE TRUE
+ #endif
+ #if !GQUEUE_NEED_ASYNC
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GAUDOUT: GQUEUE_NEED_ASYNC is required if GFX_USE_GAUDOUT is TRUE. It has been turned on for you."
+ #endif
+ #undef GQUEUE_NEED_ASYNC
+ #define GQUEUE_NEED_ASYNC TRUE
+ #endif
+ #if !GQUEUE_NEED_GSYNC
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GAUDOUT: GQUEUE_NEED_GSYNC is required if GFX_USE_GAUDOUT is TRUE. It has been turned on for you."
+ #endif
+ #undef GQUEUE_NEED_GSYNC
+ #define GQUEUE_NEED_GSYNC TRUE
+ #endif
#endif
#endif /* _GAUDOUT_RULES_H */