~ubuntu-branches/ubuntu/raring/qgo/raring

« back to all changes in this revision

Viewing changes to src/wavfile.c

  • Committer: Package Import Robot
  • Author(s): Yann Dirson
  • Date: 2012-05-19 19:05:05 UTC
  • mfrom: (5.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20120519190505-lf69o1jee5aaizd9
Tags: 2~svn764-1
* The "Raise dead" release (Closes: #673520), new maintainer.
* New upstream snapshot with Qt4 support (Closes: #604589), adjusted
  build-deps.
* Switched to source format "3.0 (quilt)", adjusted build-deps.
* Switched to dh and debhelper compat level 9, adjusted build-deps.
* Build with -fpermissive.
* New build-dep libasound2-dev, remove obsolete build-dep on libxinerama-dev.
* Refreshed patches 01_gnugo and 04_desktop, leaving 20_kfreebsd away
  for this release, and removing the remaining ones, now obsolete.
* Added patch 02_usrgames for FHS-correct install location.
* Adjusted icon names in menu file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Header: /cvsroot/qgo/qgo/src/wavfile.c,v 1.8 2005/09/08 18:46:31 yfh2 Exp $
2
 
 * Copyright: wavfile.c (c) Erik de Castro Lopo  erikd@zip.com.au
3
 
 *
4
 
 * wavfile.c - Functions for reading and writing MS-Windoze .WAV files.
5
 
 *
6
 
 *      This program is free software; you can redistribute it and/or modify
7
 
 *      it under the terms of the GNU General Public License as published by
8
 
 *      the Free Software Foundation; either version 2, or (at your option)
9
 
 *      any later version.
10
 
 *      
11
 
 *      This program is distributed in the hope that it will be useful,
12
 
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *      GNU General Public License for more details.
15
 
 *      
16
 
 *      This code was originally written to manipulate Windoze .WAV files
17
 
 *      under i386 Linux. Please send any bug reports or requests for 
18
 
 *      enhancements to : erikd@zip.com.au
19
 
 *      
20
 
 *
21
 
 * Revision 1.4  2004/05/26 17:44:05  yfh2
22
 
 * 0.2.1 b1 preparing BSD compatibiility
23
 
 *
24
 
 * Revision 1.3  2003/04/14 07:41:49  frosla
25
 
 * 0.0.16b8: skipped some widget; cosmetics
26
 
 *
27
 
 * Revision 1.1.1.1  1999/11/21 19:50:56  wwg
28
 
 * Import wavplay-1.3 into CVS
29
 
 *
30
 
 * Revision 1.2  1997/04/17 00:59:55  wwg
31
 
 * Fixed so that a fmt chunk that is larger than expected
32
 
 * is accepted, but if smaller - _then_ treat it as an
33
 
 * error.
34
 
 *
35
 
 * Revision 1.1  1997/04/14 00:14:38  wwg
36
 
 * Initial revision
37
 
 *
38
 
 *      change log:
39
 
 *      16.02.97 -      Erik de Castro Lopo             
40
 
 *      Ported from MS-Windows to Linux for Warren W. Gay's
41
 
 *      wavplay project.
42
 
 */     
43
 
 
44
 
#ifdef __linux__
45
 
 
46
 
static const char rcsid[] = "@(#)wavfile.c $Revision: 1.8 $";
47
 
 
48
 
 
49
 
#include <stdio.h>
50
 
#include <stdlib.h>
51
 
#include <stdarg.h>
52
 
#include <unistd.h>
53
 
#include <errno.h>
54
 
#include <fcntl.h>
55
 
#include <malloc.h>
56
 
#include <string.h>
57
 
#include <memory.h>
58
 
#include <signal.h>
59
 
#include <sys/types.h>
60
 
#include <sys/ipc.h>
61
 
#include <sys/ioctl.h>
62
 
#include <assert.h>
63
 
#include <linux/soundcard.h>
64
 
 
65
 
 
66
 
 
67
 
 
68
 
#if WORDS_BIGENDIAN
69
 
#define SwapLE16(x) ((((u_int16_t)x)<<8)|(((u_int16_t)x)>>8))
70
 
#define SwapLE32(x) ((((u_int32_t)x)<<24)|((((u_int32_t)x)<<8)&0x00FF0000) \
71
 
                     |((((u_int32_t)x)>>8)&0x0000FF00)|(((u_int32_t)x)>>24))
72
 
#else
73
 
#define SwapLE16(x) (x)
74
 
#define SwapLE32(x) (x)
75
 
#endif
76
 
 
77
 
 
78
 
#include "wavplay.h"
79
 
 
80
 
#define         BUFFERSIZE              1024
81
 
#define         PCM_WAVE_FORMAT         1
82
 
 
83
 
#define         TRUE                    1
84
 
#define         FALSE                   0
85
 
 
86
 
#define RECPLAY_UPDATES_PER_SEC                3
87
 
 
88
 
 
89
 
typedef  struct
90
 
{       u_int32_t  dwSize ;
91
 
        u_int16_t  wFormatTag ;
92
 
        u_int16_t  wChannels ;
93
 
        u_int32_t  dwSamplesPerSec ;
94
 
        u_int32_t  dwAvgBytesPerSec ;
95
 
        u_int16_t  wBlockAlign ;
96
 
        u_int16_t  wBitsPerSample ;
97
 
} WAVEFORMAT ;
98
 
 
99
 
typedef  struct
100
 
{       char            RiffID [4] ;
101
 
        u_int32_t       RiffSize ;
102
 
        char            WaveID [4] ;
103
 
        char            FmtID  [4] ;
104
 
        u_int32_t       FmtSize ;
105
 
        u_int16_t       wFormatTag ;
106
 
        u_int16_t       nChannels ;
107
 
        u_int32_t       nSamplesPerSec ;
108
 
        u_int32_t       nAvgBytesPerSec ;
109
 
        u_int16_t       nBlockAlign ;
110
 
        u_int16_t       wBitsPerSample ;
111
 
        char            DataID [4] ;
112
 
        u_int32_t       nDataBytes ;
113
 
} WAVE_HEADER ;
114
 
 
115
 
/*=================================================================================================*/
116
 
 
117
 
char*  findchunk (char* s1, char* s2, size_t n) ;
118
 
 
119
 
/*=================================================================================================*/
120
 
 
121
 
 
122
 
static  WAVE_HEADER  waveheader =
123
 
{       { 'R', 'I', 'F', 'F' },
124
 
                0,
125
 
        { 'W', 'A', 'V', 'E' },
126
 
        { 'f', 'm', 't', ' ' },
127
 
                16,                                                             /* FmtSize*/
128
 
                PCM_WAVE_FORMAT,                                                /* wFormatTag*/
129
 
                0,                                                              /* nChannels*/
130
 
                0,
131
 
                0,
132
 
                0,
133
 
                0,
134
 
        { 'd', 'a', 't', 'a' },
135
 
                0
136
 
} ; /* waveheader*/
137
 
 
138
 
static ErrFunc v_erf;                           /* wwg: Error reporting function */
139
 
 
140
 
static void _v_erf(const char *, va_list);      /* This module's error reporting function */
141
 
static char emsg[2048];
142
 
 
143
 
 
144
 
 
145
 
/*
146
 
 * Error reporting function for this source module:
147
 
 */
148
 
static void
149
 
err(const char *format,...) {
150
 
        va_list ap;
151
 
   fprintf(stdout, "error : %s \n",format);
152
 
        /*/if ( v_erf == NULL )*/
153
 
        /*/     return;                         /* Only report error if we have function */
154
 
        va_start(ap,format);
155
 
        _v_erf(format,ap);                      /* Use caller's supplied function */
156
 
        va_end(ap);
157
 
}
158
 
 
159
 
 
160
 
static void
161
 
_v_erf(const char *format,va_list ap) {
162
 
        vsprintf(emsg,format,ap);               /* Capture message into emsg[] */
163
 
}
164
 
 
165
 
 
166
 
 
167
 
int  WaveReadHeader  (int wavefile, int* channels, u_long* samplerate, int* samplebits, u_long* samples, u_long* datastart,ErrFunc erf)
168
 
{       static  WAVEFORMAT  waveformat ;
169
 
        static  char   buffer [ BUFFERSIZE ] ;          /* Function is not reentrant.*/
170
 
        char*   ptr ;
171
 
        u_long  databytes ;
172
 
 
173
 
        v_erf = erf;                                    /* wwg: Set error reporting function */
174
 
 
175
 
        if (lseek (wavefile, 0L, SEEK_SET)) {
176
 
                err("%s",sys_errlist[errno]);           /* wwg: Report error */
177
 
                return  WR_BADSEEK ;
178
 
        }
179
 
 
180
 
        read (wavefile, buffer, BUFFERSIZE) ;
181
 
 
182
 
        if (findchunk (buffer, "RIFF", BUFFERSIZE) != buffer) {
183
 
                err("Bad format: Cannot find RIFF file marker");        /* wwg: Report error */
184
 
                return  WR_BADRIFF ;
185
 
        }
186
 
 
187
 
        if (! findchunk (buffer, "WAVE", BUFFERSIZE)) {
188
 
                err("Bad format: Cannot find WAVE file marker");        /* wwg: report error */
189
 
                return  WR_BADWAVE ;
190
 
        }
191
 
 
192
 
        ptr = findchunk (buffer, "fmt ", BUFFERSIZE) ;
193
 
 
194
 
        if (! ptr) {
195
 
                err("Bad format: Cannot find 'fmt' file marker");       /* wwg: report error */
196
 
                return  WR_BADFORMAT ;
197
 
        }
198
 
 
199
 
        ptr += 4 ;      /* Move past "fmt ".*/
200
 
        memcpy (&waveformat, ptr, sizeof (WAVEFORMAT)) ;
201
 
        waveformat.dwSize = SwapLE32(waveformat.dwSize);
202
 
        waveformat.wFormatTag = SwapLE16(waveformat.wFormatTag) ;
203
 
        waveformat.wChannels = SwapLE16(waveformat.wChannels) ;
204
 
        waveformat.dwSamplesPerSec = SwapLE32(waveformat.dwSamplesPerSec) ;
205
 
        waveformat.dwAvgBytesPerSec = SwapLE32(waveformat.dwAvgBytesPerSec) ;
206
 
        waveformat.wBlockAlign = SwapLE16(waveformat.wBlockAlign) ;
207
 
        waveformat.wBitsPerSample = SwapLE16(waveformat.wBitsPerSample) ;
208
 
        
209
 
        if (waveformat.dwSize < (sizeof (WAVEFORMAT) - sizeof (u_long))) {
210
 
                err("Bad format: Bad fmt size");                        /* wwg: report error */
211
 
                return  WR_BADFORMATSIZE ;
212
 
        }
213
 
 
214
 
        if (waveformat.wFormatTag != PCM_WAVE_FORMAT) {
215
 
                err("Only supports PCM wave format");                   /* wwg: report error */
216
 
                return  WR_NOTPCMFORMAT ;
217
 
        }
218
 
 
219
 
        ptr = findchunk (buffer, "data", BUFFERSIZE) ;
220
 
 
221
 
        if (! ptr) {
222
 
                err("Bad format: unable to find 'data' file marker");   /* wwg: report error */
223
 
                return  WR_NODATACHUNK ;
224
 
        }
225
 
 
226
 
        ptr += 4 ;      /* Move past "data".*/
227
 
        memcpy (&databytes, ptr, sizeof (u_long)) ;
228
 
 
229
 
        /* Everything is now cool, so fill in output data.*/
230
 
 
231
 
        *channels   = waveformat.wChannels ;
232
 
        *samplerate = waveformat.dwSamplesPerSec ;
233
 
        *samplebits = waveformat.wBitsPerSample ;
234
 
        *samples    = databytes / waveformat.wBlockAlign ;
235
 
        
236
 
        *datastart  = ((u_long) (ptr + 4)) - ((u_long) (&(buffer[0]))) ;
237
 
 
238
 
        if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wBlockAlign) {
239
 
                err("Bad file format");                 /* wwg: report error */
240
 
                return  WR_BADFORMATDATA ;
241
 
        }
242
 
 
243
 
        if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wChannels / ((waveformat.wBitsPerSample == 16) ? 2 : 1)) {
244
 
                err("Bad file format");                 /* wwg: report error */
245
 
                return  WR_BADFORMATDATA ;
246
 
        }
247
 
 
248
 
  return  0 ;
249
 
} ; /* WaveReadHeader*/
250
 
 
251
 
/*===========================================================================================*/
252
 
 
253
 
#if 0
254
 
char*  WaveFileError (int  errno)
255
 
{       switch (errno)
256
 
        {       case    WW_BADOUTPUTFILE        : return "Bad output file.\n" ;
257
 
                case    WW_BADWRITEHEADER       : return "Not able to write WAV header.\n" ;
258
 
                
259
 
                case    WR_BADALLOC                     : return "Not able to allocate memory.\n" ;
260
 
                case    WR_BADSEEK              : return "fseek failed.\n" ;
261
 
                case    WR_BADRIFF              : return "Not able to find 'RIFF' file marker.\n" ;
262
 
                case    WR_BADWAVE              : return "Not able to find 'WAVE' file marker.\n" ;
263
 
                case    WR_BADFORMAT            : return "Not able to find 'fmt ' file marker.\n" ;
264
 
                case    WR_BADFORMATSIZE        : return "Format size incorrect.\n" ;
265
 
                case    WR_NOTPCMFORMAT         : return "Not PCM format WAV file.\n" ;
266
 
                case    WR_NODATACHUNK          : return "Not able to find 'data' file marker.\n" ;
267
 
                case    WR_BADFORMATDATA        : return "Format data questionable.\n" ;
268
 
                default                                 :  return "No error\n" ;
269
 
        } ;
270
 
        return  NULL ;  
271
 
} ; /* WaveFileError*/
272
 
#endif
273
 
/*===========================================================================================*/
274
 
 
275
 
char* findchunk  (char* pstart, char* fourcc, size_t n)
276
 
{       char    *pend ;
277
 
        int             k, test ;
278
 
 
279
 
        pend = pstart + n ;
280
 
 
281
 
        while (pstart < pend)
282
 
        {       if (*pstart == *fourcc)       /* found match for first char*/
283
 
                {       test = TRUE ;
284
 
                        for (k = 1 ; fourcc [k] != 0 ; k++)
285
 
                                test = (test ? ( pstart [k] == fourcc [k] ) : FALSE) ;
286
 
                        if (test)
287
 
                                return  pstart ;
288
 
                        } ; /* if*/
289
 
                pstart ++ ;
290
 
                } ; /* while lpstart*/
291
 
 
292
 
        return  NULL ;
293
 
} ; /* findchuck*/
294
 
 
295
 
/* $Source: /cvsroot/qgo/qgo/src/wavfile.c,v $ */
296
 
/*
297
 
 * Internal routine to allocate WAVFILE structure:
298
 
 */
299
 
static WAVFILE *
300
 
wavfile_alloc(const char *Pathname) {
301
 
        WAVFILE *wfile = (WAVFILE *) malloc(sizeof (WAVFILE));
302
 
 
303
 
        if ( wfile == NULL ) {
304
 
                err("%s: Allocating WAVFILE structure",sys_errlist[ENOMEM]);
305
 
                return NULL;
306
 
        }
307
 
 
308
 
        memset(wfile,0,sizeof *wfile);
309
 
 
310
 
        if ( (wfile->Pathname = strdup(Pathname)) == NULL ) {
311
 
                free(wfile);
312
 
                err("%s: Allocating storage for WAVFILE.Pathname",sys_errlist[ENOMEM]);
313
 
                return NULL;
314
 
        }
315
 
 
316
 
        wfile->fd = -1;                         /* Initialize fd as not open */
317
 
        wfile->wavinfo.Channels = Mono;
318
 
        wfile->wavinfo.DataBits = 8;
319
 
 
320
 
        return wfile;
321
 
}
322
 
 
323
 
/*
324
 
 * Internal routine to release WAVFILE structure:
325
 
 * No errors reported.
326
 
 */
327
 
static void
328
 
wavfile_free(WAVFILE *wfile) {
329
 
        if ( wfile->Pathname != NULL )
330
 
                free(wfile->Pathname);
331
 
        free(wfile);
332
 
}
333
 
 
334
 
/*
335
 
 * Open a WAV file for reading: returns (WAVFILE *)
336
 
 *
337
 
 * The opened file is positioned at the first byte of WAV file data, or
338
 
 * NULL is returned if the open is unsuccessful.
339
 
 */
340
 
WAVFILE *
341
 
WavOpenForRead(const char *Pathname,ErrFunc erf) {
342
 
        WAVFILE *wfile = wavfile_alloc(Pathname);
343
 
        int e;                                  /* Saved errno value */
344
 
        UInt32 offset;                          /* File offset */
345
 
        Byte ubuf[4];                           /* 4 byte buffer */
346
 
        UInt32 dbytes;                          /* Data byte count */
347
 
                                                /* wavfile.c values : */
348
 
        int channels;                           /* Channels recorded in this wav file */
349
 
        u_long samplerate;                      /* Sampling rate */
350
 
        int sample_bits;                        /* data bit size (8/12/16) */
351
 
        u_long samples;                         /* The number of samples in this file */
352
 
        u_long datastart;                       /* The offset to the wav data */
353
 
 
354
 
        v_erf = erf;                            /* Set error reporting function */
355
 
 
356
 
        if ( wfile == NULL )
357
 
                return NULL;                    /* Insufficient memory (class B msg) */
358
 
 
359
 
        /*
360
 
         * Open the file for reading:
361
 
         */
362
 
        if ( (wfile->fd = open(wfile->Pathname,O_RDONLY)) < 0 ) {
363
 
                err("%s:\nOpening WAV file %s",
364
 
                        sys_errlist[errno],
365
 
                        wfile->Pathname);
366
 
                goto errxit;
367
 
        }
368
 
 
369
 
        if ( lseek(wfile->fd,0L,SEEK_SET) != 0L ) {
370
 
                err("%s:\nRewinding WAV file %s",
371
 
                        sys_errlist[errno],
372
 
                        wfile->Pathname);
373
 
                goto errxit;            /* Wav file must be seekable device */
374
 
        }
375
 
 
376
 
        if ( (e = WaveReadHeader(wfile->fd,&channels,&samplerate,&sample_bits,&samples,&datastart,_v_erf)) != 0 ) {
377
 
                err("%s:\nReading WAV header from %s",
378
 
                        emsg,
379
 
                        wfile->Pathname);
380
 
                goto errxit;
381
 
        }
382
 
 
383
 
        /*
384
 
         * Copy WAV data over to WAVFILE struct:
385
 
         */
386
 
        if ( channels == 2 )
387
 
                wfile->wavinfo.Channels = Stereo;
388
 
        else    wfile->wavinfo.Channels = Mono;
389
 
 
390
 
        wfile->wavinfo.SamplingRate = (UInt32) samplerate;
391
 
        wfile->wavinfo.Samples = (UInt32) samples;
392
 
        wfile->wavinfo.DataBits = (UInt16) sample_bits;
393
 
        wfile->wavinfo.DataStart = (UInt32) datastart;
394
 
        wfile->num_samples = wfile->wavinfo.Samples;
395
 
        wfile->rw = 'R';                        /* Read mode */
396
 
 
397
 
        offset = wfile->wavinfo.DataStart - 4;
398
 
 
399
 
        /*
400
 
         * Seek to byte count and read dbytes:
401
 
         */
402
 
        if ( lseek(wfile->fd,offset,SEEK_SET) != offset ) {
403
 
                err("%s:\nSeeking to WAV data in %s",sys_errlist[errno],wfile->Pathname);
404
 
                goto errxit;                    /* Seek failure */
405
 
        }
406
 
 
407
 
        if ( read(wfile->fd,ubuf,4) != 4 ) {
408
 
                err("%s:\nReading dbytes from %s",sys_errlist[errno],wfile->Pathname);
409
 
                goto errxit;
410
 
        }
411
 
 
412
 
        /*
413
 
         * Put little endian value into 32 bit value:
414
 
         */
415
 
        dbytes = ubuf[3];
416
 
        dbytes = (dbytes << 8) | ubuf[2];
417
 
        dbytes = (dbytes << 8) | ubuf[1];
418
 
        dbytes = (dbytes << 8) | ubuf[0];
419
 
 
420
 
        wfile->wavinfo.DataBytes = dbytes;
421
 
 
422
 
        /*
423
 
         * Open succeeded:
424
 
         */
425
 
        return wfile;                           /* Return open descriptor */
426
 
 
427
 
        /*
428
 
         * Return error after failed open:
429
 
         */
430
 
errxit: e = errno;                              /* Save errno */
431
 
        free(wfile->Pathname);                  /* Dispose of copied pathname */
432
 
        free(wfile);                            /* Dispose of WAVFILE struct */
433
 
        errno = e;                              /* Restore error number */
434
 
        return NULL;                            /* Return error indication */
435
 
}
436
 
 
437
 
/*
438
 
 * Apply command line option overrides to the interpretation of the input
439
 
 * wav file:
440
 
 *
441
 
 */
442
 
void
443
 
WavReadOverrides(WAVFILE *wfile,WavPlayOpts *wavopts) {
444
 
        UInt32 num_samples;
445
 
 
446
 
        /*
447
 
         * Override sampling rate: -s sampling_rate
448
 
         */
449
 
        if ( wavopts->SamplingRate.optChar != 0 ) {
450
 
                wfile->wavinfo.SamplingRate = wavopts->SamplingRate.optValue;
451
 
                wfile->wavinfo.bOvrSampling = 1;
452
 
        }
453
 
 
454
 
        /*
455
 
         * Override mono/stereo mode: -S / -M
456
 
         */
457
 
        if ( wavopts->Channels.optChar != 0 ) {
458
 
                wfile->wavinfo.Channels = wavopts->Channels.optValue;
459
 
                wfile->wavinfo.bOvrMode = 1;
460
 
        }
461
 
 
462
 
        /*
463
 
         * Override the sample size in bits: -b bits
464
 
         */
465
 
        if ( wavopts->DataBits.optChar != 0 ) {
466
 
                wfile->wavinfo.DataBits = wavopts->DataBits.optValue;
467
 
                wfile->wavinfo.bOvrBits = 1;
468
 
        }
469
 
 
470
 
        /*
471
 
         * Set the first sample:
472
 
         */
473
 
        wfile->StartSample = 0;
474
 
        num_samples = wfile->wavinfo.Samples = wfile->num_samples;
475
 
        if ( wavopts->StartSample != 0 ) {
476
 
                wfile->StartSample = wavopts->StartSample;
477
 
                wfile->wavinfo.Samples -= wfile->StartSample;
478
 
        }
479
 
 
480
 
        /*
481
 
         * Override # of samples if -t seconds option given:
482
 
         */
483
 
        if ( wavopts->Seconds != 0 ) {
484
 
                wfile->wavinfo.Samples = wavopts->Seconds * wfile->wavinfo.SamplingRate;
485
 
                if (wfile->StartSample+wfile->wavinfo.Samples > num_samples)
486
 
                        wfile->wavinfo.Samples = num_samples-1;
487
 
        }
488
 
}
489
 
 
490
 
/*
491
 
 * Close a WAVFILE
492
 
 */
493
 
int
494
 
WavClose(WAVFILE *wfile,ErrFunc erf) {
495
 
        int e = 0;                              /* Returned error code */
496
 
        int channels;                           /* Channels recorded in this wav file */
497
 
        u_long samplerate;                      /* Sampling rate */
498
 
        int sample_bits;                        /* data bit size (8/12/16) */
499
 
        u_long samples;                         /* The number of samples in this file */
500
 
        u_long datastart;                       /* The offset to the wav data */
501
 
        long fpos;                              /* File position in bytes */
502
 
 
503
 
        v_erf = erf;                            /* Set error reporting function */
504
 
 
505
 
        if ( wfile == NULL ) {
506
 
                err("%s: WAVFILE pointer is NULL!",sys_errlist[EINVAL]);
507
 
                errno = EINVAL;
508
 
                return -1;
509
 
        }
510
 
 
511
 
        /*
512
 
         * If the wav file was open for write, update the actual number
513
 
         * of samples written to the file:
514
 
         */
515
 
        if ( wfile->rw == 'W' ) {
516
 
                fpos = lseek(wfile->fd,0L,SEEK_CUR);    /* Get out file position */
517
 
                if ( (e = WaveReadHeader(wfile->fd,&channels,&samplerate,&sample_bits,&samples,&datastart,_v_erf)) != 0 )
518
 
                        err("%s:\nReading WAV header from %s",emsg,wfile->Pathname);
519
 
                else if ( lseek(wfile->fd,(long)(datastart-4),SEEK_SET) != (long)(datastart-4) )
520
 
                        err("%s:\nSeeking in WAV header file %s",sys_errlist[errno],wfile->Pathname);
521
 
                else if ( write(wfile->fd,&wfile->wavinfo.Samples,sizeof wfile->wavinfo.Samples) != sizeof wfile->wavinfo.Samples )
522
 
                        err("%s:\nWriting in WAV header file %s",sys_errlist[errno],wfile->Pathname);
523
 
                else    {
524
 
                        /*
525
 
                         * 'data' chunk was updated OK: Now we have to update the RIFF block
526
 
                         * count. Someday very soon, a real RIFF module is going to replace
527
 
                         * this fudging.
528
 
                         */
529
 
                        if ( ftruncate(wfile->fd,(size_t)fpos) )
530
 
                                err("%s:\nTruncating file %s to correct size",
531
 
                                        sys_errlist[errno],
532
 
                                        wfile->Pathname);
533
 
                        else if ( lseek(wfile->fd,4L,SEEK_SET) < 0L )
534
 
                                err("%s:\nSeek 4 for RIFF block update of %s",
535
 
                                        sys_errlist[errno],
536
 
                                        wfile->Pathname);
537
 
                        else    {
538
 
                                fpos -= 8;              /* Byte count for RIFF block */
539
 
                                if ( write(wfile->fd,&fpos,sizeof fpos) != sizeof fpos )
540
 
                                        err("%s:\nUpdate of RIFF block count in %s failed",
541
 
                                                sys_errlist[errno],
542
 
                                                wfile->Pathname);
543
 
                        }
544
 
                }
545
 
        }
546
 
 
547
 
        if ( close(wfile->fd) < 0 ) {
548
 
                err("%s:\nClosing WAV file",sys_errlist[errno]);
549
 
                e = errno;                      /* Save errno value to return */
550
 
        }
551
 
 
552
 
        wavfile_free(wfile);                    /* Release WAVFILE structure */
553
 
 
554
 
        if ( (errno = e) != 0 )
555
 
                return -1;                      /* Failed exit */
556
 
        return 0;                               /* Successful exit */
557
 
}
558
 
 
559
 
/*
560
 
 
561
 
/*
562
 
 * Open /dev/dsp for reading or writing:
563
 
 */
564
 
DSPFILE *
565
 
OpenDSP(WAVFILE *wfile,int omode,ErrFunc erf) {
566
 
        int e;                                  /* Saved errno value */
567
 
        int t;                                  /* Work int */
568
 
        unsigned long ul;                       /* Work unsigned long */
569
 
        DSPFILE *dfile = (DSPFILE *) malloc(sizeof (DSPFILE));
570
 
 
571
 
        v_erf = erf;                            /* Set error reporting function */
572
 
 
573
 
        if ( dfile == NULL ) {
574
 
                err("%s: Opening DSP device",sys_errlist[errno=ENOMEM]);
575
 
                return NULL;
576
 
        }
577
 
 
578
 
        memset(dfile,0,sizeof *dfile);
579
 
        dfile->dspbuf = NULL;
580
 
 
581
 
        /*
582
 
         * Open the device driver:
583
 
         */
584
 
        if ( (dfile->fd = open(AUDIODEV,omode,0)) < 0 ) {
585
 
                err("%s:\nOpening audio device %s",
586
 
                        sys_errlist[errno],
587
 
                        AUDIODEV);
588
 
                goto errxit;
589
 
        }
590
 
 
591
 
        /*
592
 
         * Determine the audio device's block size.  Should be done after
593
 
         * setting sampling rate etc.
594
 
         */
595
 
        if ( ioctl(dfile->fd,SNDCTL_DSP_GETBLKSIZE,&dfile->dspblksiz) < 0 ) {
596
 
                err("%s: Optaining DSP's block size",sys_errlist[errno]);
597
 
                goto errxit;
598
 
        }
599
 
 
600
 
        /*
601
 
         * Check the range on the buffer sizes:
602
 
         */
603
 
        /* Minimum was 4096 but es1370 returns 1024 for 44.1kHz, 16 bit */
604
 
        /* and 64 for 8130Hz, 8 bit */
605
 
        if ( dfile->dspblksiz < 32 || dfile->dspblksiz > 65536 ) {
606
 
                err("%s: Audio block size (%d bytes)",
607
 
                        sys_errlist[errno=EINVAL],
608
 
                        (int)dfile->dspblksiz);
609
 
                goto errxit;
610
 
        }
611
 
 
612
 
        /*
613
 
         * Allocate a buffer to do the I/O through:
614
 
         */
615
 
        if ( (dfile->dspbuf = (char *) malloc(dfile->dspblksiz)) == NULL ) {
616
 
                err("%s: For DSP I/O buffer",sys_errlist[errno]);
617
 
                goto errxit;
618
 
        }
619
 
 
620
 
        /*
621
 
         * Set the data bit size:
622
 
         */
623
 
        t = wfile->wavinfo.DataBits;
624
 
        if ( ioctl(dfile->fd,SNDCTL_DSP_SAMPLESIZE,&t) < 0 ) {
625
 
                err("%s: Setting DSP to %u bits",sys_errlist[errno],(unsigned)t);
626
 
                goto errxit;
627
 
        }
628
 
 
629
 
        /*
630
 
         * Set the mode to be Stereo or Mono:
631
 
         */
632
 
        t = wfile->wavinfo.Channels == Stereo ? 1 : 0;
633
 
        if ( ioctl(dfile->fd,SNDCTL_DSP_STEREO,&t) < 0 ) {
634
 
                err("%s: Unable to set DSP to %s mode",
635
 
                        sys_errlist[errno],
636
 
                        t?"Stereo":"Mono");
637
 
                goto errxit;
638
 
        }
639
 
 
640
 
        /*
641
 
         * Set the sampling rate:
642
 
         */
643
 
        ul = wfile->wavinfo.SamplingRate;
644
 
        if ( ioctl(dfile->fd,SNDCTL_DSP_SPEED,&ul) < 0 ) {
645
 
                err("Unable to set audio sampling rate",sys_errlist[errno]);
646
 
                goto errxit;
647
 
        }
648
 
 
649
 
        /*
650
 
         * Return successfully opened device:
651
 
         */
652
 
        return dfile;                           /* Return file descriptor */
653
 
 
654
 
        /*
655
 
         * Failed to open/initialize properly:
656
 
         */
657
 
errxit: e = errno;                              /* Save the errno value */
658
 
 
659
 
 fprintf(stdout, "error %s : \n",sys_errlist[errno]);
660
 
 
661
 
        if ( dfile->fd >= 0 )
662
 
                close(dfile->fd);               /* Close device */
663
 
        if ( dfile->dspbuf != NULL )
664
 
                free(dfile->dspbuf);
665
 
        free(dfile);
666
 
        errno = e;                              /* Restore error code */
667
 
        return NULL;                            /* Return error indication */
668
 
}
669
 
 
670
 
/*
671
 
 * Close the DSP device:
672
 
 */
673
 
int
674
 
CloseDSP(DSPFILE *dfile,ErrFunc erf) {
675
 
        int fd;
676
 
 
677
 
        v_erf = erf;                            /* Set error reporting function */
678
 
 
679
 
        if ( dfile == NULL ) {
680
 
                err("%s: DSPFILE is not open",sys_errlist[errno=EINVAL]);
681
 
                return -1;
682
 
        }
683
 
 
684
 
        fd = dfile->fd;
685
 
        if ( dfile->dspbuf != NULL )
686
 
                free(dfile->dspbuf);
687
 
        free(dfile);
688
 
 
689
 
        if ( close(fd) ) {
690
 
                err("%s: Closing DSP fd %d",sys_errlist[errno],fd);
691
 
                return -1;
692
 
        }
693
 
 
694
 
        return 0;
695
 
}
696
 
 
697
 
/*
698
 
 * Play DSP from WAV file:
699
 
 */
700
 
int
701
 
PlayDSP(DSPFILE *dfile,WAVFILE *wfile,DSPPROC work_proc,ErrFunc erf) {
702
 
        UInt32 byte_count = (UInt32) wfile->wavinfo.Samples;
703
 
        int bytes;
704
 
        int n;
705
 
        int byte_modulo;
706
 
        int total_bytes, update_bytes;
707
 
        SVRMSG msg;
708
 
 
709
 
        v_erf = erf;                            /* Set error reporting function */
710
 
 
711
 
        /*
712
 
         * Check that the WAVFILE is open for reading:
713
 
         */
714
 
        if ( wfile->rw != 'R' ) {
715
 
                err("%s: WAVFILE must be open for reading",sys_errlist[errno=EINVAL]);
716
 
                return -1;
717
 
        }
718
 
 
719
 
        /*
720
 
         * First determine how many bytes are required for each channel's sample:
721
 
         */
722
 
        switch ( wfile->wavinfo.DataBits ) {
723
 
        case 8 :
724
 
                byte_count = 1;
725
 
                break;
726
 
        case 16 :
727
 
                byte_count = 2;
728
 
                break;
729
 
        default :
730
 
                err("%s: Cannot process %u bit samples",
731
 
                        sys_errlist[errno=EINVAL],
732
 
                        (unsigned)wfile->wavinfo.DataBits);
733
 
                return -1;
734
 
        }
735
 
 
736
 
        /*
737
 
         * Allow for Mono/Stereo difference:
738
 
         */
739
 
        if ( wfile->wavinfo.Channels == Stereo )
740
 
                byte_count *= 2;                /* Twice as many bytes for stereo */
741
 
        else if ( wfile->wavinfo.Channels != Mono ) {
742
 
                err("%s: DSPFILE control block is corrupted (chan_mode)",
743
 
                        sys_errlist[errno=EINVAL]);
744
 
                return -1;
745
 
        }
746
 
 
747
 
        byte_modulo = byte_count;                               /* This many bytes per sample */
748
 
        byte_count  = wfile->wavinfo.Samples * byte_modulo;     /* Total bytes to process */
749
 
        total_bytes = byte_count;
750
 
 
751
 
        /* Number of bytes to write between client updates.  Must be */
752
 
        /* a multiple of dspblksiz.  */
753
 
        update_bytes = ((wfile->wavinfo.SamplingRate*byte_modulo) / (RECPLAY_UPDATES_PER_SEC*dfile->dspblksiz)) * dfile->dspblksiz;
754
 
 
755
 
        if ( ioctl(dfile->fd,SNDCTL_DSP_SYNC,0) != 0 )
756
 
                err("%s: ioctl(%d,SNDCTL_DSP_SYNC,0)",sys_errlist[errno]);
757
 
 
758
 
        /* Seek to requested start sample */
759
 
        lseek(wfile->fd,wfile->StartSample*byte_modulo,SEEK_CUR);
760
 
 
761
 
        for ( ; byte_count > 0 && wfile->wavinfo.DataBytes > 0; byte_count -= (UInt32) n ) {
762
 
 
763
 
                bytes = (int) ( byte_count > dfile->dspblksiz ? dfile->dspblksiz : byte_count );
764
 
 
765
 
                if ( bytes > wfile->wavinfo.DataBytes ) /* Size bigger than data chunk? */
766
 
                        bytes = wfile->wavinfo.DataBytes;       /* Data chunk only has this much left */
767
 
 
768
 
                if ( (n = read(wfile->fd,dfile->dspbuf,bytes)) != bytes ) {
769
 
                        if ( n >= 0 )
770
 
                                err("Unexpected EOF reading samples from WAV file",sys_errlist[errno=EIO]);
771
 
                        else    err("Reading samples from WAV file",sys_errlist[errno]);
772
 
                        goto errxit;
773
 
                }
774
 
                /*
775
 
                if ((clntIPC >= 0) && !((total_bytes-byte_count) % update_bytes)) {
776
 
                        msg.msg_type = ToClnt_PlayState;
777
 
                        msg.bytes = sizeof(msg.u.toclnt_playstate);
778
 
                        msg.u.toclnt_playstate.SamplesLeft = byte_count / byte_modulo;
779
 
                        msg.u.toclnt_playstate.CurrentSample =
780
 
                          wfile->num_samples - msg.u.toclnt_playstate.SamplesLeft;
781
 
                        MsgToClient(clntIPC,&msg,0);
782
 
                }    /* Tell client playback status */
783
 
 
784
 
                if ( write(dfile->fd,dfile->dspbuf,n) != n ) {
785
 
                        err("Writing samples to audio device",sys_errlist[errno]);
786
 
                        goto errxit;
787
 
                }
788
 
 
789
 
                wfile->wavinfo.DataBytes -= (UInt32) bytes;     /* We have fewer bytes left to read */
790
 
 
791
 
                /*
792
 
                 * The work procedure function is called when operating
793
 
                 * in server mode to check for more server messages:
794
 
                 */
795
 
                if ( work_proc != NULL && work_proc(dfile) )    /* Did work_proc() return TRUE? */
796
 
                        break;                                  /* Yes, quit playing */
797
 
        }
798
 
 
799
 
#if 0   /* I think this is doing a destructive flush: disabled */
800
 
        if ( ioctl(dfile->fd,SNDCTL_DSP_SYNC,0) != 0 )
801
 
                err("%s: ioctl(%d,SNDCTL_DSP_SYNC,0)",sys_errlist[errno]);
802
 
#endif
803
 
        /* Update client time display at end of sucessful play
804
 
        if (clntIPC >= 0) {
805
 
                msg.msg_type = ToClnt_PlayState;
806
 
                msg.bytes = sizeof(msg.u.toclnt_playstate);
807
 
                msg.u.toclnt_playstate.SamplesLeft = byte_count / byte_modulo;
808
 
                msg.u.toclnt_playstate.CurrentSample =
809
 
                  wfile->num_samples - msg.u.toclnt_playstate.SamplesLeft;
810
 
                MsgToClient(clntIPC,&msg,0);
811
 
        }               /* Tell client playback status */
812
 
        return 0;       /* All samples played successfully */
813
 
 
814
 
errxit: return -1;      /* Indicate error return */
815
 
}
816
 
 
817
 
 
818
 
 
819
 
 
820
 
#endif