1 /* libSoX file format: IRCAM SoundFile (c) 2008 robs@users.sourceforge.net
3 * See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/IRCAM/IRCAM.html
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation; either version 2.1 of the License, or (at
8 * your option) any later version.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
13 * General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 /* Magic numbers used in IRCAM audio files */
24 static struct {char str
[4]; sox_bool reverse_bytes
; char const * desc
;} id
[] = {
25 {"\144\243\001\0", MACHINE_IS_BIGENDIAN
, "little-endian VAX (native)"},
26 {"\0\001\243\144", MACHINE_IS_LITTLEENDIAN
, "big-endian VAX"},
27 {"\144\243\002\0", MACHINE_IS_LITTLEENDIAN
, "big-endian Sun (native)"},
28 {"\0\002\243\144", MACHINE_IS_BIGENDIAN
, "little-endian Sun"},
29 {"\144\243\003\0", MACHINE_IS_BIGENDIAN
, "little-endian MIPS (DEC)"},
30 {"\0\003\243\144", MACHINE_IS_LITTLEENDIAN
, "big-endian MIPS (SGI)"},
31 {"\144\243\004\0", MACHINE_IS_LITTLEENDIAN
, "big-endian NeXT"},
34 #define FIXED_HDR 1024
35 #define SF_COMMENT 2 /* code for "comment line" */
37 typedef enum {Unspecified
,
38 Linear_8
= 0x00001, Alaw_8
= 0x10001, Mulaw_8
= 0x20001, Linear_16
= 0x00002,
39 Linear_24
= 0x00003, Linear_32
= 0x40004, Float
= 0x00004, Double
= 0x00008
42 static ft_encoding_t
ft_enc(unsigned size
, sox_encoding_t encoding
)
44 if (encoding
== SOX_ENCODING_ULAW
&& size
== 8) return Mulaw_8
;
45 if (encoding
== SOX_ENCODING_ALAW
&& size
== 8) return Alaw_8
;
46 if (encoding
== SOX_ENCODING_SIGN2
&& size
== 8) return Linear_8
;
47 if (encoding
== SOX_ENCODING_SIGN2
&& size
== 16) return Linear_16
;
48 if (encoding
== SOX_ENCODING_SIGN2
&& size
== 24) return Linear_24
;
49 if (encoding
== SOX_ENCODING_SIGN2
&& size
== 32) return Linear_32
;
50 if (encoding
== SOX_ENCODING_FLOAT
&& size
== 32) return Float
;
51 if (encoding
== SOX_ENCODING_FLOAT
&& size
== 64) return Double
;
55 static sox_encoding_t
sox_enc(uint32_t ft_encoding
, unsigned * size
)
57 switch (ft_encoding
) {
58 case Mulaw_8
: *size
= 8; return SOX_ENCODING_ULAW
;
59 case Alaw_8
: *size
= 8; return SOX_ENCODING_ALAW
;
60 case Linear_8
: *size
= 8; return SOX_ENCODING_SIGN2
;
61 case Linear_16
: *size
= 16; return SOX_ENCODING_SIGN2
;
62 case Linear_24
: *size
= 24; return SOX_ENCODING_SIGN2
;
63 case Linear_32
: *size
= 32; return SOX_ENCODING_SIGN2
;
64 case Float
: *size
= 32; return SOX_ENCODING_FLOAT
;
65 case Double
: *size
= 64; return SOX_ENCODING_FLOAT
;
66 default: return SOX_ENCODING_UNKNOWN
;
70 static int startread(sox_format_t
* ft
)
74 uint32_t channels
, ft_encoding
;
75 unsigned i
, bits_per_sample
;
76 sox_encoding_t encoding
;
79 if (lsx_readchars(ft
, magic
, sizeof(magic
)))
82 for (i
= 0; id
[i
].desc
&& memcmp(magic
, id
[i
].str
, sizeof(magic
)); ++i
);
84 lsx_fail_errno(ft
, SOX_EHDR
, "sf: can't find IRCAM identifier");
87 lsx_report("found %s identifier", id
[i
].desc
);
88 ft
->encoding
.reverse_bytes
= id
[i
].reverse_bytes
;
90 if (lsx_readf(ft
, &rate
) || lsx_readdw(ft
, &channels
) || lsx_readdw(ft
, &ft_encoding
))
93 if (!(encoding
= sox_enc(ft_encoding
, &bits_per_sample
))) {
94 lsx_fail_errno(ft
, SOX_EFMT
, "sf: unsupported encoding %#x)", ft_encoding
);
98 if (lsx_readw(ft
, &code
) || lsx_readw(ft
, &size
))
100 if (code
== SF_COMMENT
) {
101 char * buf
= lsx_calloc(1, (size_t)size
+ 1); /* +1 ensures null-terminated */
102 if (lsx_readchars(ft
, buf
, (size_t) size
) != SOX_SUCCESS
) {
106 sox_append_comments(&ft
->oob
.comments
, buf
);
109 else if (lsx_skipbytes(ft
, (size_t) size
))
112 if (lsx_skipbytes(ft
, FIXED_HDR
- (size_t)lsx_tell(ft
)))
115 return lsx_check_read_params(ft
, channels
, rate
, encoding
, bits_per_sample
, (uint64_t)0, sox_true
);
118 static int write_header(sox_format_t
* ft
)
120 char * comment
= lsx_cat_comments(ft
->oob
.comments
);
121 size_t len
= min(FIXED_HDR
- 26, strlen(comment
)) + 1; /* null-terminated */
122 size_t info_len
= max(4, (len
+ 3) & ~3u); /* Minimum & multiple of 4 bytes */
123 int i
= ft
->encoding
.reverse_bytes
== MACHINE_IS_BIGENDIAN
? 0 : 2;
124 sox_bool error
= sox_false
125 ||lsx_writechars(ft
, id
[i
].str
, sizeof(id
[i
].str
))
126 ||lsx_writef(ft
, ft
->signal
.rate
)
127 ||lsx_writedw(ft
, ft
->signal
.channels
)
128 ||lsx_writedw(ft
, ft_enc(ft
->encoding
.bits_per_sample
, ft
->encoding
.encoding
))
129 ||lsx_writew(ft
, SF_COMMENT
)
130 ||lsx_writew(ft
, (unsigned) info_len
)
131 ||lsx_writechars(ft
, comment
, len
)
132 ||lsx_padbytes(ft
, FIXED_HDR
- 20 - len
);
134 return error
? SOX_EOF
: SOX_SUCCESS
;
137 LSX_FORMAT_HANDLER(sf
)
139 static char const * const names
[] = {"sf", "ircam", NULL
};
140 static unsigned const write_encodings
[] = {
141 SOX_ENCODING_ULAW
, 8, 0,
142 SOX_ENCODING_ALAW
, 8, 0,
143 SOX_ENCODING_SIGN2
, 8, 16, 24, 32, 0,
144 SOX_ENCODING_FLOAT
, 32, 64, 0,
146 static sox_format_handler_t
const handler
= {SOX_LIB_VERSION_CODE
,
147 "Institut de Recherche et Coordination Acoustique/Musique",
148 names
, SOX_FILE_LIT_END
,
149 startread
, lsx_rawread
, NULL
,
150 write_header
, lsx_rawwrite
, NULL
,
151 lsx_rawseek
, write_encodings
, NULL
, 0