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 ALubyte SUBTYPE_BFORMAT_PCM
[] = {
48 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
49 0xca, 0x00, 0x00, 0x00
52 static const ALubyte SUBTYPE_BFORMAT_FLOAT
[] = {
53 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
54 0xca, 0x00, 0x00, 0x00
57 static void fwrite16le(ALushort val
, FILE *f
)
59 ALubyte data
[2] = { val
&0xff, (val
>>8)&0xff };
60 fwrite(data
, 1, 2, f
);
63 static void fwrite32le(ALuint val
, FILE *f
)
65 ALubyte data
[4] = { val
&0xff, (val
>>8)&0xff, (val
>>16)&0xff, (val
>>24)&0xff };
66 fwrite(data
, 1, 4, f
);
70 typedef struct ALCwaveBackend
{
71 DERIVE_FROM_TYPE(ALCbackend
);
83 static int ALCwaveBackend_mixerProc(void *ptr
);
85 static void ALCwaveBackend_Construct(ALCwaveBackend
*self
, ALCdevice
*device
);
86 static DECLARE_FORWARD(ALCwaveBackend
, ALCbackend
, void, Destruct
)
87 static ALCenum
ALCwaveBackend_open(ALCwaveBackend
*self
, const ALCchar
*name
);
88 static void ALCwaveBackend_close(ALCwaveBackend
*self
);
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
;
117 static int ALCwaveBackend_mixerProc(void *ptr
)
119 ALCwaveBackend
*self
= (ALCwaveBackend
*)ptr
;
120 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
121 struct timespec now
, start
;
125 const long restTime
= (long)((ALuint64
)device
->UpdateSize
* 1000000000 /
126 device
->Frequency
/ 2);
128 althrd_setname(althrd_current(), MIXER_THREAD_NAME
);
130 frameSize
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
133 if(altimespec_get(&start
, AL_TIME_UTC
) != AL_TIME_UTC
)
135 ERR("Failed to get starting time\n");
138 while(!self
->killNow
&& device
->Connected
)
140 if(altimespec_get(&now
, AL_TIME_UTC
) != AL_TIME_UTC
)
142 ERR("Failed to get current time\n");
146 avail
= (now
.tv_sec
- start
.tv_sec
) * device
->Frequency
;
147 avail
+= (ALint64
)(now
.tv_nsec
- start
.tv_nsec
) * device
->Frequency
/ 1000000000;
150 /* Oops, time skipped backwards. Reset the number of samples done
151 * with one update available since we (likely) just came back from
153 done
= avail
- device
->UpdateSize
;
156 if(avail
-done
< device
->UpdateSize
)
157 al_nssleep(restTime
);
158 else while(avail
-done
>= device
->UpdateSize
)
160 ALCwaveBackend_lock(self
);
161 aluMixData(device
, self
->mBuffer
, device
->UpdateSize
);
162 ALCwaveBackend_unlock(self
);
163 done
+= device
->UpdateSize
;
165 if(!IS_LITTLE_ENDIAN
)
167 ALuint bytesize
= BytesFromDevFmt(device
->FmtType
);
172 ALushort
*samples
= self
->mBuffer
;
173 ALuint len
= self
->mSize
/ 2;
174 for(i
= 0;i
< len
;i
++)
176 ALushort samp
= samples
[i
];
177 samples
[i
] = (samp
>>8) | (samp
<<8);
180 else if(bytesize
== 4)
182 ALuint
*samples
= self
->mBuffer
;
183 ALuint len
= self
->mSize
/ 4;
184 for(i
= 0;i
< len
;i
++)
186 ALuint samp
= samples
[i
];
187 samples
[i
] = (samp
>>24) | ((samp
>>8)&0x0000ff00) |
188 ((samp
<<8)&0x00ff0000) | (samp
<<24);
193 fs
= fwrite(self
->mBuffer
, frameSize
, device
->UpdateSize
, self
->mFile
);
195 if(ferror(self
->mFile
))
197 ERR("Error writing to file\n");
198 ALCdevice_Lock(device
);
199 aluHandleDisconnect(device
);
200 ALCdevice_Unlock(device
);
210 static ALCenum
ALCwaveBackend_open(ALCwaveBackend
*self
, const ALCchar
*name
)
215 fname
= GetConfigValue(NULL
, "wave", "file", "");
216 if(!fname
[0]) return ALC_INVALID_VALUE
;
220 else if(strcmp(name
, waveDevice
) != 0)
221 return ALC_INVALID_VALUE
;
223 self
->mFile
= al_fopen(fname
, "wb");
226 ERR("Could not open file '%s': %s\n", fname
, strerror(errno
));
227 return ALC_INVALID_VALUE
;
230 device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
231 alstr_copy_cstr(&device
->DeviceName
, name
);
236 static void ALCwaveBackend_close(ALCwaveBackend
*self
)
243 static ALCboolean
ALCwaveBackend_reset(ALCwaveBackend
*self
)
245 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
246 ALuint channels
=0, bits
=0, chanmask
=0;
250 fseek(self
->mFile
, 0, SEEK_SET
);
251 clearerr(self
->mFile
);
253 if(GetConfigValueBool(NULL
, "wave", "bformat", 0))
255 device
->FmtChans
= DevFmtAmbi3D
;
256 device
->AmbiOrder
= 1;
259 switch(device
->FmtType
)
262 device
->FmtType
= DevFmtUByte
;
265 device
->FmtType
= DevFmtShort
;
268 device
->FmtType
= DevFmtInt
;
276 switch(device
->FmtChans
)
278 case DevFmtMono
: chanmask
= 0x04; break;
279 case DevFmtStereo
: chanmask
= 0x01 | 0x02; break;
280 case DevFmtQuad
: chanmask
= 0x01 | 0x02 | 0x10 | 0x20; break;
281 case DevFmtX51
: chanmask
= 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break;
282 case DevFmtX51Rear
: chanmask
= 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break;
283 case DevFmtX61
: chanmask
= 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break;
284 case DevFmtX71
: chanmask
= 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
286 /* .amb output requires FuMa */
287 device
->AmbiLayout
= AmbiLayout_FuMa
;
288 device
->AmbiScale
= AmbiNorm_FuMa
;
293 bits
= BytesFromDevFmt(device
->FmtType
) * 8;
294 channels
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
296 fputs("RIFF", self
->mFile
);
297 fwrite32le(0xFFFFFFFF, self
->mFile
); // 'RIFF' header len; filled in at close
299 fputs("WAVE", self
->mFile
);
301 fputs("fmt ", self
->mFile
);
302 fwrite32le(40, self
->mFile
); // 'fmt ' header len; 40 bytes for EXTENSIBLE
304 // 16-bit val, format type id (extensible: 0xFFFE)
305 fwrite16le(0xFFFE, self
->mFile
);
306 // 16-bit val, channel count
307 fwrite16le(channels
, self
->mFile
);
308 // 32-bit val, frequency
309 fwrite32le(device
->Frequency
, self
->mFile
);
310 // 32-bit val, bytes per second
311 fwrite32le(device
->Frequency
* channels
* bits
/ 8, self
->mFile
);
312 // 16-bit val, frame size
313 fwrite16le(channels
* bits
/ 8, self
->mFile
);
314 // 16-bit val, bits per sample
315 fwrite16le(bits
, self
->mFile
);
316 // 16-bit val, extra byte count
317 fwrite16le(22, self
->mFile
);
318 // 16-bit val, valid bits per sample
319 fwrite16le(bits
, self
->mFile
);
320 // 32-bit val, channel mask
321 fwrite32le(chanmask
, self
->mFile
);
322 // 16 byte GUID, sub-type format
323 val
= fwrite(((bits
==32) ? (isbformat
? SUBTYPE_BFORMAT_FLOAT
: SUBTYPE_FLOAT
) :
324 (isbformat
? SUBTYPE_BFORMAT_PCM
: SUBTYPE_PCM
)), 1, 16, self
->mFile
);
327 fputs("data", self
->mFile
);
328 fwrite32le(0xFFFFFFFF, self
->mFile
); // 'data' header len; filled in at close
330 if(ferror(self
->mFile
))
332 ERR("Error writing header: %s\n", strerror(errno
));
335 self
->mDataStart
= ftell(self
->mFile
);
337 SetDefaultWFXChannelOrder(device
);
342 static ALCboolean
ALCwaveBackend_start(ALCwaveBackend
*self
)
344 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
346 self
->mSize
= device
->UpdateSize
* FrameSizeFromDevFmt(
347 device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
349 self
->mBuffer
= malloc(self
->mSize
);
352 ERR("Buffer malloc failed\n");
357 if(althrd_create(&self
->thread
, ALCwaveBackend_mixerProc
, self
) != althrd_success
)
360 self
->mBuffer
= NULL
;
368 static void ALCwaveBackend_stop(ALCwaveBackend
*self
)
378 althrd_join(self
->thread
, &res
);
381 self
->mBuffer
= NULL
;
383 size
= ftell(self
->mFile
);
386 dataLen
= size
- self
->mDataStart
;
387 if(fseek(self
->mFile
, self
->mDataStart
-4, SEEK_SET
) == 0)
388 fwrite32le(dataLen
, self
->mFile
); // 'data' header len
389 if(fseek(self
->mFile
, 4, SEEK_SET
) == 0)
390 fwrite32le(size
-8, self
->mFile
); // 'WAVE' header len
395 typedef struct ALCwaveBackendFactory
{
396 DERIVE_FROM_TYPE(ALCbackendFactory
);
397 } ALCwaveBackendFactory
;
398 #define ALCWAVEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) } }
400 ALCbackendFactory
*ALCwaveBackendFactory_getFactory(void);
402 static ALCboolean
ALCwaveBackendFactory_init(ALCwaveBackendFactory
*self
);
403 static DECLARE_FORWARD(ALCwaveBackendFactory
, ALCbackendFactory
, void, deinit
)
404 static ALCboolean
ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory
*self
, ALCbackend_Type type
);
405 static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory
*self
, enum DevProbe type
);
406 static ALCbackend
* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
407 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory
);
410 ALCbackendFactory
*ALCwaveBackendFactory_getFactory(void)
412 static ALCwaveBackendFactory factory
= ALCWAVEBACKENDFACTORY_INITIALIZER
;
413 return STATIC_CAST(ALCbackendFactory
, &factory
);
417 static ALCboolean
ALCwaveBackendFactory_init(ALCwaveBackendFactory
* UNUSED(self
))
422 static ALCboolean
ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
424 if(type
== ALCbackend_Playback
)
425 return !!ConfigValueExists(NULL
, "wave", "file");
429 static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory
* UNUSED(self
), enum DevProbe type
)
433 case ALL_DEVICE_PROBE
:
434 AppendAllDevicesList(waveDevice
);
436 case CAPTURE_DEVICE_PROBE
:
441 static ALCbackend
* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
443 if(type
== ALCbackend_Playback
)
445 ALCwaveBackend
*backend
;
446 NEW_OBJ(backend
, ALCwaveBackend
)(device
);
447 if(!backend
) return NULL
;
448 return STATIC_CAST(ALCbackend
, backend
);