Browse Source
Simplify GAUDIN (now GAUDIO RECORD) api. Update audio demo's to match. Port Win32 driver to new audio api.remotes/origin_old/ugfx_release_2.6
57 changed files with 1405 additions and 1521 deletions
@ -1,3 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/audio/oscilloscope |
|||
DEMODIR = $(GFXLIB)/demos/modules/gaudio/oscilloscope |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c $(DEMODIR)/gwinosc.c |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@ -1,3 +1,3 @@ |
|||
DEMODIR = $(GFXLIB)/demos/modules/audio/play-wave |
|||
DEMODIR = $(GFXLIB)/demos/modules/gaudio/play-wave |
|||
GFXINC += $(DEMODIR) |
|||
GFXSRC += $(DEMODIR)/main.c |
@ -1,7 +1,7 @@ |
|||
/**
|
|||
* This file was generated from "allwrong.wav" using... |
|||
* |
|||
* file2c -bcs allwrong.wav romfs_allwrong.h |
|||
* file2c -dcs allwrong.wav romfs_allwrong.h |
|||
* |
|||
*/ |
|||
static const char allwrong[] = { |
@ -1,6 +0,0 @@ |
|||
# List the required driver.
|
|||
GFXSRC += $(GFXLIB)/drivers/audio/Win32/gaudin_lld.c \
|
|||
$(GFXLIB)/drivers/audio/Win32/gaudout_lld.c |
|||
|
|||
# Required include directories
|
|||
GFXINC += $(GFXLIB)/drivers/audio/Win32 |
@ -1,170 +0,0 @@ |
|||
/*
|
|||
* This file is subject to the terms of the GFX License. If a copy of |
|||
* the license was not distributed with this file, you can obtain one at: |
|||
* |
|||
* http://ugfx.org/license.html
|
|||
*/ |
|||
|
|||
/**
|
|||
* @file drivers/audio/Win32/gaudin_lld.c |
|||
* @brief GAUDIN - Driver file for Win32. |
|||
*/ |
|||
|
|||
#include "gfx.h" |
|||
|
|||
#if GFX_USE_GAUDIN |
|||
|
|||
/* Include the driver defines */ |
|||
#include "src/gaudin/driver.h" |
|||
|
|||
#undef Red |
|||
#undef Green |
|||
#undef Blue |
|||
#define WIN32_LEAN_AND_MEAN |
|||
#include <windows.h> |
|||
#include <stdio.h> |
|||
#include <mmsystem.h> |
|||
|
|||
static HWAVEIN ah; |
|||
static volatile int nQueuedBuffers; |
|||
static bool_t isClosing; |
|||
static WAVEHDR *pWaveHdrs; |
|||
static HANDLE waveThread; |
|||
static DWORD threadID; |
|||
|
|||
/*
|
|||
static void PrintWaveErrorMsg(DWORD err, TCHAR * str) |
|||
{ |
|||
#define BUFFERSIZE 128 |
|||
char buffer[BUFFERSIZE]; |
|||
|
|||
fprintf(stderr, "GAUDIN: ERROR 0x%08X: %s\r\n", err, str); |
|||
if (mciGetErrorString(err, &buffer[0], sizeof(buffer))) |
|||
fprintf(stderr, "%s\r\n", &buffer[0]); |
|||
else |
|||
fprintf(stderr, "0x%08X returned!\r\n", err); |
|||
} |
|||
*/ |
|||
|
|||
/**************************** waveProc() *******************************
|
|||
* We don't use CALLBACK_FUNCTION because it is restricted to calling only |
|||
* a few particular Windows functions, namely some of the time functions, |
|||
* and a few of the Low Level MIDI API. If you violate this rule, your app can |
|||
* hang inside of the callback). One of the Windows API that a callback can't |
|||
* call is waveInAddBuffer() which is what we need to use whenever we receive a |
|||
* MM_WIM_DATA. My callback would need to defer that job to another thread |
|||
* anyway, so instead just use CALLBACK_THREAD here instead. |
|||
*************************************************************************/ |
|||
|
|||
static DWORD WINAPI waveProc(LPVOID arg) { |
|||
MSG msg; |
|||
(void) arg; |
|||
|
|||
while (GetMessage(&msg, 0, 0, 0)) { |
|||
switch (msg.message) { |
|||
case MM_WIM_DATA: |
|||
GAUDIN_ISR_CompleteI((audin_sample_t *)((WAVEHDR *)msg.lParam)->lpData, ((WAVEHDR *)msg.lParam)->dwBytesRecorded/sizeof(audin_sample_t)); |
|||
|
|||
/* Are we closing? */ |
|||
if (isClosing) { |
|||
/* Yes. We aren't recording, so another WAVEHDR has been returned to us after recording has stopped.
|
|||
* When we get all of them back, things can be cleaned up |
|||
*/ |
|||
nQueuedBuffers--; |
|||
waveInUnprepareHeader(ah, (WAVEHDR *)msg.lParam, sizeof(WAVEHDR)); |
|||
} else { |
|||
/* No. Now we need to requeue this buffer so the driver can use it for another block of audio
|
|||
* data. NOTE: We shouldn't need to waveInPrepareHeader() a WAVEHDR that has already been prepared once. |
|||
* Note: We are assuming here that both the application can still access the buffer while |
|||
* it is on the queue. |
|||
*/ |
|||
waveInAddBuffer(ah, (WAVEHDR *)msg.lParam, sizeof(WAVEHDR)); |
|||
} |
|||
|
|||
break; |
|||
} |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
/*===========================================================================*/ |
|||
/* External declarations. */ |
|||
/*===========================================================================*/ |
|||
|
|||
void gaudin_lld_deinit(void) { |
|||
if (ah) { |
|||
isClosing = TRUE; |
|||
waveInReset(ah); |
|||
while(nQueuedBuffers) Sleep(1); |
|||
waveInClose(ah); |
|||
ah = 0; |
|||
if (pWaveHdrs) gfxFree(pWaveHdrs); |
|||
pWaveHdrs = 0; |
|||
isClosing = FALSE; |
|||
} |
|||
} |
|||
|
|||
void gaudin_lld_init(const gaudin_params *paud) { |
|||
WAVEFORMATEX wfx; |
|||
size_t spaceleft; |
|||
audin_sample_t *p; |
|||
WAVEHDR *phdr; |
|||
size_t nBuffers; |
|||
size_t sz; |
|||
|
|||
if (!waveThread) { |
|||
if (!(waveThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveProc, 0, 0, &threadID))) { |
|||
fprintf(stderr, "GAUDIN/GAUDOUT: Can't create WAVE recording thread\n"); |
|||
return; |
|||
} |
|||
CloseHandle(waveThread); |
|||
} |
|||
|
|||
gaudin_lld_deinit(); |
|||
|
|||
wfx.wFormatTag = WAVE_FORMAT_PCM; |
|||
wfx.nChannels = paud->channel == GAUDIN_STEREO ? 2 : 1; |
|||
wfx.nSamplesPerSec = paud->frequency; |
|||
wfx.nBlockAlign = wfx.nChannels * sizeof(audin_sample_t); |
|||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; |
|||
wfx.wBitsPerSample = sizeof(audin_sample_t) * 8; |
|||
wfx.cbSize = 0; |
|||
|
|||
if (waveInOpen(&ah, WAVE_MAPPER, &wfx, (DWORD_PTR)threadID, (DWORD_PTR)paud, CALLBACK_THREAD)) { |
|||
fprintf(stderr, "GAUDIN: Can't open WAVE recording device\n"); |
|||
return; |
|||
} |
|||
|
|||
/* We need to allocate a wave header for each buffer */ |
|||
nBuffers = (paud->bufcount + paud->samplesPerEvent - 1) / paud->samplesPerEvent; |
|||
if (!(pWaveHdrs = gfxAlloc(nBuffers * sizeof(WAVEHDR)))) { |
|||
fprintf(stderr, "GAUDIN: Buffer header allocation failed\n"); |
|||
return; |
|||
} |
|||
|
|||
/* Prepare each buffer and send to the wavein device */ |
|||
spaceleft = paud->bufcount; |
|||
for(p = paud->buffer, phdr = pWaveHdrs, spaceleft = paud->bufcount; spaceleft; p += sz, phdr++, spaceleft -= sz) { |
|||
sz = spaceleft > paud->samplesPerEvent ? paud->samplesPerEvent : spaceleft; |
|||
phdr->dwBufferLength = sz * sizeof(audin_sample_t); |
|||
phdr->lpData = (LPSTR)p; |
|||
phdr->dwFlags = 0; |
|||
if (!waveInPrepareHeader(ah, phdr, sizeof(WAVEHDR)) |
|||
&& !waveInAddBuffer(ah, phdr, sizeof(WAVEHDR))) |
|||
nQueuedBuffers++; |
|||
else |
|||
fprintf(stderr, "GAUDIN: Buffer prepare failed\n"); |
|||
} |
|||
if (!nQueuedBuffers) |
|||
fprintf(stderr, "GAUDIN: Failed to prepare any buffers\n"); |
|||
} |
|||
|
|||
void gaudin_lld_start(void) { |
|||
waveInStart(ah); |
|||
} |
|||
|
|||
void gaudin_lld_stop(void) { |
|||
waveInStop(ah); |
|||
} |
|||
|
|||
#endif /* GFX_USE_GAUDIN */ |
@ -1,64 +0,0 @@ |
|||
/*
|
|||
* This file is subject to the terms of the GFX License. If a copy of |
|||
* the license was not distributed with this file, you can obtain one at: |
|||
* |
|||
* http://ugfx.org/license.html
|
|||
*/ |
|||
|
|||
/**
|
|||
* @file drivers/audio/Win32/gaudin_lld_config.h |
|||
* @brief GAUDIN Driver config file. |
|||
* |
|||
* @addtogroup GAUDIN |
|||
* @{ |
|||
*/ |
|||
|
|||
#ifndef GAUDIN_LLD_CONFIG_H |
|||
#define GAUDIN_LLD_CONFIG_H |
|||
|
|||
#if GFX_USE_GAUDIN |
|||
|
|||
/*===========================================================================*/ |
|||
/* Driver hardware support. */ |
|||
/*===========================================================================*/ |
|||
|
|||
/**
|
|||
* @brief The audio input sample type |
|||
*/ |
|||
//typedef uint8_t audin_sample_t;
|
|||
typedef int16_t audin_sample_t; |
|||
|
|||
/**
|
|||
* @brief The maximum sample frequency supported by this audio device |
|||
*/ |
|||
#define GAUDIN_MAX_SAMPLE_FREQUENCY 44100 |
|||
|
|||
/**
|
|||
* @brief The number of bits in a sample |
|||
*/ |
|||
//#define GAUDIN_BITS_PER_SAMPLE 8
|
|||
#define GAUDIN_BITS_PER_SAMPLE 16 |
|||
|
|||
/**
|
|||
* @brief The format of an audio sample |
|||
*/ |
|||
//#define GAUDIN_SAMPLE_FORMAT ARRAY_DATA_8BITUNSIGNED
|
|||
#define GAUDIN_SAMPLE_FORMAT ARRAY_DATA_16BITSIGNED |
|||
|
|||
/**
|
|||
* @brief The number of audio channels supported by this driver |
|||
*/ |
|||
#define GAUDIN_NUM_CHANNELS 2 |
|||
|
|||
/**
|
|||
* @brief The list of audio channels and their uses |
|||
* @{ |
|||
*/ |
|||
#define GAUDIN_MONO 0 |
|||
#define GAUDIN_STEREO 1 |
|||
/** @} */ |
|||
|
|||
#endif /* GFX_USE_GAUDIN */ |
|||
|
|||
#endif /* GAUDIN_LLD_CONFIG_H */ |
|||
/** @} */ |
@ -1,10 +0,0 @@ |
|||
This driver uses the Win32 audio system to provide GAUDIN and GAUDOUT channels. |
|||
|
|||
For GAUDIN - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. |
|||
For GAUDOUT - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. |
|||
|
|||
For stereo, the samples are interleaved. Remember to allocate enough space for two samples per |
|||
sample period. |
|||
|
|||
This is a simple driver that makes no changes to the mixer so set up the audio mixer using |
|||
the windows control panel audio mixer before starting recording/playback. |
@ -1,5 +0,0 @@ |
|||
# List the required driver.
|
|||
GFXSRC += $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.c |
|||
|
|||
# Required include directories
|
|||
GFXINC += $(GFXLIB)/drivers/audio/gadc |
@ -0,0 +1,6 @@ |
|||
# List the required driver.
|
|||
GFXSRC += $(GFXLIB)/drivers/gaudio/Win32/gaudio_record_lld.c \
|
|||
$(GFXLIB)/drivers/gaudio/Win32/gaudio_play_lld.c |
|||
|
|||
# Required include directories
|
|||
GFXINC += $(GFXLIB)/drivers/gaudio/Win32 |
@ -0,0 +1,63 @@ |
|||
/*
|
|||
* This file is subject to the terms of the GFX License. If a copy of |
|||
* the license was not distributed with this file, you can obtain one at: |
|||
* |
|||
* http://ugfx.org/license.html
|
|||
*/ |
|||
|
|||
/**
|
|||
* @file drivers/gaudio/Win32/gaudio_record_config.h |
|||
* @brief GAUDIO Record Driver config file. |
|||
* |
|||
* @addtogroup GAUDIO |
|||
* @{ |
|||
*/ |
|||
|
|||
#ifndef GAUDIO_RECORD_CONFIG_H |
|||
#define GAUDIO_RECORD_CONFIG_H |
|||
|
|||
#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD |
|||
|
|||
/*===========================================================================*/ |
|||
/* Driver hardware support. */ |
|||
/*===========================================================================*/ |
|||
|
|||
/**
|
|||
* @brief The maximum sample frequency supported by this audio device |
|||
*/ |
|||
#define GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY 44100 |
|||
|
|||
/**
|
|||
* @brief The number of audio formats supported by this driver |
|||
*/ |
|||
#define GAUDIO_RECORD_NUM_FORMATS 2 |
|||
|
|||
/**
|
|||
* @brief The available audio sample formats in order of preference |
|||
*/ |
|||
#define GAUDIO_RECORD_FORMAT1 ARRAY_DATA_16BITSIGNED |
|||
#define GAUDIO_RECORD_FORMAT2 ARRAY_DATA_8BITUNSIGNED |
|||
|
|||
/**
|
|||
* @brief The number of audio channels supported by this driver |
|||
*/ |
|||
#define GAUDIO_RECORD_NUM_CHANNELS 2 |
|||
|
|||
/**
|
|||
* @brief Whether each channel is mono or stereo |
|||
*/ |
|||
#define GAUDIO_RECORD_CHANNEL0_IS_STEREO FALSE |
|||
#define GAUDIO_RECORD_CHANNEL1_IS_STEREO TRUE |
|||
|
|||
/**
|
|||
* @brief The list of audio channels and their uses |
|||
* @{ |
|||
*/ |
|||
#define GAUDIO_RECORD_MONO 0 |
|||
#define GAUDIO_RECORD_STEREO 1 |
|||
/** @} */ |
|||
|
|||
#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ |
|||
|
|||
#endif /* GAUDIO_RECORD_CONFIG_H */ |
|||
/** @} */ |
@ -0,0 +1,187 @@ |
|||
/*
|
|||
* This file is subject to the terms of the GFX License. If a copy of |
|||
* the license was not distributed with this file, you can obtain one at: |
|||
* |
|||
* http://ugfx.org/license.html
|
|||
*/ |
|||
|
|||
/**
|
|||
* @file drivers/gaudio/Win32/gaudio_record_lld.c |
|||
* @brief GAUDIO - Record Driver file for Win32. |
|||
*/ |
|||
|
|||
#include "gfx.h" |
|||
|
|||
#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD |
|||
|
|||
/* Include the driver defines */ |
|||
#include "src/gaudio/driver_record.h" |
|||
|
|||
#undef Red |
|||
#undef Green |
|||
#undef Blue |
|||
#define WIN32_LEAN_AND_MEAN |
|||
#include <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 chews buffers on the free-list.
|
|||
|
|||
static HWAVEIN ah = 0; |
|||
static volatile int nQueuedBuffers; |
|||
static bool_t isRunning; |
|||
static WAVEHDR WaveHdrs[MAX_WAVE_HEADERS]; |
|||
static HANDLE waveThread; |
|||
static DWORD threadID; |
|||
|
|||
/**************************** waveProc() *******************************
|
|||
* We don't use CALLBACK_FUNCTION because it is restricted to calling only |
|||
* a few particular Windows functions, namely some of the time functions, |
|||
* and a few of the Low Level MIDI API. If you violate this rule, your app can |
|||
* hang inside of the callback). One of the Windows API that a callback can't |
|||
* call is waveInAddBuffer() which is what we need to use whenever we receive a |
|||
* MM_WIM_DATA. My callback would need to defer that job to another thread |
|||
* anyway, so instead just use CALLBACK_THREAD here instead. |
|||
*************************************************************************/ |
|||
|
|||
static bool_t getbuffer(WAVEHDR *pwh) { |
|||
GAudioData *paud; |
|||
|
|||
// Get the next data block to send
|
|||
gfxSystemLock(); |
|||
paud = gaudioRecordGetFreeBlockI(); |
|||
if (!paud && !nQueuedBuffers) |
|||
gaudioRecordDoneI(); |
|||
gfxSystemUnlock(); |
|||
if (!paud) |
|||
return FALSE; |
|||
|
|||
// Prepare the wave header for Windows
|
|||
pwh->dwUser = (DWORD_PTR)paud; |
|||
pwh->lpData = (LPSTR)(paud+1); // The data is on the end of the structure
|
|||
pwh->dwBufferLength = paud->size; |
|||
pwh->dwFlags = 0; |
|||
if (waveInPrepareHeader(ah, pwh, sizeof(WAVEHDR))) { |
|||
fprintf(stderr, "GAUDIO: Failed to prepare a record buffer"); |
|||
exit(-1); |
|||
} |
|||
|
|||
// Send it to windows
|
|||
if (waveInAddBuffer(ah, pwh, sizeof(WAVEHDR))) { |
|||
fprintf(stderr, "GAUDIO: Failed to add the record buffer"); |
|||
exit(-1); |
|||
} |
|||
|
|||
nQueuedBuffers++; |
|||
return TRUE; |
|||
} |
|||
|
|||
static DWORD WINAPI waveProc(LPVOID arg) { |
|||
MSG msg; |
|||
WAVEHDR *pwh; |
|||
GAudioData *paud; |
|||
(void) arg; |
|||
|
|||
while (GetMessage(&msg, 0, 0, 0)) { |
|||
switch (msg.message) { |
|||
case MM_WIM_DATA: |
|||
pwh = (WAVEHDR *)msg.lParam; |
|||
|
|||
// Windows - Let go!
|
|||
waveInUnprepareHeader(ah, pwh, sizeof(WAVEHDR)); |
|||
|
|||
// Save the buffer in the audio record list
|
|||
paud = (GAudioData *)pwh->dwUser; |
|||
paud->len = pwh->dwBytesRecorded; |
|||
gfxSystemLock(); |
|||
gaudioRecordSaveDataBlockI(paud); |
|||
gfxSystemUnlock(); |
|||
pwh->lpData = 0; |
|||
nQueuedBuffers--; |
|||
|
|||
// Are we stopping?
|
|||
if (!isRunning) { |
|||
// Have we finished yet?
|
|||
if (!nQueuedBuffers) { |
|||
gfxSystemLock(); |
|||
gaudioRecordDoneI(); |
|||
gfxSystemUnlock(); |
|||
} |
|||
break; |
|||
} |
|||
|
|||
// Try and get a new block
|
|||
getbuffer(pwh); |
|||
break; |
|||
} |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
/*===========================================================================*/ |
|||
/* External declarations. */ |
|||
/*===========================================================================*/ |
|||
|
|||
bool_t gaudio_record_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { |
|||
WAVEFORMATEX wfx; |
|||
|
|||
if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_16BITSIGNED) |
|||
return FALSE; |
|||
|
|||
if (!waveThread) { |
|||
if (!(waveThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)waveProc, 0, 0, &threadID))) { |
|||
fprintf(stderr, "GAUDIO: Can't create WAVE recording thread\n"); |
|||
exit(-1); |
|||
} |
|||
CloseHandle(waveThread); |
|||
} |
|||
|
|||
wfx.wFormatTag = WAVE_FORMAT_PCM; |
|||
wfx.nChannels = channel == GAUDIO_RECORD_STEREO ? 2 : 1; |
|||
wfx.nSamplesPerSec = frequency; |
|||
wfx.nBlockAlign = wfx.nChannels * (format == ARRAY_DATA_8BITUNSIGNED ? 1 : 2); |
|||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; |
|||
wfx.wBitsPerSample = (format == ARRAY_DATA_8BITUNSIGNED ? 8 : 16); |
|||
wfx.cbSize = 0; |
|||
|
|||
if (ah) { |
|||
waveInClose(ah); |
|||
ah = 0; |
|||
} |
|||
if (waveInOpen(&ah, WAVE_MAPPER, &wfx, (DWORD_PTR)threadID, 0, CALLBACK_THREAD)) { |
|||
fprintf(stderr, "GAUDIN: Can't open WAVE recording device\n"); |
|||
exit(-1); |
|||
} |
|||
|
|||
return TRUE; |
|||
} |
|||
|
|||
void gaudio_record_lld_start(void) { |
|||
WAVEHDR *pwh; |
|||
|
|||
if (!ah) |
|||
return; |
|||
|
|||
while (nQueuedBuffers < MAX_WAVE_HEADERS) { |
|||
// Find the empty one - there will always be at least one.
|
|||
for(pwh = WaveHdrs; pwh->lpData; pwh++); |
|||
|
|||
// Grab the next audio block from the free-list
|
|||
if (!getbuffer(pwh)) |
|||
break; |
|||
} |
|||
if (!isRunning) { |
|||
isRunning = TRUE; |
|||
waveInStart(ah); |
|||
} |
|||
} |
|||
|
|||
void gaudio_record_lld_stop(void) { |
|||
isRunning = FALSE; |
|||
waveInReset(ah); |
|||
while(nQueuedBuffers) Sleep(1); |
|||
} |
|||
|
|||
#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */ |
@ -0,0 +1,10 @@ |
|||
This driver uses the Win32 audio system to provide GAUDIO play and record channels. |
|||
|
|||
For PLAY - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. |
|||
For RECORD - It supports 2 channels, Channel 0 being a mono channel and Channel 1 being a stereo channel. |
|||
|
|||
For stereo, the samples are interleaved. Remember to allocate enough space for two samples per |
|||
sample period. |
|||
|
|||
This is a simple driver that makes no changes to the mixer so set up the audio mixer using |
|||
the windows control panel audio mixer before starting recording/playback. |
@ -0,0 +1,5 @@ |
|||
# List the required driver.
|
|||
GFXSRC += $(GFXLIB)/drivers/gaudio/gadc/gaudio_record_lld.c |
|||
|
|||
# Required include directories
|
|||
GFXINC += $(GFXLIB)/drivers/gaudio/gadc |