aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2008-01-11 09:32:22 -0800
committerChris Robinson <[email protected]>2008-01-11 09:32:22 -0800
commitf10408739e22cea6b3c52b8a9f6e36792c33d855 (patch)
tree547df88fe3dcbbbd51c72c56067e5cf173b3f9ae
parente1d0ad749bd5772d968aa8b5ed600dee905310a4 (diff)
Add a wave file writing backend
-rw-r--r--Alc/ALc.c2
-rw-r--r--Alc/wave.c335
-rw-r--r--CMakeLists.txt4
-rw-r--r--OpenAL32/Include/alMain.h1
-rw-r--r--openalrc.sample8
5 files changed, 349 insertions, 1 deletions
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 <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#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