From 298f6f440ae87373d92b2e392f0cc7780453d144 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2008 01:15:44 -0800 Subject: Add missing header include --- OpenAL32/alBuffer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'OpenAL32') diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 2bcb6562..1ea54fce 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -22,6 +22,7 @@ #include #include +#include #include "alMain.h" #include "AL/al.h" #include "AL/alc.h" -- cgit v1.2.3 From a97ecb8690c64a6007ad3f0e983cb8ef67b47795 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Jan 2008 06:01:51 -0800 Subject: Add a timing wrapper, using gettimeofday --- CMakeLists.txt | 5 +++++ OpenAL32/Include/alMain.h | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'OpenAL32') diff --git a/CMakeLists.txt b/CMakeLists.txt index a35c5dea..86fc4fd1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,6 +132,11 @@ ENDIF() # Check if we have Windows headers CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H) IF(NOT "${HAVE_WINDOWS_H}") + CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY) + IF(NOT "${HAVE_GETTIMEOFDAY}") + MESSAGE(FATAL_ERROR "No timing function found!") + ENDIF() + # We need pthreads outside of Windows CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H) IF(NOT "${HAVE_PTHREAD_H}") diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d8611a71..adf3f2c3 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -13,6 +13,7 @@ #include #include +#include #define IsBadWritePtr(a,b) (0) @@ -52,6 +53,21 @@ static inline void DeleteCriticalSection(CRITICAL_SECTION *cs) assert(ret == 0); } +/* NOTE: This wrapper isn't quite accurate as it returns an ALuint, as opposed + * to the expected DWORD. Both are defined as unsigned 32-bit types, however. + * Additionally, Win32 is supposed to measure the time since Windows started, + * as opposed to the actual time. */ +static inline ALuint timeGetTime(void) +{ + struct timeval tv; + int ret; + + ret = gettimeofday(&tv, NULL); + assert(ret == 0); + + return tv.tv_usec/1000 + tv.tv_sec*1000; +} + #define min(x,y) (((x)<(y))?(x):(y)) #define max(x,y) (((x)>(y))?(x):(y)) #endif -- cgit v1.2.3 From 2a5a5b5c1b97cfe66149bd77b4402e80f69c37c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Jan 2008 06:54:09 -0800 Subject: Add Sleep wrapper --- CMakeLists.txt | 5 +++++ OpenAL32/Include/alMain.h | 1 + 2 files changed, 6 insertions(+) (limited to 'OpenAL32') diff --git a/CMakeLists.txt b/CMakeLists.txt index 86fc4fd1..32f717a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,6 +137,11 @@ IF(NOT "${HAVE_WINDOWS_H}") MESSAGE(FATAL_ERROR "No timing function found!") ENDIF() + CHECK_FUNCTION_EXISTS(usleep HAVE_USLEEP) + IF(NOT "${HAVE_USLEEP}") + MESSAGE(FATAL_ERROR "No sleep function found!") + ENDIF() + # We need pthreads outside of Windows CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H) IF(NOT "${HAVE_PTHREAD_H}") diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index adf3f2c3..113101e4 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -68,6 +68,7 @@ static inline ALuint timeGetTime(void) return tv.tv_usec/1000 + tv.tv_sec*1000; } +#define Sleep(x) ((void)usleep((unsigned int)x*1000)) #define min(x,y) (((x)<(y))?(x):(y)) #define max(x,y) (((x)>(y))?(x):(y)) #endif -- cgit v1.2.3 From e1d0ad749bd5772d968aa8b5ed600dee905310a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Jan 2008 08:15:44 -0800 Subject: Use nanosleep instead of usleep So not to rely on the non-standard unistd.h header --- CMakeLists.txt | 4 ++-- OpenAL32/Include/alMain.h | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'OpenAL32') diff --git a/CMakeLists.txt b/CMakeLists.txt index 32f717a2..4955d250 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,8 +137,8 @@ IF(NOT "${HAVE_WINDOWS_H}") MESSAGE(FATAL_ERROR "No timing function found!") ENDIF() - CHECK_FUNCTION_EXISTS(usleep HAVE_USLEEP) - IF(NOT "${HAVE_USLEEP}") + CHECK_FUNCTION_EXISTS(nanosleep HAVE_NANOSLEEP) + IF(NOT "${HAVE_NANOSLEEP}") MESSAGE(FATAL_ERROR "No sleep function found!") ENDIF() diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 113101e4..c238a3a9 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -14,6 +14,8 @@ #include #include #include +#include +#include #define IsBadWritePtr(a,b) (0) @@ -68,7 +70,15 @@ static inline ALuint timeGetTime(void) return tv.tv_usec/1000 + tv.tv_sec*1000; } -#define Sleep(x) ((void)usleep((unsigned int)x*1000)) +static inline void Sleep(ALuint t) +{ + struct timespec tv, rem; + tv.tv_nsec = (t*1000000)%1000000000; + tv.tv_sec = t/1000; + + while(nanosleep(&tv, &rem) == -1 && errno == EINTR) + tv = rem; +} #define min(x,y) (((x)<(y))?(x):(y)) #define max(x,y) (((x)>(y))?(x):(y)) #endif -- cgit v1.2.3 From f10408739e22cea6b3c52b8a9f6e36792c33d855 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Jan 2008 09:32:22 -0800 Subject: Add a wave file writing backend --- Alc/ALc.c | 2 + Alc/wave.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 4 + OpenAL32/Include/alMain.h | 1 + openalrc.sample | 8 +- 5 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 Alc/wave.c (limited to 'OpenAL32') diff --git a/Alc/ALc.c b/Alc/ALc.c index d33390f7..0ec42533 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -61,6 +61,8 @@ struct { { "winmm", alcWinMMInit, EmptyFuncs }, #endif + { "wave", alc_wave_init, EmptyFuncs }, + { NULL, NULL, EmptyFuncs } }; #undef EmptyFuncs diff --git a/Alc/wave.c b/Alc/wave.c new file mode 100644 index 00000000..3de7ea80 --- /dev/null +++ b/Alc/wave.c @@ -0,0 +1,335 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + + +typedef struct { + FILE *f; + long DataStart; + + ALvoid *buffer; + ALuint size; + + int killNow; + ALvoid *thread; +} wave_data; + + +static ALCchar *waveDevice; + + +static ALuint WaveProc(ALvoid *ptr) +{ + ALCdevice *pDevice = (ALCdevice*)ptr; + wave_data *data = (wave_data*)pDevice->ExtraData; + ALuint frameSize; + ALuint now, last; + size_t WriteCnt; + ALuint avail; + union { + short s; + char b[sizeof(short)]; + } uSB; + + uSB.s = 1; + frameSize = aluBytesFromFormat(pDevice->Format) * + aluChannelsFromFormat(pDevice->Format); + + last = timeGetTime(); + while(!data->killNow) + { + now = timeGetTime(); + + avail = (now-last) * pDevice->Frequency / 1000; + if(avail < pDevice->UpdateFreq/4) + { + Sleep(1); + continue; + } + + while(avail > 0) + { + SuspendContext(NULL); + WriteCnt = min(data->size, avail); + aluMixData(pDevice->Context, data->buffer, WriteCnt * frameSize, + pDevice->Format); + ProcessContext(NULL); + + if(uSB.b[0] != 1 && aluBytesFromFormat(pDevice->Format) > 1) + { + ALubyte *bytes = data->buffer; + ALuint i; + + for(i = 0;i < WriteCnt*frameSize;i++) + fputc(bytes[i^1], data->f); + } + else + fwrite(data->buffer, frameSize, WriteCnt, data->f); + if(ferror(data->f)) + { + AL_PRINT("Error writing to file\n"); + data->killNow = 1; + break; + } + + avail -= WriteCnt; + } + last = now; + } + + return 0; +} + +static ALCboolean wave_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + wave_data *data; + ALuint channels; + ALuint bits; + char fname[64]; + int i; + + strncpy(fname, GetConfigValue("wave", "file", ""), sizeof(fname)-1); + fname[sizeof(fname)-1] = 0; + if(!fname[0]) + return ALC_FALSE; + + if(deviceName) + { + if(strcmp(deviceName, waveDevice) != 0) + return ALC_FALSE; + device->szDeviceName = waveDevice; + } + else + device->szDeviceName = waveDevice; + + data = (wave_data*)calloc(1, sizeof(wave_data)); + + data->f = fopen(fname, "wb"); + if(!data->f) + { + free(data); + AL_PRINT("Could not open file '%s': %s\n", fname, strerror(errno)); + return ALC_FALSE; + } + + bits = aluBytesFromFormat(device->Format) * 8; + channels = aluChannelsFromFormat(device->Format); + switch(bits) + { + case 8: + case 16: + if(channels == 0) + { + AL_PRINT("Unknown format?! %x\n", device->Format); + fclose(data->f); + free(data); + return ALC_FALSE; + } + break; + + default: + AL_PRINT("Unknown format?! %x\n", device->Format); + fclose(data->f); + free(data); + return ALC_FALSE; + } + + fprintf(data->f, "RIFF"); + fputc(0, data->f); // 'RIFF' header len; filled in at close + fputc(0, data->f); + fputc(0, data->f); + fputc(0, data->f); + + fprintf(data->f, "WAVE"); + + fprintf(data->f, "fmt "); + fputc(16, data->f); // 'fmt ' header len; 16 bytes for PCM + fputc(0, data->f); + fputc(0, data->f); + fputc(0, data->f); + // 16-bit val, format type id (PCM: 1) + fputc(1, data->f); + fputc(0, data->f); + // 16-bit val, channel count + fputc(channels&0xff, data->f); + fputc((channels>>8)&0xff, data->f); + // 32-bit val, frequency + fputc(device->Frequency&0xff, data->f); + fputc((device->Frequency>>8)&0xff, data->f); + fputc((device->Frequency>>16)&0xff, data->f); + fputc((device->Frequency>>24)&0xff, data->f); + // 32-bit val, bytes per second + i = device->Frequency * channels * bits / 8; + fputc(i&0xff, data->f); + fputc((i>>8)&0xff, data->f); + fputc((i>>16)&0xff, data->f); + fputc((i>>24)&0xff, data->f); + // 16-bit val, frame size + i = channels * bits / 8; + fputc(i&0xff, data->f); + fputc((i>>8)&0xff, data->f); + // 16-bit val, bits per sample + fputc(bits&0xff, data->f); + fputc((bits>>8)&0xff, data->f); + + fprintf(data->f, "data"); + fputc(0, data->f); // 'data' header len; filled in at close + fputc(0, data->f); + fputc(0, data->f); + fputc(0, data->f); + + data->DataStart = ftell(data->f); + if(data->DataStart == -1 || ferror(data->f)) + { + AL_PRINT("Error writing header: %s\n", strerror(errno)); + fclose(data->f); + free(data); + return ALC_FALSE; + } + + device->MaxNoOfSources = 256; + device->UpdateFreq = max(device->UpdateFreq, 2048); + + data->size = device->UpdateFreq; + data->buffer = malloc(data->size * channels * bits / 8); + if(!data->buffer) + { + AL_PRINT("buffer malloc failed\n"); + fclose(data->f); + free(data); + return ALC_FALSE; + } + + device->ExtraData = data; + data->thread = StartThread(WaveProc, device); + if(data->thread == NULL) + { + device->ExtraData = NULL; + fclose(data->f); + free(data->buffer); + free(data); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void wave_close_playback(ALCdevice *device) +{ + wave_data *data = (wave_data*)device->ExtraData; + ALuint dataLen; + long size; + + data->killNow = 1; + StopThread(data->thread); + + size = ftell(data->f); + if(size > 0) + { + dataLen = size - data->DataStart; + if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0) + { + fputc(dataLen&0xff, data->f); // 'data' header len + fputc((dataLen>>8)&0xff, data->f); + fputc((dataLen>>16)&0xff, data->f); + fputc((dataLen>>24)&0xff, data->f); + } + if(fseek(data->f, 4, SEEK_SET) == 0) + { + size -= 8; + fputc(size&0xff, data->f); // 'WAVE' header len + fputc((size>>8)&0xff, data->f); + fputc((size>>16)&0xff, data->f); + fputc((size>>24)&0xff, data->f); + } + } + + fclose(data->f); + free(data->buffer); + free(data); + device->ExtraData = NULL; +} + + +static ALCboolean wave_open_capture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) +{ + (void)pDevice; + (void)deviceName; + (void)frequency; + (void)format; + (void)SampleSize; + return ALC_FALSE; +} + +static void wave_close_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void wave_start_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void wave_stop_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void wave_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) +{ + (void)pDevice; + (void)pBuffer; + (void)lSamples; +} + +static ALCuint wave_available_samples(ALCdevice *pDevice) +{ + (void)pDevice; + return 0; +} + + +BackendFuncs wave_funcs = { + wave_open_playback, + wave_close_playback, + wave_open_capture, + wave_close_capture, + wave_start_capture, + wave_stop_capture, + wave_capture_samples, + wave_available_samples +}; + +void alc_wave_init(BackendFuncs *func_list) +{ + *func_list = wave_funcs; + + waveDevice = AppendDeviceList("Wave File Writer"); + AppendAllDeviceList(waveDevice); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 4955d250..ee2cc94e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,6 +190,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/alcRing.c Alc/alcThread.c Alc/bs2b.c + Alc/wave.c ) SET(BACKENDS "") @@ -263,6 +264,9 @@ IF("${HAVE_WINDOWS_H}") ENDIF() ENDIF() +# This is always available +SET(BACKENDS ${BACKENDS} WaveFile) + # End configuration CONFIGURE_FILE( "${OpenAL_SOURCE_DIR}/config.h.in" diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index c238a3a9..840c6993 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -149,6 +149,7 @@ void alc_alsa_init(BackendFuncs *func_list); void alc_oss_init(BackendFuncs *func_list); void alcDSoundInit(BackendFuncs *func_list); void alcWinMMInit(BackendFuncs *FuncList); +void alc_wave_init(BackendFuncs *func_list); struct ALCdevice_struct diff --git a/openalrc.sample b/openalrc.sample index 0e378a84..37325d14 100644 --- a/openalrc.sample +++ b/openalrc.sample @@ -44,7 +44,7 @@ drivers = # Sets the backend driver list order, comma-seperated. Unknown # backends and duplicated names are ignored, and unlisted backends # won't be considered for use. An empty list means the default. # Default is: - # alsa,oss,dsound,winmm + # alsa,oss,dsound,winmm,wave [alsa] # ALSA backend stuff device = default # Sets the device name for the default playback device. @@ -67,3 +67,9 @@ capture = /dev/dsp # Sets the device name for OSS capture. Default is /dev/dsp [winmm] # Windows Multimedia backend stuff # Nothing yet... + +[wave] # Wave File Writer stuff +file = # Sets the filename of the wave file to write to. An empty name + # prevents the backend from opening, even when explicitly requested. + # THIS WILL OVERWRITE EXISTING FILES WITHOUT QUESTION! + # Default is empty -- cgit v1.2.3