aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/backends/wave.c
diff options
context:
space:
mode:
Diffstat (limited to 'Alc/backends/wave.c')
-rw-r--r--Alc/backends/wave.c325
1 files changed, 195 insertions, 130 deletions
diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c
index 421ca5d7..6b47c611 100644
--- a/Alc/backends/wave.c
+++ b/Alc/backends/wave.c
@@ -13,8 +13,8 @@
*
* 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.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -24,26 +24,13 @@
#include <stdio.h>
#include <memory.h>
#include <errno.h>
-#ifdef HAVE_WINDOWS_H
-#include <windows.h>
-#endif
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "compat.h"
-
-typedef struct {
- FILE *f;
- long DataStart;
-
- ALvoid *buffer;
- ALuint size;
-
- volatile int killNow;
- althrd_t thread;
-} wave_data;
+#include "backends/base.h"
static const ALCchar waveDevice[] = "Wave File Writer";
@@ -57,18 +44,15 @@ static const ALubyte SUBTYPE_FLOAT[] = {
0x00, 0x38, 0x9b, 0x71
};
-static const ALuint channel_masks[] = {
- 0, /* invalid */
- 0x4, /* Mono */
- 0x1 | 0x2, /* Stereo */
- 0, /* 3 channel */
- 0x1 | 0x2 | 0x10 | 0x20, /* Quad */
- 0, /* 5 channel */
- 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20, /* 5.1 */
- 0x1 | 0x2 | 0x4 | 0x8 | 0x100 | 0x200 | 0x400, /* 6.1 */
- 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x200 | 0x400, /* 7.1 */
+static const ALubyte SUBTYPE_BFORMAT_PCM[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
+ 0xca, 0x00, 0x00, 0x00
};
+static const ALubyte SUBTYPE_BFORMAT_FLOAT[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
+ 0xca, 0x00, 0x00, 0x00
+};
static void fwrite16le(ALushort val, FILE *f)
{
@@ -85,10 +69,57 @@ static void fwrite32le(ALuint val, FILE *f)
}
-static int WaveProc(void *ptr)
+typedef struct ALCwaveBackend {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ FILE *mFile;
+ long mDataStart;
+
+ ALvoid *mBuffer;
+ ALuint mSize;
+
+ volatile int killNow;
+ althrd_t thread;
+} ALCwaveBackend;
+
+static int ALCwaveBackend_mixerProc(void *ptr);
+
+static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, Destruct)
+static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name);
+static void ALCwaveBackend_close(ALCwaveBackend *self);
+static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self);
+static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self);
+static void ALCwaveBackend_stop(ALCwaveBackend *self);
+static DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend)
+
+DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend);
+
+
+static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCwaveBackend, ALCbackend, self);
+
+ self->mFile = NULL;
+ self->mDataStart = -1;
+
+ self->mBuffer = NULL;
+ self->mSize = 0;
+
+ self->killNow = 1;
+}
+
+
+static int ALCwaveBackend_mixerProc(void *ptr)
{
- ALCdevice *device = (ALCdevice*)ptr;
- wave_data *data = (wave_data*)device->ExtraData;
+ ALCwaveBackend *self = (ALCwaveBackend*)ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
struct timespec now, start;
ALint64 avail, done;
ALuint frameSize;
@@ -106,7 +137,7 @@ static int WaveProc(void *ptr)
ERR("Failed to get starting time\n");
return 1;
}
- while(!data->killNow && device->Connected)
+ while(!self->killNow && device->Connected)
{
if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
{
@@ -125,41 +156,41 @@ static int WaveProc(void *ptr)
}
if(avail-done < device->UpdateSize)
- al_nssleep(0, restTime);
+ al_nssleep(restTime);
else while(avail-done >= device->UpdateSize)
{
- aluMixData(device, data->buffer, device->UpdateSize);
+ aluMixData(device, self->mBuffer, device->UpdateSize);
done += device->UpdateSize;
if(!IS_LITTLE_ENDIAN)
{
ALuint bytesize = BytesFromDevFmt(device->FmtType);
- ALubyte *bytes = data->buffer;
+ ALubyte *bytes = self->mBuffer;
ALuint i;
if(bytesize == 1)
{
- for(i = 0;i < data->size;i++)
- fputc(bytes[i], data->f);
+ for(i = 0;i < self->mSize;i++)
+ fputc(bytes[i], self->mFile);
}
else if(bytesize == 2)
{
- for(i = 0;i < data->size;i++)
- fputc(bytes[i^1], data->f);
+ for(i = 0;i < self->mSize;i++)
+ fputc(bytes[i^1], self->mFile);
}
else if(bytesize == 4)
{
- for(i = 0;i < data->size;i++)
- fputc(bytes[i^3], data->f);
+ for(i = 0;i < self->mSize;i++)
+ fputc(bytes[i^3], self->mFile);
}
}
else
{
- fs = fwrite(data->buffer, frameSize, device->UpdateSize,
- data->f);
+ fs = fwrite(self->mBuffer, frameSize, device->UpdateSize,
+ self->mFile);
(void)fs;
}
- if(ferror(data->f))
+ if(ferror(self->mFile))
{
ERR("Error writing to file\n");
ALCdevice_Lock(device);
@@ -173,52 +204,52 @@ static int WaveProc(void *ptr)
return 0;
}
-static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
+
+static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name)
{
- wave_data *data;
+ ALCdevice *device;
const char *fname;
- fname = GetConfigValue("wave", "file", "");
- if(!fname[0])
- return ALC_INVALID_VALUE;
+ fname = GetConfigValue(NULL, "wave", "file", "");
+ if(!fname[0]) return ALC_INVALID_VALUE;
- if(!deviceName)
- deviceName = waveDevice;
- else if(strcmp(deviceName, waveDevice) != 0)
+ if(!name)
+ name = waveDevice;
+ else if(strcmp(name, waveDevice) != 0)
return ALC_INVALID_VALUE;
- data = (wave_data*)calloc(1, sizeof(wave_data));
-
- data->f = al_fopen(fname, "wb");
- if(!data->f)
+ self->mFile = al_fopen(fname, "wb");
+ if(!self->mFile)
{
- free(data);
ERR("Could not open file '%s': %s\n", fname, strerror(errno));
return ALC_INVALID_VALUE;
}
- al_string_copy_cstr(&device->DeviceName, deviceName);
- device->ExtraData = data;
+ device = STATIC_CAST(ALCbackend, self)->mDevice;
+ al_string_copy_cstr(&device->DeviceName, name);
+
return ALC_NO_ERROR;
}
-static void wave_close_playback(ALCdevice *device)
+static void ALCwaveBackend_close(ALCwaveBackend *self)
{
- wave_data *data = (wave_data*)device->ExtraData;
-
- fclose(data->f);
- free(data);
- device->ExtraData = NULL;
+ if(self->mFile)
+ fclose(self->mFile);
+ self->mFile = NULL;
}
-static ALCboolean wave_reset_playback(ALCdevice *device)
+static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
{
- wave_data *data = (wave_data*)device->ExtraData;
- ALuint channels=0, bits=0;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ ALuint channels=0, bits=0, chanmask=0;
+ int isbformat = 0;
size_t val;
- fseek(data->f, 0, SEEK_SET);
- clearerr(data->f);
+ fseek(self->mFile, 0, SEEK_SET);
+ clearerr(self->mFile);
+
+ if(GetConfigValueBool(NULL, "wave", "bformat", 0))
+ device->FmtChans = DevFmtBFormat3D;
switch(device->FmtType)
{
@@ -237,135 +268,156 @@ static ALCboolean wave_reset_playback(ALCdevice *device)
case DevFmtFloat:
break;
}
+ switch(device->FmtChans)
+ {
+ case DevFmtMono: chanmask = 0x04; break;
+ case DevFmtStereo: chanmask = 0x01 | 0x02; break;
+ case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break;
+ case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break;
+ case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break;
+ case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break;
+ case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
+ case DevFmtBFormat3D:
+ isbformat = 1;
+ chanmask = 0;
+ break;
+ }
bits = BytesFromDevFmt(device->FmtType) * 8;
channels = ChannelsFromDevFmt(device->FmtChans);
- fprintf(data->f, "RIFF");
- fwrite32le(0xFFFFFFFF, data->f); // 'RIFF' header len; filled in at close
+ fprintf(self->mFile, "RIFF");
+ fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close
- fprintf(data->f, "WAVE");
+ fprintf(self->mFile, "WAVE");
- fprintf(data->f, "fmt ");
- fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE
+ fprintf(self->mFile, "fmt ");
+ fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE
// 16-bit val, format type id (extensible: 0xFFFE)
- fwrite16le(0xFFFE, data->f);
+ fwrite16le(0xFFFE, self->mFile);
// 16-bit val, channel count
- fwrite16le(channels, data->f);
+ fwrite16le(channels, self->mFile);
// 32-bit val, frequency
- fwrite32le(device->Frequency, data->f);
+ fwrite32le(device->Frequency, self->mFile);
// 32-bit val, bytes per second
- fwrite32le(device->Frequency * channels * bits / 8, data->f);
+ fwrite32le(device->Frequency * channels * bits / 8, self->mFile);
// 16-bit val, frame size
- fwrite16le(channels * bits / 8, data->f);
+ fwrite16le(channels * bits / 8, self->mFile);
// 16-bit val, bits per sample
- fwrite16le(bits, data->f);
+ fwrite16le(bits, self->mFile);
// 16-bit val, extra byte count
- fwrite16le(22, data->f);
+ fwrite16le(22, self->mFile);
// 16-bit val, valid bits per sample
- fwrite16le(bits, data->f);
+ fwrite16le(bits, self->mFile);
// 32-bit val, channel mask
- fwrite32le(channel_masks[channels], data->f);
+ fwrite32le(chanmask, self->mFile);
// 16 byte GUID, sub-type format
- val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f);
+ val = fwrite(((bits==32) ? (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
+ (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM)), 1, 16, self->mFile);
(void)val;
- fprintf(data->f, "data");
- fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close
+ fprintf(self->mFile, "data");
+ fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close
- if(ferror(data->f))
+ if(ferror(self->mFile))
{
ERR("Error writing header: %s\n", strerror(errno));
return ALC_FALSE;
}
- data->DataStart = ftell(data->f);
+ self->mDataStart = ftell(self->mFile);
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
-static ALCboolean wave_start_playback(ALCdevice *device)
+static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self)
{
- wave_data *data = (wave_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
- data->buffer = malloc(data->size);
- if(!data->buffer)
+ self->mSize = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ self->mBuffer = malloc(self->mSize);
+ if(!self->mBuffer)
{
ERR("Buffer malloc failed\n");
return ALC_FALSE;
}
- data->killNow = 0;
- if(althrd_create(&data->thread, WaveProc, device) != althrd_success)
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success)
{
- free(data->buffer);
- data->buffer = NULL;
+ free(self->mBuffer);
+ self->mBuffer = NULL;
+ self->mSize = 0;
return ALC_FALSE;
}
return ALC_TRUE;
}
-static void wave_stop_playback(ALCdevice *device)
+static void ALCwaveBackend_stop(ALCwaveBackend *self)
{
- wave_data *data = (wave_data*)device->ExtraData;
ALuint dataLen;
long size;
int res;
- if(data->killNow)
+ if(self->killNow)
return;
- data->killNow = 1;
- althrd_join(data->thread, &res);
+ self->killNow = 1;
+ althrd_join(self->thread, &res);
- free(data->buffer);
- data->buffer = NULL;
+ free(self->mBuffer);
+ self->mBuffer = NULL;
- size = ftell(data->f);
+ size = ftell(self->mFile);
if(size > 0)
{
- dataLen = size - data->DataStart;
- if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0)
- fwrite32le(dataLen, data->f); // 'data' header len
- if(fseek(data->f, 4, SEEK_SET) == 0)
- fwrite32le(size-8, data->f); // 'WAVE' header len
+ dataLen = size - self->mDataStart;
+ if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0)
+ fwrite32le(dataLen, self->mFile); // 'data' header len
+ if(fseek(self->mFile, 4, SEEK_SET) == 0)
+ fwrite32le(size-8, self->mFile); // 'WAVE' header len
}
}
-static const BackendFuncs wave_funcs = {
- wave_open_playback,
- wave_close_playback,
- wave_reset_playback,
- wave_start_playback,
- wave_stop_playback,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- ALCdevice_GetLatencyDefault
-};
+typedef struct ALCwaveBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCwaveBackendFactory;
+#define ALCWAVEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
+
+static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self);
+static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit)
+static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type);
+static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory);
+
-ALCboolean alc_wave_init(BackendFuncs *func_list)
+ALCbackendFactory *ALCwaveBackendFactory_getFactory(void)
{
- *func_list = wave_funcs;
- return ALC_TRUE;
+ static ALCwaveBackendFactory factory = ALCWAVEBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
}
-void alc_wave_deinit(void)
+
+static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory* UNUSED(self))
{
+ return ALC_TRUE;
}
-void alc_wave_probe(enum DevProbe type)
+static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUSED(self), ALCbackend_Type type)
{
- if(!ConfigValueExists("wave", "file"))
- return;
+ if(type == ALCbackend_Playback)
+ return !!ConfigValueExists(NULL, "wave", "file");
+ return ALC_FALSE;
+}
+static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type)
+{
switch(type)
{
case ALL_DEVICE_PROBE:
@@ -375,3 +427,16 @@ void alc_wave_probe(enum DevProbe type)
break;
}
}
+
+static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCwaveBackend *backend;
+ NEW_OBJ(backend, ALCwaveBackend)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}