2 * Copyright 2006 Chun-Yu Shei <cshei AT cs.indiana.edu>
4 * Cleaned up by Timo Hirvonen <tihirvon@gmail.com>
12 #include "read_wrapper.h"
14 #include <mpcdec/mpcdec.h>
30 * the api doc says this is pcm samples per mpc frame
31 * but it's really pcm _frames_ per mpc frame
32 * MPC_FRAME_LENGTH = 36 * 32 (1152)
34 * this is wrong, it should be 2 * MPC_FRAME_LENGTH (2304)
35 * MPC_DECODER_BUFFER_LENGTH = 4 * MPC_FRAME_LENGTH (4608)
37 * use MPC_DECODER_BUFFER_LENGTH just to be sure it works
39 MPC_SAMPLE_FORMAT samples
[MPC_DECODER_BUFFER_LENGTH
];
43 static mpc_int32_t
read_impl(void *data
, void *ptr
, mpc_int32_t size
)
45 struct input_plugin_data
*ip_data
= data
;
48 rc
= read_wrapper(ip_data
, ptr
, size
);
58 static mpc_bool_t
seek_impl(void *data
, mpc_int32_t offset
)
60 struct input_plugin_data
*ip_data
= data
;
63 rc
= lseek(ip_data
->fd
, offset
, SEEK_SET
);
69 static mpc_int32_t
tell_impl(void *data
)
71 struct input_plugin_data
*ip_data
= data
;
73 return lseek(ip_data
->fd
, 0, SEEK_CUR
);
76 static mpc_int32_t
get_size_impl(void *data
)
78 struct input_plugin_data
*ip_data
= data
;
79 struct mpc_private
*priv
= ip_data
->private;
81 return priv
->file_size
;
84 static mpc_bool_t
canseek_impl(void *data
)
86 struct input_plugin_data
*ip_data
= data
;
88 return !ip_data
->remote
;
91 static int mpc_open(struct input_plugin_data
*ip_data
)
93 struct mpc_private
*priv
;
95 priv
= xnew0(struct mpc_private
, 1);
98 if (!ip_data
->remote
) {
99 priv
->file_size
= lseek(ip_data
->fd
, 0, SEEK_END
);
100 lseek(ip_data
->fd
, 0, SEEK_SET
);
103 /* set up an mpc_reader linked to our function implementations */
104 priv
->reader
.read
= read_impl
;
105 priv
->reader
.seek
= seek_impl
;
106 priv
->reader
.tell
= tell_impl
;
107 priv
->reader
.get_size
= get_size_impl
;
108 priv
->reader
.canseek
= canseek_impl
;
109 priv
->reader
.data
= ip_data
;
111 /* must be before mpc_streaminfo_read() */
112 ip_data
->private = priv
;
114 /* read file's streaminfo data */
115 mpc_streaminfo_init(&priv
->info
);
116 if (mpc_streaminfo_read(&priv
->info
, &priv
->reader
) != ERROR_CODE_OK
) {
118 return -IP_ERROR_FILE_FORMAT
;
121 /* instantiate a decoder with our file reader */
122 mpc_decoder_setup(&priv
->decoder
, &priv
->reader
);
123 if (!mpc_decoder_initialize(&priv
->decoder
, &priv
->info
)) {
125 return -IP_ERROR_FILE_FORMAT
;
128 priv
->samples_avail
= 0;
129 priv
->samples_pos
= 0;
131 ip_data
->sf
= sf_rate(priv
->info
.sample_freq
) | sf_channels(priv
->info
.channels
) |
132 sf_bits(16) | sf_signed(1);
136 static int mpc_close(struct input_plugin_data
*ip_data
)
138 struct mpc_private
*priv
= ip_data
->private;
141 ip_data
->private = NULL
;
145 static int scale(struct input_plugin_data
*ip_data
, char *buffer
, int count
)
147 struct mpc_private
*priv
= ip_data
->private;
148 const MPC_SAMPLE_FORMAT
*samples
;
149 const int clip_min
= -1 << (16 - 1);
150 const int clip_max
= (1 << (16 - 1)) - 1;
151 const int float_scale
= 1 << (16 - 1);
154 /* number of bytes to 16-bit samples */
155 sample_count
= count
/ 2;
156 if (sample_count
> priv
->samples_avail
)
157 sample_count
= priv
->samples_avail
;
159 /* scale 32-bit samples to 16-bit */
160 samples
= priv
->samples
+ priv
->samples_pos
;
161 for (i
= 0; i
< sample_count
; i
++) {
164 val
= samples
[i
] * float_scale
;
165 if (val
< clip_min
) {
167 } else if (val
> clip_max
) {
171 buffer
[i
* 2 + 0] = val
& 0xff;
172 buffer
[i
* 2 + 1] = val
>> 8;
175 priv
->samples_pos
+= sample_count
;
176 priv
->samples_avail
-= sample_count
;
177 if (priv
->samples_avail
== 0)
178 priv
->samples_pos
= 0;
180 /* number of 16-bit samples to bytes */
181 return sample_count
* 2;
184 static int mpc_read(struct input_plugin_data
*ip_data
, char *buffer
, int count
)
186 struct mpc_private
*priv
= ip_data
->private;
188 if (priv
->samples_avail
== 0) {
189 uint32_t status
= mpc_decoder_decode(&priv
->decoder
, priv
->samples
, NULL
, NULL
);
191 if (status
== (uint32_t)(-1)) {
193 return -IP_ERROR_ERRNO
;
200 /* status seems to be number of _frames_
201 * the api documentation is wrong
203 priv
->samples_avail
= status
* priv
->info
.channels
;
205 return scale(ip_data
, buffer
, count
);
208 static int mpc_seek(struct input_plugin_data
*ip_data
, double offset
)
210 struct mpc_private
*priv
= ip_data
->private;
212 priv
->samples_pos
= 0;
213 priv
->samples_avail
= 0;
215 if (mpc_decoder_seek_seconds(&priv
->decoder
, offset
))
220 static const char *gain_to_str(int gain
)
223 int b
, a
= gain
/ 100;
230 sprintf(buf
, "%d.%02d", a
, b
);
234 static const char *peak_to_str(unsigned int peak
)
237 sprintf(buf
, "%d.%05d", peak
/ 32767, peak
% 32767);
241 static int mpc_read_comments(struct input_plugin_data
*ip_data
, struct keyval
**comments
)
243 struct mpc_private
*priv
= ip_data
->private;
248 count
= ape_read_tags(&ape
, ip_data
->fd
, 1);
252 for (i
= 0; i
< count
; i
++) {
254 k
= ape_get_comment(&ape
, &v
);
257 comments_add(&c
, k
, v
);
262 if (priv
->info
.gain_title
&& priv
->info
.peak_title
) {
263 comments_add_const(&c
, "replaygain_track_gain", gain_to_str(priv
->info
.gain_title
));
264 comments_add_const(&c
, "replaygain_track_peak", peak_to_str(priv
->info
.peak_title
));
266 if (priv
->info
.gain_album
&& priv
->info
.peak_album
) {
267 comments_add_const(&c
, "replaygain_album_gain", gain_to_str(priv
->info
.gain_album
));
268 comments_add_const(&c
, "replaygain_album_peak", peak_to_str(priv
->info
.peak_album
));
270 comments_terminate(&c
);
272 *comments
= c
.comments
;
277 static int mpc_duration(struct input_plugin_data
*ip_data
)
279 struct mpc_private
*priv
= ip_data
->private;
281 /* priv->info.pcm_samples seems to be number of frames
282 * priv->info.frames is _not_ pcm frames
284 return priv
->info
.pcm_samples
/ priv
->info
.sample_freq
;
287 const struct input_plugin_ops ip_ops
= {
292 .read_comments
= mpc_read_comments
,
293 .duration
= mpc_duration
296 const char *const ip_extensions
[] = { "mpc", "mpp", "mp+", NULL
};
297 const char *const ip_mime_types
[] = { "audio/x-musepack", NULL
};