2 * Copyright 2007 Johannes Weißl
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
24 #include "read_wrapper.h"
28 #include <wavpack/wavpack.h>
32 #include <sys/types.h>
37 #define WV_CHANNEL_MAX 2
39 struct wavpack_private
{
42 int32_t samples
[CHUNK_SIZE
* WV_CHANNEL_MAX
];
45 /* http://www.wavpack.com/lib_use.txt */
47 static int32_t read_bytes(void *data
, void *ptr
, int32_t count
)
49 struct input_plugin_data
*ip_data
= data
;
52 rc
= read_wrapper(ip_data
, ptr
, count
);
54 d_print("error: %s\n", strerror(errno
));
64 static uint32_t get_pos(void *data
)
66 struct input_plugin_data
*ip_data
= data
;
68 return lseek(ip_data
->fd
, 0, SEEK_CUR
);
71 static int set_pos_abs(void *data
, uint32_t pos
)
73 struct input_plugin_data
*ip_data
= data
;
75 lseek(ip_data
->fd
, pos
, SEEK_SET
);
79 static int set_pos_rel(void *data
, int32_t delta
, int mode
)
81 struct input_plugin_data
*ip_data
= data
;
83 lseek(ip_data
->fd
, delta
, mode
);
87 static int push_back_byte(void *data
, int c
)
90 d_print("NOT POSSIBLE\n");
94 static uint32_t get_length(void *data
)
96 struct input_plugin_data
*ip_data
= data
;
97 struct wavpack_private
*priv
= ip_data
->private;
101 static int can_seek(void *data
)
103 struct input_plugin_data
*ip_data
= data
;
104 return !ip_data
->remote
;
107 static int32_t write_bytes(void *data
, void *ptr
, int32_t count
)
109 /* we shall not write any bytes */
116 * int32_t (*read_bytes)(void *id, void *data, int32_t bcount);
117 * uint32_t (*get_pos)(void *id);
118 * int (*set_pos_abs)(void *id, uint32_t pos);
119 * int (*set_pos_rel)(void *id, int32_t delta, int mode);
120 * int (*push_back_byte)(void *id, int c);
121 * uint32_t (*get_length)(void *id);
122 * int (*can_seek)(void *id);
124 * // this callback is for writing edited tags only
125 * int32_t (*write_bytes)(void *id, void *data, int32_t bcount);
126 * } WavpackStreamReader;
128 static WavpackStreamReader callbacks
= {
129 .read_bytes
= read_bytes
,
131 .set_pos_abs
= set_pos_abs
,
132 .set_pos_rel
= set_pos_rel
,
133 .push_back_byte
= push_back_byte
,
134 .get_length
= get_length
,
135 .can_seek
= can_seek
,
136 .write_bytes
= write_bytes
139 static int wavpack_open(struct input_plugin_data
*ip_data
)
141 struct wavpack_private
*priv
;
145 priv
= xnew(struct wavpack_private
, 1);
148 if (!ip_data
->remote
&& !fstat(ip_data
->fd
, &st
))
149 priv
->len
= st
.st_size
;
150 ip_data
->private = priv
;
154 priv
->wpc
= WavpackOpenFileInputEx(&callbacks
, ip_data
, NULL
, msg
,
155 OPEN_2CH_MAX
| OPEN_NORMALIZE
, 0);
158 d_print("WavpackOpenFileInputEx failed: %s\n", msg
);
160 return -IP_ERROR_FILE_FORMAT
;
163 ip_data
->sf
= sf_rate(WavpackGetSampleRate(priv
->wpc
))
164 | sf_channels(WavpackGetReducedChannels(priv
->wpc
))
165 | sf_bits(WavpackGetBitsPerSample(priv
->wpc
))
170 static int wavpack_close(struct input_plugin_data
*ip_data
)
172 struct wavpack_private
*priv
;
174 priv
= ip_data
->private;
175 priv
->wpc
= WavpackCloseFile(priv
->wpc
);
177 ip_data
->private = NULL
;
181 /* from wv_engine.cpp (C) 2006 by Peter Lemenkov <lemenkov@newmail.ru> */
182 static char *format_samples(int bps
, char *dst
, int32_t *src
, uint32_t count
)
189 *dst
++ = *src
++ + 128;
193 *dst
++ = (char) (temp
= *src
++);
194 *dst
++ = (char) (temp
>> 8);
199 *dst
++ = (char) (temp
= *src
++);
200 *dst
++ = (char) (temp
>> 8);
201 *dst
++ = (char) (temp
>> 16);
206 *dst
++ = (char) (temp
= *src
++);
207 *dst
++ = (char) (temp
>> 8);
208 *dst
++ = (char) (temp
>> 16);
209 *dst
++ = (char) (temp
>> 24);
217 static int wavpack_read(struct input_plugin_data
*ip_data
, char *buffer
, int count
)
219 struct wavpack_private
*priv
;
220 int rc
, bps
, sample_count
, channels
;
222 priv
= ip_data
->private;
223 channels
= sf_get_channels(ip_data
->sf
);
224 bps
= WavpackGetBytesPerSample(priv
->wpc
);
226 sample_count
= count
/ bps
;
228 rc
= WavpackUnpackSamples(priv
->wpc
, priv
->samples
, sample_count
/ channels
);
229 format_samples(bps
, buffer
, priv
->samples
, rc
* channels
);
230 return rc
* channels
* bps
;
233 static int wavpack_seek(struct input_plugin_data
*ip_data
, double offset
)
235 struct wavpack_private
*priv
= ip_data
->private;
237 if (!WavpackSeekSample(priv
->wpc
, WavpackGetSampleRate(priv
->wpc
) * offset
))
238 return -IP_ERROR_INTERNAL
;
242 static int wavpack_read_comments(struct input_plugin_data
*ip_data
,
243 struct keyval
**comments
)
250 fd
= open(ip_data
->filename
, O_RDONLY
);
253 d_print("filename: %s\n", ip_data
->filename
);
256 rc
= id3_read_tags(&id3
, fd
, ID3_V1
);
262 d_print("error: %s\n", strerror(errno
));
265 d_print("corrupted tag?\n");
269 for (i
= 0; i
< NUM_ID3_KEYS
; i
++) {
270 char *val
= id3_get_comment(&id3
, i
);
272 comments_add(&c
, id3_key_names
[i
], val
);
278 rc
= ape_read_tags(&ape
, ip_data
->fd
, 1);
282 for (i
= 0; i
< rc
; i
++) {
284 k
= ape_get_comment(&ape
, &v
);
287 comments_add(&c
, k
, v
);
294 comments_terminate(&c
);
295 *comments
= c
.comments
;
299 static int wavpack_duration(struct input_plugin_data
*ip_data
)
301 struct wavpack_private
*priv
;
304 priv
= ip_data
->private;
305 duration
= WavpackGetNumSamples(priv
->wpc
) /
306 WavpackGetSampleRate(priv
->wpc
);
311 const struct input_plugin_ops ip_ops
= {
312 .open
= wavpack_open
,
313 .close
= wavpack_close
,
314 .read
= wavpack_read
,
315 .seek
= wavpack_seek
,
316 .read_comments
= wavpack_read_comments
,
317 .duration
= wavpack_duration
320 const char * const ip_extensions
[] = { "wv", NULL
};
321 const char * const ip_mime_types
[] = { "audio/x-wavpack", NULL
};