Mercurial > audio-send
diff Alc/backends/wave.c @ 0:f9476ff7637e
initial forking of open-al to create multiple listeners
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Tue, 25 Oct 2011 13:02:31 -0700 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/Alc/backends/wave.c Tue Oct 25 13:02:31 2011 -0700 1.3 @@ -0,0 +1,357 @@ 1.4 +/** 1.5 + * OpenAL cross platform audio library 1.6 + * Copyright (C) 1999-2007 by authors. 1.7 + * This library is free software; you can redistribute it and/or 1.8 + * modify it under the terms of the GNU Library General Public 1.9 + * License as published by the Free Software Foundation; either 1.10 + * version 2 of the License, or (at your option) any later version. 1.11 + * 1.12 + * This library is distributed in the hope that it will be useful, 1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.15 + * Library General Public License for more details. 1.16 + * 1.17 + * You should have received a copy of the GNU Library General Public 1.18 + * License along with this library; if not, write to the 1.19 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 1.20 + * Boston, MA 02111-1307, USA. 1.21 + * Or go to http://www.gnu.org/copyleft/lgpl.html 1.22 + */ 1.23 + 1.24 +#include "config.h" 1.25 + 1.26 +#include <stdlib.h> 1.27 +#include <stdio.h> 1.28 +#include <memory.h> 1.29 +#include "alMain.h" 1.30 +#include "AL/al.h" 1.31 +#include "AL/alc.h" 1.32 + 1.33 + 1.34 +typedef struct { 1.35 + FILE *f; 1.36 + long DataStart; 1.37 + 1.38 + ALvoid *buffer; 1.39 + ALuint size; 1.40 + 1.41 + volatile int killNow; 1.42 + ALvoid *thread; 1.43 +} wave_data; 1.44 + 1.45 + 1.46 +static const ALCchar waveDevice[] = "Wave File Writer"; 1.47 + 1.48 +static const ALubyte SUBTYPE_PCM[] = { 1.49 + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 1.50 + 0x00, 0x38, 0x9b, 0x71 1.51 +}; 1.52 +static const ALubyte SUBTYPE_FLOAT[] = { 1.53 + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 1.54 + 0x00, 0x38, 0x9b, 0x71 1.55 +}; 1.56 + 1.57 +static const ALuint channel_masks[] = { 1.58 + 0, /* invalid */ 1.59 + 0x4, /* Mono */ 1.60 + 0x1 | 0x2, /* Stereo */ 1.61 + 0, /* 3 channel */ 1.62 + 0x1 | 0x2 | 0x10 | 0x20, /* Quad */ 1.63 + 0, /* 5 channel */ 1.64 + 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20, /* 5.1 */ 1.65 + 0x1 | 0x2 | 0x4 | 0x8 | 0x100 | 0x200 | 0x400, /* 6.1 */ 1.66 + 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x200 | 0x400, /* 7.1 */ 1.67 +}; 1.68 + 1.69 + 1.70 +static void fwrite16le(ALushort val, FILE *f) 1.71 +{ 1.72 + fputc(val&0xff, f); 1.73 + fputc((val>>8)&0xff, f); 1.74 +} 1.75 + 1.76 +static void fwrite32le(ALuint val, FILE *f) 1.77 +{ 1.78 + fputc(val&0xff, f); 1.79 + fputc((val>>8)&0xff, f); 1.80 + fputc((val>>16)&0xff, f); 1.81 + fputc((val>>24)&0xff, f); 1.82 +} 1.83 + 1.84 + 1.85 +static ALuint WaveProc(ALvoid *ptr) 1.86 +{ 1.87 + ALCdevice *pDevice = (ALCdevice*)ptr; 1.88 + wave_data *data = (wave_data*)pDevice->ExtraData; 1.89 + ALuint frameSize; 1.90 + ALuint now, start; 1.91 + ALuint64 avail, done; 1.92 + size_t fs; 1.93 + union { 1.94 + short s; 1.95 + char b[sizeof(short)]; 1.96 + } uSB; 1.97 + const ALuint restTime = (ALuint64)pDevice->UpdateSize * 1000 / 1.98 + pDevice->Frequency / 2; 1.99 + 1.100 + uSB.s = 1; 1.101 + frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); 1.102 + 1.103 + done = 0; 1.104 + start = timeGetTime(); 1.105 + while(!data->killNow && pDevice->Connected) 1.106 + { 1.107 + now = timeGetTime(); 1.108 + 1.109 + avail = (ALuint64)(now-start) * pDevice->Frequency / 1000; 1.110 + if(avail < done) 1.111 + { 1.112 + /* Timer wrapped. Add the remainder of the cycle to the available 1.113 + * count and reset the number of samples done */ 1.114 + avail += (ALuint64)0xFFFFFFFFu*pDevice->Frequency/1000 - done; 1.115 + done = 0; 1.116 + } 1.117 + if(avail-done < pDevice->UpdateSize) 1.118 + { 1.119 + Sleep(restTime); 1.120 + continue; 1.121 + } 1.122 + 1.123 + while(avail-done >= pDevice->UpdateSize) 1.124 + { 1.125 + aluMixData(pDevice, data->buffer, pDevice->UpdateSize); 1.126 + done += pDevice->UpdateSize; 1.127 + 1.128 + if(uSB.b[0] != 1) 1.129 + { 1.130 + ALuint bytesize = BytesFromDevFmt(pDevice->FmtType); 1.131 + ALubyte *bytes = data->buffer; 1.132 + ALuint i; 1.133 + 1.134 + if(bytesize == 1) 1.135 + { 1.136 + for(i = 0;i < data->size;i++) 1.137 + fputc(bytes[i], data->f); 1.138 + } 1.139 + else if(bytesize == 2) 1.140 + { 1.141 + for(i = 0;i < data->size;i++) 1.142 + fputc(bytes[i^1], data->f); 1.143 + } 1.144 + else if(bytesize == 4) 1.145 + { 1.146 + for(i = 0;i < data->size;i++) 1.147 + fputc(bytes[i^3], data->f); 1.148 + } 1.149 + } 1.150 + else 1.151 + fs = fwrite(data->buffer, frameSize, pDevice->UpdateSize, 1.152 + data->f); 1.153 + if(ferror(data->f)) 1.154 + { 1.155 + ERR("Error writing to file\n"); 1.156 + aluHandleDisconnect(pDevice); 1.157 + break; 1.158 + } 1.159 + } 1.160 + } 1.161 + 1.162 + return 0; 1.163 +} 1.164 + 1.165 +static ALCboolean wave_open_playback(ALCdevice *device, const ALCchar *deviceName) 1.166 +{ 1.167 + wave_data *data; 1.168 + const char *fname; 1.169 + 1.170 + fname = GetConfigValue("wave", "file", ""); 1.171 + if(!fname[0]) 1.172 + return ALC_FALSE; 1.173 + 1.174 + if(!deviceName) 1.175 + deviceName = waveDevice; 1.176 + else if(strcmp(deviceName, waveDevice) != 0) 1.177 + return ALC_FALSE; 1.178 + 1.179 + data = (wave_data*)calloc(1, sizeof(wave_data)); 1.180 + 1.181 + data->f = fopen(fname, "wb"); 1.182 + if(!data->f) 1.183 + { 1.184 + free(data); 1.185 + ERR("Could not open file '%s': %s\n", fname, strerror(errno)); 1.186 + return ALC_FALSE; 1.187 + } 1.188 + 1.189 + device->szDeviceName = strdup(deviceName); 1.190 + device->ExtraData = data; 1.191 + return ALC_TRUE; 1.192 +} 1.193 + 1.194 +static void wave_close_playback(ALCdevice *device) 1.195 +{ 1.196 + wave_data *data = (wave_data*)device->ExtraData; 1.197 + 1.198 + fclose(data->f); 1.199 + free(data); 1.200 + device->ExtraData = NULL; 1.201 +} 1.202 + 1.203 +static ALCboolean wave_reset_playback(ALCdevice *device) 1.204 +{ 1.205 + wave_data *data = (wave_data*)device->ExtraData; 1.206 + ALuint channels=0, bits=0; 1.207 + size_t val; 1.208 + 1.209 + fseek(data->f, 0, SEEK_SET); 1.210 + clearerr(data->f); 1.211 + 1.212 + switch(device->FmtType) 1.213 + { 1.214 + case DevFmtByte: 1.215 + device->FmtType = DevFmtUByte; 1.216 + break; 1.217 + case DevFmtUShort: 1.218 + device->FmtType = DevFmtShort; 1.219 + break; 1.220 + case DevFmtUByte: 1.221 + case DevFmtShort: 1.222 + case DevFmtFloat: 1.223 + break; 1.224 + } 1.225 + bits = BytesFromDevFmt(device->FmtType) * 8; 1.226 + channels = ChannelsFromDevFmt(device->FmtChans); 1.227 + 1.228 + fprintf(data->f, "RIFF"); 1.229 + fwrite32le(0xFFFFFFFF, data->f); // 'RIFF' header len; filled in at close 1.230 + 1.231 + fprintf(data->f, "WAVE"); 1.232 + 1.233 + fprintf(data->f, "fmt "); 1.234 + fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE 1.235 + 1.236 + // 16-bit val, format type id (extensible: 0xFFFE) 1.237 + fwrite16le(0xFFFE, data->f); 1.238 + // 16-bit val, channel count 1.239 + fwrite16le(channels, data->f); 1.240 + // 32-bit val, frequency 1.241 + fwrite32le(device->Frequency, data->f); 1.242 + // 32-bit val, bytes per second 1.243 + fwrite32le(device->Frequency * channels * bits / 8, data->f); 1.244 + // 16-bit val, frame size 1.245 + fwrite16le(channels * bits / 8, data->f); 1.246 + // 16-bit val, bits per sample 1.247 + fwrite16le(bits, data->f); 1.248 + // 16-bit val, extra byte count 1.249 + fwrite16le(22, data->f); 1.250 + // 16-bit val, valid bits per sample 1.251 + fwrite16le(bits, data->f); 1.252 + // 32-bit val, channel mask 1.253 + fwrite32le(channel_masks[channels], data->f); 1.254 + // 16 byte GUID, sub-type format 1.255 + val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f); 1.256 + 1.257 + fprintf(data->f, "data"); 1.258 + fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close 1.259 + 1.260 + if(ferror(data->f)) 1.261 + { 1.262 + ERR("Error writing header: %s\n", strerror(errno)); 1.263 + return ALC_FALSE; 1.264 + } 1.265 + 1.266 + data->DataStart = ftell(data->f); 1.267 + 1.268 + data->size = device->UpdateSize * channels * bits / 8; 1.269 + data->buffer = malloc(data->size); 1.270 + if(!data->buffer) 1.271 + { 1.272 + ERR("Buffer malloc failed\n"); 1.273 + return ALC_FALSE; 1.274 + } 1.275 + 1.276 + SetDefaultWFXChannelOrder(device); 1.277 + 1.278 + data->thread = StartThread(WaveProc, device); 1.279 + if(data->thread == NULL) 1.280 + { 1.281 + free(data->buffer); 1.282 + data->buffer = NULL; 1.283 + return ALC_FALSE; 1.284 + } 1.285 + 1.286 + return ALC_TRUE; 1.287 +} 1.288 + 1.289 +static void wave_stop_playback(ALCdevice *device) 1.290 +{ 1.291 + wave_data *data = (wave_data*)device->ExtraData; 1.292 + ALuint dataLen; 1.293 + long size; 1.294 + 1.295 + if(!data->thread) 1.296 + return; 1.297 + 1.298 + data->killNow = 1; 1.299 + StopThread(data->thread); 1.300 + data->thread = NULL; 1.301 + 1.302 + data->killNow = 0; 1.303 + 1.304 + free(data->buffer); 1.305 + data->buffer = NULL; 1.306 + 1.307 + size = ftell(data->f); 1.308 + if(size > 0) 1.309 + { 1.310 + dataLen = size - data->DataStart; 1.311 + if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0) 1.312 + fwrite32le(dataLen, data->f); // 'data' header len 1.313 + if(fseek(data->f, 4, SEEK_SET) == 0) 1.314 + fwrite32le(size-8, data->f); // 'WAVE' header len 1.315 + } 1.316 +} 1.317 + 1.318 + 1.319 +static const BackendFuncs wave_funcs = { 1.320 + wave_open_playback, 1.321 + wave_close_playback, 1.322 + wave_reset_playback, 1.323 + wave_stop_playback, 1.324 + NULL, 1.325 + NULL, 1.326 + NULL, 1.327 + NULL, 1.328 + NULL, 1.329 + NULL 1.330 +}; 1.331 + 1.332 +ALCboolean alc_wave_init(BackendFuncs *func_list) 1.333 +{ 1.334 + *func_list = wave_funcs; 1.335 + printf("WAVE: I'm init!!\n"); 1.336 + return ALC_TRUE; 1.337 +} 1.338 + 1.339 +void alc_wave_deinit(void) 1.340 +{ 1.341 +} 1.342 + 1.343 +void alc_wave_probe(enum DevProbe type) 1.344 +{ 1.345 + printf("WAVE: I'm being probed :)\n"); 1.346 + if(!ConfigValueExists("wave", "file")) 1.347 + return; 1.348 + 1.349 + switch(type) 1.350 + { 1.351 + case DEVICE_PROBE: 1.352 + AppendDeviceList(waveDevice); 1.353 + break; 1.354 + case ALL_DEVICE_PROBE: 1.355 + AppendAllDeviceList(waveDevice); 1.356 + break; 1.357 + case CAPTURE_DEVICE_PROBE: 1.358 + break; 1.359 + } 1.360 +}