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
29 #include <sys/types.h>
33 unsigned int pcm_start
;
34 unsigned int pcm_size
;
37 /* size of one second of data */
38 unsigned int sec_size
;
41 static int read_chunk_header(int fd
, const char *name
, unsigned int *size
)
46 rc
= read_all(fd
, buf
, 8);
48 return -IP_ERROR_ERRNO
;
50 return -IP_ERROR_FILE_FORMAT
;
51 *size
= read_le32(buf
+ 4);
52 if (memcmp(buf
, name
, 4))
53 return -IP_ERROR_FILE_FORMAT
;
57 static int find_chunk(int fd
, const char *name
, unsigned int *size
)
62 rc
= read_chunk_header(fd
, name
, size
);
65 if (rc
!= -IP_ERROR_FILE_FORMAT
)
67 d_print("seeking %d\n", *size
);
68 if (lseek(fd
, *size
, SEEK_CUR
) == -1) {
69 d_print("seek failed\n");
70 return -IP_ERROR_ERRNO
;
75 static int wav_open(struct input_plugin_data
*ip_data
)
77 struct wav_private
*priv
;
81 unsigned int riff_size
, fmt_size
;
84 d_print("file: %s\n", ip_data
->filename
);
85 priv
= xnew(struct wav_private
, 1);
86 ip_data
->private = priv
;
87 rc
= read_chunk_header(ip_data
->fd
, "RIFF", &riff_size
);
90 rc
= read_all(ip_data
->fd
, buf
, 4);
95 if (rc
!= 4 || memcmp(buf
, "WAVE", 4) != 0) {
96 rc
= -IP_ERROR_FILE_FORMAT
;
100 rc
= find_chunk(ip_data
->fd
, "fmt ", &fmt_size
);
104 d_print("size of \"fmt \" chunk is invalid (%d)\n", fmt_size
);
105 rc
= -IP_ERROR_FILE_FORMAT
;
108 fmt
= xnew(char, fmt_size
);
109 rc
= read_all(ip_data
->fd
, fmt
, fmt_size
);
114 rc
= -IP_ERROR_ERRNO
;
117 if (rc
!= fmt_size
) {
121 rc
= -IP_ERROR_FILE_FORMAT
;
125 int format_tag
, channels
, rate
, bits
;
127 format_tag
= read_le16(fmt
+ 0);
128 channels
= read_le16(fmt
+ 2);
129 rate
= read_le32(fmt
+ 4);
130 /* 4 bytes, bytes per second */
131 /* 2 bytes, bytes per sample */
132 bits
= read_le16(fmt
+ 14);
135 if (format_tag
!= 1) {
136 d_print("invalid format tag %d, should be 1\n", format_tag
);
137 rc
= -IP_ERROR_FILE_FORMAT
;
140 if ((bits
!= 8 && bits
!= 16) || channels
< 1 || channels
> 2) {
141 rc
= -IP_ERROR_SAMPLE_FORMAT
;
144 ip_data
->sf
= sf_channels(channels
) | sf_rate(rate
) | sf_bits(bits
) |
148 rc
= find_chunk(ip_data
->fd
, "data", &priv
->pcm_size
);
151 rc
= lseek(ip_data
->fd
, 0, SEEK_CUR
);
153 rc
= -IP_ERROR_ERRNO
;
156 priv
->pcm_start
= rc
;
158 priv
->sec_size
= sf_get_second_size(ip_data
->sf
);
161 d_print("pcm start: %u\n", priv
->pcm_start
);
162 d_print("pcm size: %u\n", priv
->pcm_size
);
164 d_print("sr: %d, ch: %d, bits: %d, signed: %d\n", sf_get_rate(ip_data
->sf
),
165 sf_get_channels(ip_data
->sf
), sf_get_bits(ip_data
->sf
),
166 sf_get_signed(ip_data
->sf
));
168 /* clamp pcm_size to full frames (file might be corrupt or truncated) */
169 priv
->pcm_size
= priv
->pcm_size
& ~((unsigned int)sf_get_frame_size(ip_data
->sf
) - 1U);
178 static int wav_close(struct input_plugin_data
*ip_data
)
180 struct wav_private
*priv
;
182 priv
= ip_data
->private;
184 ip_data
->private = NULL
;
188 static int wav_read(struct input_plugin_data
*ip_data
, char *buffer
, int _count
)
190 struct wav_private
*priv
= ip_data
->private;
191 unsigned int count
= _count
;
194 if (priv
->pos
== priv
->pcm_size
) {
198 if (count
> priv
->pcm_size
- priv
->pos
)
199 count
= priv
->pcm_size
- priv
->pos
;
200 rc
= read(ip_data
->fd
, buffer
, count
);
202 d_print("read error\n");
203 return -IP_ERROR_ERRNO
;
213 static int wav_seek(struct input_plugin_data
*ip_data
, double _offset
)
215 struct wav_private
*priv
= ip_data
->private;
219 offset
= (unsigned int)(_offset
* (double)priv
->sec_size
+ 0.5);
220 /* align to 4 bytes (2 * 16 / 8) */
223 rc
= lseek(ip_data
->fd
, priv
->pcm_start
+ offset
, SEEK_SET
);
229 static int wav_read_comments(struct input_plugin_data
*ip_data
,
230 struct keyval
**comments
)
232 *comments
= xnew0(struct keyval
, 1);
236 static int wav_duration(struct input_plugin_data
*ip_data
)
238 struct wav_private
*priv
;
241 priv
= ip_data
->private;
242 duration
= priv
->pcm_size
/ priv
->sec_size
;
246 const struct input_plugin_ops ip_ops
= {
251 .read_comments
= wav_read_comments
,
252 .duration
= wav_duration
255 const char * const ip_extensions
[] = { "wav", NULL
};
256 const char * const ip_mime_types
[] = { NULL
};