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