/* * Copyright 2014 Boris Timofeev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include "../comment.h" #include "../debug.h" #include "../ip.h" #include "../utils.h" #include "../xmalloc.h" #include #include struct vtx_private { ayemu_ay_t ay; ayemu_ay_reg_frame_t regs; ayemu_vtx_t *vtx; int pos; int left; }; static const int sample_rate = 44100; static const int channels = 2; static const int bits = 16; static int vtx_open(struct input_plugin_data *ip_data) { struct vtx_private *priv; priv = xnew(struct vtx_private, 1); ip_data->private = priv; priv->vtx = ayemu_vtx_load_from_file(ip_data->filename); if (!priv->vtx) { d_print("error: failed to open file %s\n", ip_data->filename); free(priv); return -IP_ERROR_INTERNAL; } ayemu_init(&priv->ay); ayemu_set_sound_format(&priv->ay, sample_rate, channels, bits); ayemu_set_chip_type(&priv->ay, priv->vtx->chiptype, NULL); ayemu_set_chip_freq(&priv->ay, priv->vtx->chipFreq); ayemu_set_stereo(&priv->ay, priv->vtx->stereo, NULL); ip_data->sf = sf_bits(bits) | sf_rate(sample_rate) | sf_channels(channels) | sf_signed(1); ip_data->sf |= sf_host_endian(); channel_map_init_stereo(ip_data->channel_map); priv->pos = 0; priv->left = 0; return 0; } static int vtx_close(struct input_plugin_data *ip_data) { struct vtx_private *priv = ip_data->private; ayemu_vtx_free(priv->vtx); free(priv); ip_data->private = NULL; return 0; } static int vtx_read(struct input_plugin_data *ip_data, char *buffer, int count) { struct vtx_private *priv = ip_data->private; int need = count; int donow = 0; while (need > 0) { if (priv->left > 0) { donow = min_i(need, priv->left); buffer = ayemu_gen_sound(&priv->ay, (char *)buffer, donow); priv->left -= donow; need -= donow; } else { if (priv->pos >= priv->vtx->frames) return 0; ayemu_vtx_getframe(priv->vtx, priv->pos++, priv->regs); ayemu_set_regs(&priv->ay, priv->regs); priv->left = (sample_rate / priv->vtx->playerFreq) * (channels * bits / 8); } } return count; } static int vtx_seek(struct input_plugin_data *ip_data, double offset) { struct vtx_private *priv = ip_data->private; int sample = sample_rate * offset; int samples_per_frame = sample_rate / priv->vtx->playerFreq; priv->pos = sample / samples_per_frame; if (priv->pos >= priv->vtx->frames) { return 0; } ayemu_vtx_getframe(priv->vtx, priv->pos, priv->regs); priv->left = samples_per_frame - (sample % samples_per_frame); return 0; } static int vtx_read_comments(struct input_plugin_data *ip_data, struct keyval **comments) { struct vtx_private *priv = ip_data->private; GROWING_KEYVALS(c); const char *str; str = priv->vtx->author; if (str && str[0]) comments_add_const(&c, "artist", str); str = priv->vtx->from; if (str && str[0]) comments_add_const(&c, "album", str); str = priv->vtx->title; if (str && str[0]) comments_add_const(&c, "title", str); int year = priv->vtx->year; if (year > 0) { char buf[16] = {0}; snprintf(buf, sizeof buf, "%d", year); comments_add_const(&c, "date", buf); } str = priv->vtx->comment; if (str && str[0]) comments_add_const(&c, "comment", str); keyvals_terminate(&c); *comments = c.keyvals; return 0; } static int vtx_duration(struct input_plugin_data *ip_data) { struct vtx_private *priv = ip_data->private; return (int)(priv->vtx->frames / priv->vtx->playerFreq); } static long vtx_bitrate(struct input_plugin_data *ip_data) { return -IP_ERROR_FUNCTION_NOT_SUPPORTED; } static long vtx_current_bitrate(struct input_plugin_data *ip_data) { return -IP_ERROR_FUNCTION_NOT_SUPPORTED; } static char *vtx_codec(struct input_plugin_data *ip_data) { return xstrdup("vtx"); } static char *vtx_codec_profile(struct input_plugin_data *ip_data) { return NULL; } const struct input_plugin_ops ip_ops = { .open = vtx_open, .close = vtx_close, .read = vtx_read, .seek = vtx_seek, .read_comments = vtx_read_comments, .duration = vtx_duration, .bitrate = vtx_bitrate, .bitrate_current = vtx_current_bitrate, .codec = vtx_codec, .codec_profile = vtx_codec_profile }; const int ip_priority = 50; const char * const ip_extensions[] = {"vtx", NULL}; const char * const ip_mime_types[] = { NULL }; const struct input_plugin_opt ip_options[] = { { NULL } }; const unsigned ip_abi_version = IP_ABI_VERSION;