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.
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.
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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
33 #include "backends/base.h"
36 static const ALCchar waveDevice
[] = "Wave File Writer";
38 static const ALubyte SUBTYPE_PCM
[] = {
39 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
40 0x00, 0x38, 0x9b, 0x71
42 static const ALubyte SUBTYPE_FLOAT
[] = {
43 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
44 0x00, 0x38, 0x9b, 0x71
47 static const ALuint channel_masks
[] = {
50 0x1 | 0x2, /* Stereo */
52 0x1 | 0x2 | 0x10 | 0x20, /* Quad */
54 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20, /* 5.1 */
55 0x1 | 0x2 | 0x4 | 0x8 | 0x100 | 0x200 | 0x400, /* 6.1 */
56 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x200 | 0x400, /* 7.1 */
60 static void fwrite16le(ALushort val
, FILE *f
)
63 fputc((val
>>8)&0xff, f
);
66 static void fwrite32le(ALuint val
, FILE *f
)
69 fputc((val
>>8)&0xff, f
);
70 fputc((val
>>16)&0xff, f
);
71 fputc((val
>>24)&0xff, f
);
75 typedef struct ALCwaveBackend
{
76 DERIVE_FROM_TYPE(ALCbackend
);
88 static int ALCwaveBackend_mixerProc(void *ptr
);
90 static void ALCwaveBackend_Construct(ALCwaveBackend
*self
, ALCdevice
*device
);
91 static DECLARE_FORWARD(ALCwaveBackend
, ALCbackend
, void, Destruct
)
92 static ALCenum
ALCwaveBackend_open(ALCwaveBackend
*self
, const ALCchar
*name
);
93 static void ALCwaveBackend_close(ALCwaveBackend
*self
);
94 static ALCboolean
ALCwaveBackend_reset(ALCwaveBackend
*self
);
95 static ALCboolean
ALCwaveBackend_start(ALCwaveBackend
*self
);
96 static void ALCwaveBackend_stop(ALCwaveBackend
*self
);
97 static DECLARE_FORWARD2(ALCwaveBackend
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
98 static DECLARE_FORWARD(ALCwaveBackend
, ALCbackend
, ALCuint
, availableSamples
)
99 static DECLARE_FORWARD(ALCwaveBackend
, ALCbackend
, ALint64
, getLatency
)
100 static DECLARE_FORWARD(ALCwaveBackend
, ALCbackend
, void, lock
)
101 static DECLARE_FORWARD(ALCwaveBackend
, ALCbackend
, void, unlock
)
102 DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend
)
104 DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend
);
107 static void ALCwaveBackend_Construct(ALCwaveBackend
*self
, ALCdevice
*device
)
109 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
110 SET_VTABLE2(ALCwaveBackend
, ALCbackend
, self
);
113 self
->mDataStart
= -1;
115 self
->mBuffer
= NULL
;
122 static int ALCwaveBackend_mixerProc(void *ptr
)
124 ALCwaveBackend
*self
= (ALCwaveBackend
*)ptr
;
125 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
126 struct timespec now
, start
;
130 const long restTime
= (long)((ALuint64
)device
->UpdateSize
* 1000000000 /
131 device
->Frequency
/ 2);
133 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
135 frameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
138 if(altimespec_get(&start
, AL_TIME_UTC
) != AL_TIME_UTC
)
140 ERR("Failed to get starting time\n");
143 while(!self
->killNow
&& device
->Connected
)
145 if(altimespec_get(&now
, AL_TIME_UTC
) != AL_TIME_UTC
)
147 ERR("Failed to get current time\n");
151 avail
= (now
.tv_sec
- start
.tv_sec
) * device
->Frequency
;
152 avail
+= (ALint64
)(now
.tv_nsec
- start
.tv_nsec
) * device
->Frequency
/ 1000000000;
155 /* Oops, time skipped backwards. Reset the number of samples done
156 * with one update available since we (likely) just came back from
158 done
= avail
- device
->UpdateSize
;
161 if(avail
-done
< device
->UpdateSize
)
162 al_nssleep(restTime
);
163 else while(avail
-done
>= device
->UpdateSize
)
165 aluMixData(device
, self
->mBuffer
, device
->UpdateSize
);
166 done
+= device
->UpdateSize
;
168 if(!IS_LITTLE_ENDIAN
)
170 ALuint bytesize
= BytesFromDevFmt(device
->FmtType
);
171 ALubyte
*bytes
= self
->mBuffer
;
176 for(i
= 0;i
< self
->mSize
;i
++)
177 fputc(bytes
[i
], self
->mFile
);
179 else if(bytesize
== 2)
181 for(i
= 0;i
< self
->mSize
;i
++)
182 fputc(bytes
[i
^1], self
->mFile
);
184 else if(bytesize
== 4)
186 for(i
= 0;i
< self
->mSize
;i
++)
187 fputc(bytes
[i
^3], self
->mFile
);
192 fs
= fwrite(self
->mBuffer
, frameSize
, device
->UpdateSize
,
196 if(ferror(self
->mFile
))
198 ERR("Error writing to file\n");
199 ALCdevice_Lock(device
);
200 aluHandleDisconnect(device
);
201 ALCdevice_Unlock(device
);
211 static ALCenum
ALCwaveBackend_open(ALCwaveBackend
*self
, const ALCchar
*name
)
216 fname
= GetConfigValue("wave", "file", "");
217 if(!fname
[0]) return ALC_INVALID_VALUE
;
221 else if(strcmp(name
, waveDevice
) != 0)
222 return ALC_INVALID_VALUE
;
224 self
->mFile
= al_fopen(fname
, "wb");
227 ERR("Could not open file '%s': %s\n", fname
, strerror(errno
));
228 return ALC_INVALID_VALUE
;
231 device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
232 al_string_copy_cstr(&device
->DeviceName
, name
);
237 static void ALCwaveBackend_close(ALCwaveBackend
*self
)
244 static ALCboolean
ALCwaveBackend_reset(ALCwaveBackend
*self
)
246 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
247 ALuint channels
=0, bits
=0;
250 fseek(self
->mFile
, 0, SEEK_SET
);
251 clearerr(self
->mFile
);
253 switch(device
->FmtType
)
256 device
->FmtType
= DevFmtUByte
;
259 device
->FmtType
= DevFmtShort
;
262 device
->FmtType
= DevFmtInt
;
270 bits
= BytesFromDevFmt(device
->FmtType
) * 8;
271 channels
= ChannelsFromDevFmt(device
->FmtChans
);
273 fprintf(self
->mFile
, "RIFF");
274 fwrite32le(0xFFFFFFFF, self
->mFile
); // 'RIFF' header len; filled in at close
276 fprintf(self
->mFile
, "WAVE");
278 fprintf(self
->mFile
, "fmt ");
279 fwrite32le(40, self
->mFile
); // 'fmt ' header len; 40 bytes for EXTENSIBLE
281 // 16-bit val, format type id (extensible: 0xFFFE)
282 fwrite16le(0xFFFE, self
->mFile
);
283 // 16-bit val, channel count
284 fwrite16le(channels
, self
->mFile
);
285 // 32-bit val, frequency
286 fwrite32le(device
->Frequency
, self
->mFile
);
287 // 32-bit val, bytes per second
288 fwrite32le(device
->Frequency
* channels
* bits
/ 8, self
->mFile
);
289 // 16-bit val, frame size
290 fwrite16le(channels
* bits
/ 8, self
->mFile
);
291 // 16-bit val, bits per sample
292 fwrite16le(bits
, self
->mFile
);
293 // 16-bit val, extra byte count
294 fwrite16le(22, self
->mFile
);
295 // 16-bit val, valid bits per sample
296 fwrite16le(bits
, self
->mFile
);
297 // 32-bit val, channel mask
298 fwrite32le(channel_masks
[channels
], self
->mFile
);
299 // 16 byte GUID, sub-type format
300 val
= fwrite(((bits
==32) ? SUBTYPE_FLOAT
: SUBTYPE_PCM
), 1, 16, self
->mFile
);
303 fprintf(self
->mFile
, "data");
304 fwrite32le(0xFFFFFFFF, self
->mFile
); // 'data' header len; filled in at close
306 if(ferror(self
->mFile
))
308 ERR("Error writing header: %s\n", strerror(errno
));
311 self
->mDataStart
= ftell(self
->mFile
);
313 SetDefaultWFXChannelOrder(device
);
318 static ALCboolean
ALCwaveBackend_start(ALCwaveBackend
*self
)
320 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
322 self
->mSize
= device
->UpdateSize
* FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
323 self
->mBuffer
= malloc(self
->mSize
);
326 ERR("Buffer malloc failed\n");
331 if(althrd_create(&self
->thread
, ALCwaveBackend_mixerProc
, self
) != althrd_success
)
334 self
->mBuffer
= NULL
;
342 static void ALCwaveBackend_stop(ALCwaveBackend
*self
)
352 althrd_join(self
->thread
, &res
);
355 self
->mBuffer
= NULL
;
357 size
= ftell(self
->mFile
);
360 dataLen
= size
- self
->mDataStart
;
361 if(fseek(self
->mFile
, self
->mDataStart
-4, SEEK_SET
) == 0)
362 fwrite32le(dataLen
, self
->mFile
); // 'data' header len
363 if(fseek(self
->mFile
, 4, SEEK_SET
) == 0)
364 fwrite32le(size
-8, self
->mFile
); // 'WAVE' header len
369 typedef struct ALCwaveBackendFactory
{
370 DERIVE_FROM_TYPE(ALCbackendFactory
);
371 } ALCwaveBackendFactory
;
372 #define ALCWAVEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) } }
374 ALCbackendFactory
*ALCwaveBackendFactory_getFactory(void);
376 static ALCboolean
ALCwaveBackendFactory_init(ALCwaveBackendFactory
*self
);
377 static DECLARE_FORWARD(ALCwaveBackendFactory
, ALCbackendFactory
, void, deinit
)
378 static ALCboolean
ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory
*self
, ALCbackend_Type type
);
379 static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory
*self
, enum DevProbe type
);
380 static ALCbackend
* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
381 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory
);
384 ALCbackendFactory
*ALCwaveBackendFactory_getFactory(void)
386 static ALCwaveBackendFactory factory
= ALCWAVEBACKENDFACTORY_INITIALIZER
;
387 return STATIC_CAST(ALCbackendFactory
, &factory
);
391 static ALCboolean
ALCwaveBackendFactory_init(ALCwaveBackendFactory
* UNUSED(self
))
396 static ALCboolean
ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
398 if(type
== ALCbackend_Playback
)
399 return !!ConfigValueExists("wave", "file");
403 static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory
* UNUSED(self
), enum DevProbe type
)
407 case ALL_DEVICE_PROBE
:
408 AppendAllDevicesList(waveDevice
);
410 case CAPTURE_DEVICE_PROBE
:
415 static ALCbackend
* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
417 if(type
== ALCbackend_Playback
)
419 ALCwaveBackend
*backend
;
421 backend
= ALCwaveBackend_New(sizeof(*backend
));
422 if(!backend
) return NULL
;
423 memset(backend
, 0, sizeof(*backend
));
425 ALCwaveBackend_Construct(backend
, device
);
427 return STATIC_CAST(ALCbackend
, backend
);
433 void alc_wave_probe(enum DevProbe type
)
435 if(!ConfigValueExists("wave", "file"))
440 case ALL_DEVICE_PROBE
:
441 AppendAllDevicesList(waveDevice
);
443 case CAPTURE_DEVICE_PROBE
: