2
** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
4
** This program is free software; you can redistribute it and/or modify
5
** it under the terms of the GNU Lesser General Public License as published by
6
** the Free Software Foundation; either version 2.1 of the License, or
7
** (at your option) any later version.
9
** This program 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
12
** GNU Lesser General Public License for more details.
14
** You should have received a copy of the GNU Lesser General Public License
15
** along with this program; if not, write to the Free Software
16
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31
/*------------------------------------------------------------------------------
32
* Macros to handle big/little endian issues.
35
#define FORM_MARKER (MAKE_MARKER ('F', 'O', 'R', 'M'))
36
#define SVX8_MARKER (MAKE_MARKER ('8', 'S', 'V', 'X'))
37
#define SV16_MARKER (MAKE_MARKER ('1', '6', 'S', 'V'))
38
#define VHDR_MARKER (MAKE_MARKER ('V', 'H', 'D', 'R'))
39
#define BODY_MARKER (MAKE_MARKER ('B', 'O', 'D', 'Y'))
41
#define ATAK_MARKER (MAKE_MARKER ('A', 'T', 'A', 'K'))
42
#define RLSE_MARKER (MAKE_MARKER ('R', 'L', 'S', 'E'))
44
#define c_MARKER (MAKE_MARKER ('(', 'c', ')', ' '))
45
#define NAME_MARKER (MAKE_MARKER ('N', 'A', 'M', 'E'))
46
#define AUTH_MARKER (MAKE_MARKER ('A', 'U', 'T', 'H'))
47
#define ANNO_MARKER (MAKE_MARKER ('A', 'N', 'N', 'O'))
48
#define CHAN_MARKER (MAKE_MARKER ('C', 'H', 'A', 'N'))
50
/*------------------------------------------------------------------------------
51
* Typedefs for file chunks.
55
{ unsigned int oneShotHiSamples, repeatHiSamples, samplesPerHiCycle ;
56
unsigned short samplesPerSec ;
57
unsigned char octave, compression ;
69
/*------------------------------------------------------------------------------
70
* Private static functions.
73
static int svx_close (SF_PRIVATE *psf) ;
74
static int svx_write_header (SF_PRIVATE *psf, int calc_length) ;
75
static int svx_read_header (SF_PRIVATE *psf) ;
77
/*------------------------------------------------------------------------------
82
svx_open (SF_PRIVATE *psf)
85
if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
86
{ if ((error = svx_read_header (psf)))
89
psf->endian = SF_ENDIAN_BIG ; /* All SVX files are big endian. */
91
psf->blockwidth = psf->sf.channels * psf->bytewidth ;
93
psf->sf.frames = psf->datalength / psf->blockwidth ;
95
psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
98
if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
100
return SFE_NO_PIPE_WRITE ;
102
if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_SVX)
103
return SFE_BAD_OPEN_FORMAT ;
105
psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
107
if (psf->endian == SF_ENDIAN_LITTLE || (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU))
108
return SFE_BAD_ENDIAN ;
110
psf->endian = SF_ENDIAN_BIG ; /* All SVX files are big endian. */
112
error = svx_write_header (psf, SF_FALSE) ;
116
psf->write_header = svx_write_header ;
119
psf->container_close = svx_close ;
121
if ((error = pcm_init (psf)))
127
/*------------------------------------------------------------------------------
131
svx_read_header (SF_PRIVATE *psf)
133
unsigned int FORMsize, vhdrsize, dword, marker ;
134
int filetype = 0, parsestage = 0, done = 0 ;
135
int bytecount = 0, channels ;
137
memset (&vhdr, 0, sizeof (vhdr)) ;
138
psf_binheader_readf (psf, "p", 0) ;
140
/* Set default number of channels. Currently can't handle stereo SVX files. */
141
psf->sf.channels = 1 ;
143
psf->sf.format = SF_FORMAT_SVX ;
146
{ psf_binheader_readf (psf, "m", &marker) ;
150
return SFE_SVX_NO_FORM ;
152
psf_binheader_readf (psf, "E4", &FORMsize) ;
154
if (FORMsize != psf->filelength - 2 * sizeof (dword))
155
{ dword = psf->filelength - 2 * sizeof (dword) ;
156
psf_log_printf (psf, "FORM : %d (should be %d)\n", FORMsize, dword) ;
160
psf_log_printf (psf, "FORM : %d\n", FORMsize) ;
161
parsestage |= HAVE_FORM ;
166
if (! (parsestage & HAVE_FORM))
167
return SFE_SVX_NO_FORM ;
169
psf_log_printf (psf, " %M\n", marker) ;
170
parsestage |= HAVE_SVX ;
174
if (! (parsestage & (HAVE_FORM | HAVE_SVX)))
175
return SFE_SVX_NO_FORM ;
177
psf_binheader_readf (psf, "E4", &vhdrsize) ;
179
psf_log_printf (psf, " VHDR : %d\n", vhdrsize) ;
181
psf_binheader_readf (psf, "E4442114", &(vhdr.oneShotHiSamples), &(vhdr.repeatHiSamples),
182
&(vhdr.samplesPerHiCycle), &(vhdr.samplesPerSec), &(vhdr.octave), &(vhdr.compression),
185
psf_log_printf (psf, " OneShotHiSamples : %d\n", vhdr.oneShotHiSamples) ;
186
psf_log_printf (psf, " RepeatHiSamples : %d\n", vhdr.repeatHiSamples) ;
187
psf_log_printf (psf, " samplesPerHiCycle : %d\n", vhdr.samplesPerHiCycle) ;
188
psf_log_printf (psf, " Sample Rate : %d\n", vhdr.samplesPerSec) ;
189
psf_log_printf (psf, " Octave : %d\n", vhdr.octave) ;
191
psf_log_printf (psf, " Compression : %d => ", vhdr.compression) ;
193
switch (vhdr.compression)
194
{ case 0 : psf_log_printf (psf, "None.\n") ;
196
case 1 : psf_log_printf (psf, "Fibonacci delta\n") ;
198
case 2 : psf_log_printf (psf, "Exponential delta\n") ;
202
psf_log_printf (psf, " Volume : %d\n", vhdr.volume) ;
204
psf->sf.samplerate = vhdr.samplesPerSec ;
206
if (filetype == SVX8_MARKER)
207
{ psf->sf.format |= SF_FORMAT_PCM_S8 ;
210
else if (filetype == SV16_MARKER)
211
{ psf->sf.format |= SF_FORMAT_PCM_16 ;
215
parsestage |= HAVE_VHDR ;
219
if (! (parsestage & HAVE_VHDR))
220
return SFE_SVX_NO_BODY ;
222
psf_binheader_readf (psf, "E4", &dword) ;
223
psf->datalength = dword ;
225
psf->dataoffset = psf_ftell (psf) ;
227
if (psf->datalength > psf->filelength - psf->dataoffset)
228
{ psf_log_printf (psf, " BODY : %D (should be %D)\n", psf->datalength, psf->filelength - psf->dataoffset) ;
229
psf->datalength = psf->filelength - psf->dataoffset ;
232
psf_log_printf (psf, " BODY : %D\n", psf->datalength) ;
234
parsestage |= HAVE_BODY ;
236
if (! psf->sf.seekable)
239
psf_fseek (psf, psf->datalength, SEEK_CUR) ;
243
if (! (parsestage & HAVE_SVX))
244
return SFE_SVX_NO_FORM ;
246
psf_binheader_readf (psf, "E4", &dword) ;
248
psf_log_printf (psf, " %M : %d\n", marker, dword) ;
250
if (strlen (psf->filename) != dword)
251
{ if (dword > sizeof (psf->filename) - 1)
252
return SFE_SVX_BAD_NAME_LENGTH ;
254
psf_binheader_readf (psf, "b", psf->filename, dword) ;
255
psf->filename [dword] = 0 ;
258
psf_binheader_readf (psf, "j", dword) ;
262
if (! (parsestage & HAVE_SVX))
263
return SFE_SVX_NO_FORM ;
265
psf_binheader_readf (psf, "E4", &dword) ;
267
psf_log_printf (psf, " %M : %d\n", marker, dword) ;
269
psf_binheader_readf (psf, "j", dword) ;
273
if (! (parsestage & HAVE_SVX))
274
return SFE_SVX_NO_FORM ;
276
psf_binheader_readf (psf, "E4", &dword) ;
278
psf_log_printf (psf, " %M : %d\n", marker, dword) ;
280
bytecount += psf_binheader_readf (psf, "E4", &channels) ;
281
psf->sf.channels = channels ;
283
psf_log_printf (psf, " Channels : %d\n", channels) ;
285
psf_binheader_readf (psf, "j", dword - bytecount) ;
291
if (! (parsestage & HAVE_SVX))
292
return SFE_SVX_NO_FORM ;
294
psf_binheader_readf (psf, "E4", &dword) ;
296
psf_log_printf (psf, " %M : %d\n", marker, dword) ;
298
psf_binheader_readf (psf, "j", dword) ;
302
if (isprint ((marker >> 24) & 0xFF) && isprint ((marker >> 16) & 0xFF)
303
&& isprint ((marker >> 8) & 0xFF) && isprint (marker & 0xFF))
304
{ psf_binheader_readf (psf, "E4", &dword) ;
306
psf_log_printf (psf, "%M : %d (unknown marker)\n", marker, dword) ;
308
psf_binheader_readf (psf, "j", dword) ;
311
if ((dword = psf_ftell (psf)) & 0x03)
312
{ psf_log_printf (psf, " Unknown chunk marker at position %d. Resynching.\n", dword - 4) ;
314
psf_binheader_readf (psf, "j", -3) ;
317
psf_log_printf (psf, "*** Unknown chunk marker : %X. Exiting parser.\n", marker) ;
319
} ; /* switch (marker) */
321
if (! psf->sf.seekable && (parsestage & HAVE_BODY))
324
if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (dword))
328
if (vhdr.compression)
329
return SFE_SVX_BAD_COMP ;
331
if (psf->dataoffset <= 0)
332
return SFE_SVX_NO_DATA ;
335
} /* svx_read_header */
338
svx_close (SF_PRIVATE *psf)
340
if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
341
svx_write_header (psf, SF_TRUE) ;
347
svx_write_header (SF_PRIVATE *psf, int calc_length)
348
{ static char annotation [] = "libsndfile by Erik de Castro Lopo\0\0\0" ;
351
current = psf_ftell (psf) ;
354
{ psf->filelength = psf_get_filelen (psf) ;
356
psf->datalength = psf->filelength - psf->dataoffset ;
359
psf->datalength -= psf->filelength - psf->dataend ;
361
psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
364
psf->header [0] = 0 ;
366
psf_fseek (psf, 0, SEEK_SET) ;
368
/* FORM marker and FORM size. */
369
psf_binheader_writef (psf, "Etm8", FORM_MARKER, (psf->filelength < 8) ?
370
psf->filelength * 0 : psf->filelength - 8) ;
372
psf_binheader_writef (psf, "m", (psf->bytewidth == 1) ? SVX8_MARKER : SV16_MARKER) ;
375
psf_binheader_writef (psf, "Em4", VHDR_MARKER, sizeof (VHDR_CHUNK)) ;
376
/* VHDR : oneShotHiSamples, repeatHiSamples, samplesPerHiCycle */
377
psf_binheader_writef (psf, "E444", psf->sf.frames, 0, 0) ;
378
/* VHDR : samplesPerSec, octave, compression */
379
psf_binheader_writef (psf, "E211", psf->sf.samplerate, 1, 0) ;
381
psf_binheader_writef (psf, "E4", (psf->bytewidth == 1) ? 0xFF : 0xFFFF) ;
383
/* Filename and annotation strings. */
384
psf_binheader_writef (psf, "Emsms", NAME_MARKER, psf->filename, ANNO_MARKER, annotation) ;
386
/* BODY marker and size. */
387
psf_binheader_writef (psf, "Etm8", BODY_MARKER, (psf->datalength < 0) ?
388
psf->datalength * 0 : psf->datalength) ;
390
psf_fwrite (psf->header, psf->headindex, 1, psf) ;
395
psf->dataoffset = psf->headindex ;
398
psf_fseek (psf, current, SEEK_SET) ;
401
} /* svx_write_header */
405
** Do not edit or modify anything in this comment block.
406
** The arch-tag line is a file identity tag for the GNU Arch
407
** revision control system.
409
** arch-tag: a80ab6fb-7d75-4d32-a6b0-0061a3f05d95