2 ** Copyright (C) 1999-2011 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
->file
.mode
== SFM_READ
|| (psf
->file
.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
->file
.mode
== SFM_WRITE
|| psf
->file
.mode
== SFM_RDWR
)
100 return SFE_NO_PIPE_WRITE
;
102 if ((SF_CONTAINER (psf
->sf
.format
)) != SF_FORMAT_SVX
)
103 return SFE_BAD_OPEN_FORMAT
;
105 psf
->endian
= SF_ENDIAN (psf
->sf
.format
) ;
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 if (psf
->filelength
> SF_PLATFORM_S64 (0xffffffff))
138 psf_log_printf (psf
, "Warning : filelength > 0xffffffff. This is bad!!!!\n") ;
140 memset (&vhdr
, 0, sizeof (vhdr
)) ;
141 psf_binheader_readf (psf
, "p", 0) ;
143 /* Set default number of channels. Modify later if necessary */
144 psf
->sf
.channels
= 1 ;
146 psf
->sf
.format
= SF_FORMAT_SVX
;
149 { psf_binheader_readf (psf
, "m", &marker
) ;
153 return SFE_SVX_NO_FORM
;
155 psf_binheader_readf (psf
, "E4", &FORMsize
) ;
157 if (FORMsize
!= psf
->filelength
- 2 * sizeof (dword
))
158 { dword
= psf
->filelength
- 2 * sizeof (dword
) ;
159 psf_log_printf (psf
, "FORM : %d (should be %d)\n", FORMsize
, dword
) ;
163 psf_log_printf (psf
, "FORM : %d\n", FORMsize
) ;
164 parsestage
|= HAVE_FORM
;
169 if (! (parsestage
& HAVE_FORM
))
170 return SFE_SVX_NO_FORM
;
172 psf_log_printf (psf
, " %M\n", marker
) ;
173 parsestage
|= HAVE_SVX
;
177 if (! (parsestage
& (HAVE_FORM
| HAVE_SVX
)))
178 return SFE_SVX_NO_FORM
;
180 psf_binheader_readf (psf
, "E4", &vhdrsize
) ;
182 psf_log_printf (psf
, " VHDR : %d\n", vhdrsize
) ;
184 psf_binheader_readf (psf
, "E4442114", &(vhdr
.oneShotHiSamples
), &(vhdr
.repeatHiSamples
),
185 &(vhdr
.samplesPerHiCycle
), &(vhdr
.samplesPerSec
), &(vhdr
.octave
), &(vhdr
.compression
),
188 psf_log_printf (psf
, " OneShotHiSamples : %d\n", vhdr
.oneShotHiSamples
) ;
189 psf_log_printf (psf
, " RepeatHiSamples : %d\n", vhdr
.repeatHiSamples
) ;
190 psf_log_printf (psf
, " samplesPerHiCycle : %d\n", vhdr
.samplesPerHiCycle
) ;
191 psf_log_printf (psf
, " Sample Rate : %d\n", vhdr
.samplesPerSec
) ;
192 psf_log_printf (psf
, " Octave : %d\n", vhdr
.octave
) ;
194 psf_log_printf (psf
, " Compression : %d => ", vhdr
.compression
) ;
196 switch (vhdr
.compression
)
197 { case 0 : psf_log_printf (psf
, "None.\n") ;
199 case 1 : psf_log_printf (psf
, "Fibonacci delta\n") ;
201 case 2 : psf_log_printf (psf
, "Exponential delta\n") ;
205 psf_log_printf (psf
, " Volume : %d\n", vhdr
.volume
) ;
207 psf
->sf
.samplerate
= vhdr
.samplesPerSec
;
209 if (filetype
== SVX8_MARKER
)
210 { psf
->sf
.format
|= SF_FORMAT_PCM_S8
;
213 else if (filetype
== SV16_MARKER
)
214 { psf
->sf
.format
|= SF_FORMAT_PCM_16
;
218 parsestage
|= HAVE_VHDR
;
222 if (! (parsestage
& HAVE_VHDR
))
223 return SFE_SVX_NO_BODY
;
225 psf_binheader_readf (psf
, "E4", &dword
) ;
226 psf
->datalength
= dword
;
228 psf
->dataoffset
= psf_ftell (psf
) ;
229 if (psf
->dataoffset
< 0)
230 return SFE_SVX_NO_BODY
;
232 if (psf
->datalength
> psf
->filelength
- psf
->dataoffset
)
233 { psf_log_printf (psf
, " BODY : %D (should be %D)\n", psf
->datalength
, psf
->filelength
- psf
->dataoffset
) ;
234 psf
->datalength
= psf
->filelength
- psf
->dataoffset
;
237 psf_log_printf (psf
, " BODY : %D\n", psf
->datalength
) ;
239 parsestage
|= HAVE_BODY
;
241 if (! psf
->sf
.seekable
)
244 psf_fseek (psf
, psf
->datalength
, SEEK_CUR
) ;
248 if (! (parsestage
& HAVE_SVX
))
249 return SFE_SVX_NO_FORM
;
251 psf_binheader_readf (psf
, "E4", &dword
) ;
253 psf_log_printf (psf
, " %M : %d\n", marker
, dword
) ;
255 if (strlen (psf
->file
.name
.c
) != dword
)
256 { if (dword
> sizeof (psf
->file
.name
.c
) - 1)
257 return SFE_SVX_BAD_NAME_LENGTH
;
259 psf_binheader_readf (psf
, "b", psf
->file
.name
.c
, dword
) ;
260 psf
->file
.name
.c
[dword
] = 0 ;
263 psf_binheader_readf (psf
, "j", dword
) ;
267 if (! (parsestage
& HAVE_SVX
))
268 return SFE_SVX_NO_FORM
;
270 psf_binheader_readf (psf
, "E4", &dword
) ;
272 psf_log_printf (psf
, " %M : %d\n", marker
, dword
) ;
274 psf_binheader_readf (psf
, "j", dword
) ;
278 if (! (parsestage
& HAVE_SVX
))
279 return SFE_SVX_NO_FORM
;
281 psf_binheader_readf (psf
, "E4", &dword
) ;
283 psf_log_printf (psf
, " %M : %d\n", marker
, dword
) ;
285 bytecount
+= psf_binheader_readf (psf
, "E4", &channels
) ;
287 if (channels
== 2 || channels
== 4)
288 psf_log_printf (psf
, " Channels : %d => mono\n", channels
) ;
289 else if (channels
== 6)
290 { psf
->sf
.channels
= 2 ;
291 psf_log_printf (psf
, " Channels : %d => stereo\n", channels
) ;
294 psf_log_printf (psf
, " Channels : %d *** assuming mono\n", channels
) ;
296 psf_binheader_readf (psf
, "j", dword
- bytecount
) ;
302 if (! (parsestage
& HAVE_SVX
))
303 return SFE_SVX_NO_FORM
;
305 psf_binheader_readf (psf
, "E4", &dword
) ;
307 psf_log_printf (psf
, " %M : %d\n", marker
, dword
) ;
309 psf_binheader_readf (psf
, "j", dword
) ;
313 if (psf_isprint ((marker
>> 24) & 0xFF) && psf_isprint ((marker
>> 16) & 0xFF)
314 && psf_isprint ((marker
>> 8) & 0xFF) && psf_isprint (marker
& 0xFF))
315 { psf_binheader_readf (psf
, "E4", &dword
) ;
317 psf_log_printf (psf
, "%M : %d (unknown marker)\n", marker
, dword
) ;
319 psf_binheader_readf (psf
, "j", dword
) ;
322 if ((dword
= psf_ftell (psf
)) & 0x03)
323 { psf_log_printf (psf
, " Unknown chunk marker at position %d. Resynching.\n", dword
- 4) ;
325 psf_binheader_readf (psf
, "j", -3) ;
328 psf_log_printf (psf
, "*** Unknown chunk marker : %X. Exiting parser.\n", marker
) ;
330 } ; /* switch (marker) */
332 if (! psf
->sf
.seekable
&& (parsestage
& HAVE_BODY
))
335 if (psf_ftell (psf
) >= psf
->filelength
- SIGNED_SIZEOF (dword
))
339 if (vhdr
.compression
)
340 return SFE_SVX_BAD_COMP
;
342 if (psf
->dataoffset
<= 0)
343 return SFE_SVX_NO_DATA
;
346 } /* svx_read_header */
349 svx_close (SF_PRIVATE
*psf
)
351 if (psf
->file
.mode
== SFM_WRITE
|| psf
->file
.mode
== SFM_RDWR
)
352 svx_write_header (psf
, SF_TRUE
) ;
358 svx_write_header (SF_PRIVATE
*psf
, int calc_length
)
359 { static char annotation
[] = "libsndfile by Erik de Castro Lopo\0\0\0" ;
362 current
= psf_ftell (psf
) ;
365 { psf
->filelength
= psf_get_filelen (psf
) ;
367 psf
->datalength
= psf
->filelength
- psf
->dataoffset
;
370 psf
->datalength
-= psf
->filelength
- psf
->dataend
;
372 psf
->sf
.frames
= psf
->datalength
/ (psf
->bytewidth
* psf
->sf
.channels
) ;
375 psf
->header
[0] = 0 ;
377 psf_fseek (psf
, 0, SEEK_SET
) ;
379 /* FORM marker and FORM size. */
380 psf_binheader_writef (psf
, "Etm8", FORM_MARKER
, (psf
->filelength
< 8) ?
381 psf
->filelength
* 0 : psf
->filelength
- 8) ;
383 psf_binheader_writef (psf
, "m", (psf
->bytewidth
== 1) ? SVX8_MARKER
: SV16_MARKER
) ;
386 psf_binheader_writef (psf
, "Em4", VHDR_MARKER
, sizeof (VHDR_CHUNK
)) ;
387 /* VHDR : oneShotHiSamples, repeatHiSamples, samplesPerHiCycle */
388 psf_binheader_writef (psf
, "E444", psf
->sf
.frames
, 0, 0) ;
389 /* VHDR : samplesPerSec, octave, compression */
390 psf_binheader_writef (psf
, "E211", psf
->sf
.samplerate
, 1, 0) ;
392 psf_binheader_writef (psf
, "E4", (psf
->bytewidth
== 1) ? 0xFF : 0xFFFF) ;
394 if (psf
->sf
.channels
== 2)
395 psf_binheader_writef (psf
, "Em44", CHAN_MARKER
, 4, 6) ;
397 /* Filename and annotation strings. */
398 psf_binheader_writef (psf
, "Emsms", NAME_MARKER
, psf
->file
.name
.c
, ANNO_MARKER
, annotation
) ;
400 /* BODY marker and size. */
401 psf_binheader_writef (psf
, "Etm8", BODY_MARKER
, (psf
->datalength
< 0) ?
402 psf
->datalength
* 0 : psf
->datalength
) ;
404 psf_fwrite (psf
->header
, psf
->headindex
, 1, psf
) ;
409 psf
->dataoffset
= psf
->headindex
;
412 psf_fseek (psf
, current
, SEEK_SET
) ;
415 } /* svx_write_header */