Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/openal-0.0.8/src/backends/alc_backend_wave.c @ 17

Last change on this file since 17 was 17, checked in by landauf, 16 years ago

added openal

File size: 7.9 KB
Line 
1/* -*- mode: C; tab-width:8; c-basic-offset:8 -*-
2 * vi:set ts=8:
3 *
4 * waveout.c
5 *
6 * WAVE file output.  Context writes, we save and sleep.
7 *
8 */
9#include "al_siteconfig.h"
10
11#include <AL/al.h>
12#include <fcntl.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/stat.h>
17#include <sys/time.h>
18#include <sys/types.h>
19#include <unistd.h>
20
21#include "al_main.h"
22#include "al_debug.h"
23#include "backends/alc_backend.h"
24#include "audioconvert/ac_endian.h"
25
26#define WAVEOUT_NAMELEN 16
27#define HEADERSIZE      28
28#define DATAADJUSTMENT  44
29
30
31#ifdef WORDS_BIGENDIAN
32#define RIFFMAGIC       0x52494646
33#define WAVEMAGIC       0x57415645
34#define FMTMAGIC        0x666D7420
35#define DATAMAGIC       0x64617461
36#else
37#define RIFFMAGIC       0x46464952
38#define WAVEMAGIC       0x45564157
39#define FMTMAGIC        0x20746D66
40#define DATAMAGIC       0x61746164
41#endif /* WORDS_BIGENDIAN */
42
43/* better wart needed? JIV FIXME */
44#ifdef MAXNAMELEN
45#undef MAXNAMELEN
46#endif /* MAXNAMELEN */
47
48#define MAXNAMELEN      1024
49
50typedef struct waveout_s {
51        FILE *fh;
52
53        ALuint format;
54        ALuint speed;
55        ALuint channels;
56
57        ALuint length;
58
59        ALushort bitspersample;
60
61        char name[WAVEOUT_NAMELEN];
62} waveout_t;
63
64static ALuint sleep_usec(ALuint speed, ALuint chunk);
65static void apply_header(waveout_t *wave);
66static const char *waveout_unique_name(char *template);
67
68/*
69 * convert_to_little_endian( ALuint bps, void *data, int nbytes )
70 *
71 * Convert data in place to little endian format.  NOP on little endian
72 * machines.
73 */
74static void convert_to_little_endian( ALuint bps, void *data, int nbytes );
75
76static void *grab_write_waveout(void) {
77        FILE *fh;
78        waveout_t *retval = NULL;
79        char template[MAXNAMELEN] = "openal-";
80
81        if(waveout_unique_name(template) == NULL) {
82                perror("tmpnam");
83        }
84
85        fh = fopen(template, "w+b");
86        if(fh == NULL) {
87                fprintf(stderr,
88                        "waveout grab audio %s failed\n", template);
89                return NULL;
90        }
91
92        retval = malloc(sizeof *retval);
93        if(retval == NULL) {
94                fclose(fh);
95                return NULL;
96        }
97
98        memset(retval, 0, sizeof *retval);
99
100        /* set to return params */
101        retval->fh = fh;
102        strncpy(retval->name, template, WAVEOUT_NAMELEN);
103
104        retval->length = 0;
105
106        fprintf(stderr, "waveout grab audio %s\n", template);
107
108        _alDebug(ALD_CONTEXT, __FILE__, __LINE__,
109                "waveout grab audio ok");
110
111        fseek(retval->fh, SEEK_SET, HEADERSIZE); /* leave room for header */
112        return retval;
113}
114
115static void *grab_read_waveout(void) {
116        return NULL;
117}
118
119void *
120alcBackendOpenWAVE_( ALC_OpenMode mode )
121{
122        return mode == ALC_OPEN_INPUT_ ? grab_read_waveout() : grab_write_waveout();
123}
124
125void waveout_blitbuffer(void *handle, void *dataptr, int bytes_to_write) {
126        waveout_t *whandle = NULL;
127
128        if(handle == NULL) {
129                return;
130        }
131
132        whandle = handle;
133
134        if(whandle->fh == NULL) {
135                return;
136        }
137
138        whandle->length += bytes_to_write;
139
140        /*
141         * WAV files expect their PCM data in LE format.  If we are on
142         * big endian host, we need to convert the data in place.
143         *
144         */
145        convert_to_little_endian( whandle->bitspersample,
146                                  dataptr,
147                                  bytes_to_write );
148
149        fwrite(dataptr, 1, bytes_to_write, whandle->fh);
150
151        _alMicroSleep(sleep_usec(whandle->speed, bytes_to_write));
152
153        return;
154}
155
156/*
157 *  close file, free data
158 */
159void release_waveout(void *handle) {
160        waveout_t *closer;
161
162        if(handle == NULL) {
163                return;
164        }
165
166        closer = handle;
167
168        fprintf(stderr, "releasing waveout file %s\n",
169                closer->name);
170
171        fflush( closer->fh );
172        apply_header( closer );
173
174        fclose( closer->fh );
175        free( closer );
176
177        return;
178}
179
180static ALuint sleep_usec(ALuint speed, ALuint chunk) {
181        ALuint retval;
182
183        retval = 1000000.0 * chunk / speed;
184
185#if 0
186        fprintf(stderr,
187                "(speed %d chunk %d retval = %d)\n",
188                speed,
189                chunk,
190                retval);
191#endif
192
193        return retval;
194}
195
196/*
197 *  FIXME: make endian correct
198 */
199static void apply_header(waveout_t *wave) {
200        ALushort writer16;
201        ALuint   writer32;
202
203        /* go to beginning */
204        if(fseek(wave->fh, SEEK_SET, 0) != 0) {
205                fprintf(stderr,
206                        "Couldn't reset %s\n", wave->name);
207        }
208
209        /* 'RIFF' */
210        writer32 = RIFFMAGIC;
211        fwrite(&writer32, 1, sizeof writer32, wave->fh);
212
213        /* total length */
214        writer32 = swap32le(wave->length);
215        fwrite(&writer32, 1, sizeof writer32, wave->fh);
216
217        /* 'WAVE' */
218        writer32 = WAVEMAGIC;
219        fwrite(&writer32, 1, sizeof writer32, wave->fh);
220
221        /* 'fmt ' */
222        writer32 = FMTMAGIC;
223        fwrite(&writer32, 1, sizeof writer32, wave->fh);
224
225        /* fmt chunk length */
226        writer32 = swap32le(16);
227        fwrite(&writer32, 1, sizeof writer32, wave->fh);
228
229        /* ALushort encoding */
230        writer16 = swap16le(1);
231        fwrite(&writer16, 1, sizeof writer16, wave->fh);
232
233        /* Alushort channels */
234        writer16 = swap16le(wave->channels);
235        fwrite(&writer16, 1, sizeof writer16, wave->fh);
236
237        /* ALuint frequency */
238        writer32 = swap32le(wave->speed);
239        fwrite(&writer32, 1, sizeof writer32, wave->fh);
240
241        /* ALuint byterate  */
242        writer32 = swap32le(wave->speed / sizeof (ALshort)); /* FIXME */
243        fwrite(&writer32, 1, sizeof writer32, wave->fh);
244
245        /* ALushort blockalign */
246        writer16 = 0;
247        fwrite(&writer16, 1, sizeof writer16, wave->fh);
248
249        /* ALushort bitspersample */
250        writer16 = swap16le(wave->bitspersample);
251        fwrite(&writer16, 1, sizeof writer16, wave->fh);
252
253        /* 'data' */
254        writer32 = DATAMAGIC;
255        fwrite(&writer32, 1, sizeof writer32, wave->fh);
256
257        /* data length */
258        writer32 = swap32le(wave->length - DATAADJUSTMENT); /* samples */
259        fwrite(&writer32, 1, sizeof writer32, wave->fh);
260
261        fprintf(stderr, "waveout length %d\n", wave->length);
262
263        return;
264}
265
266static const char *waveout_unique_name(char *template) {
267        static char retval[MAXNAMELEN];
268        int template_offset;
269        static int sequence = 0;
270        struct stat buf;
271
272        strncpy(retval, template, MAXNAMELEN - 2);
273        retval[MAXNAMELEN - 1] = '\0';
274
275        template_offset = strlen(retval);
276
277        if(template_offset >= MAXNAMELEN - 28) { /* kludgey */
278                /* template too big */
279                return NULL;
280        }
281
282        do {
283                /* repeat until we have a unique name */
284                snprintf(&retval[template_offset], sizeof(retval) - template_offset, "%d.wav", sequence++);
285                strncpy(template, retval, MAXNAMELEN);
286        } while(stat(retval, &buf) == 0);
287
288        return retval;
289}
290
291static ALboolean set_write_waveout(void *handle,
292                                   UNUSED(ALuint *bufsiz),
293                                   ALenum *fmt,
294                                   ALuint *speed) {
295        waveout_t *whandle;
296        ALuint chans = _alGetChannelsFromFormat( *fmt );
297
298        if(handle == NULL) {
299                return AL_FALSE;
300        }
301
302        whandle = handle;
303
304        whandle->speed    = *speed;
305        whandle->format   = *fmt;
306        whandle->channels = chans;
307        whandle->bitspersample = _alGetBitsFromFormat(*fmt);
308
309        return AL_TRUE;
310}
311
312static ALboolean set_read_waveout(UNUSED(void *handle),
313                                  UNUSED(ALuint *bufsiz),
314                                  UNUSED(ALenum *fmt),
315                                  UNUSED(ALuint *speed)) {
316
317        return AL_FALSE;
318}
319
320ALboolean
321alcBackendSetAttributesWAVE_(ALC_OpenMode mode, void *handle, ALuint *bufsiz, ALenum *fmt, ALuint *speed)
322{
323        return mode == ALC_OPEN_INPUT_ ?
324                set_read_waveout(handle, bufsiz, fmt, speed) :
325                set_write_waveout(handle, bufsiz, fmt, speed);
326}
327
328/*
329 * convert_to_little_endian( ALuint bps, void *data, int nbytes )
330 *
331 * Convert data in place to little endian format.  bps is the bits per
332 * sample in data, nbytes is the length of data in bytes.  If bps is 8,
333 * or the machine is little endian, this is a nop.
334 *
335 * FIXME:
336 *      We only handle 16-bit signed formats for now.  Should fix this.
337 */
338static void convert_to_little_endian( ALuint bps, void *data, int nbytes )
339{
340        assert( data );
341        assert( nbytes > 0 );
342
343        if( bps == 8 ) {
344                /* 8-bit samples don't need to be converted */
345                return;
346        }
347
348        assert( bps == 16 );
349
350#ifdef WORDS_BIGENDIAN
351        /* do the conversion */
352        {
353                ALshort *outp = data;
354                ALuint i;
355                for( i = 0; i < nbytes/sizeof(ALshort); i++ ) {
356                        outp[i] = swap16le( outp[i] );
357                }
358        }
359#else
360        (void)data; (void)nbytes;
361#endif /* WORDS_BIG_ENDIAN */
362}
363
364void
365pause_waveout( UNUSED(void *handle) )
366{
367}
368
369void
370resume_waveout( UNUSED(void *handle) )
371{
372}
373
374ALsizei
375capture_waveout( UNUSED(void *handle), UNUSED(void *capture_buffer), UNUSED(int bufsiz) )
376{
377        return 0;
378}
379
380ALfloat
381get_waveoutchannel( UNUSED(void *handle), UNUSED(ALuint channel) )
382{
383        return 0.0;
384}
385
386int
387set_waveoutchannel( UNUSED(void *handle), UNUSED(ALuint channel), UNUSED(ALfloat volume) )
388{
389        return 0;
390}
Note: See TracBrowser for help on using the repository browser.