dd09b46c378ef774d4f9c625cc2d71139638d89e
2 ** Copyright (C) 2004-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.
28 #define TWOBIT_MARKER (MAKE_MARKER ('2', 'B', 'I', 'T'))
29 #define AVR_HDR_SIZE 128
34 ** From: hyc@hanauma.Jpl.Nasa.Gov (Howard Chu)
36 ** A lot of PD software exists to play Mac .snd files on the ST. One other
37 ** format that seems pretty popular (used by a number of commercial packages)
38 ** is the AVR format (from Audio Visual Research). This format has a 128 byte
39 ** header that looks like this (its actually packed, but thats not portable):
43 { int marker
; /* 2BIT */
44 char name
[8] ; /* null-padded sample name */
45 short mono
; /* 0 = mono, 0xffff = stereo */
46 short rez
; /* 8 = 8 bit, 16 = 16 bit */
47 short sign
; /* 0 = unsigned, 0xffff = signed */
49 short loop
; /* 0 = no loop, 0xffff = looping sample */
50 short midi
; /* 0xffff = no MIDI note assigned, */
51 /* 0xffXX = single key note assignment */
52 /* 0xLLHH = key split, low/hi note */
53 int srate
; /* sample frequency in hertz */
54 int frames
; /* sample length in bytes or words (see rez) */
55 int lbeg
; /* offset to start of loop in bytes or words. */
56 /* set to zero if unused */
57 int lend
; /* offset to end of loop in bytes or words. */
58 /* set to sample length if unused */
59 short res1
; /* Reserved, MIDI keyboard split */
60 short res2
; /* Reserved, sample compression */
61 short res3
; /* Reserved */
62 char ext
[20] ; /* Additional filename space, used if (name[7] != 0) */
63 char user
[64] ; /* User defined. Typically ASCII message */
66 /*------------------------------------------------------------------------------
67 ** Private static functions.
70 static int avr_close (SF_PRIVATE
*psf
) ;
72 static int avr_read_header (SF_PRIVATE
*psf
) ;
73 static int avr_write_header (SF_PRIVATE
*psf
, int calc_length
) ;
75 /*------------------------------------------------------------------------------
80 avr_open (SF_PRIVATE
*psf
)
83 if (psf
->file
.mode
== SFM_READ
|| (psf
->file
.mode
== SFM_RDWR
&& psf
->filelength
> 0))
84 { if ((error
= avr_read_header (psf
)))
88 if ((SF_CONTAINER (psf
->sf
.format
)) != SF_FORMAT_AVR
)
89 return SFE_BAD_OPEN_FORMAT
;
91 if (psf
->file
.mode
== SFM_WRITE
|| psf
->file
.mode
== SFM_RDWR
)
92 { psf
->endian
= SF_ENDIAN (psf
->sf
.format
) ;
93 psf
->endian
= SF_ENDIAN_BIG
;
95 if (avr_write_header (psf
, SF_FALSE
))
98 psf
->write_header
= avr_write_header
;
101 psf
->container_close
= avr_close
;
103 psf
->blockwidth
= psf
->bytewidth
* psf
->sf
.channels
;
105 error
= pcm_init (psf
) ;
111 avr_read_header (SF_PRIVATE
*psf
)
114 memset (&hdr
, 0, sizeof (hdr
)) ;
116 psf_binheader_readf (psf
, "pmb", 0, &hdr
.marker
, &hdr
.name
, sizeof (hdr
.name
)) ;
117 psf_log_printf (psf
, "%M\n", hdr
.marker
) ;
119 if (hdr
.marker
!= TWOBIT_MARKER
)
122 psf_log_printf (psf
, " Name : %s\n", hdr
.name
) ;
124 psf_binheader_readf (psf
, "E22222", &hdr
.mono
, &hdr
.rez
, &hdr
.sign
, &hdr
.loop
, &hdr
.midi
) ;
126 psf
->sf
.channels
= (hdr
.mono
& 1) + 1 ;
128 psf_log_printf (psf
, " Channels : %d\n Bit width : %d\n Signed : %s\n",
129 (hdr
.mono
& 1) + 1, hdr
.rez
, hdr
.sign
? "yes" : "no") ;
131 switch ((hdr
.rez
<< 16) + (hdr
.sign
& 1))
132 { case ((8 << 16) + 0) :
133 psf
->sf
.format
= SF_FORMAT_AVR
| SF_FORMAT_PCM_U8
;
137 case ((8 << 16) + 1) :
138 psf
->sf
.format
= SF_FORMAT_AVR
| SF_FORMAT_PCM_S8
;
142 case ((16 << 16) + 1) :
143 psf
->sf
.format
= SF_FORMAT_AVR
| SF_FORMAT_PCM_16
;
148 psf_log_printf (psf
, "Error : bad rez/sign combination.\n") ;
152 psf_binheader_readf (psf
, "E4444", &hdr
.srate
, &hdr
.frames
, &hdr
.lbeg
, &hdr
.lend
) ;
154 psf
->sf
.frames
= hdr
.frames
;
155 psf
->sf
.samplerate
= hdr
.srate
;
157 psf_log_printf (psf
, " Frames : %D\n", psf
->sf
.frames
) ;
158 psf_log_printf (psf
, " Sample rate : %d\n", psf
->sf
.samplerate
) ;
160 psf_binheader_readf (psf
, "E222", &hdr
.res1
, &hdr
.res2
, &hdr
.res3
) ;
161 psf_binheader_readf (psf
, "bb", hdr
.ext
, sizeof (hdr
.ext
), hdr
.user
, sizeof (hdr
.user
)) ;
163 psf_log_printf (psf
, " Ext : %s\n User : %s\n", hdr
.ext
, hdr
.user
) ;
165 psf
->endian
= SF_ENDIAN_BIG
;
167 psf
->dataoffset
= AVR_HDR_SIZE
;
168 psf
->datalength
= hdr
.frames
* (hdr
.rez
/ 8) ;
170 if (psf
->fileoffset
> 0)
171 psf
->filelength
= AVR_HDR_SIZE
+ psf
->datalength
;
173 if (psf_ftell (psf
) != psf
->dataoffset
)
174 psf_binheader_readf (psf
, "j", psf
->dataoffset
- psf_ftell (psf
)) ;
176 psf
->blockwidth
= psf
->sf
.channels
* psf
->bytewidth
;
178 if (psf
->sf
.frames
== 0 && psf
->blockwidth
)
179 psf
->sf
.frames
= (psf
->filelength
- psf
->dataoffset
) / psf
->blockwidth
;
182 } /* avr_read_header */
185 avr_write_header (SF_PRIVATE
*psf
, int calc_length
)
186 { sf_count_t current
;
189 if (psf
->pipeoffset
> 0)
192 current
= psf_ftell (psf
) ;
195 { psf
->filelength
= psf_get_filelen (psf
) ;
197 psf
->datalength
= psf
->filelength
- psf
->dataoffset
;
199 psf
->datalength
-= psf
->filelength
- psf
->dataend
;
201 psf
->sf
.frames
= psf
->datalength
/ (psf
->bytewidth
* psf
->sf
.channels
) ;
204 /* Reset the current header length to zero. */
205 psf
->header
[0] = 0 ;
209 ** Only attempt to seek if we are not writng to a pipe. If we are
210 ** writing to a pipe we shouldn't be here anyway.
212 if (psf
->is_pipe
== SF_FALSE
)
213 psf_fseek (psf
, 0, SEEK_SET
) ;
215 psf_binheader_writef (psf
, "Emz22", TWOBIT_MARKER
, make_size_t (8),
216 psf
->sf
.channels
== 2 ? 0xFFFF : 0, psf
->bytewidth
* 8) ;
218 sign
= ((SF_CODEC (psf
->sf
.format
)) == SF_FORMAT_PCM_U8
) ? 0 : 0xFFFF ;
220 psf_binheader_writef (psf
, "E222", sign
, 0, 0xFFFF) ;
221 psf_binheader_writef (psf
, "E4444", psf
->sf
.samplerate
, psf
->sf
.frames
, 0, 0) ;
223 psf_binheader_writef (psf
, "E222zz", 0, 0, 0, make_size_t (20), make_size_t (64)) ;
225 /* Header construction complete so write it out. */
226 psf_fwrite (psf
->header
, psf
->headindex
, 1, psf
) ;
231 psf
->dataoffset
= psf
->headindex
;
234 psf_fseek (psf
, current
, SEEK_SET
) ;
237 } /* avr_write_header */
240 avr_close (SF_PRIVATE
*psf
)
242 if (psf
->file
.mode
== SFM_WRITE
|| psf
->file
.mode
== SFM_RDWR
)
243 avr_write_header (psf
, SF_TRUE
) ;