1 /* libSoX NIST Sphere file format handler.
5 * Copyright (C) 2000 Chris Bagwell (cbagwell@sprynet.com)
7 * This library is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
15 * General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 static int start_read(sox_format_t
* ft
)
27 unsigned long header_size_ul
= 0, num_samples_ul
= 0;
28 sox_encoding_t encoding
= SOX_ENCODING_SIGN2
;
29 size_t header_size
, bytes_read
;
30 size_t num_samples
= 0;
31 unsigned bytes_per_sample
= 0;
32 unsigned channels
= 1;
33 unsigned rate
= 16000;
34 char fldname
[64], fldtype
[16], fldsval
[128];
38 if (lsx_reads(ft
, fldname
, (size_t)8) || strncmp(fldname
, "NIST_1A", (size_t)7) != 0) {
39 lsx_fail_errno(ft
, SOX_EHDR
, "Sphere header does not begin with magic word `NIST_1A'");
43 if (lsx_reads(ft
, fldsval
, (size_t)8)) {
44 lsx_fail_errno(ft
, SOX_EHDR
, "Error reading Sphere header");
48 /* Determine header size, and allocate a buffer large enough to hold it. */
49 sscanf(fldsval
, "%lu", &header_size_ul
);
50 buf
= lsx_malloc(header_size
= header_size_ul
);
52 /* Skip what we have read so far */
55 if (lsx_reads(ft
, buf
, header_size
) == SOX_EOF
) {
56 lsx_fail_errno(ft
, SOX_EHDR
, "Error reading Sphere header");
61 header_size
-= (strlen(buf
) + 1);
63 while (strncmp(buf
, "end_head", (size_t)8) != 0) {
64 if (strncmp(buf
, "sample_n_bytes", (size_t)14) == 0)
65 sscanf(buf
, "%63s %15s %u", fldname
, fldtype
, &bytes_per_sample
);
66 else if (strncmp(buf
, "channel_count", (size_t)13) == 0)
67 sscanf(buf
, "%63s %15s %u", fldname
, fldtype
, &channels
);
68 else if (strncmp(buf
, "sample_count ", (size_t)13) == 0)
69 sscanf(buf
, "%53s %15s %lu", fldname
, fldtype
, &num_samples_ul
);
70 else if (strncmp(buf
, "sample_rate ", (size_t)12) == 0)
71 sscanf(buf
, "%53s %15s %u", fldname
, fldtype
, &rate
);
72 else if (strncmp(buf
, "sample_coding", (size_t)13) == 0) {
73 sscanf(buf
, "%63s %15s %127s", fldname
, fldtype
, fldsval
);
74 if (!strcasecmp(fldsval
, "ulaw") || !strcasecmp(fldsval
, "mu-law"))
75 encoding
= SOX_ENCODING_ULAW
;
76 else if (!strcasecmp(fldsval
, "pcm"))
77 encoding
= SOX_ENCODING_SIGN2
;
79 lsx_fail_errno(ft
, SOX_EFMT
, "sph: unsupported coding `%s'", fldsval
);
84 else if (strncmp(buf
, "sample_byte_format", (size_t)18) == 0) {
85 sscanf(buf
, "%53s %15s %127s", fldname
, fldtype
, fldsval
);
86 if (strcmp(fldsval
, "01") == 0) /* Data is little endian. */
87 ft
->encoding
.reverse_bytes
= MACHINE_IS_BIGENDIAN
;
88 else if (strcmp(fldsval
, "10") == 0) /* Data is big endian. */
89 ft
->encoding
.reverse_bytes
= MACHINE_IS_LITTLEENDIAN
;
90 else if (strcmp(fldsval
, "1")) {
91 lsx_fail_errno(ft
, SOX_EFMT
, "sph: unsupported coding `%s'", fldsval
);
97 if (lsx_reads(ft
, buf
, header_size
) == SOX_EOF
) {
98 lsx_fail_errno(ft
, SOX_EHDR
, "Error reading Sphere header");
103 header_size
-= (strlen(buf
) + 1);
106 if (!bytes_per_sample
)
107 bytes_per_sample
= encoding
== SOX_ENCODING_ULAW
? 1 : 2;
109 while (header_size
) {
110 bytes_read
= lsx_readbuf(ft
, buf
, header_size
);
111 if (bytes_read
== 0) {
115 header_size
-= bytes_read
;
120 /* Check first four bytes of data to see if it's shorten compressed. */
121 char shorten_check
[4];
123 if (lsx_readchars(ft
, shorten_check
, sizeof(shorten_check
)))
125 lsx_seeki(ft
, -(off_t
)sizeof(shorten_check
), SEEK_CUR
);
127 if (!memcmp(shorten_check
, "ajkg", sizeof(shorten_check
))) {
128 lsx_fail_errno(ft
, SOX_EFMT
,
129 "File uses shorten compression, cannot handle this.");
134 num_samples
= num_samples_ul
;
135 return lsx_check_read_params(ft
, channels
, (sox_rate_t
)rate
, encoding
,
136 bytes_per_sample
<< 3, (uint64_t)num_samples
* channels
, sox_true
);
139 static int write_header(sox_format_t
* ft
)
142 uint64_t samples
= (ft
->olength
? ft
->olength
: ft
->signal
.length
) / ft
->signal
.channels
;
144 lsx_writes(ft
, "NIST_1A\n");
145 lsx_writes(ft
, " 1024\n");
148 sprintf(buf
, "sample_count -i %" PRIu64
"\n", samples
);
152 sprintf(buf
, "sample_n_bytes -i %d\n", ft
->encoding
.bits_per_sample
>> 3);
155 sprintf(buf
, "channel_count -i %d\n", ft
->signal
.channels
);
158 if (ft
->encoding
.bits_per_sample
== 8)
159 sprintf(buf
, "sample_byte_format -s1 1\n");
161 sprintf(buf
, "sample_byte_format -s2 %s\n",
162 ft
->encoding
.reverse_bytes
!= MACHINE_IS_BIGENDIAN
? "10" : "01");
165 sprintf(buf
, "sample_rate -i %u\n", (unsigned) (ft
->signal
.rate
+ .5));
168 if (ft
->encoding
.encoding
== SOX_ENCODING_ULAW
)
169 lsx_writes(ft
, "sample_coding -s4 ulaw\n");
171 lsx_writes(ft
, "sample_coding -s3 pcm\n");
173 lsx_writes(ft
, "end_head\n");
175 lsx_padbytes(ft
, 1024 - (size_t)lsx_tell(ft
));
179 LSX_FORMAT_HANDLER(sphere
)
181 static char const *const names
[] = {"sph", "nist", NULL
};
182 static unsigned const write_encodings
[] = {
183 SOX_ENCODING_SIGN2
, 8, 16, 24, 32, 0,
184 SOX_ENCODING_ULAW
, 8, 0,
187 static sox_format_handler_t
const handler
= {SOX_LIB_VERSION_CODE
,
188 "SPeech HEader Resources; defined by NIST", names
, SOX_FILE_REWIND
,
189 start_read
, lsx_rawread
, NULL
,
190 write_header
, lsx_rawwrite
, NULL
,
191 lsx_rawseek
, write_encodings
, NULL
, 0