diff ext/openal-soft/Alc/wave.c @ 0:4a0efb7baf70

* Datasets becomes the new trunk and retires after that :-)
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Sun, 29 Jun 2008 18:44:17 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ext/openal-soft/Alc/wave.c	Sun Jun 29 18:44:17 2008 +0000
@@ -0,0 +1,334 @@
+/**
+ * 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->UpdateSize/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;
+    const char *fname;
+    int i;
+
+    fname = GetConfigValue("wave", "file", "");
+    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);
+
+    if(ferror(data->f))
+    {
+        AL_PRINT("Error writing header: %s\n", strerror(errno));
+        fclose(data->f);
+        free(data);
+        return ALC_FALSE;
+    }
+
+    data->DataStart = ftell(data->f);
+
+    device->UpdateSize = max(device->UpdateSize, 2048);
+
+    data->size = device->UpdateSize;
+    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);
+}