2 * Copyright 2004-2005 Timo Hirvonen
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU 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
28 #include <sys/types.h>
32 unsigned int pcm_start
;
33 unsigned int pcm_size
;
36 /* size of one second of data */
37 unsigned int sec_size
;
40 static inline unsigned short read_u2(const char *buffer
)
42 const unsigned char *buf
= (const unsigned char *)buffer
;
44 return buf
[0] + (buf
[1] << 8);
47 static inline unsigned int read_u4(const char *buffer
)
49 const unsigned char *buf
= (const unsigned char *)buffer
;
51 return buf
[0] + (buf
[1] << 8) + (buf
[2] << 16) + (buf
[3] << 24);
54 static int read_chunk_header(int fd
, const char *name
, unsigned int *size
)
59 rc
= read_all(fd
, buf
, 8);
61 return -IP_ERROR_ERRNO
;
63 return -IP_ERROR_FILE_FORMAT
;
64 *size
= read_u4(buf
+ 4);
65 if (memcmp(buf
, name
, 4))
66 return -IP_ERROR_FILE_FORMAT
;
70 static int find_chunk(int fd
, const char *name
, unsigned int *size
)
75 rc
= read_chunk_header(fd
, name
, size
);
78 if (rc
!= -IP_ERROR_FILE_FORMAT
)
80 d_print("seeking %d\n", *size
);
81 if (lseek(fd
, *size
, SEEK_CUR
) == -1) {
82 d_print("seek failed\n");
83 return -IP_ERROR_ERRNO
;
88 static int wav_open(struct input_plugin_data
*ip_data
)
90 struct wav_private
*priv
;
94 unsigned int riff_size
, fmt_size
;
97 d_print("file: %s\n", ip_data
->filename
);
98 priv
= xnew(struct wav_private
, 1);
99 ip_data
->private = priv
;
100 rc
= read_chunk_header(ip_data
->fd
, "RIFF", &riff_size
);
103 rc
= read_all(ip_data
->fd
, buf
, 4);
105 rc
= -IP_ERROR_ERRNO
;
108 if (rc
!= 4 || memcmp(buf
, "WAVE", 4) != 0) {
109 rc
= -IP_ERROR_FILE_FORMAT
;
113 rc
= find_chunk(ip_data
->fd
, "fmt ", &fmt_size
);
117 d_print("size of \"fmt \" chunk is invalid (%d)\n", fmt_size
);
118 rc
= -IP_ERROR_FILE_FORMAT
;
121 fmt
= xnew(char, fmt_size
);
122 rc
= read_all(ip_data
->fd
, fmt
, fmt_size
);
127 rc
= -IP_ERROR_ERRNO
;
130 if (rc
!= fmt_size
) {
134 rc
= -IP_ERROR_FILE_FORMAT
;
138 int format_tag
, channels
, rate
, bits
;
140 format_tag
= read_u2(fmt
+ 0);
141 channels
= read_u2(fmt
+ 2);
142 rate
= read_u4(fmt
+ 4);
143 /* 4 bytes, bytes per second */
144 /* 2 bytes, bytes per sample */
145 bits
= read_u2(fmt
+ 14);
148 if (format_tag
!= 1) {
149 d_print("invalid format tag %d, should be 1\n", format_tag
);
150 rc
= -IP_ERROR_FILE_FORMAT
;
153 if ((bits
!= 8 && bits
!= 16) || channels
< 1 || channels
> 2) {
154 rc
= -IP_ERROR_SAMPLE_FORMAT
;
157 ip_data
->sf
= sf_channels(channels
) | sf_rate(rate
) | sf_bits(bits
) |
161 rc
= find_chunk(ip_data
->fd
, "data", &priv
->pcm_size
);
164 rc
= lseek(ip_data
->fd
, 0, SEEK_CUR
);
166 rc
= -IP_ERROR_ERRNO
;
169 priv
->pcm_start
= rc
;
171 priv
->sec_size
= sf_get_second_size(ip_data
->sf
);
174 d_print("pcm start: %d\n", priv
->pcm_start
);
175 d_print("pcm size: %d\n", priv
->pcm_size
);
177 d_print("sr: %d, ch: %d, bits: %d, signed: %d\n", sf_get_rate(ip_data
->sf
),
178 sf_get_channels(ip_data
->sf
), sf_get_bits(ip_data
->sf
),
179 sf_get_signed(ip_data
->sf
));
188 static int wav_close(struct input_plugin_data
*ip_data
)
190 struct wav_private
*priv
;
192 priv
= ip_data
->private;
194 ip_data
->private = NULL
;
198 static int wav_read(struct input_plugin_data
*ip_data
, char *buffer
, int count
)
200 struct wav_private
*priv
;
203 priv
= ip_data
->private;
204 if (priv
->pos
== priv
->pcm_size
) {
208 if (count
> priv
->pcm_size
- priv
->pos
)
209 count
= priv
->pcm_size
- priv
->pos
;
210 rc
= read(ip_data
->fd
, buffer
, count
);
212 d_print("read error\n");
213 return -IP_ERROR_ERRNO
;
223 static int wav_seek(struct input_plugin_data
*ip_data
, double _offset
)
225 struct wav_private
*priv
;
228 priv
= ip_data
->private;
229 offset
= (int)(_offset
* (double)priv
->sec_size
+ 0.5);
230 /* aling to 4 bytes (2 * 16 / 8) */
231 offset
-= offset
% 4;
233 rc
= lseek(ip_data
->fd
, priv
->pcm_start
+ offset
, SEEK_SET
);
239 static int wav_read_comments(struct input_plugin_data
*ip_data
,
240 struct keyval
**comments
)
242 *comments
= xnew0(struct keyval
, 1);
246 static int wav_duration(struct input_plugin_data
*ip_data
)
248 struct wav_private
*priv
;
251 priv
= ip_data
->private;
252 duration
= priv
->pcm_size
/ priv
->sec_size
;
256 const struct input_plugin_ops ip_ops
= {
261 .read_comments
= wav_read_comments
,
262 .duration
= wav_duration
265 const char * const ip_extensions
[] = { "wav", NULL
};
266 const char * const ip_mime_types
[] = { NULL
};