Mercurial > audio-send
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f9476ff7637e |
---|---|
1 /** | |
2 * OpenAL cross platform audio library | |
3 * Copyright (C) 1999-2007 by authors. | |
4 * This library is free software; you can redistribute it and/or | |
5 * modify it under the terms of the GNU Library General Public | |
6 * License as published by the Free Software Foundation; either | |
7 * 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 of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 * Library General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU Library General Public | |
15 * License along with this library; if not, write to the | |
16 * 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.html | |
19 */ | |
20 | |
21 #include "config.h" | |
22 | |
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" | |
29 | |
30 | |
31 typedef struct { | |
32 FILE *f; | |
33 long DataStart; | |
34 | |
35 ALvoid *buffer; | |
36 ALuint size; | |
37 | |
38 volatile int killNow; | |
39 ALvoid *thread; | |
40 } wave_data; | |
41 | |
42 | |
43 static const ALCchar waveDevice[] = "Wave File Writer"; | |
44 | |
45 static const ALubyte SUBTYPE_PCM[] = { | |
46 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, | |
47 0x00, 0x38, 0x9b, 0x71 | |
48 }; | |
49 static const ALubyte SUBTYPE_FLOAT[] = { | |
50 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, | |
51 0x00, 0x38, 0x9b, 0x71 | |
52 }; | |
53 | |
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 }; | |
65 | |
66 | |
67 static void fwrite16le(ALushort val, FILE *f) | |
68 { | |
69 fputc(val&0xff, f); | |
70 fputc((val>>8)&0xff, f); | |
71 } | |
72 | |
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 } | |
80 | |
81 | |
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; | |
96 | |
97 uSB.s = 1; | |
98 frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); | |
99 | |
100 done = 0; | |
101 start = timeGetTime(); | |
102 while(!data->killNow && pDevice->Connected) | |
103 { | |
104 now = timeGetTime(); | |
105 | |
106 avail = (ALuint64)(now-start) * pDevice->Frequency / 1000; | |
107 if(avail < done) | |
108 { | |
109 /* Timer wrapped. Add the remainder of the cycle to the available | |
110 * 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 } | |
119 | |
120 while(avail-done >= pDevice->UpdateSize) | |
121 { | |
122 aluMixData(pDevice, data->buffer, pDevice->UpdateSize); | |
123 done += pDevice->UpdateSize; | |
124 | |
125 if(uSB.b[0] != 1) | |
126 { | |
127 ALuint bytesize = BytesFromDevFmt(pDevice->FmtType); | |
128 ALubyte *bytes = data->buffer; | |
129 ALuint i; | |
130 | |
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 else | |
148 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 } | |
158 | |
159 return 0; | |
160 } | |
161 | |
162 static ALCboolean wave_open_playback(ALCdevice *device, const ALCchar *deviceName) | |
163 { | |
164 wave_data *data; | |
165 const char *fname; | |
166 | |
167 fname = GetConfigValue("wave", "file", ""); | |
168 if(!fname[0]) | |
169 return ALC_FALSE; | |
170 | |
171 if(!deviceName) | |
172 deviceName = waveDevice; | |
173 else if(strcmp(deviceName, waveDevice) != 0) | |
174 return ALC_FALSE; | |
175 | |
176 data = (wave_data*)calloc(1, sizeof(wave_data)); | |
177 | |
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 } | |
185 | |
186 device->szDeviceName = strdup(deviceName); | |
187 device->ExtraData = data; | |
188 return ALC_TRUE; | |
189 } | |
190 | |
191 static void wave_close_playback(ALCdevice *device) | |
192 { | |
193 wave_data *data = (wave_data*)device->ExtraData; | |
194 | |
195 fclose(data->f); | |
196 free(data); | |
197 device->ExtraData = NULL; | |
198 } | |
199 | |
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; | |
205 | |
206 fseek(data->f, 0, SEEK_SET); | |
207 clearerr(data->f); | |
208 | |
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); | |
224 | |
225 fprintf(data->f, "RIFF"); | |
226 fwrite32le(0xFFFFFFFF, data->f); // 'RIFF' header len; filled in at close | |
227 | |
228 fprintf(data->f, "WAVE"); | |
229 | |
230 fprintf(data->f, "fmt "); | |
231 fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE | |
232 | |
233 // 16-bit val, format type id (extensible: 0xFFFE) | |
234 fwrite16le(0xFFFE, data->f); | |
235 // 16-bit val, channel count | |
236 fwrite16le(channels, data->f); | |
237 // 32-bit val, frequency | |
238 fwrite32le(device->Frequency, data->f); | |
239 // 32-bit val, bytes per second | |
240 fwrite32le(device->Frequency * channels * bits / 8, data->f); | |
241 // 16-bit val, frame size | |
242 fwrite16le(channels * bits / 8, data->f); | |
243 // 16-bit val, bits per sample | |
244 fwrite16le(bits, data->f); | |
245 // 16-bit val, extra byte count | |
246 fwrite16le(22, data->f); | |
247 // 16-bit val, valid bits per sample | |
248 fwrite16le(bits, data->f); | |
249 // 32-bit val, channel mask | |
250 fwrite32le(channel_masks[channels], data->f); | |
251 // 16 byte GUID, sub-type format | |
252 val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f); | |
253 | |
254 fprintf(data->f, "data"); | |
255 fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close | |
256 | |
257 if(ferror(data->f)) | |
258 { | |
259 ERR("Error writing header: %s\n", strerror(errno)); | |
260 return ALC_FALSE; | |
261 } | |
262 | |
263 data->DataStart = ftell(data->f); | |
264 | |
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 } | |
272 | |
273 SetDefaultWFXChannelOrder(device); | |
274 | |
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 } | |
282 | |
283 return ALC_TRUE; | |
284 } | |
285 | |
286 static void wave_stop_playback(ALCdevice *device) | |
287 { | |
288 wave_data *data = (wave_data*)device->ExtraData; | |
289 ALuint dataLen; | |
290 long size; | |
291 | |
292 if(!data->thread) | |
293 return; | |
294 | |
295 data->killNow = 1; | |
296 StopThread(data->thread); | |
297 data->thread = NULL; | |
298 | |
299 data->killNow = 0; | |
300 | |
301 free(data->buffer); | |
302 data->buffer = NULL; | |
303 | |
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 len | |
310 if(fseek(data->f, 4, SEEK_SET) == 0) | |
311 fwrite32le(size-8, data->f); // 'WAVE' header len | |
312 } | |
313 } | |
314 | |
315 | |
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 NULL | |
327 }; | |
328 | |
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 } | |
335 | |
336 void alc_wave_deinit(void) | |
337 { | |
338 } | |
339 | |
340 void alc_wave_probe(enum DevProbe type) | |
341 { | |
342 printf("WAVE: I'm being probed :)\n"); | |
343 if(!ConfigValueExists("wave", "file")) | |
344 return; | |
345 | |
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 } |