8d21ad8b535d0c5d1ff4d568d0a0709a21fa5606
2 * This file is part of DisOrder.
3 * Portions copyright (C) 2004, 2005 Richard Kettlewell (see also below)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program 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
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 #include <sys/types.h>
33 #include <vorbis/vorbisfile.h>
40 static void *mmap_file(const char *path
, size_t *lengthp
) {
45 if((fd
= open(path
, O_RDONLY
)) < 0) {
46 disorder_error(errno
, "error opening %s", path
);
49 if(fstat(fd
, &sb
) < 0) {
50 disorder_error(errno
, "error calling stat on %s", path
);
53 if(sb
.st_size
== 0) /* can't map 0-length files */
55 if((base
= mmap(0, sb
.st_size
, PROT_READ
,
56 MAP_SHARED
, fd
, 0)) == (void *)-1) {
57 disorder_error(errno
, "error calling mmap on %s", path
);
60 *lengthp
= sb
.st_size
;
68 static long tl_mp3(const char *path
) {
73 if(!(base
= mmap_file(path
, &length
))) return -1;
74 b
.duration
= mad_timer_zero
;
75 scan_mp3(base
, length
, &b
);
77 return b
.duration
.seconds
+ !!b
.duration
.fraction
;
80 static long tl_ogg(const char *path
) {
86 if(!(fp
= fopen(path
, "rb"))) goto error
;
87 if(ov_open(fp
, &vf
, 0, 0)) goto error
;
89 length
= ov_time_total(&vf
, -1);
97 static long tl_wav(const char *path
) {
102 unsigned n
, m
, data_bytes
= 0, samples_per_second
= 0;
103 unsigned n_channels
= 0, bits_per_sample
= 0, sample_point_size
;
104 unsigned sample_frame_size
, n_samples
;
108 * http://www.technology.niagarac.on.ca/courses/comp530/WavFileFormat.html
109 * http://www.borg.com/~jglatt/tech/wave.htm
110 * http://www.borg.com/~jglatt/tech/aboutiff.htm
112 * These files consists of a header followed by chunks.
113 * Multibyte values are little-endian.
115 * 12 byte file header:
116 * offset size meaning
118 * 04 4 length of rest of file
121 * The length includes 'WAVE' but excludes the 1st 8 bytes.
125 * 04 4 length of rest of chunk
127 * The stated length may be odd, if so then there is an implicit padding byte
128 * appended to the chunk to make it up to an even length (someone wasn't
129 * think about 32/64-bit worlds).
131 * Also some files seem to have extra stuff at the end of chunks that nobody
132 * I know of documents. Go figure, but check the length field rather than
133 * deducing the length from the ID.
137 * 04 4 length of rest of chunk
138 * 08 2 compression (1 = none)
139 * 0a 2 number of channels
140 * 0c 4 samples/second
141 * 10 4 average bytes/second, = (samples/sec) * (bytes/sample)
143 * 16 2 bits/sample point
145 * 'sample' means 'sample frame' above, i.e. a sample point for each channel.
149 * 04 4 length of rest of chunk
152 * There is only allowed to be one data chunk. Some people violate this; we
153 * shall encourage people to fix their broken WAV files by not supporting
154 * this violation and because it's easier.
156 * As to the encoding of the data:
158 * Firstly, samples up to 8 bits in size are unsigned, larger samples are
161 * Secondly sample points are stored rounded up to a multiple of 8 bits in
162 * size. Marginally saner.
164 * Written as a single word (of 8, 16, 24, whatever bits) the padding to
165 * implement this happens at the right hand (least significant) end.
166 * e.g. assuming a 9 bit sample:
168 * | padded sample word |
169 * | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
170 * | 8 7 6 5 4 3 2 1 0 - - - - - - - |
172 * But this is a little-endian file format so the least significant byte is
173 * the first, which means that the padding is "between" the bits if you
174 * imagine them in their usual order:
176 * | first byte | second byte |
177 * | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 |
178 * | 0 - - - - - - - | 8 7 6 5 4 3 2 1 |
180 * Sample points are grouped into sample frames, consisting of as many
181 * samples points as their are channels. It seems that there are standard
182 * orderings of different channels.
184 * Given all of the above all we need to do is pick up some numbers from the
185 * format chunk, and the length of the data chunk, and do some arithmetic.
187 if(!(base
= mmap_file(path
, &length
))) return -1;
188 #define get16(p) ((p)[0] + 256 * (p)[1])
189 #define get32(p) ((p)[0] + 256 * ((p)[1] + 256 * ((p)[2] + 256 * (p)[3])))
191 if(length
< 12) goto out
;
192 if(strncmp((char *)ptr
, "RIFF", 4)) goto out
; /* wrong type */
193 n
= get32(ptr
+ 4); /* file length */
194 if(n
> length
- 8) goto out
; /* truncated */
195 ptr
+= 8; /* skip file header */
196 if(n
< 4 || strncmp((char *)ptr
, "WAVE", 4)) goto out
; /* wrong type */
197 ptr
+= 4; /* skip 'WAVE' */
200 m
= get32(ptr
+ 4); /* chunk length */
201 if(m
> n
- 8) goto out
; /* truncated */
202 if(!strncmp((char *)ptr
, "fmt ", 4)) {
203 if(samples_per_second
) goto out
; /* duplicate format chunk! */
204 n_channels
= get16(ptr
+ 0x0a);
205 samples_per_second
= get32(ptr
+ 0x0c);
206 bits_per_sample
= get16(ptr
+ 0x16);
207 if(!samples_per_second
) goto out
; /* bogus! */
208 } else if(!strncmp((char *)ptr
, "data", 4)) {
209 if(data_bytes
) goto out
; /* multiple data chunks! */
210 data_bytes
= m
; /* remember data size */
212 m
+= 8; /* include chunk header */
213 ptr
+= m
; /* skip chunk */
216 sample_point_size
= (bits_per_sample
+ 7) / 8;
217 sample_frame_size
= sample_point_size
* n_channels
;
218 if(!sample_frame_size
) goto out
; /* bogus or overflow */
219 n_samples
= data_bytes
/ sample_frame_size
;
220 duration
= (n_samples
+ samples_per_second
- 1) / samples_per_second
;
222 munmap(base
, length
);
226 static const struct {
228 long (*fn
)(const char *path
);
237 #define N_FILE_FORMATS (int)(sizeof file_formats / sizeof *file_formats)
239 long disorder_tracklength(const char attribute((unused
)) *track
,
241 const char *ext
= strrchr(path
, '.');
242 int l
, r
, m
= 0, c
= 0; /* quieten compiler */
246 r
= N_FILE_FORMATS
- 1;
247 while(l
<= r
&& (c
= strcmp(ext
, file_formats
[m
= (l
+ r
) / 2].ext
)))
253 return file_formats
[m
].fn(path
);
265 /* arch-tag:fb794bf679375f55bf26fbb7a96a39de */