Mercurial > audio-send
view 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 source
1 /**2 * OpenAL cross platform audio library3 * Copyright (C) 1999-2007 by authors.4 * This library is free software; you can redistribute it and/or5 * modify it under the terms of the GNU Library General Public6 * License as published by the Free Software Foundation; either7 * version 2 of the License, or (at your option) any later version.8 *9 * This library is distributed in the hope that it will be useful,10 * but WITHOUT ANY WARRANTY; without even the implied warranty of11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12 * Library General Public License for more details.13 *14 * You should have received a copy of the GNU Library General Public15 * License along with this library; if not, write to the16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,17 * Boston, MA 02111-1307, USA.18 * Or go to http://www.gnu.org/copyleft/lgpl.html19 */21 #include "config.h"23 #include <stdlib.h>24 #include <stdio.h>25 #include <memory.h>26 #include "alMain.h"27 #include "AL/al.h"28 #include "AL/alc.h"31 typedef struct {32 FILE *f;33 long DataStart;35 ALvoid *buffer;36 ALuint size;38 volatile int killNow;39 ALvoid *thread;40 } wave_data;43 static const ALCchar waveDevice[] = "Wave File Writer";45 static const ALubyte SUBTYPE_PCM[] = {46 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,47 0x00, 0x38, 0x9b, 0x7148 };49 static const ALubyte SUBTYPE_FLOAT[] = {50 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,51 0x00, 0x38, 0x9b, 0x7152 };54 static const ALuint channel_masks[] = {55 0, /* invalid */56 0x4, /* Mono */57 0x1 | 0x2, /* Stereo */58 0, /* 3 channel */59 0x1 | 0x2 | 0x10 | 0x20, /* Quad */60 0, /* 5 channel */61 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20, /* 5.1 */62 0x1 | 0x2 | 0x4 | 0x8 | 0x100 | 0x200 | 0x400, /* 6.1 */63 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x200 | 0x400, /* 7.1 */64 };67 static void fwrite16le(ALushort val, FILE *f)68 {69 fputc(val&0xff, f);70 fputc((val>>8)&0xff, f);71 }73 static void fwrite32le(ALuint val, FILE *f)74 {75 fputc(val&0xff, f);76 fputc((val>>8)&0xff, f);77 fputc((val>>16)&0xff, f);78 fputc((val>>24)&0xff, f);79 }82 static ALuint WaveProc(ALvoid *ptr)83 {84 ALCdevice *pDevice = (ALCdevice*)ptr;85 wave_data *data = (wave_data*)pDevice->ExtraData;86 ALuint frameSize;87 ALuint now, start;88 ALuint64 avail, done;89 size_t fs;90 union {91 short s;92 char b[sizeof(short)];93 } uSB;94 const ALuint restTime = (ALuint64)pDevice->UpdateSize * 1000 /95 pDevice->Frequency / 2;97 uSB.s = 1;98 frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);100 done = 0;101 start = timeGetTime();102 while(!data->killNow && pDevice->Connected)103 {104 now = timeGetTime();106 avail = (ALuint64)(now-start) * pDevice->Frequency / 1000;107 if(avail < done)108 {109 /* Timer wrapped. Add the remainder of the cycle to the available110 * count and reset the number of samples done */111 avail += (ALuint64)0xFFFFFFFFu*pDevice->Frequency/1000 - done;112 done = 0;113 }114 if(avail-done < pDevice->UpdateSize)115 {116 Sleep(restTime);117 continue;118 }120 while(avail-done >= pDevice->UpdateSize)121 {122 aluMixData(pDevice, data->buffer, pDevice->UpdateSize);123 done += pDevice->UpdateSize;125 if(uSB.b[0] != 1)126 {127 ALuint bytesize = BytesFromDevFmt(pDevice->FmtType);128 ALubyte *bytes = data->buffer;129 ALuint i;131 if(bytesize == 1)132 {133 for(i = 0;i < data->size;i++)134 fputc(bytes[i], data->f);135 }136 else if(bytesize == 2)137 {138 for(i = 0;i < data->size;i++)139 fputc(bytes[i^1], data->f);140 }141 else if(bytesize == 4)142 {143 for(i = 0;i < data->size;i++)144 fputc(bytes[i^3], data->f);145 }146 }147 else148 fs = fwrite(data->buffer, frameSize, pDevice->UpdateSize,149 data->f);150 if(ferror(data->f))151 {152 ERR("Error writing to file\n");153 aluHandleDisconnect(pDevice);154 break;155 }156 }157 }159 return 0;160 }162 static ALCboolean wave_open_playback(ALCdevice *device, const ALCchar *deviceName)163 {164 wave_data *data;165 const char *fname;167 fname = GetConfigValue("wave", "file", "");168 if(!fname[0])169 return ALC_FALSE;171 if(!deviceName)172 deviceName = waveDevice;173 else if(strcmp(deviceName, waveDevice) != 0)174 return ALC_FALSE;176 data = (wave_data*)calloc(1, sizeof(wave_data));178 data->f = fopen(fname, "wb");179 if(!data->f)180 {181 free(data);182 ERR("Could not open file '%s': %s\n", fname, strerror(errno));183 return ALC_FALSE;184 }186 device->szDeviceName = strdup(deviceName);187 device->ExtraData = data;188 return ALC_TRUE;189 }191 static void wave_close_playback(ALCdevice *device)192 {193 wave_data *data = (wave_data*)device->ExtraData;195 fclose(data->f);196 free(data);197 device->ExtraData = NULL;198 }200 static ALCboolean wave_reset_playback(ALCdevice *device)201 {202 wave_data *data = (wave_data*)device->ExtraData;203 ALuint channels=0, bits=0;204 size_t val;206 fseek(data->f, 0, SEEK_SET);207 clearerr(data->f);209 switch(device->FmtType)210 {211 case DevFmtByte:212 device->FmtType = DevFmtUByte;213 break;214 case DevFmtUShort:215 device->FmtType = DevFmtShort;216 break;217 case DevFmtUByte:218 case DevFmtShort:219 case DevFmtFloat:220 break;221 }222 bits = BytesFromDevFmt(device->FmtType) * 8;223 channels = ChannelsFromDevFmt(device->FmtChans);225 fprintf(data->f, "RIFF");226 fwrite32le(0xFFFFFFFF, data->f); // 'RIFF' header len; filled in at close228 fprintf(data->f, "WAVE");230 fprintf(data->f, "fmt ");231 fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE233 // 16-bit val, format type id (extensible: 0xFFFE)234 fwrite16le(0xFFFE, data->f);235 // 16-bit val, channel count236 fwrite16le(channels, data->f);237 // 32-bit val, frequency238 fwrite32le(device->Frequency, data->f);239 // 32-bit val, bytes per second240 fwrite32le(device->Frequency * channels * bits / 8, data->f);241 // 16-bit val, frame size242 fwrite16le(channels * bits / 8, data->f);243 // 16-bit val, bits per sample244 fwrite16le(bits, data->f);245 // 16-bit val, extra byte count246 fwrite16le(22, data->f);247 // 16-bit val, valid bits per sample248 fwrite16le(bits, data->f);249 // 32-bit val, channel mask250 fwrite32le(channel_masks[channels], data->f);251 // 16 byte GUID, sub-type format252 val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f);254 fprintf(data->f, "data");255 fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close257 if(ferror(data->f))258 {259 ERR("Error writing header: %s\n", strerror(errno));260 return ALC_FALSE;261 }263 data->DataStart = ftell(data->f);265 data->size = device->UpdateSize * channels * bits / 8;266 data->buffer = malloc(data->size);267 if(!data->buffer)268 {269 ERR("Buffer malloc failed\n");270 return ALC_FALSE;271 }273 SetDefaultWFXChannelOrder(device);275 data->thread = StartThread(WaveProc, device);276 if(data->thread == NULL)277 {278 free(data->buffer);279 data->buffer = NULL;280 return ALC_FALSE;281 }283 return ALC_TRUE;284 }286 static void wave_stop_playback(ALCdevice *device)287 {288 wave_data *data = (wave_data*)device->ExtraData;289 ALuint dataLen;290 long size;292 if(!data->thread)293 return;295 data->killNow = 1;296 StopThread(data->thread);297 data->thread = NULL;299 data->killNow = 0;301 free(data->buffer);302 data->buffer = NULL;304 size = ftell(data->f);305 if(size > 0)306 {307 dataLen = size - data->DataStart;308 if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0)309 fwrite32le(dataLen, data->f); // 'data' header len310 if(fseek(data->f, 4, SEEK_SET) == 0)311 fwrite32le(size-8, data->f); // 'WAVE' header len312 }313 }316 static const BackendFuncs wave_funcs = {317 wave_open_playback,318 wave_close_playback,319 wave_reset_playback,320 wave_stop_playback,321 NULL,322 NULL,323 NULL,324 NULL,325 NULL,326 NULL327 };329 ALCboolean alc_wave_init(BackendFuncs *func_list)330 {331 *func_list = wave_funcs;332 printf("WAVE: I'm init!!\n");333 return ALC_TRUE;334 }336 void alc_wave_deinit(void)337 {338 }340 void alc_wave_probe(enum DevProbe type)341 {342 printf("WAVE: I'm being probed :)\n");343 if(!ConfigValueExists("wave", "file"))344 return;346 switch(type)347 {348 case DEVICE_PROBE:349 AppendDeviceList(waveDevice);350 break;351 case ALL_DEVICE_PROBE:352 AppendAllDeviceList(waveDevice);353 break;354 case CAPTURE_DEVICE_PROBE:355 break;356 }357 }