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
34 #include "backends/base.h"
37 static const ALCchar waveDevice
[] = "Wave File Writer";
39 static const ALubyte SUBTYPE_PCM
[] = {
40 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
41 0x00, 0x38, 0x9b, 0x71
43 static const ALubyte SUBTYPE_FLOAT
[] = {
44 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
45 0x00, 0x38, 0x9b, 0x71
48 static const ALubyte SUBTYPE_BFORMAT_PCM
[] = {
49 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
50 0xca, 0x00, 0x00, 0x00
53 static const ALubyte SUBTYPE_BFORMAT_FLOAT
[] = {
54 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
55 0xca, 0x00, 0x00, 0x00
58 static void fwrite16le(ALushort val
, FILE *f
)
60 ALubyte data
[2] = { val
&0xff, (val
>>8)&0xff };
61 fwrite(data
, 1, 2, f
);
64 static void fwrite32le(ALuint val
, FILE *f
)
66 ALubyte data
[4] = { val
&0xff, (val
>>8)&0xff, (val
>>16)&0xff, (val
>>24)&0xff };
67 fwrite(data
, 1, 4, f
);
71 typedef struct ALCwaveBackend
{
72 DERIVE_FROM_TYPE(ALCbackend
);
80 ATOMIC(ALenum
) killNow
;
84 static int ALCwaveBackend_mixerProc(void *ptr
);
86 static void ALCwaveBackend_Construct(ALCwaveBackend
*self
, ALCdevice
*device
);
87 static void ALCwaveBackend_Destruct(ALCwaveBackend
*self
);
88 static ALCenum
ALCwaveBackend_open(ALCwaveBackend
*self
, const ALCchar
*name
);
89 static ALCboolean
ALCwaveBackend_reset(ALCwaveBackend
*self
);
90 static ALCboolean
ALCwaveBackend_start(ALCwaveBackend
*self
);
91 static void ALCwaveBackend_stop(ALCwaveBackend
*self
);
92 static DECLARE_FORWARD2(ALCwaveBackend
, ALCbackend
, ALCenum
, captureSamples
, void*, ALCuint
)
93 static DECLARE_FORWARD(ALCwaveBackend
, ALCbackend
, ALCuint
, availableSamples
)
94 static DECLARE_FORWARD(ALCwaveBackend
, ALCbackend
, ClockLatency
, getClockLatency
)
95 static DECLARE_FORWARD(ALCwaveBackend
, ALCbackend
, void, lock
)
96 static DECLARE_FORWARD(ALCwaveBackend
, ALCbackend
, void, unlock
)
97 DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend
)
99 DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend
);
102 static void ALCwaveBackend_Construct(ALCwaveBackend
*self
, ALCdevice
*device
)
104 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
105 SET_VTABLE2(ALCwaveBackend
, ALCbackend
, self
);
108 self
->mDataStart
= -1;
110 self
->mBuffer
= NULL
;
113 ATOMIC_INIT(&self
->killNow
, AL_TRUE
);
116 static void ALCwaveBackend_Destruct(ALCwaveBackend
*self
)
122 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
125 static int ALCwaveBackend_mixerProc(void *ptr
)
127 ALCwaveBackend
*self
= (ALCwaveBackend
*)ptr
;
128 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
129 struct timespec now
, start
;
133 const long restTime
= (long)((ALuint64
)device
->UpdateSize
* 1000000000 /
134 device
->Frequency
/ 2);
136 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
138 frameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
141 if(altimespec_get(&start
, AL_TIME_UTC
) != AL_TIME_UTC
)
143 ERR("Failed to get starting time\n");
146 while(!ATOMIC_LOAD(&self
->killNow
, almemory_order_acquire
) &&
147 ATOMIC_LOAD(&device
->Connected
, almemory_order_acquire
))
149 if(altimespec_get(&now
, AL_TIME_UTC
) != AL_TIME_UTC
)
151 ERR("Failed to get current time\n");
155 avail
= (now
.tv_sec
- start
.tv_sec
) * device
->Frequency
;
156 avail
+= (ALint64
)(now
.tv_nsec
- start
.tv_nsec
) * device
->Frequency
/ 1000000000;
159 /* Oops, time skipped backwards. Reset the number of samples done
160 * with one update available since we (likely) just came back from
162 done
= avail
- device
->UpdateSize
;
165 if(avail
-done
< device
->UpdateSize
)
166 al_nssleep(restTime
);
167 else while(avail
-done
>= device
->UpdateSize
)
169 ALCwaveBackend_lock(self
);
170 aluMixData(device
, self
->mBuffer
, device
->UpdateSize
);
171 ALCwaveBackend_unlock(self
);
172 done
+= device
->UpdateSize
;
174 if(!IS_LITTLE_ENDIAN
)
176 ALuint bytesize
= BytesFromDevFmt(device
->FmtType
);
181 ALushort
*samples
= self
->mBuffer
;
182 ALuint len
= self
->mSize
/ 2;
183 for(i
= 0;i
< len
;i
++)
185 ALushort samp
= samples
[i
];
186 samples
[i
] = (samp
>>8) | (samp
<<8);
189 else if(bytesize
== 4)
191 ALuint
*samples
= self
->mBuffer
;
192 ALuint len
= self
->mSize
/ 4;
193 for(i
= 0;i
< len
;i
++)
195 ALuint samp
= samples
[i
];
196 samples
[i
] = (samp
>>24) | ((samp
>>8)&0x0000ff00) |
197 ((samp
<<8)&0x00ff0000) | (samp
<<24);
202 fs
= fwrite(self
->mBuffer
, frameSize
, device
->UpdateSize
, self
->mFile
);
204 if(ferror(self
->mFile
))
206 ERR("Error writing to file\n");
207 ALCdevice_Lock(device
);
208 aluHandleDisconnect(device
, "Failed to write playback samples");
209 ALCdevice_Unlock(device
);
219 static ALCenum
ALCwaveBackend_open(ALCwaveBackend
*self
, const ALCchar
*name
)
224 fname
= GetConfigValue(NULL
, "wave", "file", "");
225 if(!fname
[0]) return ALC_INVALID_VALUE
;
229 else if(strcmp(name
, waveDevice
) != 0)
230 return ALC_INVALID_VALUE
;
232 self
->mFile
= al_fopen(fname
, "wb");
235 ERR("Could not open file '%s': %s\n", fname
, strerror(errno
));
236 return ALC_INVALID_VALUE
;
239 device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
240 alstr_copy_cstr(&device
->DeviceName
, name
);
245 static ALCboolean
ALCwaveBackend_reset(ALCwaveBackend
*self
)
247 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
248 ALuint channels
=0, bits
=0, chanmask
=0;
252 fseek(self
->mFile
, 0, SEEK_SET
);
253 clearerr(self
->mFile
);
255 if(GetConfigValueBool(NULL
, "wave", "bformat", 0))
257 device
->FmtChans
= DevFmtAmbi3D
;
258 device
->AmbiOrder
= 1;
261 switch(device
->FmtType
)
264 device
->FmtType
= DevFmtUByte
;
267 device
->FmtType
= DevFmtShort
;
270 device
->FmtType
= DevFmtInt
;
278 switch(device
->FmtChans
)
280 case DevFmtMono
: chanmask
= 0x04; break;
281 case DevFmtStereo
: chanmask
= 0x01 | 0x02; break;
282 case DevFmtQuad
: chanmask
= 0x01 | 0x02 | 0x10 | 0x20; break;
283 case DevFmtX51
: chanmask
= 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break;
284 case DevFmtX51Rear
: chanmask
= 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break;
285 case DevFmtX61
: chanmask
= 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break;
286 case DevFmtX71
: chanmask
= 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
288 /* .amb output requires FuMa */
289 device
->AmbiLayout
= AmbiLayout_FuMa
;
290 device
->AmbiScale
= AmbiNorm_FuMa
;
295 bits
= BytesFromDevFmt(device
->FmtType
) * 8;
296 channels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
298 fputs("RIFF", self
->mFile
);
299 fwrite32le(0xFFFFFFFF, self
->mFile
); // 'RIFF' header len; filled in at close
301 fputs("WAVE", self
->mFile
);
303 fputs("fmt ", self
->mFile
);
304 fwrite32le(40, self
->mFile
); // 'fmt ' header len; 40 bytes for EXTENSIBLE
306 // 16-bit val, format type id (extensible: 0xFFFE)
307 fwrite16le(0xFFFE, self
->mFile
);
308 // 16-bit val, channel count
309 fwrite16le(channels
, self
->mFile
);
310 // 32-bit val, frequency
311 fwrite32le(device
->Frequency
, self
->mFile
);
312 // 32-bit val, bytes per second
313 fwrite32le(device
->Frequency
* channels
* bits
/ 8, self
->mFile
);
314 // 16-bit val, frame size
315 fwrite16le(channels
* bits
/ 8, self
->mFile
);
316 // 16-bit val, bits per sample
317 fwrite16le(bits
, self
->mFile
);
318 // 16-bit val, extra byte count
319 fwrite16le(22, self
->mFile
);
320 // 16-bit val, valid bits per sample
321 fwrite16le(bits
, self
->mFile
);
322 // 32-bit val, channel mask
323 fwrite32le(chanmask
, self
->mFile
);
324 // 16 byte GUID, sub-type format
325 val
= fwrite((device
->FmtType
== DevFmtFloat
) ?
326 (isbformat
? SUBTYPE_BFORMAT_FLOAT
: SUBTYPE_FLOAT
) :
327 (isbformat
? SUBTYPE_BFORMAT_PCM
: SUBTYPE_PCM
), 1, 16, self
->mFile
);
330 fputs("data", self
->mFile
);
331 fwrite32le(0xFFFFFFFF, self
->mFile
); // 'data' header len; filled in at close
333 if(ferror(self
->mFile
))
335 ERR("Error writing header: %s\n", strerror(errno
));
338 self
->mDataStart
= ftell(self
->mFile
);
340 SetDefaultWFXChannelOrder(device
);
345 static ALCboolean
ALCwaveBackend_start(ALCwaveBackend
*self
)
347 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
349 self
->mSize
= device
->UpdateSize
* FrameSizeFromDevFmt(
350 device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
352 self
->mBuffer
= malloc(self
->mSize
);
355 ERR("Buffer malloc failed\n");
359 ATOMIC_STORE(&self
->killNow
, AL_FALSE
, almemory_order_release
);
360 if(althrd_create(&self
->thread
, ALCwaveBackend_mixerProc
, self
) != althrd_success
)
363 self
->mBuffer
= NULL
;
371 static void ALCwaveBackend_stop(ALCwaveBackend
*self
)
377 if(ATOMIC_EXCHANGE(&self
->killNow
, AL_TRUE
, almemory_order_acq_rel
))
379 althrd_join(self
->thread
, &res
);
382 self
->mBuffer
= NULL
;
384 size
= ftell(self
->mFile
);
387 dataLen
= size
- self
->mDataStart
;
388 if(fseek(self
->mFile
, self
->mDataStart
-4, SEEK_SET
) == 0)
389 fwrite32le(dataLen
, self
->mFile
); // 'data' header len
390 if(fseek(self
->mFile
, 4, SEEK_SET
) == 0)
391 fwrite32le(size
-8, self
->mFile
); // 'WAVE' header len
396 typedef struct ALCwaveBackendFactory
{
397 DERIVE_FROM_TYPE(ALCbackendFactory
);
398 } ALCwaveBackendFactory
;
399 #define ALCWAVEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) } }
401 ALCbackendFactory
*ALCwaveBackendFactory_getFactory(void);
403 static ALCboolean
ALCwaveBackendFactory_init(ALCwaveBackendFactory
*self
);
404 static DECLARE_FORWARD(ALCwaveBackendFactory
, ALCbackendFactory
, void, deinit
)
405 static ALCboolean
ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory
*self
, ALCbackend_Type type
);
406 static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory
*self
, enum DevProbe type
);
407 static ALCbackend
* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
408 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory
);
411 ALCbackendFactory
*ALCwaveBackendFactory_getFactory(void)
413 static ALCwaveBackendFactory factory
= ALCWAVEBACKENDFACTORY_INITIALIZER
;
414 return STATIC_CAST(ALCbackendFactory
, &factory
);
418 static ALCboolean
ALCwaveBackendFactory_init(ALCwaveBackendFactory
* UNUSED(self
))
423 static ALCboolean
ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
425 if(type
== ALCbackend_Playback
)
426 return !!ConfigValueExists(NULL
, "wave", "file");
430 static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory
* UNUSED(self
), enum DevProbe type
)
434 case ALL_DEVICE_PROBE
:
435 AppendAllDevicesList(waveDevice
);
437 case CAPTURE_DEVICE_PROBE
:
442 static ALCbackend
* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
444 if(type
== ALCbackend_Playback
)
446 ALCwaveBackend
*backend
;
447 NEW_OBJ(backend
, ALCwaveBackend
)(device
);
448 if(!backend
) return NULL
;
449 return STATIC_CAST(ALCbackend
, backend
);