139 lines
3.0 KiB
C
139 lines
3.0 KiB
C
#include "coding.h"
|
|
#include "ice_decoder_icelib.h"
|
|
|
|
|
|
typedef struct {
|
|
STREAMFILE* sf;
|
|
int offset;
|
|
} icelib_io_t;
|
|
|
|
struct ice_codec_data {
|
|
STREAMFILE* sf;
|
|
int channels;
|
|
icesnd_handle_t* ctx;
|
|
icelib_io_t io;
|
|
};
|
|
|
|
static void icelib_set_callbacks(icesnd_callback_t* cb, STREAMFILE* sf, icelib_io_t* io);
|
|
|
|
ice_codec_data* init_ice(STREAMFILE* sf, int subsong) {
|
|
ice_codec_data* data = NULL;
|
|
|
|
data = calloc(1, sizeof(ice_codec_data));
|
|
if (!data) goto fail;
|
|
|
|
data->sf = reopen_streamfile(sf, 0);
|
|
if (!data->sf) goto fail;
|
|
|
|
{
|
|
icesnd_callback_t cb = {0};
|
|
icesnd_info_t info = {0};
|
|
int err;
|
|
|
|
icelib_set_callbacks(&cb, data->sf, &data->io);
|
|
|
|
data->ctx = icesnd_init(subsong, &cb);
|
|
if (!data->ctx) goto fail;
|
|
|
|
err = icesnd_info(data->ctx, &info);
|
|
if (err < ICESND_RESULT_OK) goto fail;
|
|
|
|
data->channels = info.channels;
|
|
}
|
|
|
|
return data;
|
|
fail:
|
|
free_ice(data);
|
|
return NULL;
|
|
}
|
|
|
|
void decode_ice(ice_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
|
|
int channels = data->channels;
|
|
|
|
while (samples_to_do > 0) {
|
|
int done = icesnd_decode(data->ctx, outbuf, samples_to_do);
|
|
if (done <= 0) goto decode_fail;
|
|
|
|
outbuf += done * channels;
|
|
samples_to_do -= done;
|
|
}
|
|
|
|
return;
|
|
|
|
decode_fail:
|
|
VGM_LOG("ICE: decode error\n");
|
|
memset(outbuf, 0, samples_to_do * channels * sizeof(sample_t));
|
|
}
|
|
|
|
void reset_ice(ice_codec_data* data) {
|
|
if (!data) return;
|
|
|
|
icesnd_reset(data->ctx, 0);
|
|
}
|
|
|
|
void seek_ice(ice_codec_data* data, int32_t num_sample) {
|
|
if (!data) return;
|
|
|
|
//todo discard (this should only be called when looping)
|
|
icesnd_reset(data->ctx, 1);
|
|
}
|
|
|
|
void free_ice(ice_codec_data* data) {
|
|
if (!data) return;
|
|
|
|
close_streamfile(data->sf);
|
|
icesnd_free(data->ctx);
|
|
free(data);
|
|
}
|
|
|
|
/* ************************* */
|
|
|
|
static int icelib_read(void* dst, int size, int n, void* arg) {
|
|
icelib_io_t* io = arg;
|
|
int bytes_read, items_read;
|
|
|
|
bytes_read = read_streamfile(dst, io->offset, size * n, io->sf);
|
|
items_read = bytes_read / size;
|
|
io->offset += bytes_read;
|
|
|
|
return items_read;
|
|
}
|
|
|
|
static int icelib_seek(void* arg, int offset, int whence) {
|
|
icelib_io_t* io = arg;
|
|
int base_offset, new_offset;
|
|
|
|
switch (whence) {
|
|
case ICESND_SEEK_SET:
|
|
base_offset = 0;
|
|
break;
|
|
case ICESND_SEEK_CUR:
|
|
base_offset = io->offset;
|
|
break;
|
|
case ICESND_SEEK_END:
|
|
base_offset = get_streamfile_size(io->sf);
|
|
break;
|
|
default:
|
|
return -1;
|
|
break;
|
|
}
|
|
|
|
new_offset = base_offset + offset;
|
|
if (new_offset < 0 /*|| new_offset > get_streamfile_size(config->sf)*/) {
|
|
return -1; /* unseekable */
|
|
}
|
|
else {
|
|
io->offset = new_offset;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void icelib_set_callbacks(icesnd_callback_t* cb, STREAMFILE* sf, icelib_io_t* io) {
|
|
io->offset = 0;
|
|
io->sf = sf;
|
|
|
|
cb->arg = io;
|
|
cb->read = icelib_read;
|
|
cb->seek = icelib_seek;
|
|
}
|