diff options
author | waker <wakeroid@gmail.com> | 2010-12-05 16:06:29 +0100 |
---|---|---|
committer | waker <wakeroid@gmail.com> | 2010-12-05 16:06:29 +0100 |
commit | 4a04da22d9faf432962e98dbc8dae2e3df9b16c3 (patch) | |
tree | 8a43fa66cace8de729d4c8bcaa95d23a684c6174 /plugins | |
parent | ad085a1661d4a46eefb4a8d7359ea1b58bf8cc08 (diff) |
added UADE2 plugin
Diffstat (limited to 'plugins')
62 files changed, 12457 insertions, 0 deletions
diff --git a/plugins/ddb_input_uade2/plugin.c b/plugins/ddb_input_uade2/plugin.c new file mode 100644 index 00000000..72919783 --- /dev/null +++ b/plugins/ddb_input_uade2/plugin.c @@ -0,0 +1,692 @@ +/* + ddb_input_uade2 - UADE input plugin for DeaDBeeF player + Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net> + based on UADE2 plugin for Audacious, Copyright (C) 2005-2006 Heikki Orsila, UADE TEAM + + 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <signal.h> +#include "../../deadbeef.h" +#include "uadeipc.h" +#include "eagleplayer.h" +#include "uadeconfig.h" +#include "uadecontrol.h" +#include "uadeconstants.h" +#include "ossupport.h" +#include "uadeconf.h" +#include "effects.h" +#include "sysincludes.h" +#include "songdb.h" +#include "songinfo.h" + +#define min(x,y) ((x)<(y)?(x):(y)) +#define max(x,y) ((x)>(y)?(x):(y)) + +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) + +static char configname[PATH_MAX]; +static struct uade_config config_backup; +static time_t config_load_time; +static time_t md5_load_time; +static char md5name[PATH_MAX]; +static char songconfname[PATH_MAX]; +static char gui_filename[PATH_MAX]; + +static const char * +get_uade_base_conf_dir (void) { + return UADE_CONFIG_BASE_DIR; +} + +static void load_content_db(void) +{ + struct stat st; + time_t curtime = time(NULL); + char name[PATH_MAX]; + + if (curtime) + md5_load_time = curtime; + + if (md5name[0] == 0) { + char *home = uade_open_create_home(); + if (home) + snprintf(md5name, sizeof md5name, "%s/.uade2/contentdb", home); + } + + /* User database has priority over global database, so we read it first */ + if (md5name[0]) { + if (stat(md5name, &st) == 0) { + if (uade_read_content_db(md5name)) + return; + } else { + FILE *f = fopen(md5name, "w"); + if (f) + fclose(f); + uade_read_content_db(md5name); + } + } + + snprintf(name, sizeof name, "%s/contentdb.conf", get_uade_base_conf_dir ()); + if (stat(name, &st) == 0) + uade_read_content_db(name); +} + +/* xmms initializes uade by calling this function */ +static void uade_init(void) +{ + static int initialized = 0; + if (!initialized) { + char *home; + int config_loaded; + + config_load_time = time(NULL); + + config_loaded = uade_load_initial_config(configname, sizeof configname, + &config_backup, NULL); + + load_content_db(); + + uade_load_initial_song_conf(songconfname, sizeof songconfname, + &config_backup, NULL); + + home = uade_open_create_home(); + + if (home != NULL) { + /* If config exists in home, ignore global uade.conf. */ + snprintf(configname, sizeof configname, "%s/.uade2/uade.conf", home); + } + + if (config_loaded == 0) { + fprintf(stderr, "No config file found for UADE XMMS plugin. Will try to load config from\n"); + fprintf(stderr, "$HOME/.uade2/uade.conf in the future.\n"); + } + initialized = 1; + } +} + +static void uade_get_song_info(const char *filename, char **title, int *length) +{ + char tempname[PATH_MAX]; + const char *t; + + if (strncmp(filename, "uade://", 7) == 0) + filename += 7; + + strlcpy(tempname, filename, sizeof tempname); + t = basename(tempname); + if (t == NULL) + t = filename; + if ((*title = strdup(t)) == NULL) + trace("Not enough memory for song info.\n"); + *length = -1; +} + +int uade_get_max_subsong(struct uade_state *state, int def) +{ + int subsong; + subsong = -1; + if (state->song != NULL) + subsong = state->song->max_subsong; + if (subsong == -1) + subsong = def; + return subsong; +} + + +int uade_get_min_subsong(struct uade_state *state, int def) +{ + int subsong; + subsong = -1; + if (state->song != NULL) + subsong = state->song->min_subsong; + if (subsong == -1) + subsong = def; + return subsong; +} + +DB_functions_t *deadbeef; +static DB_decoder_t plugin; + +static const char *exts[] = { NULL }; +static const char *prefixes[] = { "mod", NULL }; +static const char *filetypes[] = { "UADE", NULL }; + +#define UADE_BUFFER_SIZE 100000 + +typedef struct { + DB_fileinfo_t info; + struct uade_state state; + int controlstate; + int record_playtime; + int remaining; + char buffer[UADE_BUFFER_SIZE]; + int subsong_end; + int song_end_trigger; + int64_t skip_bytes; + int abort_playing; + int uade_seek_forward; +} uade_info_t; + +DB_fileinfo_t * +uadeplug_open (uint32_t hints) { + DB_fileinfo_t *_info = malloc (sizeof (uade_info_t)); + uade_info_t *info = (uade_info_t *)_info; + memset (info, 0, sizeof (uade_info_t)); + return _info; +} + +static int +uadeplug_init (DB_fileinfo_t *_info, DB_playItem_t *it) { + uade_info_t *info = (uade_info_t *)_info; + + uade_init (); + char modulename[PATH_MAX]; + char playername[PATH_MAX]; + char scorename[PATH_MAX]; + char gui_module_filename[PATH_MAX]; + char gui_player_filename[PATH_MAX]; + + info->state.config = config_backup; + info->state.validconfig = 1; + + printf ("probing the file\n"); + int ret = uade_is_our_file(it->fname, 0, &info->state); + + if (!ret) { + trace ("not uade file\n"); + return -1; + } + strlcpy(modulename, it->fname, sizeof modulename); + trace ("modulename: %s\n", modulename); + strlcpy(gui_module_filename, it->fname, sizeof gui_module_filename); + trace ("gui_module_fname: %s\n", gui_module_filename); + + snprintf(scorename, sizeof scorename, "%s/score", get_uade_base_conf_dir ()); + trace ("scorename: %s\n", scorename); + + if (strcmp(info->state.ep->playername, "custom") == 0) { + strlcpy(playername, modulename, sizeof playername); + modulename[0] = 0; + gui_module_filename[0] = 0; + } else { + snprintf(playername, sizeof playername, "%s/players/%s", get_uade_base_conf_dir (), info->state.ep->playername); + } + trace ("playername: %s\n", playername); + + if (!uade_alloc_song(&info->state, it->fname)) { + trace ("uade_alloc_song fail\n"); + return -1; + } + + uade_set_ep_attributes(&info->state); + + uade_set_song_attributes(&info->state, playername, sizeof playername); + + uade_set_effects(&info->state); + + strlcpy(gui_player_filename, playername, sizeof gui_player_filename); + + if (!info->state.pid) { + char configname[PATH_MAX]; + snprintf(configname, sizeof configname, "%s/uaerc", UADE_CONFIG_BASE_DIR); + uade_spawn(&info->state, UADE_CONFIG_UADE_CORE, configname); + } + + printf ("uade_song_initialization\n"); + ret = uade_song_initialization(scorename, playername, modulename, &info->state); + if (ret) { + if (ret != UADECORE_CANT_PLAY && ret != UADECORE_INIT_ERROR) { + fprintf(stderr, "Can not initialize song. Unknown error.\n"); + return -1; + } + uade_unalloc_song(&info->state); + return -1; + } + printf ("init done\n"); + int minsong = uade_get_min_subsong (&info->state, 0); + int maxsong = uade_get_max_subsong (&info->state, 0); + info->state.song->cur_subsong = it->tracknum; + uade_change_subsong(&info->state); + + _info->fmt.bps = 16; + _info->fmt.channels = UADE_CHANNELS; + _info->fmt.samplerate = info->state.config.frequency; + for (int i = 0; i < _info->fmt.channels; i++) { + _info->fmt.channelmask |= 1 << i; + } + _info->readpos = 0; + _info->plugin = &plugin; + info->record_playtime = 1; + info->controlstate = UADE_S_STATE; + + return 0; +} + +// free everything allocated in _init +static void +uadeplug_free (DB_fileinfo_t *_info) { + uade_info_t *info = (uade_info_t *)_info; + if (info) { + uade_unalloc_song(&info->state); + if (info->state.pid) { + kill(info->state.pid, SIGTERM); + } + free (info); + } +} + +int +uadeplug_frame (uade_info_t *info) { + uint8_t space[UADE_MAX_MESSAGE_SIZE]; + struct uade_msg *um = (struct uade_msg *) space; + uint16_t *sm; + int i; + unsigned int play_bytes, tailbytes = 0; + uint64_t subsong_bytes = 0; + int framesize = UADE_CHANNELS * UADE_BYTES_PER_SAMPLE; + int left = 0; + char gui_formatname[256]; + char gui_modulename[256]; + char gui_playername[256]; + char *reason; + uint32_t *u32ptr; + int frame_received = 0; + + while (!frame_received) { + if (info->controlstate == UADE_S_STATE) { + + assert(left == 0); + + if (info->abort_playing) { + info->record_playtime = 0; + break; + } + + if (info->uade_seek_forward) { + info->skip_bytes += info->uade_seek_forward * (UADE_BYTES_PER_FRAME * info->state.config.frequency); + info->uade_seek_forward = 0; + } + + left = uade_read_request(&info->state.ipc); + + if (uade_send_short_message(UADE_COMMAND_TOKEN, &info->state.ipc)) { + fprintf(stderr, "Can not send token.\n"); + return -1; + } + info->controlstate = UADE_R_STATE; + + } else { + + if (uade_receive_message(um, sizeof(space), &info->state.ipc) <= 0) { + fprintf(stderr, "Can not receive events from uade\n"); + exit(-1); + } + + + switch (um->msgtype) { + + case UADE_COMMAND_TOKEN: + info->controlstate = UADE_S_STATE; + break; + + case UADE_REPLY_DATA: + sm = (uint16_t *) um->data; + for (i = 0; i < um->size; i += 2) { + *sm = ntohs(*sm); + sm++; + } + + if (info->subsong_end) { + play_bytes = tailbytes; + tailbytes = 0; + } else { + play_bytes = um->size; + } + + if (info->subsong_end == 0 && info->song_end_trigger == 0 && + uade_test_silence(um->data, play_bytes, &info->state)) { + info->subsong_end = 1; + } + + subsong_bytes += play_bytes; + info->state.song->out_bytes += play_bytes; + + if (info->skip_bytes > 0) { + if (play_bytes <= info->skip_bytes) { + info->skip_bytes -= play_bytes; + play_bytes = 0; + } else { + play_bytes -= info->skip_bytes; + info->skip_bytes = 0; + } + } + + uade_effect_run(&info->state.effects, (int16_t *) um->data, play_bytes / framesize); + + // ... copy data ... + memcpy (info->buffer + info->remaining, um->data, play_bytes); + frame_received = 1; + info->remaining += play_bytes; + + if (info->state.config.timeout != -1 && info->state.config.use_timeouts) { + if (info->song_end_trigger == 0) { + if (info->state.song->out_bytes / (UADE_BYTES_PER_FRAME * info->state.config.frequency) >= info->state.config.timeout) { + info->song_end_trigger = 1; + info->record_playtime = 0; + } + } + } + + if (info->state.config.subsong_timeout != -1 && info->state.config.use_timeouts) { + if (info->subsong_end == 0 && info->song_end_trigger == 0) { + if (subsong_bytes / (UADE_BYTES_PER_FRAME * info->state.config.frequency) >= info->state.config.subsong_timeout) { + info->subsong_end = 1; + info->record_playtime = 0; + } + } + } + + assert (left >= um->size); + left -= um->size; + break; + + case UADE_REPLY_FORMATNAME: + uade_check_fix_string(um, 128); + strlcpy(gui_formatname, (char *) um->data, sizeof gui_formatname); + strlcpy(info->state.song->formatname, (char *) um->data, sizeof info->state.song->formatname); + break; + + case UADE_REPLY_MODULENAME: + uade_check_fix_string(um, 128); + strlcpy(gui_modulename, (char *) um->data, sizeof gui_modulename); + strlcpy(info->state.song->modulename, (char *) um->data, sizeof info->state.song->modulename); + break; + + case UADE_REPLY_MSG: + uade_check_fix_string(um, 128); + trace ("Message: %s\n", (char *) um->data); + break; + + case UADE_REPLY_PLAYERNAME: + uade_check_fix_string(um, 128); + strlcpy(gui_playername, (char *) um->data, sizeof gui_playername); + strlcpy(info->state.song->playername, (char *) um->data, sizeof info->state.song->playername); + break; + + case UADE_REPLY_SONG_END: + if (um->size < 9) { + fprintf(stderr, "Invalid song end reply\n"); + exit(-1); + } + tailbytes = ntohl(((uint32_t *) um->data)[0]); + /* next ntohl() is only there for a principle. it is not useful */ + if (ntohl(((uint32_t *) um->data)[1]) == 0) { + /* normal happy song end. go to next subsong if any */ + info->subsong_end = 1; + } else { + /* unhappy song end (error in the 68k side). skip to next song + ignoring possible subsongs */ + info->song_end_trigger = 1; + } + i = 0; + reason = (char *) &um->data[8]; + while (reason[i] && i < (um->size - 8)) + i++; + if (reason[i] != 0 || (i != (um->size - 9))) { + fprintf(stderr, "Broken reason string with song end notice\n"); + exit(-1); + } + /* fprintf(stderr, "Song end (%s)\n", reason); */ + break; + + case UADE_REPLY_SUBSONG_INFO: + if (um->size != 12) { + fprintf(stderr, "subsong info: too short a message\n"); + exit(-1); + } + u32ptr = (uint32_t *) um->data; + info->state.song->min_subsong = ntohl(u32ptr[0]); + info->state.song->max_subsong = ntohl(u32ptr[1]); + info->state.song->cur_subsong = ntohl(u32ptr[2]); + + if (!(-1 <= info->state.song->min_subsong && info->state.song->min_subsong <= info->state.song->cur_subsong && info->state.song->cur_subsong <= info->state.song->max_subsong)) { + int tempmin = info->state.song->min_subsong, tempmax = info->state.song->max_subsong; + fprintf(stderr, "uade: The player is broken. Subsong info does not match with %s.\n", gui_filename); + info->state.song->min_subsong = tempmin <= tempmax ? tempmin : tempmax; + info->state.song->max_subsong = tempmax >= tempmin ? tempmax : tempmin; + if (info->state.song->cur_subsong > info->state.song->max_subsong) + info->state.song->max_subsong = info->state.song->cur_subsong; + else if (info->state.song->cur_subsong < info->state.song->min_subsong) + info->state.song->min_subsong = info->state.song->cur_subsong; + } + break; + + default: + fprintf(stderr, "Expected sound data. got %d.\n", um->msgtype); + return -1; + } + } + } + return 0; +} + + +// try decode `size' bytes +// return number of decoded bytes +// or 0 on EOF/error +static int +uadeplug_read (DB_fileinfo_t *_info, char *bytes, int size) { + uade_info_t *info = (uade_info_t *)_info; + int samplesize = _info->fmt.channels * _info->fmt.bps / 8; + int initsize = size; + + while (size > 0) { + if (info->remaining) { + int n = min (info->remaining, size); + memcpy (bytes, info->buffer, n); + bytes += n; + size -= n; + if (n < info->remaining) { + memmove (info->buffer, info->buffer + n, info->remaining-n); + info->remaining -= n; + break; + } + info->remaining = 0; + } + + if (uadeplug_frame (info) < 0) { + return initsize-size; + } + } + + _info->readpos += ((initsize-size) / samplesize) / (float)(_info->fmt.samplerate); + return initsize-size; +} + +// seek to specified sample (frame) +// return 0 on success +// return -1 on failure +static int +uadeplug_seek_sample (DB_fileinfo_t *_info, int sample) { + uade_info_t *info = (uade_info_t *)_info; + + _info->readpos = (float)sample / _info->fmt.samplerate; + return 0; +} + +// seek to specified time in seconds +// return 0 on success +// return -1 on failure +static int +uadeplug_seek (DB_fileinfo_t *_info, float time) { + return uadeplug_seek_sample (_info, time * _info->fmt.samplerate); +} + +static DB_playItem_t * +uadeplug_insert (DB_playItem_t *after, const char *fname) { + uade_init (); + + char modulename[PATH_MAX]; + char playername[PATH_MAX]; + char scorename[PATH_MAX]; + char gui_module_filename[PATH_MAX]; + char gui_player_filename[PATH_MAX]; + + struct uade_state state; + memset (&state, 0, sizeof (state)); + state.config = config_backup; + state.validconfig = 1; + + printf ("probing the file\n"); + int ret = uade_is_our_file(fname, 0, &state); + + if (!ret) { + trace ("not uade file\n"); + return NULL; + } + + strlcpy(modulename, fname, sizeof modulename); + trace ("modulename: %s\n", modulename); + strlcpy(gui_module_filename, fname, sizeof gui_module_filename); + trace ("gui_module_fname: %s\n", gui_module_filename); + + snprintf(scorename, sizeof scorename, "%s/score", get_uade_base_conf_dir ()); + trace ("scorename: %s\n", scorename); + + if (strcmp(state.ep->playername, "custom") == 0) { + strlcpy(playername, modulename, sizeof playername); + modulename[0] = 0; + gui_module_filename[0] = 0; + } else { + snprintf(playername, sizeof playername, "%s/players/%s", get_uade_base_conf_dir (), state.ep->playername); + } + trace ("playername: %s\n", playername); + + if (!uade_alloc_song(&state, fname)) { + trace ("uade_alloc_song fail\n"); + return NULL; + } + + uade_set_ep_attributes(&state); + + uade_set_song_attributes(&state, playername, sizeof playername); + + uade_set_effects(&state); + + strlcpy(gui_player_filename, playername, sizeof gui_player_filename); + + if (!state.pid) { + char configname[PATH_MAX]; + snprintf(configname, sizeof configname, "%s/uaerc", UADE_CONFIG_BASE_DIR); + uade_spawn(&state, UADE_CONFIG_UADE_CORE, configname); + } + + printf ("uade_song_initialization\n"); + ret = uade_song_initialization(scorename, playername, modulename, &state); + if (ret) { + if (ret != UADECORE_CANT_PLAY && ret != UADECORE_INIT_ERROR) { + fprintf(stderr, "Can not initialize song. Unknown error.\n"); + return NULL; + } + uade_unalloc_song(&state); + return NULL; + } + printf ("init done\n"); + int minsong = uade_get_min_subsong (&state, 0); + int maxsong = uade_get_max_subsong (&state, 0); + + char info[256]; + int playtime = state.song->playtime; + + /* Hack. Set info text and song length late because we didn't know + subsong amounts before this. Pass zero as a length so that the + graphical play time counter will run but seek is still enabled. + Passing -1 as playtime would disable seeking. */ + if (playtime <= 0) + playtime = 0; + + if (uade_generate_song_title(info, sizeof info, &state)) + strlcpy(info, gui_filename, sizeof info); + +// playhandle->set_params(playhandle, info, playtime, +// UADE_BYTES_PER_FRAME * state.config.frequency, +// state.config.frequency, UADE_CHANNELS); + + + // no cuesheet, prepare track for addition + DB_playItem_t *it = deadbeef->pl_item_alloc (); + it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id); + it->fname = strdup (fname); + it->filetype = filetypes[0]; + float duration = -1; + if (playtime != -1) { + duration = playtime / 1000.f; + } + deadbeef->pl_set_item_duration (it, duration); + + // title is empty, this call will set track title to filename without extension + const char *fn = strrchr (fname, '/'); + if (fn) { + fn++; + } + else { + fn = fname; + } + deadbeef->pl_add_meta (it, "title", info); + + // now the track is ready, insert into playlist + after = deadbeef->pl_insert_item (after, it); + deadbeef->pl_item_unref (it); + uade_unalloc_song(&state); + if (state.pid) { + kill(state.pid, SIGTERM); + } + return after; +} + +// define plugin interface +static DB_decoder_t plugin = { + DB_PLUGIN_SET_API_VERSION + .plugin.version_major = 1, + .plugin.version_minor = 0, + .plugin.type = DB_PLUGIN_DECODER, + .plugin.id = "uade", + .plugin.name = "UADE player", + .plugin.descr = "amiga module player based on UADE (http://zakalwe.fi/uade/)", + .plugin.author = "Alexey Yakovenko", + .plugin.email = "waker@users.sourceforge.net", + .plugin.website = "http://deadbeef.sf.net", + .open = uadeplug_open, + .init = uadeplug_init, + .free = uadeplug_free, + .read = uadeplug_read, + .seek = uadeplug_seek, + .seek_sample = uadeplug_seek_sample, + .insert = uadeplug_insert, + .exts = exts, + .prefixes = prefixes, + .filetypes = filetypes +}; + +DB_plugin_t * +ddb_input_uade2_load (DB_functions_t *api) { + deadbeef = api; + return DB_PLUGIN (&plugin); +} diff --git a/plugins/ddb_input_uade2/uade-2.13/AUTHORS b/plugins/ddb_input_uade2/uade-2.13/AUTHORS new file mode 100644 index 00000000..b1d24130 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/AUTHORS @@ -0,0 +1,59 @@ +Authors of UADE +--------------- + +Main authors +------------ + + - Heikki Orsila <heikki.orsila@iki.fi> + - Michael Doering <mldoering@gmx.net> + +Subsystems +---------- + + - Antti S. Lankila <alankila@bel.fi> for filter emulation and sound effects + - Claudio Matsuoka and Hipolito Carraro Jr for module decruncing code in + uade 1.xy. + jah@fh-zwickau.de for unsqsh + Sipos Attila for unsqsh checksum + Olivier Lapicque for mmcp + Marc Espie (old depack.c) + - Harry "Piru" Sintonen <sintonen@iki.fi> for AmigaOS and MorphOS port + - Martin Blapp for configure fixes and enhancements from FreeBSD project + - Michael S. Baltaks for Mac OS X port + - Nicolas A. Mendoza (part of the AmigaOS port) + - Stuart 'kyzer' Caie for Mac OS X port and powerpacker decruncher + http://www.kyz.uklinux.net + +Everyone from UAE project. See doc/UAE-CREDITS. + +Eagleplayers +------------ + + - Don Adan / Wanted Team + - Eagleeye and Buggs from Defect (Eagleplayer project authors) + - Nicolas Frank <gryzor@club-internet.fr> for PTK-Prowiz + - Andy Silva <silva@psi5.com> for his replayers + - Bartman and Dexter from Abyss for AHX v2 replay routine: + http://www.the-leader-of-the-eighties.de + - Brian Postma <b.postma@hetnet.nl> for Brian's Soundmonitor player + http://www.homepages.hetnet.nl/~brianpostma + - Nicolas Pomared <npomarede@kaptech.com> for MYST/YMST replayer + - Sean Connolly for EMS V6 replay: http://www.cosine-systems.com/ + - Stephen Mifsud (Malta) <teknologik@technologist.com> for Darius Zendeh + replayer. http://www.marz-kreations.com + - Sunbeam/Shelter for his replayers + - Paul v.d. Valk for Medley replay routine + - Tap & Walt for digibooster source + http://www.highantdev2.de/dbpro/index.php + - The Welder / Divine for protracker replay routine + + - Everyone else whose Eagleplayer plugins we use. Respective authors of + eagleplayer plugins can be found from inside the plugin. + +Media +----- + +Manfred Linzner aka Pink/Abyss <linzner@shinen.com> for a great test tune +(AHX.Cruisin). + + diff --git a/plugins/ddb_input_uade2/uade-2.13/COPYING b/plugins/ddb_input_uade2/uade-2.13/COPYING new file mode 100644 index 00000000..d8917caa --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/COPYING @@ -0,0 +1,12 @@ +This source distribution contains works with various licenses. Please read +copyright notices of those works before reuse. + +All the code from the UAE (Unix Amiga Emulator) project is licensed +under the GNU GPL. Read COPYING.GPL for details of the GNU GPL license. +UAE people work is credited in doc/UAE-* files. + +Files under players/ directory are licensed with various different licenses +and quite a many different copyright holders. See inside the player binaries +for more details. + +Sound core in directory amigasrc/score/ is licensed under the GNU LGPL. diff --git a/plugins/ddb_input_uade2/uade-2.13/COPYING.GPL b/plugins/ddb_input_uade2/uade-2.13/COPYING.GPL new file mode 100644 index 00000000..60549be5 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/COPYING.GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/plugins/ddb_input_uade2/uade-2.13/COPYING.LGPL b/plugins/ddb_input_uade2/uade-2.13/COPYING.LGPL new file mode 100644 index 00000000..8add30ad --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/COPYING.LGPL @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/plugins/ddb_input_uade2/uade-2.13/ChangeLog b/plugins/ddb_input_uade2/uade-2.13/ChangeLog new file mode 100644 index 00000000..54a2d409 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/ChangeLog @@ -0,0 +1,1907 @@ + +* ALL THE CHANGE LOG ENTRIES SINCE 2007-05-28 ARE IN THE GIT REPOSITORY. USE + "git log" COMMAND + +2007-05-28 Heikki Orsila <heikki.orsila@iki.fi> + - The development has been moved to a Git repository. Please issue + "git-clone git://zakalwe.fi/uade uade.git" to checkout the latest + version from the repository. + +2007-05-27 Heikki Orsila <heikki.orsila@iki.fi> + - Commit messages into version repository should from now on include + a short tag explaining the nature of the commit. + The tags are: + * [ADAPTIVE] - adaptive maintenance: the commit makes software to + work better with the surrounding environment (compilers, libraries, + path names ...) + * [CORRECTVE] - corrective maintenance: fix a defect in the program + * [PERFECTIVE] - perfective maintenance: used when adding a feature + or improving an existing feature + * [PREVENTIVE] - preventive maintenance: used when refactoring, + cleaning or asserting the code, or adding self-tests + + See http://www.site.uottawa.ca:4321/oose/index.html#maintenance + + - Fixed Audacious plugin to work for Audacious 1.4/2.x + Christian Birchinger <joker@netswarm.net> [ADAPTIVE] [CORRECTIVE] + +2007-05-03 Michael Doering <mld@users.sourceforge.net> + - Added a new version of Synthdream replayer from Don Adan + +2007-04-30 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 2.07 (Walpurgis night) + - Added Special FX ST replayer from Don Adan + - Added a new version of Special FX replayer from Don Adan + - Work-arounded libao/alsa so that it drains the audio device for + the last few milliseconds of sample data for the last played song. + Thanks to Cthulhu for pointing out the problem. + - Many fixes in song length database code + # Fixed a bug that only the last played subsong time was recorded + into the song db + # Fixed a file-locking race condition in song db + # Fixed a song db corruption bug + # Cleaned song db code + - Support for full Drag and Drop/Local URL Support in Audacious 1.3 + plugin + - Fixed misdetection and modlen calculation bug of Soundtracker IV + mods + +2007-04-29 Heikki Orsila <heikki.orsila@iki.fi> + - Added Special FX ST replayer from Don Adan + - Added a new version of Special FX replayer from Don Adan + +2007-04-27 Heikki Orsila <heikki.orsila@iki.fi> + - Work-arounded libao/alsa so that it drains the audio device for + the last few milliseconds of song data for the last played song. + Thanks to Cthulhu for pointing out the problem. + +2007-04-15 Michael Doering <mld@users.sourceforge.net> + - Bug in songlength database handling fixed (shd) + +2007-04-14 Michael Doering <mld@users.sourceforge.net> + - Support for full Drag and Drop/Local URL Support in Audacious 1.3 + plugin. (shd, mld) + - Fixed misdetection and modlen calculation bug of Soundtracker IV + mods. (shd/mld) + +2007-04-09 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 2.06 (7 YEARS BIRTHDAY PARTY AT PAULAS!) + - UADE project is now exactly 7 years old \o/ PARTY! + - Started working for Audacious 1.3 support, at least songs that + are added directly through playlist should work if they are + regular files. Audacious VFS is not supported in general. Nothing + else is guaranteed. Audacious < 1.3 works as in the past. + - Infogrames replayer improved, gobliins 2 et al. play with correct + tempo + - Added new Quartet ST player from Don Adan / Wanted Team + (qts.* files) + - KRIS aka Chip Tracker replayer (KRIS.* files) from Don Adan / + Wanted team. This replaces PTK-Prowiz for Chip Tracker songs, so + not a new format. + - Quartet PSG replayer (SQT.* files) from Don Adan / Wanted Team + - Many small changes, cleanups etc + + - Fixed user installation of Audacious 1.3 plugin... + +2007-03-19 Michael Doering <mld@users.sourceforge.net> + - Merged Christian Birchingers Audacious 1.3.x API Patches in. + +2007-03-03 Heikki Orsila <heikki.orsila@iki.fi> + - KRIS aka Chip Tracker replayer (KRIS.* files) from Don Adan / + Wanted team. This replaces PTK-Prowiz for Chip Tracker songs, so + not a new format. + - Quartet PSG replayer (SQT.* files) from Don Adan / Wanted Team + +2007-02-13 Heikki Orsila <heikki.orsila@iki.fi> + - Updated Inforgrames player to use tempo 0x24ff for Ween songs. + Thanks to DrMcCoy of SCUMM VM project. + - Reverted Michael's 2007-02-13 patch regarding LC_Numeric and + strtod(). Fixed the problem manually by converting x,y values into + x.y format and vice versa. + +2007-02-13 Michael Doering <mld@users.sourceforge.net> + - Fix for German LC_Numeric="," parameters in uadeconfig.c. + Thanks for Steffen Wulf for reporting. + - Bumped Version to 2.05. :-) + +2007-02-08 Michael Doering <mld@users.sourceforge.net> + - Added new Quartet ST player from Don Adan / Wanted Team + (qts.* files). Great work as ever Don! + - Disabled Hippel COSO check in amifilemagic.c to avoid a conflict + between Amiga and Atari ST Coso Files. + TODO: The file heuristics for Coso in amifilemagic.c has to be fixed, + the checkroutine of the Amiga Hippel-Coso replayer isn't HIP-ST Coso + aware either. + +2007-02-06 Michael Doering <mld@users.sourceforge.net> + - Small correction of shd's patch in PTK-Prowiz commited. + +2007-02-05 Michael Doering <mld@users.sourceforge.net> + - Applied shd's uade_new_get_info patch to PTK-Prowiz. + +2007-02-04 Michael Doering <mld@users.sourceforge.net> + - Added sanity check to query eagleopts in PTK-Prowiz (needed for + score fix) + - Added a new uade.library method: UadeNewGetInfo(). It is now used + with Infogrames replayer (see + amigasrc/players/infogrames/Infogrames.asm). It will be used with + PTK-Prowiz soon. Documentation for UadeNewGetInfo() can be read + from amigasrc/score/score.s, see function "uade_new_get_info". + +2007-02-03 Heikki Orsila <heikki.orsila@iki.fi> + - Disassembled Andy Silvas Infogrames replayer, added a work-around + list for Gobliins 2 songs to fix tempo. Thanks to Sven Hesse of + ScummVM project for letting us know of the tempo problem. + The next thing to do is go through all Infogrames games with UAE + and record the tempo value for each song? Any volunteers?-) + +2007-01-30 Michael Doering <mld@users.sourceforge.net> + - Changed Scrollbar policy for audacious modinfo to avoid + ugly line breaking in hexmode + +2007-01-25 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 2.05 (It came from the Paula) + - This release workarounds scheduler features of some 2.6.x Linux + kernels. IPC method was changed to use sockets instead of pipes, + which significantly reduces buffer underruns. This is really the + only change affecting scheduling! Weird. + +2007-01-24 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed compilation for platforms that lack memmem(), such as Mac. + The compilation bug was introduced at 2007-01-21 when unixipc + and unixsupport were merged. + +2007-01-22 Michael Doering <mld@users.sourceforge.net> + - Fixed songinfo for mods detected as Protracker compatible + +2007-01-21 Heikki Orsila <heikki.orsila@iki.fi> + - Merge unixipc.c and unixsupport.c. Modularise uadecore spawn into + unixsupport.c. + - Move from pipe based IPC communication to UNIX socket based + communication. This solves a scheduling problem for some 2.6.x Linux + kernels. + +2007-01-21 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 2.04 (Defective by Design .org) + - Added Jochen Hippel ST player (hst.* files) + - Added Quartet player from Don Adan / Wanted Team (qpa.* files) + - Updated Mark Cookset replayer with a new version from Don Adan of + Wanted Team + - It's now possible to command an eagleplayer listed in + eagleplayer.conf to ignore file type check. This is useful + with the CustomMade replayer as it rejects some valid song files. + See the change log entry from 2007-01-02 and the man page + about song.conf and eagleplayer.conf. + - Cygwin work-around (locking on song contents db is broken). Does + NOT affect unixes. + - Amiga memory size can now be configured properly from ~/.uade2/uaerc. + This is useful with big sound files (rare). + - Fixed the sinc filter, it had a bug that made it less accurate + - Man page updates about filters + - GCC 4.x clean ups + - Small bug fixes. The default uade.conf had a deprecated option + in comments. It was removed. + - Updated installation instructions + +2007-01-18 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed a bug in default uade.conf. "headphone" option for the + uade.conf was obsoleted at 2006-05-13, the new option name + became "headphones". The backward compatibility is retained + again and thus "headphone" option will work to some future. + - Fixed several missing cvs sticky bits (-kb) in players/ dir + +2007-01-15 Michael Doering <mld@users.sourceforge.net> + - Made "detect_format_by_content" parameter for modfiles default. + This way only true Amiga 4ch mod files now get played. + - Added Quartet player from Don Adan / Wanted Team. It recognizes + QPA.* files. + +2007-01-12 Heikki Orsila <heikki.orsila@iki.fi> + - Added "ignore_player_check" option for eagleplayer.conf and + song.conf. It is useful with bad eagleplayers and rips. This + feature was requested for use with CustomMade player and therefore + this option will also be made default for that player. See the + new eagleplayer.conf. + +2007-01-11 Antti S. Lankila <alankila@bel.fi> + - Correct some ancient mistakes in uade123.1, regarding filter + operation. For instance the LED filter center frequency was + reported halved due to an earlier mistake in graph drawing + +2006-12-22 Heikki Orsila <heikki.orsila@iki.fi> + - Added Jochen Hippel ST player from Don Adan / Wanted Team. It + recognizes HST.* files + - Replaced old Mark Cooksey replayer with a new version from + Don Adan / Wanted Team + +2006-12-07 Antti S. Lankila <alankila@bel.fi> + - Remove uadecore with make clean + +2006-12-03 Antti S. Laknila <alankila@bel.fi> + - Fixed a strict aliasing warning that occured with GCC 4.1 in + newcpu.h + +2006-12-01 Heikki Orsila <heikki.orsila@iki.fi> + - Memory size of Amiga can now be increased over 2 MiB by editing + the uaerc file (e.g. ~/.uade2/uaerc). The variable named chipmem_size + should be edited. Allocated memory for the amiga is determined by + chipmem_size * 512 KiB + By default, chipmem_size = 4 -> 2 MiB of memory. This variable can + be set up to 16 (8 MiB of memory). + +2006-11-26 Heikki Orsila <heikki.orsila@iki.fi> + - Updated instructions about -x option in uade123 and its man page. + +2006-10-28 Antti S. Lankila <alankila@bel.fi> + - Due to me misunderstanding the Kaiser window beta parameter, + the BLEP tables for sinc synthesis were set to attenuate aliasing + only for 40 dB instead of the target 80 dB. + +2006-10-24 Heikki Orsila <heikki.orsila@iki.fi> + - No locking with Cygwin -> uade is dangerous with songdb. + +2006-10-02 Heikki Orsila <heikki.orsila@iki.fi> + - Updated INSTALL.readme to include more dependencies (pkg-config + and sed) and tips for Mac OS X compiling (workarounds) + +2006-08-27 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 2.03 (Microsoft punishment) + - Added song.conf support to set song specific attributes for + playback, such as ntsc, blank, filtering etc. See the man + page. An example, one may add following line to ~/.uade2/song.conf + to make fred.hybris_light always timeout on 200 seconds: + md5=60f3bb11cc1bacaf77d7c16d13361844 broken_song_end timeout=200 comment FRED.Hybris_Light + This need not be added manually, one can just issue: + uade123 --set=broken_song_end --set=timeout=200 FRED.Hybris_Light + and afterwards uade will always play the song correctly. + Similarly, one can fix volume gain for some songs: + uade123 --set=gain=2 foo + To reset all options for a given song, do: + uade123 --set= foo + - Fixed PAL audio synthesis frequency (inaudible) + - --interpolator=x is now --resampler=x because the function of + interpolators was actually resampling. + - Only A500 and A1200 filters are now supported and A500 is the + default. + - Added Play time database support for uade123 + - Compatibility fixes + - Lots of bug fixes + - Improvements in uade123 UI (press i or I for info on song) + - Improved file magic support for some formats (P61A, Fuzzac, ...) + - Hacky NTSC mode support available now. Use --ntsc or ntsc + directive in uade123. Also works per-song with song.conf. + One can now make specific songs be played in NTSC mode by + programming song.conf with proper values. One can issue: + uade123 --set=ntsc dw.FooBar + or put a line to ~/.uade2/song.conf: + md5=225bbb405433c7c05fe10b99b8e088ff ntsc comment dw.AlfredChicken + - One can force protracker replayer to use VBlank timing with many + ways, see the man page on section EAGLEPLAYER OPTIONS. For example, + do: + uade123 -x vblank mod.FooBar + - Enhancements in PTK-Prowiz. Protracker version is now selectable + between 3.0b, 2.3a and 1.0c. See the man page section EAGLEPLAYERS + OPTIONS. This option is not yet guaranteed to be 100% but may + fix some immediate problems with some songs.. These settings + may also be recorded to song.conf so that one only has to give + these parameters once. Example: + uade123 -x type:pt10c mod.TheClassicProtrackerVersionedSong + btw. uade is probably the first mod player for non-amigas that + has a direct version support for protrackers. + - Improved some players + - Titles in audacious and xmms plugins on the playlist are now + programmable with uade.conf. The default is + song_title %F %X [%P] + This displays filename, subsong (if more than one) and player. + See SONG TITLE SPECIFICATION section in the man page. There's a + small help in the uade.conf too. + - Significant code refactorizations + - Fixed a memory leak issue (see Change log on 2006-04-15) + - Added Dirk Bialluch format support by Don Adan/Wanted Team + +2006-07-27 Heikki Orsila <heikki.orsila@iki.fi> + - Removed -fno-strength-reduce from src/Makefile.in. Some old + GCC 2.x versions had bugged strength reduce, but it shouldn't + matter anymore. Maybe the compiler will produce better code + without this. AHX.cruisin showed approx 3% speedup :) Thanks + to alankila for pointing out use of this flag. + +2006-07-17 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed a segfault bug in songdb caused by recent changes to add + subsong volume normalisation info to contentdb. Segfaults were + catched in several places due to uninitialized vplist in + struct uade_content. + +2006-07-02 Heikki Orsila <heikki.orsila@iki.fi> + - Merged an initial version of volume normalization effect from + alankila. + - Split song.conf and contentdb related functionality away from + eagleplayer.c to songdb.c. + +2006-06-30 Heikki Orsila <heikki.orsila@iki.fi> + - Work-arounded signedness warnings with GCC4 in src/frontends/common/ + +2006-06-23 Heikki Orsila <heikki.orsila@iki.fi> + - Fix sinc resampler to support --filter=none (alankila) + - Optimize sinc_handler() inner-loop by avoiding unnecessary + indexing (alankila) + +2006-06-22 Heikki Orsila <heikki.orsila@iki.fi> + - Separated accumulator and sinc resamplers into separate functions + in src/audio.c. + - Removed "anti" name from resampler list. "anti" has been the + "default" for a long time already. + - Change FIR convolution of sinc into bandlimited step synthesis. + Filters are applied directly by the BLEPs. Warning, sinc and + filtering are now integrated together so they can not be + changed separately (breaking modular development idea). The + default resampler does not suffer from this modularity problem + and it is still the recommended resampler. (alankila) + +2006-06-18 Heikki Orsila <heikki.orsila@iki.fi> + - Added play time database saving support into uade123. + +2006-05-22 Heikki Orsila <heikki.orsila@iki.fi> + - Changed --magic to --detect-format-by-content and changed + corresponding "content_detection" directive in eagleplayer.conf and + uade.conf to "detect_format_by_content". Changed --no-song-end to + "--no-ep-end-detect". + +2006-05-20 Heikki Orsila <heikki.orsila@iki.fi> + - Changed default input file to be /dev/tty instead of stdin for + uade123. Also, failing terminal setup (input file is not a tty) + is not a fatal error. + - Added a warning to eagleplayer.conf parsing for the situation + that user has removed all prefixes from an eagleplayer. It makes + all kind of detection (including content detection) unusable. + If you don't want to detect a particular file type by name + extensions, add "content_detection" option for the line in + eagleplayer.conf. But note that there isn't content detection + for all formats. For example, adding "content_detection" for + Thomas Hermann player will make all Thomas Hermann songs + unplayable because there is no content detection for it. + +2006-05-19 Heikki Orsila <heikki.orsila@iki.fi> + - Added Gryzors (Nicholas Franck <gryzor@club-internet.fr>) + Protracker converter source code into CVS. See + amigasrc/players/tracker/converter/README.txt for copyright and + licensing information. Thanks to Stuart Caie for leading us + to the distribution terms (we did have the source before :-) + +2006-05-18 Heikki Orsila <heikki.orsila@iki.fi> + - Added p5x and p6x file extensions for The Player 5.x/6.x to + eagleplayer.conf (Stuart Caie requested it) + - Added "P50A" four letter magic detection to amifilemagic.c + +2006-05-17 Michael Doering <mld@users.sourceforge.net> + - Removed deprecated <audacious/configfile.h> from audacious + plugin. Thanks to Joker for the report. + +2006-05-16 Michael Doering <mld@users.sourceforge.net> + - Raised length of extension[] in uade_analyze_file from 11 to 16, + which caused the xmms and audacious plugin to segfault on + very long prefixes (such as mod15_st-iv) in eagleplayer.conf. + +2006-06-15 Heikki Orsila <heikki.orsila@iki.fi> + - Added "-x y" to set eagleplayer options more conveniently. It's + now possible to do: uade123 -x type:pt11b mod.foo. -x can be + used multiple times on the same command line. + +2006-05-15 Michael Doering <mld@users.sourceforge.net> + - PTK-Prowiz now uses the epopt config system. You can set options + such as "vblank" and/or "type:" on a song base with the uade123 + "--set=xyz" command line parameter or edit uade.conf or song.conf + manually. For valid protracker types: check the uade123 man page. + Please test. I hope I didn't break anything. + - Changed Protracker and compatible tag in amifilemagic. It seems + it was too long for xmms/audacious and crashed. Odd. + +2006-05-13 Heikki Orsila <heikki.orsila@iki.fi> + - Merged man page update from alankila, explaining filter and + resampling features + - Merged headphones 2 effect patch from alankila, making it sample + rate independent + - Added --version to uade123 + - Cleaned up frontends with respect to configuration management. + Initial configuration loading is made in uade_load_initial_config() + in all frontends. + - Fixed song.conf locking + - Fixed recursive mode song.conf option setting. Try: + uade123 -r --set=gain=2 songdir + +2006-05-12 Michael Doering <mld@users.sourceforge.net> + - Audacious modinfo GTK-2.8's assertion error fixed by "porting" + the legacy gdk_font_load/gtk_text to gtk2's tag, viewport, + buffer system. + - Worked around gtk2's assumption any text has to be clean UTF-8 + which obviously will break when displaying binaryhexdumps or + Amiga locale strings. + +2006-05-11 Heikki Orsila <heikki.orsila@iki.fi> + - Updated documentation to reflect implementation. + - Added support for eagleplayer/song specific eagleplayer options. + Use epopt=x in eagleplayer.conf and song.conf. Look at the + man page section "EAGLEPLAYER OPTIONS" for valid options. + +2006-05-09 Heikki Orsila <heikki.orsila@iki.fi> + - Added information about sample rate into effects API. + - Fixed a race condition for Audacious and XMMS plugins. + A shared static buffer was not locked for file magic detection + in eagleplayer.c:analyze_file_format(). + - Fixed a bug in eagleplayer.c:analyze_file_format() that might + have caused a partial read for file to be detected. + - Fixed a buffer overrun bug in uade.c:uade_get_amiga_message(). + With AMIGAMSG_GET_INFO request, the eagleplayer could + cause a slight overrun of the amiga memory to uade data memory. + The attacker could not however choose the string to be written + over the bounds. + +2006-05-07 Heikki Orsila <heikki.orsila@iki.fi> + - Improved filters to work on arbitrary frequency (alankila) + - Removed A500S and A1200S filters. For compatibility, they're now + aliased to A500 and A1200. + - Moved computation of audio emulation parameters away from + init_sound() to audio_set_rate(). init_sound() calls + audio_set_rate(). + - It's now possible to use frequency directive in uade.conf to + set playback frequency. But watch out, it can cause bugs + and sound quality degradation. + - Now only two models (FILTER_MODEL_(A500|A1200)) exist in + amigafilter.h. + - Code cleanups + - Renamed interpolator to be resampler in command line options + and configuration files. Use --resampler=x instead of + --interpolator=x. + - Fixed IIR filter not to waste CPU time with denormal numbers. + This idea was presented to us by Antti Huovilainen, thanks. + Try playing BD.Mickey_mouse with an older version and see how + much cpu it takes with A500 filter. The new version is one + quarter CPU time on an AMD64 machine (alankila) + - Optimized event handling in include/events.h by removing + redundant vsynctime check that relied upon processor/OS + specific timers (that we've removed long ago). + +2006-05-06 Heikki Orsila <heikki.orsila@iki.fi> + - Added two util functions into uadeipc.c. They are uade_send_u32() + and uade_send_two_u32s(). + - Started changes towards changeable output frequency. You can + experiment with --freq=x but filter emulation only works for + 44,1 kHz at the moment. Note that filter emulation always has an + effect on sound. + +2006-05-05 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed --filter=x and --force-led=y to work again. + +2006-05-02 Michael Doering <mld@users.sourceforge.net> + - Fixed crash due to uninitialized pointer to subsong scale in seek + window for xmms and auda plugin. + Seems the UI got into a race condition when trying to update the + scale belonging to the seek window and the pointer for the seek + window was there, while the scale wasn't ready. This happend for + very short subsongs only... + - Added NTK/STK detection to modinfo + - Check for Dirk Bialluch songs in amifilemagic. + +2006-05-02 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed a small bug that allows resetting song.conf options from + the command line. Use 'uade123 --set= foo' to reset options. + +2006-05-01 Heikki Orsila <heikki.orsila@iki.fi> + - Changing to a previous song is now possible in uade123. Try + pressing '<'. -z option now means randomizing the playlist + order before playing, but random play mode (press 's') does + randomizing on the fly. Both alternatives support seeking to + previous song in the same way, but seeking to next song will + always be random in random play mode (not with -z). + - Added --repeat option into uade123 to play playlist over and + over again. + +2006-04-30 Heikki Orsila <heikki.orsila@iki.fi> + - It's now possible to set options into song.conf by using uade123 + directly. This is not the final feature, only a step towards + a more usable feature. Try: + # uade123 --set="gain=2" foo + It should add the associated entry into ~/.uade2/song.conf. + Eventually uade123 should be used like: + # uade123 --set --gain=2 foo + +2006-04-29 Heikki Orsila <heikki.orsila@iki.fi> + - Changed hexdump of module/player to show 2 KiBs of text. + - Fixed some memory leaks in eagleplayer.c and songinfo.c. + - Removed doc/eagleplayer.conf and doc/song.conf. doc/uade123.1 is + the authorative documentation for all configuration files. + - Many uade song attribute and configuration management changes. + - Added broken song end directive for eagleplayers and songs. + To work-around a defective timeout logics in song.conf you could + add a following line to your song.conf: + md5=60f3bb11cc1bacaf77d7c16d13361844 broken_song_end timeout=200 comment FRED.Hybris_Light + - Marked song end detection of FRED format as defective in + eagleplayer.conf: + Fred prefixes=fred broken_song_end + - Unified eagleplayer.conf and song.conf settings. See uade123 + man page for those options. + +2006-04-28 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed another config bug introduced by last config refactorization. + Filter type could not be set from config file in uade123. The bug + did not happen on Audacious/XMMS plugins. + - uade123 -v now prints the uade.conf and song.conf files that were + loaded. + +2006-04-28 Michael Doering <mld@users.sourceforge.net> + - Fixed bug in Soundtracker 31 instruments check introduced + by fixing the misdetection of a digibooster as protracker mod which + was introduced by easing accepting mods with bad length... + See a pattern there, folks?!? + - Along the way, added a distinction between Soundtracker 2.5/ + Noisetracker1.0 and Soundtracker 2.4. ST2.5/NT1.0 obviously shared + the same replay by Kaktus & Mahoney, while ST2.4 was still based on + the old 2.3 replay by Unknown and Mnemotron (using repeat offset in + bytes). + +2006-04-27 Michael Doering <mld@users.sourceforge.net> + - Fixed misdetection of a digibooster mod as protracker in + amifilemagic. + - Fortified modplayer checks against amifilemagic's new policy + to accept modfiles with trailing garbage... + +2006-04-26 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed panning, gain and recursive mode to work again. The problem + was the new configuration management system. Command line options + were not merged into used options. Also, even if they were merged, + they would happen before effects were set ;) Sorry. Fixed now. + - Improved gain effect. It can now clip samples if an overflow + happens. + - Improved song.conf settings. It now supports all but two + options. See doc/song.conf. + +2006-04-21 Michael Doering <mld@users.sourceforge.net> + - Fixed detection bug triptodestroy.mod in PTK-Prowiz. Thanks to + Joker for the report. + The mod uses very large instruments with loops which rolled over + to negative checking instrument sizes in words and when large + enough. Stupid bug. Stupid me. :-) + - Replaced \t with white spaces. This might fix Joker's bug report + about garbled output in modinfo for audacious. + - Fixed audacious crash, when trying to access fileinfo while not + playing a song... Bug was simple we did't have uadesong struct. + get_cur_subsong, get_max_subsong and get_min_ subsong was trying + read from that struct even when idle and uade went up in a blaze... + Now checking towards uadsong struct exists and all is nice + - Fixed the Audacious crash fix. It contained a race condition with + respect to the NULL pointer. Also fixed the XMMS plugin. (shd) + +2006-04-19 Michael Doering <mld@users.sourceforge.net> + - Added new replayer for the Dirk Bialluch format by + Don Adan/Wanted Team. + - Amended Startrekker/Audiosculpture detection in amifilemagic again. + +2006-04-18 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed a bug in memmem() replacement. If needle length was zero, + it returned NULL, but glibc would return pointer to haystack. + +2006-04-15 Michael Doering <mld@users.sourceforge.net> + - Fixed bug in sanity check in pt_karplusstrong effect (e8x) in + mod player. (thanks Heikki) + - Disabled Effect E8x for Protracker 2.3a, 1.1b and 1.0c compatibility + mode in PTK-Prowiz. + E.g. Playing mod.cyberlogik as PTK3.0 will result in timing bugs, + playing it as PTK2.3a will play ok. + - Fixed a very serious memory leak issue. Each played song that was + read into memory was leaked. My chip collection is 230 MiB and + after running + valgrind -zr -t1 --enable-timeouts -f /dev/null /chips + I noticed a huge chunk of mem leaked :( Now it's fixed. (shd) + +2006-04-14 Heikki Orsila <heikki.orsila@iki.fi> + - Refactored and changed amifilemagic.c. Changed tracker type magic + values into enums. A warning about differing file size and + calculated file size for protracker modules is given if one of + two conditions happen: + - uade123 is run in verbose mode (-v) + - xmms or audacious plugin starts to play file + - Refactored configuration code + - Fixed a subsong/total timeout bug in xmms and audacious plugins. + Always ends directive was not obeyed. + +2006-04-13 Heikki Orsila <heikki.orsila@iki.fi> + - Committed a programmable option for displaying song titles on + playlist. Try setting + song_title %F %X [%P] + to uade.conf. + - Reverted xmms buffer underrun fix that was ported to audacious + plugin. With produce_audio() one does not need to wait for + buffer_free(). (shd) + [Comment: it still locks up here :-\] (mld) + - Added songtitle feature to audacious plugin and uade.conf (mld) + - Added #include <songinfo.h> to audacious plugin and removed some + unused variables. + - Added a work-around against ALSA output plugin into XMMS plugin + which avoids to old subsong change blocking bug. Now sleeping is + hardlimited to 5 secs. If work-around is activated, you will see: + UADE: blocking work-around activated. + on stderr. It seems like snd_pcm_state(pcm) in ALSA output plugin + never comes out of SND_PCM_STATE_RUNNING. + - Set song_title default to %F %X [%P] + - Fixed all xmms and audacious plugin symbols to be non-exportable + symbols. The get_iplugin_info() remains the only exportable + symbol. 'objcopy -G get_iplugin_info foo.so' should do it, right? + +2006-04-12 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed configure script to handle uade.pc file correctly in the + situation of '--user'. + - Added a user warning to amifilemagic.c about truncated protracker + modules. + - Reverted Michaels change partially. Audacious and XMMS plugins will + not show song name that is obtained from the module because it + is unreliable. This will be made configurable in the future. + - Fixed a potential bug in XMMS plugin. If maximum free audio buffers + was less than 4088 bytes, uade plugin would refuse to write + anything. This was noticed because XMMS wouldn't recover from + a buffer underrun in ALSA mmap mode. The output plugin would + not increase the amount of free buffers even if time passes. + XMMS 1.2.10 ALSA output plugin (or alsa library) is still buggy. + - Ported shd's xmms buffer underrun fix to audacious (mld) + - Changed user warning about truncated protracker modules in + amifilemagic to produce less false positives. (mld) + +2006-04-11 Michael Doering <mld@users.sourceforge.net> + - Fixed my crap indentation in audacious plugin + - Sync'd xmms and audacious playlist display + - Fixed possible changing current subsong > maximal subsong + in audacious plugin. + +2006-04-10 Heikki Orsila <heikki.orsila@iki.fi> + - --no-song-end is now aliased to -n in uade123 + - Fixed bug in ArtOfNoise8 replayer end routine. (mld) + - Added Songtitle to ArtOfNoise 4V/8V players (mld) + - Display "Guru Meditation" error in audacious playlist for a song + that crashed uadecore. :-) (mld). + - Fixed bug updating the playtime in audacious playlist (mld) + +2006-04-09 Heikki Orsila <heikki.orsila@iki.fi> + - Code refactorization to unify configuration, effect and song + attribute handling among all frontends. + - Added memmem() replacement for operating systems not having it. + - Added uade.pc for pkg-config. + - Upgraded MED/OctaMED replay to v7.0, using Fastmem replay if + available and needed by the song (long samples :-) (mld) + - DigiBooster player now reports songname. (mld) + - Fixed ommited pointer in MED/Octamed fastmem replay detection. + (mld) + +2006-04-06 Heikki Orsila <heikki.orsila@iki.fi> + - Added a small README file + - Moved some effect related configuration issues to + src/frontends/common/ so that they're not reimplemented in all + frontends. See src/frontends/common/uadeconf.c function + uade_enable_conf_effects(). + - Use of uade_enable_conf_effects() in audacious plugin (mld) + - Disabled debug messages in Audacious and XMMS plugins + - Removed debug message about song.conf not found. It's perfectly + valid that song.conf does not exist anywhere. + - Cleaned songinfo.c. Added a common implementation of read_be_u16/u32 + to src/include/uadeutils.h, which is now used from songinfo.c and + amifilemagic.c. Changed length types to size_t. Made find_tag() + more generic and made it use memmem() function. + - Added Heikki's dpiutil to songinfo for CUST.* songs. (mld) + +2006-04-05 Michael Doering <mld@users.sourceforge.net> + - PTK-Prowiz: changed opcodes beq, sf to seq on Heikkis advice. + - Tiny Protracker player compatibility change when calling + playvoice. + - Nicer playlist entries for Audcious plugin: + title (cur/max) - [Format] + +2006-04-03 Heikki Orsila <heikki.orsila@iki.fi> + - Implemented NTSC mode support. It can be buggy and it will not + affect some players at all (those which set CIA tempo by + themselves). NTSC mode can detected in eagleplayers by reading + $212(execbase) aka VBlankFrequency(execbase). It's a byte + with value 50 (PAL) or 60 (NTSC): + move.l 4.w,a6 + cmp.b #60,$212(a6) + beq is_an_ntsc_system + * pal system + - Changed Timing configuration in players/env/PTK-Prowiz.cfg + from CIA <-> VBI/NTSC to CIA <-> VBI. (mld) + - Mod player now honours pal/ntsc setting automatically. (mld) + - Fixed stupid *oops* in mod player reading cia timing from config + file. + - Added ntsc option uade.conf. (mld) + +2006-04-02 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed P61A detection (introduced by mlds change sometime ago). + src/frontends/common/amifilemagic.c had "P60A" as the pattern + for Player 6.1, but obviously it should be "P61A". + - Improved the man page. + +2006-03-31 Michael Doering <mld@users.sourceforge.net> + - Changed DMAWait to dtg_DMAWait and add dtg_Timer support + to DIGI-Booster + - DIGI-booster songinfo now matches modfiles songinfo. + +2006-03-30 Michael Doering <mld@users.sourceforge.net> + - Small check for Fuzzac Packer in amifilemagic. + +2006-03-27 Michael Doering <mld@users.sourceforge.net> + - Renamed XANN-Packer to XANN-Player, following Sylvain 'Asle' + Chipeaux' suggestion. + - Merged Funkok saftey check from EP2.04 to protracker player... + +2006-03-25 Heikki Orsila <heikki.orsila@iki.fi> + - Added a new action key into uade123. 'i' will print module info + and 'I' will print a hex dump of a head of the module. + +2006-03-23 Michael Doering <mld@users.sourceforge.net> + - Sync'd songinfo for modfiles with the more verbose appearance of + Asle's ModInfo v2.31 appearance... It displays now sample sizes, + volume, finetune, loop start and loop size, too. + - Added yet some more tiny differences between Protracker 2.3 and 3.0 + compatibility mode for completeness... (set sample_num in pt_plvskip, + and n_period in pt_doretrig). + These changes might have no effect on the replay quality like e.g. + earlier mentioned Updatefunk calling difference or volume setting, + though. + +2006-03-21 Michael Doering <mld@users.sourceforge.net> + - Small protacker replayer config file parsing fix... + +2006-03-20 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed slight bugs in build system. Architecture specific CFLAGS + were missing from xmms and audacious frontends. Also, those flags + will be the last flags always so that they can be used for + overriding other options. + - Made debug flags really optional. They can be turned off with + --no-debug (for configure). + +2006-03-20 Michael Doering <mld@users.sourceforge.net> + - Figured out the period multiplier issue. It was a bug in my + brain. *g* + - Forgot to add notecut volume setting for protracker 2.3 and below. + This is now fixed. + - Set the default playback style to Protracker 3.0b. + - Added an experimental hybrid protracker setup: 9. + Effects are done ptk2.3a style, volume setting like 3.0. + This fixes some pops and clicks which even the original + protacker 2.3a replay and below had. + +2006-03-17 Michael Doering <mld@users.sourceforge.net> + - Enhanced compatibilty concerning protracker 2.3a/1.1b(fixed), + 2.1a/1.1b, 1.0c and Prottracker 3.0b concerning access of + the periodtable while using the effects. + It's astonishing in how many ways the protracker replays + differ... :-) + E.g. Protracker 3.0b (like Noisetracker) uses a multiplication of + 37*2 for all effects to get the right period. Protracker 2.3a and + the socalled bugfixed 1.1b replay use a value of 36*2 (like the + old Soundtracker) + Last but least ptk 1.0c, the original ptk1.1b and ptk2.1a use + one or the other value for some effects... + All in all, it's a mess and we have 4 different setups in our + protracker config file :-) + - Temporarily disabled the period multiplier hack mentioned above + because it borked on some tunes. + - Added "update volume when skip/hold note" for protracker 2.3 and + below. Protracker 3.0 doesn't do it. + +2006-03-16 Heikki Orsila <heikki.orsila@iki.fi> + - Changed PAL audio synthesis frequency to be exactly 3546895 Hz. It + was 3541200 Hz before. The old value was totally synchronous with + video hw. Changing this does not affect anything else than audio. + The new value is from the hardware reference manual. + +2006-03-16 Michael Doering <mld@users.sourceforge.net> + - Compatibility for PTK-Prowiz can now be set to play files like + Protracker 3.0b, 2.3a or 1.0c. + INFO: Files being played as PT1.0c will have a different vibrato + depth, and use funk_repeat effect instead of the invert loop effect + which might break all mods composed with later protrackers. + - Added support for the different ways Protrackers 1.0, 2.3 and 3.0 + updated periods. + +2006-03-14 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 2.02 (Muhammad pictures) + - Fixed a bug in xmms plugin that cut off sound data from the end of + a song. + - New Sierra AGI player by Don Adan / Wanted Team + - Better support for old sonic arranger files. + - Improved file type detection on many formats. + - Debugger improvements (see 'c' and 'i' commands) + - Added --buffer-time=x option for uade123 to set audio buffer + length in milliseconds. + - A configuration file was added for PTK-Prowiz (that plays protracker + and clones) to set compatibility to either protracker v3.0b or + v2.3a. Please edit file: players/ENV/EaglePlayer/EP-PTK-Prowiz.cfg. + - More KDE integration: support for kfmexec wrapper. + - Fixed many bugs. + - Many other changes :-) + +2006-03-12 Heikki Orsila <heikki.orsila@iki.fi> + - Changed various uade123 parameters. -k and -K have been changed + to one option: + -k x or --keys=x, where x is 0 or 1 (disabling and enabling action + keys). + --no-filter has been removed. Use --filter=none instead. + +2006-03-10 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed some compiler warnings. Using %u to print unsigned ints :) + +2006-03-01 Heikki Orsila <heikki.orsila@iki.fi> + - Reverted mlds work-around to avoid subsong change lockups. + - Did a potential fix for the XMMS plugin lockup bug. However, I + do not have a test case for this. The problem was, I think, that + play_loop() called uade_lock(), then called + uade_gui_subsong_changed(), then gtk called some function, + which would eventually call get_next_subsong() which would + try to re-take the mutex by uade_lock() -> deadlock. + * THIS THEORY WAS WRONG. + - Merged a patch from Martin Jeppensen to rename some eagleplayers + to better names. + +2006-02-28 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed -m option for uade123. "uade123 -m file" would only print help + but not play the file. + +2006-02-17 Michael Doering <mld@users.sourceforge.net> + - Added some missing file extensions for the KDE mimelnk. + - Use of kfmexec wrapper in KDE mimelnk for easy ftp:// http://, + smb://, zip:// etc. support under KDE/Konqueror. + - Added install script for KDE users in /src/frontents/uade123/KDE. + Now playing Amiga music is just one click away from you ;-) + +2006-02-15 Michael Doering <mld@users.sourceforge.net> + - NTSC Flag in config file ENV:eagleplayer/ for PTK-Prowiz affecting + Sound, Noisetracker, Startrekker and Protracker (vblank) added. + Normal Pro- and Fastracker are not affected. + Info: it's not a real ntsc mode in emulation but just calculating + the CIAA timer to use a value ~ 7.15Mhz, 60khz, 125bpm on PAL + machines... + It's a cludge I know :) + +2006-02-14 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed /dev/urandom detection. Using test -c rather than test -e. + Test -c is more compatible and more exact too. + - Worked around random lock ups when switching very short subsongs + with the xmms subsong changer (mld) + - Config file for PTK-Prowiz' Protracker engine added to set the + way _Protracker_ mods are played. There's currently two values: 0 + for Protracker 3.0b like, 1 for Protracker 2.3A like (for anyone + interested: funkrepeat is updated before parsing the extended fx :) + Differences are probl. not audible but Latter is currently the + default. If it breaks a mod file, you can savely turn back to + "0" (mld) + +2006-02-13 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed uade123 to accept -k and -K switches. Their meaning is now + changed. '-k' disables action keys and '-K' enables. + +2006-02-10 Michael Doering <mld@users.sourceforge.net> + - A new email alias. ;) + - Cosmetical change in name from 32 to 31 instr. for Soundtracker II + in PTK-Prowiz. + +2006-02-08 Michael Doering <mldoering@gmx.net> + - Updated mod2ogg.sh to set encoding quality (Giulio Canevari). + +2006-02-07 Michael Doering <mldoering@gmx.net> + - Put new Sierra AGI player by Don Adan/Wanted Team into players dir. + +2006-02-02 Heikki Orsila <heikki.orsila@iki.fi> + - Cleaned up gensound.h. It contained unuseful external variables + such as sample16s_handler and sample_handler. + - Improved mod detection in amifilemagic and Protracker replayer for + Protracker compatible mods using effects 5,6,7 and 9. (mld) + - Quick "work around" of a lock up with the subsong seek popup and very + short subsongs in audacious plugin. Needs further investigation + though. Some kind of race condition, I think. (mld) + - Reintroduced produce_audio(); to audacious plugin for the freshly + released Audacious 0.2 at http://audacious-media-player.org (mld) + +2006-02-01 Michael Doering <mldoering@gmx.net> + - Changed association of jp file extension to Jason Page New. + - Added simple detection for Jason Page old in amifilemagic. + - Added alternative Jason Page Player for one file Jason Page New + files (Thanks dom from the legacy.de for the report). + - Changed HIP, HIPC and HIP7 to SOG, SOC and S7G prefix in + amifilemagic. + +2006-01-31 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed song length database bug in the XMMS plugin. The XMMS plugin + didn't use the correct md5sum in struct uade_song, instead it used + the old and useless array called curmd5[] which was an empty + string. + - Continued to move common variables in frontends to struct uade_song. + - Fixed instrument name len in songinfo for mods. (mld) + +2006-01-25 Michael Doering <mldoering@gmx.net> + - Added Turbo/Infect's SonicArranger Player for "old" sa.* files + - Added experimental filedetection for two different + Sonicarranger_pc types... + +2006-01-24 Michael Doering <mldoering@gmx.net> + - Synced audacious plugin with xmms plugin and changed back + to support the current stable audacious 0.1.2. + The audacious supporting "produce_audio()" will be supported as + soon as there's a stable release... (mld) + - Ported songinfo for Wanted Team song formats [e.g BSS, DL, FP...] + - Fixed mod title display in songinfo + +2006-01-22 Heikki Orsila <heikki.orsila@iki.fi> + - Added a new option to uade.conf: buffer_time x. buffer_time x in + uade.conf sets audio buffer length to x milliseconds. This can + be used to avoid buffer underruns on some systems. Beware that + Alsa support in libao is buggy in versions 0.8.6 and earlier so + that the actual buffer time must be given in microseconds. At + this time it is not fixed in any official libao releases. + - uade123 option --buffer-time=x can be used to set audio buffer + length to x milliseconds. + +2006-01-21 Heikki Orsila <heikki.orsila@iki.fi> + - Imported the LGPL'ed Max Trax source to amigasrc/players/max_trax. + Then applied a patch from alankila. It is not yet an eagleplayer + but a work-in-progress. (alankila) + - Added a command 'i' to the debugger that traces till next hw + interrupt. + - 'c' command in debugger will now also print cycle count. + +2006-01-20 Heikki Orsila <heikki.orsila@iki.fi> + - Continued frontend modularization and code sharing effort. Created + struct uade_song in eagleplayer.h to store relevant properties + of songs that are played. Modified uade123 and XMMS plugin to use + it. The transition is not completed yet. Many fields are still + unused and those fields unnecessarily duplicated in frontends. + Notice that audacious plugin is broken because of this, but it's + also in a transition phase. + - Fixed merging conflicts between latest frontend modularization + effort and mlds mod/fileinfo changes. + - Fixed bugs in songinfo.c. Some file checking could have read over + over memory boundary causing a segfault (but nothing else). + - Backported fileinfo for DIGI-Booster mods. (mld) + - Fixed a bug in XMMS plugin that it stopped a subsong too early + if there was another subsong to play. The sound data that was + buffered in audio output plugin was discarded. Thanks to Cthulhu + (the old one) for the bug report. + + +2006-01-19 Michael Doering <mldoering@gmx.net> + - Improved vblank detection in Protracker replay for mod.slow_motion + by Jogeir Liljedahl. (mld) + - Started work on backporting modinfo from uade 1. Ideally all + frontends should be able to use it. (mld) + - Experimental "update fileinfo window on songchange" feature... + +2006-01-18 Heikki Orsila <heikki.orsila@iki.fi> + - Added a simple and broken XMMS file info window. Module info + displays a hexdump of the first 1024 bytes of the module. + - Fixed #include issues with FreeBSD in unixatomic.c. + - Optimized sinc interpolator (alankila) + - Changed fileinfo.c to allow many different types of infos for + modules. Hexdump is the current default since nothing else has + been implemented. + +2006-01-17 Michael Doering <mldoering@gmx.net> + - (hopefully) Fixed broken subsong detection for Digital Illusion + mods. + - Fixed unallocating timer resources when changing subsong in + MED/Octamed replayer. As a consequence, changing subsongs works + again. + - Removed sinc table from audio.c and put it into a separate file + named sinctable.c. (alankila) + - audacious plugin: changed legacy uade_ip audio output from xmms + to audacious 0.2 produce_audio(); Seems to work here, but I'm not + sure if it's 100% ok... So give it a test and report back. + - Fixed strlrep.h to #include <strings.h> to have size_t type (shd) + +2006-01-15 Heikki Orsila <heikki.orsila@iki.fi> + - Added more debug messages into the interface between emulator and + sound core. Now Amiga file loading events will give informative + message to the frontend. Use uade123 with -v to see all the spam. + +2006-01-14 Heikki Orsila <heikki.orsila@iki.fi> + - Merged sinc interpolator patch (alankila) + - Changed RK to CM prefix in amifilemagic. This affects custom made + format. Old RK and RKB prefixes are still supported but they may + be removed in the future. + - Added contrib/sinc-integral.py which computes the sinc antialiasing + window for audio.c synthesis. (alankila) + - Made huge changes into sound cores subsong restart and interrupt + logic. Some formats were fixed with respect to subsong changing. + Try Monkey Island now. The tempo should be correct after subsong + change. 4ch MED/OctaMED is still broken. Try changing to subsong + 9 in DaveNinja.med (some channels do not get re-initialized and + a disturbing sound plays on the background). The changes are: + 1. Earlier we didn't call StopInt and EndSound in subsong change, + but now we do. The old procedure just called InitSound and + StartInt because our allocators in sound core were robust + against double allocation. + 2. Implemented unallocation for CIA resources. See + rem_cia[ab]_interrupt functions. + 3. StopInt unallocates the CIA resource used for the player + interrupt. Set_player_interrupt allocates the player interrupt + and calls StartInt. + 4. EndSound has a default code now which turns off audio DMA and + sets volumes to zero. + 5. exec.library/SetIntVector() does not enable interrupts anymore. + If interrupts are disabled they stay disabled. + +2006-01-12 Heikki Orsila <heikki.orsila@iki.fi> + - Made anti (accumulator) interpolator to be the default. + +2006-01-08 Michael Doering <mldoering@gmx.net> + - Commited audacious input plugin based on the XMMS plugin + (http://audacious.nenoload.net). + +2006-01-08 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed XMMS plugin installation which didn't obey package prefix + (Michal Januszewski <spock@gentoo.org>). + - Added some more b-flags for fopen(). This time in code in + src/frontends/common. + - Cleaned up sound data buffering code in uadeipc.c, uade.c and + audio.c. Removed uademsg.h as being useless. + - Changed uadecontrol.c to uadeipc.c in src/Makefile.in because + uadecontrol.c is long gone. + - Optimized uade123 to issue next song data request for the uadecore + before passing sample data to libao. This way the uadecore may + do useful work while libao is blocked on sound device. This didn't + solve the underrun problem completely but effect of improving + behavior is clearly observable with 'top'. Before this change, top + showed only 0.4% CPU usage for uadecore, but after the change it + shows 3.3% CPU usage, and the latter reflects reality much better. + +2006-01-07 Heikki Orsila <heikki.orsila@iki.fi> + - Changed fopen() to use "b" flag for porting to Windows environment. + - Thanks to sasq <jonas@nightmode.org> for help with cross-compiling. + +2006-01-06 Heikki Orsila <heikki.orsila@iki.fi> + - Made uadeipc() re-entrant so that uadecore and a frontend could in + theory be run in the same process but different threads. + - Replaced poll() with select() in unixatomic.c to be compatible with + weak systems. + +2006-01-05 Heikki Orsila <heikki.orsila@iki.fi> + - Continued cleaning up run-time configuration issues. uade123 and + XMMS plugin do not duplicate settings anymore. Most configuration + and command line options are stored inside 'struct uade_config' + which is defined in src/frontends/common/uadeconf.h. + +2006-01-04 Heikki Orsila <heikki.orsila@iki.fi> + - Changed -I./include/ to be -I./include in src/Makefile.in to make + it compatible with mingw. + - PTK-Prowiz now accepts mods with max 1KiB trailing garbage... + Nevertheless use 100% good rips, people! (mld) + - Fixed spelling mistake in PTK-Prowiz *g* (mld) + - Updated uade123 man page with apologies about bad file detection + heuristic :( + +2006-01-04 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 2.01 + - Compatibility fixes for OpenLSD and Mac OS X to make UADE compile + - Added 'cm.' prefix for CustomMade format (Ron Klaren) + - PTK-Prowiz subsong scanning was improved (mld) + +2006-01-03 Heikki Orsila <heikki.orsila@iki.fi> + - Cleaned up post-processing of sound data. Removed postprocessing.[ch] + because it was redundant functionality and added necessary + functionality into effects.[ch]. Also, moved effect state out of + effects.c by creating 'struct uade_effect'. This allows easy + loading and storing of state. + The goal is to have a unified mechanism for handling information + from command line options, uade.conf, eagleplayer.conf and + song.conf that is easy. All the setting must be storable and + restorable through that mechanism. Currently that is broken, + incomplete and messy. The functionality is even duplicated between + frontends :( It will probably take many cleanup steps to achieve + the goal. + - Fixed Mac OS X compatibility issue. poll() was replaced with + select(). Thanks to Juuso Raitala. + - Improved (hopefully) subsong detection for mods and similar. Now + there should be less false positives in PTK-Prowiz than there + used to be. (mld) + - Removed 255 BPM SetTempo fix in PTK-Prowiz for mod.loader from + Coolspot to fix mod.alkupala by jorma... *sigh* (mld) + - Fixed broken Prorunner support introduced by reorganization + PTK-Prowiz (mld) + +2006-01-02 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed a configure bug that occured when --with-xmms was specified. + (Michal Januszewski <spock@gentoo.org>) + - Made contrib/uadexmmsadd script to be installed if XMMS plugin is + installed + - Added a work-around for OpenBSD 3.8 which lacks portable types from + stdint.h. inttypes.h is used instead. Possibly this avoids type + problems on some other OSes too. Note that we require some C99 + features from standard C libraries. Thanks to ave@silokki.org. + - Made OpenBSD use 'gmake'. Thanks to ave@silokki.org. + - Fixed execlp() call in src/frontends/common/uadecontrol.c by + casting NULL as (char *). Thanks to ave@silokki.org. + +2006-01-01 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 2.00 (Mental hangover) + - Finally the first stable release of UADE 2 series. The work began + 6 months ago. There are still rough edges and deficiencies but + it is superior to UADE 1 in many respects. + - UADE 2 series has following improvements over UADE 1 series: + * Superior audio quality due to excellent Amiga 500 and 1200 + filter models. The default sound model is now the Amiga 500 + model. This affects all songs whether or not they use filtering. + (Antti S. Lankila) + * A component architecture which makes creating new frontends + easier + * Unified configuration files to set defaults for all frontends + * Improved command line tool, uade123, supports run-time control + of song playback for switching subsong, skipping to next song, + skipping fast forward, pausing and altering post-processing + effects + * Post-processing effect for headphone users (Antti S. Lankila) + * Skip fast forward feature in uade123 and XMMS plugin + * Many core subsystems have been rewritten or heavily altered + * New supported formats + * UADE 1 produces snaps in audio output because of a bug in + audio DMA engine, but is fixed in UADE 2 + +2006-01-01 Heikki Orsila <heikki.orsila@iki.fi> + - Added contrib/uadexmmsadd script to add uade:// prefixed songs into + XMMS playlist. This is useful to avoid conflicts with protracker + songs with modplug and other XMMS plugins. Any other plugin will not + accept uade:// prefixed entries from the playlist. + - Changed forward seeking button in XMMS plugin from ">>" to "10s fwd". + - Allow gain values greater than 1.0. + - Improved uade123 man page. + - Fixed a NULL pointer derefecence in eagleplayer.conf loading. If + eagleplayer.conf couldn't be loaded it would crash. + - Fixed a directory creation problem with 'make feinstall'. + +2005-12-30 Heikki Orsila <heikki.orsila@iki.fi> + - Merged an altered sample accumulation patch from alankila. The + patch has an effect only if anti interpolator is used. + - Removed crux, linear and rh interpolators because they're broken + by design. Only default and anti are now supported. + +2005-12-22 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed shared library compilation for Mac OS X. Thanks to + Michael Baltaks <mbaltaks@mac.com> for information. + +2005-12-21 Michael Doering <mldoering@gmx.net> + - PTK-Prowiz: Commited various changes to cvs. + o Almost finished reorganizing and redoing the mod checks. + o Fixed bug in Soundtracker with repeat in bytes handling. + o Fixed some bugs in handling empty instruments. + o Added hack for vblank mod detection. + o Hopefully working, support for Karplusstrong fx. + - Amifilemagic: backported a small bugfix in mod detection. + +2005-12-20 Heikki Orsila <heikki.orsila@iki.fi> + - Added a short note for Max OS X users to address a compilation + problem. + - Renamed INSTALL to be INSTALL.readme to avoid makefile problems with + Mac OS X. + +2005-12-19 Heikki Orsila <heikki.orsila@iki.fi> + - Merged accurate audio output patch from Antti S. Lankila. The patch + solves the problem that Paula's 3.5 MHz output was sampled at + regular integer valued intervals that caused inaccuracy. The old + interval was round_down(3541200 / 44100) = 80 paula cycles, but + the real interval is ~80.299 paula cycles. This means 0.4% relative + error in outputted sampling rate that is not audible, but it is + harming filter accuracy analysis. + +2005-12-17 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 1.50-pre10 + - Cleaned up src/include/events.h. Removed unnecessary event + scheduler. + - Reworked audio subsystem to be more debuggable and added comments. + - Fixed a bug in audio state engine that caused DMA engine to play + one word too much of sample data. How could this bug have gone + unnoticed for so long? The same bug exists in UAE too. + - Reverted back to not using interpolation with A500E and A1200E + filters. The anti interpolator caused problems with many songs. + It will be fixed at some point and changed back, but at the + moment there's doubt how to fix the problem. + +2005-12-16 Heikki Orsila <heikki.orsila@iki.fi> + - Applied filter improvement and optimization to audio.c. The + filter should be slightly better than the old. Affects only + A500E and A1200E filters. (alankila) + - Cleaned up audio.c + - Reworked configuration loading system to avoid conflicts with + uade123 command line parameters. Command line parameters have + priority over uade.conf. + +2005-12-15 Michael Doering <mldoering@gmx.net> + - Some progress on porting the mod detection to m68k asm. + +2005-12-15 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed a bug that forced filter to be A500E type when --force-led + was uade with uade123. (alankila) + +2005-12-14 Heikki Orsila <heikki.orsila@iki.fi> + - Added displaying total playtime based on content database into + uade123 + +2005-12-12 Michael Doering <mldoering@gmx.net> + - replaced Grouleff replayer with Wanted Team's EarAche. + - added new EMS replayer by Wanted Team. + +2005-12-12 Heikki Orsila <heikki.orsila@iki.fi> + - Added INSTALL file to document build process. + +2005-12-11 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 1.50-pre9 + - An XMMS plugin has been added. New features compared to UADE1 XMMS + plugin are seek fast forward and correct subsong seeking bar. The + plugin still lacks GUI for configuration, but uade.conf can be + edited directly. + - Filtering settings are audibly different compared to last release. + A500E filter model is now the default. It was A1200 in the last + release. This affects all songs, even those which do not use the + filter. + - New players for 15 instrument soundtracker variants have been added. + - uade123 man page has been updated. + - Most subsystems have gone through changes. Some important changes + have been left out. See log entries for further details. + +2005-12-11 Heikki Orsila <heikki.orsila@iki.fi> + - Significant changes in filter default values. Current default filter + is A500E, which is audibly different on every song compared to the + old default (A1200). To restore the old behavior, set "filter a1200" + in uade.conf. If you want to advocate another default value, please + post to the forum or send email. The forum is preferred. + +2005-12-10 Heikki Orsila <heikki.orsila@iki.fi> + - Added notices to documentation that setting filter model has an + audible effect even if a song doesn't use filtering at all. + - Cleaned up configure script (that is originated from uade1) + +2005-12-07 Heikki Orsila <heikki.orsila@iki.fi> + - Added unrecognizable type "packed" into amifilemagic. It is + used to inform user about files that are packed with an amiga + packer. + - some work on m68k mod checking and replay routine (mld) + +2005-12-06 Michael Doering <mldoering@gmx.net> + - XMMS plugin now automagically advances the subsong seek slider, if + the replay rolls over to the next subsong. + - Soundtracker15 name check that was added yesterday was removed. (shd) + - Fixed a bug in uade_filemagic() that char *pre was not initialized + to be an empty string by default. This caused + uade_analyze_file_format() to receive garbage data when file format + was not recognized. (shd) + - Valgrinded a memory allocation bug in two places of eagleplayer.c + (the same error actually due to replicating same lines of code), + where space for (n + 1) pointers should have been allocated, but + only ((n * sizeof ptr) + 1) bytes was allocated. (shd) + - Added gain effect into uade.conf. You can use variable named + 'gain' to set scaling value for each outputted sample. For + example, add a following line to uade.conf: + gain 0.25 (shd) + - Made length test of mods with 32 instruments less strict. Due to + popular demand *g* now "oversize mods" get accepted. + - Added check for sane finetune and volume values in modchecks. + +2005-12-05 Heikki Orsila <heikki.orsila@iki.fi> + - Added initial version of song length database into XMMS plugin. It + is compatible with uade1 db-content, but named differently: + ~/.uade2/contentdb. You can just copy the old db: + cp ~/.uade/db-content ~/.uade2/contentdb + - Content db is loaded during play_file if it has changed + on the disk. If it has not changed on the disk, then it is + saved if an hour has passed and the db has been changed. + - Added a requirement for Soundtracker15 song content detection that + the name must have prefix or postix being: "mod", "mod15", or + "mod15_". This change could be reverted at some point but now it's + the safest choice. + +2005-12-04 Heikki Orsila <heikki.orsila@iki.fi> + - Added missing #include for uadecontrol.h (sys/types.h for pid_t). + +2005-12-03 Heikki Orsila <heikki.orsila@iki.fi> + - Made XMMS plugin display play time correctly in the play list + after a song ends. If song ended volutarily, tell XMMS the + play time. If song ended involuntarily by user intervention, + error, or timeout, tell XMMS that the song doesn't have a length + leaving the play list time empty. + +2005-12-02 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed a latency and time bug in the XMMS plugin that affected + fast forward seeking. When forward seeking happened the XMMS time + display was not updated and the seeking happened with a delay. + - Made XMMS plugin report the play time for XMMS after a song + ends. + - Added comments about variable locking in XMMS plugin. + +2005-12-01 Michael Doering <mldoering@gmx.net> + - eagleplayer.conf: Amended the different MarkCooksey prefixes. + - amifilemagic: fixed TFMX 1.5 detection bug introduced by the recent + clean-up. + - amifilemagic: fixed another TFMX detection bug. Should be alright + again now. + +2005-11-30 Heikki Orsila <heikki.orsila@iki.fi> + - Make XMMS plugin auto detectable in configure script. The plugin is + still very experimental and incomplete in features, but it can + already play songs, or at least it should. + - GCC4 gave warnings of problems I had not noticed: Fixed a bug in + md5.h. uint32_t was accidently redefined (that is #included + originally from stdint.h). XMMS plugin's uade_ip structure was + declared static but later as external. Fixed signedness warnings + from various modules. + - Added seek-forward button into XMMS plugin. (mld) + - New replayer for Soundtracker v2-v5 mods with 15 instruments and + a lot of different effects added. (mld) + - fixed WaitAudioDMA for all old mod15 replayers. (thanks heikki!) + - changed mod15 (again) for stricter st-iv detection (mld) + - changed to a stricter tracker module length policy... + If uade doesn't play your modfiles anymore, it's a bad rip. + Get a good one! :) + - Since Master-Soundtracker files seem to use a subset of the normal + Soundtracker fx, they now get played with the mod15 replay + This makes Master-ST replayer kind of obsolete atm. (mld) + +2005-11-29 Heikki Orsila <heikki.orsila@iki.fi> + - Partial and buggy implementation of song.conf. It is used for uade + specific work-arounds for broken or bad songs. Look at doc/song.conf + and src/frontends/common/eagleplayer.c. Please do not use this yet. + - Fixed some compiler warnings that surprisingly came with gcc 4.0.2. + - Fixed Makefile.in to not report error on 'make install' when XMMS + plugin is not installed. + +2005-11-28 Heikki Orsila <heikki.orsila@iki.fi> + - Modularized loading and parsing on uade.conf options. See + src/frontends/common/uadeconf.[ch]. + - It is possible that config parsing for uade123 breaks now. + - Added partial config loading support for XMMS plugin. Doesn't + support setting filter type or interpolation mode yet. You must + edit uade.conf by hand if you want configuration changes. No GUI + for setting options yet. + - Added cleaning rule for XMMS plugin + - New make rule: 'make feclean' will clean all frontend objects + - The XMMS plugin determines configuration file path for uade.conf + once during XMMS plugin initialization, and it will not change + afterwards. If no global or user configuration is found, then + the plugin chooses the file under HOME ($HOME/.uade2/uade.conf). + It will try to load the configuration each time a new song is + selected from the XMMS. + - Optimization: XMMS will re-read configuration when a new song is + selected if the file timestamp of uade.conf has changed. + - Fixed synchronization problem in XMMS plugin's play loop. The audio + device is drained of written sound data before actually stopping + the device. The earlier version cut of audible data from the end + of the song :( However, draining can be interrupted if the user + requests something urgent, such as wanting an immediate song change. + Draining takes time as long as audio + device has buffered data. Buffering settings can be found from + output plugin settings, as usual. + +2005-11-28 Heikki Orsila <heikki.orsila@iki.fi> + - Added hardcoded timeouts for the XMMS plugin. They are the same + as uade123 defaults. 20 seconds for silence and 512 seconds for + subsong. Reading uade.conf variables is not supported yet. + +2005-11-27 Heikki Orsila <heikki.orsila@iki.fi> + - Continuing modularization of uade frontends. Various commands, + such as set subsong, change subsong, set filter type, and set + interpolation mode, were moved to src/frontends/common/uadecontrol.c. + The idea is that all the non-trivial commands have a wrapper in + uadecontrol.c, but trivial commands that don't require parameters + can be used through uadeipc.c (uade_send_short_message()). + - Added src/include/uadeconstants.h that should contain constants that + are common with uadecore and frontends. + - Subsong seeking works in XMMS plugin :-) + - Made XMMS plugin globally installable as it should be + +2005-11-26 Heikki Orsila <heikki.orsila@iki.fi> + - Continuing modularization of uade frontends. Renamed + src/uadecontrol.c to be src/uadeipc.c, and added + src/frontends/common/uadecontrol.c which contains a set of + helper functions to control and spawn uadecore. + - Added --with-xmms to configure script for developing the XMMS + plugin. It does not work yet! + +2005-11-25 Heikki Orsila <heikki.orsila@iki.fi> + - Cleaned up and fixed tronictest check in amifilemagic. Added + read_be_u16() and read_be_u32() to help parsing amiga formats. + - Cleaned up tfmxtest in amifilemagic. + - Cleaned up modparsing in amifilemagic. + +2005-11-24 Michael Doering <mldoering@gmx.net> + - amifilemagic: improved mod32 and mod15 checks a bit + - ha! found pitchbend incompatibility bewteen + Master-ST and DOC Soundtracker II in amifilemagic. Now + Mods using the pitchbends bigger than 0xf are played as + DOC Soundtracker II:) + +2005-11-23 Michael Doering <mldoering@gmx.net> + - Master-ST and Ultimate-ST replayers now check for a valid file + length, thus badly ripped mod15 songs won't get played anymore with + UADE. No exceptions. + FYI this will also be future for all other Sound and Protracker + derivates, so for anyone having bad rips - get some valid files! :) + +2005-11-22 Michael Doering <mldoering@gmx.net> + - Improved amifilemagic: mod32 check now tries to distinguish + 10 different mod types. (BTW. 4ch Fastracker mods and similar + now default to mod_pc and get played by the Multichannel PS3M player) + - Some more work on the mod15 check in amifilemagic again. + - Started to update the amiga mod15 replayers (Ultimate-ST and + Master-ST with better checks, resulting in breaking support for other + players like EP or DT atm. + +2005-11-18 Michael Doering <mldoering@gmx.net> + - Lowered the file buffer size to 8192 bytes to reduce overhead with + xmms plugin scans. Unfortunately mods with a header and pattern data + beyond that buffer size can't be detected properly and get played + as plain mod15. + - Improved mod15 check. It should produce now less false positives. + - Added a smarter(?) way of the mod check for larger files that + don't fit into the check buffer completely. + - Renamed filemagic() to uade_filemagic() (shd) + - Filemagic buffer size (8192) is now passed as an argument to + uade_filemagic(). Previously both the caller and callee knew the + size. + - Made amifilemagic tables static (only visible inside the module) + (shd) + - Name prefix conflict between Future Player and PTK-Prowiz was + resolved in favor of Future Player. The name prefix/extension is + 'fp'. (shd) + +2005-11-16 Heikki Orsila <heikki.orsila@iki.fi> + - Made install to a standard path by default. That is /usr/local. + Use ./configure --prefix to override. configure --user will install + to users home directory as in the past. + - Committed initial version of man page for uade123. + - added a first uade-only mod15_Mastertracker player (mld) + - improved (?) mod15 type checks in amifilemagic (mld) + - started to work on more complete mod type check in amifilemagic + (mld) + +2005-11-13 Heikki Orsila <heikki.orsila@iki.fi> + - Cleaned up src/frontends/common/eagleplayer.c. Removed skip_ws(), + skip_nws(), and loops that used them, and replaced those with + shorted loops that use strsep(). Changed index variables to use + size_t instead of int to be more robust against bad input. + - Fixed a bug that if eagleplayers.conf specifies always_ends for + an eagleplayer then forcing timeout from command line with -t + didn't work. + - Fixed a dirty bug in score that made score crash if an eagleplayer + gave a NULL pointer as module name. This happened with Frontier + custom. Closer inspection revealed that Frontier custom is also + buggy because it sets module name in InitSound() but the + specification says module name is evaluated after InitPlayer() + which is before InitSound(). This looks like a design bug in + the interface, or a typo in the documentation, because setting + module separately for each subsong is useful, and that is what + Frontier actually does. + +2005-11-12 Heikki Orsila <heikki.orsila@iki.fi> + - Add new antialiasing interpolation mode, which corrects for noisy + treble especially audible in the A1200 filter model. It does its + work by computing the average value of Paula's output pins between + samples. + +2005-11-09 Michael Doering <mldoering@gmx.net> + - Fixed missing hipc and soc prefixes in eagleplayer.conf. + - Associated #chn, ##ch mods to PS3M again. (note: s3m, xm or mtm + are still omitted by uade) + +2005-11-08 Heikki Orsila <heikki.orsila@iki.fi> + - Added slight noise reduction into CSpline code to reduce + noise due to interpolation errors, and snapping sounds from + sudden volume changes. (alankila) + - Updated headphone filtering parameters to place virtual + sound sources closer to head and reduced the associated treble + filtering to make the sound at the same time brighter and more + forward placed. The sources still appear slightly behind and + perhaps elevated, so the illusion will be further improved. + (alankila) + - fixed AON8 timing now for real *grin* (mld) + - added Musicline Editor to be detected by amifilemagic (mld) + +2005-11-07 Michael Doering <mldoering@gmx.net> + - Removed dupes from new eagleplayer.conf (mld) + - Added new player: Musicline Editor (mld) + - Broke ArtOfNoise8 timing, and added song end detection. (mld) + +2005-11-06 Heikki Orsila <heikki.orsila@iki.fi> + - Added an experimental support for eagleplayer.conf, which is + specified at doc/eagleplayer.conf. The new system allows eagleplayer + specific settings. uadeformats is no longer used, so it has been + removed. Here's a list of currently possible eagleplayer options: + a500 (A500 type filter emulation is used.) + a1200 (A1200 type filter emulation is used.) + always_ends (A song always ends, so timeouts are not used.) + content_detection (File name prefix or postfix heuristics are not + used for determining format.) + speed_hack (Speed hack is enabled.) + Tips: + Speed hack can be turned on for a specific format by editing + eagleplayer.conf. A format can be marked as ending always, which + means that timeout values are not used (except silence timeout). + There are other options too, and all of them are specified in + doc/eagleplayer.conf. + + +2005-11-05 Heikki Orsila <heikki.orsila@iki.fi> + - Player interrupt is now a CIA A interrupt by default. As a + consequence CUST.Loom works (it requires that player interrupt + runs at a lower priority level than audio interrupts). + THM.BlueAngel69 might play better now - a good comparison is needed. + There are still a few things to do in the sound core's interrupt + system, see amigasrc/score/todo.txt. + - Headphones effect clipping fix (alankila) + - Added improved (but currently experimental) LED filtering code. + The old code was based on assumption that A500 and A1200 have same + output filtering circuitry, but this was not correct. After + analysing hi-fi measurements by pyksy, I designed new filters + by tweaking a couple of equalizers on top of a RC filter that + provided basic treble attenuation. Use --filter=a500e or a1200e to + test the new filters. (alankila) + +2005-11-04 Heikki Orsila <heikki.orsila@iki.fi> + - Separated CIA B timer A and timer B interrupts finally. Some + Forgotten World songs started to work, but not all. Thomas + Herman BlueAngel69 swent back to its earlier buggy state. Our + recent interrupt handler change broke Thomas Hermann completely. + This change fixes our original design fault that only one CIA + timer interrupt may be used, but not both. This patch takes us + much closer to full CIA interrupt handler support. + - Heikki's CIAB-A and CIAB-B separation in soundcore gave us full + support of the MusiclineEditor player from Eagleplayer 2.02. + You still have to use --speedhack to give it enough + cpu cycles, though. (mld) + - forgot to add detection bug fix of the two different MCMD formats + in amifilemagic to changelog *grin* (mld) + +2005-11-03 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 1.50-pre8 + - Many bug fixes and cleanups. + - Headphones postprocessing effect. + - Improved A1200 filter emulation. + - Added A500 filter emulation. Use --filter=a500. + - Cleaned up sound cores timer code. + - Fixed CIA timer initialization. + - Improved uade123 user interface. Press 'h' in uade123 or list + action keys with uade123 --help. + - New sample interpolation code (--interpolator=cspline). + - --stderr can be used to pipe sound data to stdout. + +2005-11-02 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed a very stupid bug I introduced yesterday to src/uade.c. + if (curs > maxs) + foo(); + bar(); + Duh. Why did I forgot {}?? + - Network byte orderized, or big endianized, subsong info transmission + between uadecore and frontend. This wasn't a bug. Just a change for + consistency. + +2005-11-01 Heikki Orsila <heikki.orsila@iki.fi> + - Removed src/effects.c. It was accidently left there from uade 1 + (alankila) + - Removed unnecessary functionality from src/players.c. Black listing + Protracker modules to be VBI timed should be in frontend logic + rather than emulator logic. + - Cleaned up text messages all over the place. + +2005-10-31 Heikki Orsila <heikki.orsila@iki.fi> + - Did highly experimental changes to sound core's timing interrupt + system. I tested the change with all known players, and only the + Thomas Hermann broke out, but it was broken already, so no big + loss there. Of course I only tested each format with a few songs, + so it's very possible that if the new system doesn't work, + then I couldn't catch the problems. Nevertheless, I spent over an + hour listening to different samples. Testing this change would be + appreciated. One should especially pay attention to tempo, because + that may have gone wrong. The changes I technically made were: + - Made default interrupt timer to be CIA B timer A. Took away all + the hacks to use VBI when ever possible to be the default timer. + - While turning on any CIA B timer (A or B), it does not turn off + the other CIA B timer. + - Fixed CIA B timer initialization. Setting a timer (A or B) gets + the timer value from dtg_Timer(eaglebase). + - Cleaned up audio interrupt server. + - Fixed tiny bug in uade123 file extension detection (mld) + - Moved amifilemagic, uadeformats, and unixwalkdir modules to + frontends/common/ where they belong. + +2005-10-30 Heikki Orsila <heikki.orsila@iki.fi> + - Modified headphones effect. (alankila) + - Added 'H' action key to toggle headphones effect, and 'P' to toggle + panning effect. Default panning value is 0.7, unless specified + otherwise with command line option or in uade.conf. + - Added forgotten -O2 optimization flag to uade123 Makefile + - Cleaned audio.c. Removed some debug #defines. + - Imported amiga player sources from uade1 project to amigasrc/players/ + +2005-10-29 Heikki Orsila <heikki.orsila@iki.fi> + - Antti S. Lankila <alankila@bel.fi> will be referred to as 'alankila' + in ChangeLog from now. + - Beautified and cleaned up audio.c and sd-sound-generic.h. + - Fixed a bug that caused 1 bit precision loss in audio output. + Sample data was multiplied after filtering, but it should have been + multiplied before. (alankila) + - cust.Bubble_Bobble gives wrong subsong information. Added a logic + into uade123 that determines subsong ranges if default subsong + is outside the reported range. + - Changed score's CIA setup so that both CIA-A and CIA-B time of day + counters run continously. Some players, such as Oktalyzer and + sean connolly depend on this. As a consequence it was possible to + remove a work around from score that patched the sean connolly + player not to use CIA TOD. However, any player using CIA TOD is at + risk of not functioning properly, but I have only seen two cases + so far (those which I mentioned). + - Removed score from uade source root, now it's only located at + amigasrc/score/ directory. + - Fixed a bug in uade123/playloop.c. If one subsong ended because of + silence, all the rest subsongs would end because of silence too. + I forgot to reset the silence counter to zero.. + - Added a headphone postprocessing effect, and an effect framework for + different uade frontends. Try --headphone. (alankila) + - Try pressing 'p' on uade123 to toggle postprocessing effects on + and off. + - New filter code (alankila) + +2005-10-28 Heikki Orsila <heikki.orsila@iki.fi> + - Radical cleaned up in audio.c. + - Fixed rh and crux interpolators. Thanks to Antti S. Lankila. + <alankila@bel.fi> + - Removed lots of unnecessary macros, variables and functions. + - rh interpolator is now names as linear. + - Removed src/config.h. It is unnecessary. + - uade123 help will now print usable action keys too. Also, one may + press 'h' at run-time to see usable keys. It will print currently + as follows: + Action keys for interactive mode: + '.' Skip 10 seconds forward. + SPACE, 'b' Go to next subsong. + 'c' Pause. + 'f' Toggle filter (takes filter control away from eagleplayer). + 'h' Print this list. + RETURN, 'n' Next song. + 'q' Quit. + 's' Toggle between shuffle mode and normal play. + 'x' Restart current subsong. + 'z' Previous subsong. + - To verify whether a song uses filter or not, enable verbose mode + for uade123 by -v. You'll see messages like: + Message: Filter ON + - Added two different types of filters: A500 and A1200. Thanks to + Antti S. Lankila, again. Use --filter=a500 or --filter=a1200, + the A1200 case is the default. Both types of filter are + but A1200 filter is better tested. We need feedback on A500 filter. + - --force-filter was changed to --force-led. + - Fixed a bug with getopts. The long options list was not zero + terminated, and it had worked by luck so long.. + - Added good ol' speed hack feature into uade123. Use --speedhack + to increase CPU speed for players that extra virtual power. It + is useful for players that require more cpu than 68k can give, + multichannel oktalyzer for example. + +2005-10-27 Heikki Orsila <heikki.orsila@iki.fi> + - Made interpolation mode selectable from command line. Use + --interpolator=x to choose the interpolation mode, where + x = default (no interpolation), + rh = rh interpolator (broken atm), + crux = crux interpolator (broken atm), + cspline = Antti S. Lankila's spline interpolator + (This is not recommended for chip songs! The spline + spline interpolator is good for natural instruments, + but may produce bad sounds with chips.) + - Interpolator is selectable from uade.conf file by adding line: + interpolator foo + Note that using anything else but default is not recommended + at the moment. + - As per Michael Doering's needs, I added --stderr option to uade123. + It will force all terminal output printed onto the stderr, and thus + allows piping pure sound data. Example: + uade123 --stderr -e raw -f /dev/stdout DW.Platoon |postprocessing + +2005-10-27 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 1.50-pre7 + - Antti S. Lankila <alankila@bel.fi> fixed and improved filter + behavior. The filter state must be updated even when filtering + is not outputted. Output scaling was fixed to the right place + so that it does not distort filter state. Unnecessary range + scaling of input samples was removed. Some documentation was + added about technical properties of the IIR filter. + - Filtering by default was not enabled for those people who had an + earlier uade2 version installed to their home directory, because + make install does not overwrite ~/.uade2/uade.conf. Now the default + is hard coded into the source code. + +2005-10-27 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 1.50-pre6 (tester pre) + - Uade core now supports only 16-bits stereo. If 8-bits or mono is + needed the sample data can be postprocessed. + - Added experimental filtering support. It should be better than the + one found from uade1. Thanks to Antti S. Lankila <alankila@bel.fi> + for IIR filter coefficients and advice. + - New uade.conf options: + filter - enable filter emulation + no_filter - disable filter emulation + filter_off - turn filter always off + - New command line options: + --filter Enable filter emulation + --force-filter=x, where x = 0, or x = 1. Set filter state either + off (0) or on (1). + +2005-10-16 Heikki Orsila <heikki.orsila@iki.fi> + - Added a fuzzy state diagram on client-server interaction from client + perspective. + +2005-10-08 Heikki Orsila <heikki.orsila@iki.fi> + - Unknown keywords in uade.conf are ignored. Old behavior was to + terminate uade123 on an unknown keyword. + - First try to load uade.conf from ~/.uade2/uade.conf, and then + try the global config file ($PREFIX/etc/uade.conf) + - Simplify playloop in uade123. + - Beautify directory hierarchy scanning by avoiding unnecessary + '/' characters. + - Started specifying uade client-server protocol. See + doc/play_loop_state_diagram.dia. + - Removed S3M support. It's not an Amiga format, and thus it doesn't + belong to UADE. It might also interfere with other players when + UADE is used as an XMMS plugin. Use XMP, modplug or something + else for these formats. + - 'make check' is now 'make soundcheck' because it's more a sound + check than a good test set. + +2005-10-03 Heikki Orsila <heikki.orsila@iki.fi> + - Action keys made into default behavior for uade123. + +2005-09-08 Heikki Orsila <heikki.orsila@iki.fi> + - Giulio Canevari pointed out that --panning doesn't work. For + some reason I didn't notice that (perhaps didn't test ;-). The + problem was false parameters for GNU getopt. + - mod2ogg2.sh from Giulio Canevari + +2005-09-04 Heikki Orsila <heikki.orsila@iki.fi> + - Added -g option to uade123 to only print information about songs. + Songs are not played in this mode. All relevant output goes into + stdout. This should be useful for scripting people. An example: + + $ uade123 -g /svu/chip/mod/mod.Unit-a-remix 2>/dev/null + playername: Protracker & relatives + modulename: unit-a-remix + formatname: type: Protracker + subsong_info: 1 1 1 (cur, min, max) + <uade123 quits fast> + +2005-09-01 Heikki Orsila <heikki.orsila@iki.fi> + - Cygwin fixes. Add cygwin detection to configure script. Makefile + should be aware that uade123 is named uade123.exe on cygwin. + +2005-08-27 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed a memory copying bug which could cause sound data + corruption when skipping 10 seconds forward with uade123. The bug + was at playloop.c:273. memmove should be used instead of memcpy (shd) + - A patch from Jarno Paananen <jpaana@s2.org>. It fixes use of C99 + anonymous initializers with sigaction (2) on Cygwin. + +2005-07-28 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 1.50-pre5 (developer release) + - Nothing better to do. Let's release the new version for users to + test. + +2005-07-25 Heikki Orsila <heikki.orsila@iki.fi> + - It seems ALSA lib could fork and consequently terminate a process + when used through libao, and we must not consider it an error in + our signal handler that catches all dead children. The signal + handler assumed that the only child that could die is uade. (shd) + +2005-07-24 Heikki Orsila <heikki.orsila@iki.fi> + - New keys for interactive mode: + [0-9] - Select subsong in range [0, 9] + q - Quit player + s - Switch between normal and shuffle mode + x - Restart current subsong + - Added -£ or --no-song-end switches. Song just keeps playing even if + the amiga player says it has ended. Dude! You can get pretty weird + sounds with this, and sometimes the sound core crashes, and should + crash. Fortunately that doesn't kill the simulator :) + - Made help print (-h) prettier by aligning tex columns + - Added -K or --no-keys to disable action keys (this can be used to + override the uade.conf if it enables actions by default). + +2005-07-23 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 1.50-pre4 (developer release) + - Added shell interaction keys into UADE123. The keys can be enabled + with -k switch, or adding line "action_keys" into uade.conf. + The keys are (mimiking XMMS): + z - Previous subsong + c - Pause + b - Next subsong + n - Next song + . - Skip 10 seconds forward + ENTER - Next song + SPACE - Next subsong + Does someone want these configurable into uade.conf? Please email + me. + +2005-07-22 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 1.50-pre3 (developer release) + - Added a -j to skip x seconds of audio from the beginning. Note that + this does not affect timeout parameters in any way. If timeout is + 1 minute and skip is 2 minutes, the song will just end before + anything is played. + +2005-07-21 Heikki Orsila <heikki.orsila@iki.fi> + - Added silence timeout + - Wrote a config file parser for uade123. Look at uade.conf file + for instructions. uade123 tries to load following files in order on + startup: BASEDIR/uade.conf and $(HOME)/.uade2/uade.conf. Command + line options can override config file parameters. Users of uade123 + might want to configure timeout, panning and such values as + personal defaults. This is a very important feature important over + uade 1.0x command line tool. + - Restructured uade123 code into different code modules to make + maintaining and code reuse easier. + +2005-07-18 Heikki Orsila <heikki.orsila@iki.fi> + - Fixed a bug in uade123 that prevented it from playing the last + subsong of a song. + +2005-07-18 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 1.50-pre2 (developer release) + - uade123 now has eagleplayer fileformat check ignoring feature (-i), + panning (-p), song timeout (-t), and subsong timeouts (-w) + +2005-07-17 Heikki Orsila <heikki.orsila@iki.fi> + - uade123 now uses GNU getopt + - uade123 can now output both raw and wav formats by using libao + file output mechanism. Wav format is the default. Example: + uade123 -e wav -f foo.wav songfile + - The sound core now reports to the simulator when audio output should + start. Traditionally the simulator has produced audio output from + the reboot of the amiga even if it is only useful to output audio + after all the lengthy player initializations have been made in + the sound core. For example, AHX.Cruisin now has 0.96 seconds less + zero samples in the beginning. + - Cleaned up sound core a bit. Removed some unused definitions + of messages between sound core and the simulator. Removed unused + code that was designed to be used when running sound core under a + _real_ AmigaOS. + - Made uade123 less verbose. Use -v option to get more details. + - Renamed uade-trivial.c to 'uade123.c' in src/frontends/uade123 + - Renamed directory 'trivial' to 'uade123' in src/frontends/ + +2005-07-15 Heikki Orsila <heikki.orsila@iki.fi> + * UADE 1.50-pre1 (developer release) + - Lots of changes into uade123 + - This is just a preview of the new system. There are no interesting + features over uade 1.0x versions. This release doesn't even have + xmms / beepmp plugins. + - Short instructions for testing: + $ ./configure && make + $ make test + $ make install + Will install everything to $(HOME)/.uade2/. Then + $(HOME)/.uade2/uade123 is the player you can use. This version + uses libao for audio output. + +2005-07-12 Heikki Orsila <heikki.orsila@iki.fi> + - Code in src/amifilemagic.c does amiga fileformats detection. If it's + useful for any other project out there, it is now dual licensed + under the GNU GPL _and_ Public Domain. By public domain we mean + that you can do anything you like with the code, including + relicensing arbitrarily for your projects. + +2005-07-11 Heikki Orsila <heikki.orsila@iki.fi> + - Improved the command line frontend in src/frontends/trivial/, + and now it is called uade123. It can now do fileformat detection by + content, and load proper players from their installation place. + Also, it can play multiple songs in a sequence if one switches to + next song with ctrl-c before the song actually ends. If the song + ends by itself, the system will crash ;) + - Found a bug in amifilemagic by accident. chk_id_offset() function + tested patterns of length sizeof(patterns[i]) which is totally + wrong. It was corrected to strlen(patterns[i]). + +2005-07-09 Heikki Orsila <heikki.orsila@iki.fi> + - Started hacking uade. The goal is to release uade 2.00 someday + http://board.kohina.com/viewtopic.php?p=3499#3499 + - These changes start a series. Version 1.50 will be the first public + release in this series. + - src/frontends/trivial/ can now play single file songs. + - Debugging is broken because libao can't handle signals well. + - Tons of things missing from the system. diff --git a/plugins/ddb_input_uade2/uade-2.13/README b/plugins/ddb_input_uade2/uade-2.13/README new file mode 100644 index 00000000..9ada771a --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/README @@ -0,0 +1,53 @@ +UADE - Unix Amiga Delitracker Emulator +====================================== + +UADE is a music player for UNIX platforms that plays music formats used on +the Amiga computer. + +Very short instructions for installing UADE +=========================================== + +1. Read INSTALL.readme +2. Install the program globally or directly to your home directory. Do either + ./configure + or + ./configure --user (makes uade to be installed under ~/.uade2) +3. make +4. make install (as root if installed globally, but as the user if configure + was given --user) + +The program is ready now. + +Now you can edit uade.conf, if you want. uade.conf is located at +$PREFIX/share/uade2/uade.conf or ~/.uade2/uade.conf. If you installed +globally, you can make a copy of uade.conf to ~/.uade2/. + +Fire up xmms, audacious or use the command line tool. + +$ uade123 -zr /my/chips + +Credits +======= + +See AUTHORS file for credits. + +Information sources +=================== + +Web site: + + http://zakalwe.fi/uade + +Public web forum (most issues should go here): + + http://board.kohina.net/index.php?c=5 + +Public IRC channel: + + #amigaexotic at IRCNet + +Subscribe to new releases at: http://freshmeat.net/projects/uade + +Project maintainer: + Heikki Orsila + heikki.orsila@iki.fi diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/amifilemagic.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/amifilemagic.c new file mode 100644 index 00000000..9365436c --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/amifilemagic.c @@ -0,0 +1,1168 @@ +/* + Copyright (C) 2000-2005 Heikki Orsila + Copyright (C) 2000-2005 Michael Doering + + This module is dual licensed under the GNU GPL and the Public Domain. + Hence you may use _this_ module (not another code module) in any way you + want in your projects. + + About security: + + This module tries to avoid any buffer overruns by not copying anything but + hard coded strings (such as "FC13"). This doesn't + copy any data from modules to program memory. Any memory writing with + non-hard-coded data is an error by assumption. This module will only + determine the format of a given module. + + Occasional memory reads over buffer ranges can occur, but they will of course + be fixed when spotted :P The worst that can happen with reading over the + buffer range is a core dump :) +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <uadeutils.h> +#include <amifilemagic.h> + +#define FILEMAGIC_DEBUG 0 + +#if FILEMAGIC_DEBUG +#define amifiledebug(fmt, args...) do { fprintf(stderr, "%s:%d: %s: " fmt, __FILE__, __LINE__, __func__, ## args); } while(0) +#else +#define amifiledebug(fmt, args...) +#endif + +#define WAV_HEADER_LEN 44 + +enum { + MOD_UNDEFINED = 0, + MOD_SOUNDTRACKER25_NOISETRACKER10, + MOD_NOISETRACKER12, + MOD_NOISETRACKER20, + MOD_STARTREKKER4, + MOD_STARTREKKER8, + MOD_AUDIOSCULPTURE4, + MOD_AUDIOSCULPTURE8, + MOD_PROTRACKER, + MOD_FASTTRACKER, + MOD_NOISETRACKER, + MOD_PTK_COMPATIBLE, + MOD_SOUNDTRACKER24 +}; + + +#define S15_HEADER_LENGTH 600 +#define S31_HEADER_LENGTH 1084 + + +static int chk_id_offset(unsigned char *buf, int bufsize, + const char *patterns[], int offset, char *pre); + + +/* Do not use '\0'. They won't work in patterns */ +static const char *offset_0000_patterns[] = { + /* ID: Prefix: Desc: */ + "DIGI Booster", "DIGI", /* Digibooster */ + "OKTASONG", "OKT", /* Oktalyzer */ + "SYNTRACKER", "SYNMOD", /* Syntracker */ + "OBISYNTHPACK", "OSP", /* Synthpack */ + "SOARV1.0", "SA", /* Sonic Arranger */ + "AON4", "AON4", /* Art Of Noise (4ch) */ + "AON8", "AON8", /* Art Of Noise (8ch) */ + "ARP.", "MTP2", /* HolyNoise / Major Tom */ + "AmBk", "ABK", /* Amos ABK */ + "FUCO", "BSI", /* FutureComposer BSI */ + "MMU2", "DSS", /* DSS */ + "GLUE", "GLUE", /* GlueMon */ + "ISM!", "IS", /* In Stereo */ + "IS20", "IS20", /* In Stereo 2 */ + "SMOD", "FC13", /* FC 1.3 */ + "FC14", "FC14", /* FC 1.4 */ + "MMDC", "MMDC", /* Med packer */ + "MSOB", "MSO", /* Medley */ + "MODU", "NTP", /* Novotrade */ +/* HIPPEL-ST CONFLICT: "COSO", "SOC",*/ /* Hippel Coso */ + "BeEp", "JAM", /* Jamcracker */ + "ALL ", "DM1", /* Deltamusic 1 */ + "YMST", "YM", /* MYST ST-YM */ + "AMC ", "AMC", /* AM-Composer */ + "P40A", "P40A", /* The Player 4.0a */ + "P40B", "P40B", /* The Player 4.0b */ + "P41A", "P41A", /* The Player 4.1a */ + "P50A", "P50A", /* The Player 5.0a */ + "P60A", "P60A", /* The Player 6.0a */ + "P61A", "P61A", /* The Player 6.1a */ + "SNT!", "PRU2", /* Prorunner 2 */ + "MEXX_TP2", "TP2", /* Tracker Packer 2 */ + "CPLX_TP3", "TP3", /* Tracker Packer 3 */ + "MEXX", "TP1", /* Tracker Packer 2 */ + "PM40", "PM40", /* Promizer 4.0 */ + "FC-M", "FC-M", /* FC-M */ + "E.M.S. V6.", "EMSV6", /* EMS version 6 */ + "MCMD", "MCMD_org", /* 0x00 MCMD format */ + "STP3", "STP3", /* Soundtracker Pro 2 */ + "MTM", "MTM", /* Multitracker */ + "Extended Module:", "XM", /* Fasttracker2 */ + "MLEDMODL", "ML", /* Musicline Editor */ + "FTM", "FTM", /* Face The Music */ + "MXTX", "MXTX", /* Maxtrax*/ + "M1.0", "FUZZ", /* Fuzzac*/ + "MSNG", "TPU", /* Dirk Bialluch*/ + "YM!", "", /* stplay -- intentionally sabotaged */ + "ST1.2 ModuleINFO", "", /* Startrekker AM .NT -- intentionally sabotaged */ + "AudioSculpture10", "", /* Audiosculpture .AS -- intentionally sabotaged */ + NULL, NULL +}; + +static const char *offset_0024_patterns[] = { + /* ID: Prefix: Desc: */ + "UNCLEART", "DL", /* Dave Lowe WT */ + "DAVELOWE", "DL_deli", /* Dave Lowe Deli */ + "J.FLOGEL", "JMF", /* Janko Mrsic-Flogel */ + "BEATHOVEN", "BSS", /* BSS */ + "FREDGRAY", "GRAY", /* Fred Gray */ + "H.DAVIES", "HD", /* Howie Davies */ + "RIFFRAFF", "RIFF", /* Riff Raff */ + "!SOPROL!", "SPL", /* Soprol */ + "F.PLAYER", "FP", /* F.Player */ + "S.PHIPPS", "CORE", /* Core Design */ + "DAGLISH!", "BDS", /* Benn Daglish */ + NULL, NULL +}; + + +/* check for 'pattern' in 'buf'. + the 'pattern' must lie inside range [0, maxlen) in the buffer. + returns true if pattern is at buf[offset], otherwrise false + */ +static int patterntest(const unsigned char *buf, const char *pattern, + int offset, int bytes, int maxlen) +{ + if ((offset + bytes) <= maxlen) + return (memcmp(buf + offset, pattern, bytes) == 0) ? 1 : 0; + return 0; +} + + +static int tronictest(unsigned char *buf, size_t bufsize) +{ + size_t a = read_be_u16(&buf[0x02]) + read_be_u16(&buf[0x06]) + + read_be_u16(&buf[0x0a]) + read_be_u16(&buf[0x0e]) + 0x10; + + if (((a + 2) >= bufsize) || (a & 1)) + return 0; /* size & btst #0, d1; */ + + a = read_be_u16(&buf[a]) + a; + if (((a + 8) >= bufsize) || (a & 1)) + return 0; /*size & btst #0,d1 */ + + if (read_be_u32(&buf[a + 4]) != 0x5800b0) + return 0; + + amifiledebug("tronic recognized\n"); + + return 1; +} + +static int tfmxtest(unsigned char *buf, size_t bufsize, char *pre) +{ + if (bufsize <= 0x208) + return 0; + + if (strncmp((char *) buf, "TFHD", 4) == 0) { + if (buf[0x8] == 0x01) { + strcpy(pre, "TFHD1.5"); /* One File TFMX format by Alexis NASR */ + return 1; + } else if (buf[0x8] == 0x02) { + strcpy(pre, "TFHDPro"); + return 1; + } else if (buf[0x8] == 0x03) { + strcpy(pre, "TFHD7V"); + return 1; + } + } + + if (strncasecmp((char *) buf, "TFMX", 4) == 0) { + if (strncmp((char *) &buf[4], "-SONG", 5) == 0 || + strncmp((char *) &buf[4], "_SONG ", 6) == 0 || + strncasecmp((char *) &buf[4], "SONG", 4) == 0 || + buf[4] == 0x20) { + strcpy(pre, "MDAT"); /*default TFMX: TFMX Pro */ + + if (strncmp((char *) &buf[10], "by", 2) == 0 || + strncmp((char *) &buf[16], " ", 2) == 0 || + strncmp((char *) &buf[16], "(Empty)", 7) == 0 || + /* Lethal Zone */ + (buf[16] == 0x30 && buf[17] == 0x3d) || + (buf[4] == 0x20)){ + + if (read_be_u32(&buf[464]) == 0x00000000) { + uint16_t x = read_be_u16(&buf[14]); + if ((x != 0x0e60) || /* z-out title */ + (x == 0x0860 && bufsize > 4645 && read_be_u16(&buf[4644]) != 0x090c) || /* metal law */ + (x == 0x0b20 && bufsize > 5121 && read_be_u16(&buf[5120]) != 0x8c26) || /* bug bomber */ + (x == 0x0920 && bufsize > 3977 && read_be_u16(&buf[3876]) != 0x9305)) { /* metal preview */ + strcpy(pre, "TFMX1.5"); /*TFMX 1.0 - 1.6 */ + } + } + return 1; + + } else if (((buf[0x0e] == 0x08 && buf[0x0f] == 0xb0) && /* BMWi */ + (buf[0x140] == 0x00 && buf[0x141] == 0x0b) && /*End tackstep 1st subsong */ + (buf[0x1d2] == 0x02 && buf[0x1d3] == 0x00) && /*Trackstep datas */ + (buf[0x200] == 0xff && buf[0x201] == 0x00 && /*First effect */ + buf[0x202] == 0x00 && buf[0x203] == 0x00 && + buf[0x204] == 0x01 && buf[0x205] == 0xf4 && + buf[0x206] == 0xff && buf[0x207] == 0x00)) || + ((buf[0x0e] == 0x0A && buf[0x0f] == 0xb0) && /* B.C Kid */ + (buf[0x140] == 0x00 && buf[0x141] == 0x15) && /*End tackstep 1st subsong */ + (buf[0x1d2] == 0x02 && buf[0x1d3] == 0x00) && /*Trackstep datas */ + (buf[0x200] == 0xef && buf[0x201] == 0xfe && /*First effect */ + buf[0x202] == 0x00 && buf[0x203] == 0x03 && + buf[0x204] == 0x00 && buf[0x205] == 0x0d && + buf[0x206] == 0x00 && buf[0x207] == 0x00))) { + strcpy(pre, "TFMX7V"); /* "special cases TFMX 7V */ + return 1; + + } else { + int e, i, s, t; + + /* Trackstep datas offset */ + s = read_be_u32(&buf[0x1d0]); + if (s == 0x00000000) { + /* unpacked */ + s = 0x00000800; + } + + for (i = 0; i < 0x3d; i += 2) { + if (read_be_u16(&buf[0x140 + i]) != 0x0000) { /* subsong */ + /* Start of subsongs Trackstep data :) */ + t = read_be_u16(&buf[0x100 + i]) * 16 + s; + /* End of subsongs Trackstep data :) */ + e = read_be_u16(&buf[0x140 + i]) * 16 + s; + if (e < bufsize) { + for (; t < e && (t + 6) < bufsize; t += 2) { + if (read_be_u16(&buf[t]) == 0xeffe && + read_be_u32(&buf[t + 2]) == 0x0003ff00 && + buf[t + 6] == 0x00) { + strcpy(pre, "TFMX7V"); /*TFMX 7V */ + return 1; + } + } + } + } + } + } + } + } + return 0; +} + +/* Calculate Module length: Just need at max 1084 */ +/* data in buf for a */ +/* succesful calculation */ +/* returns: */ +/* -1 for no mod */ +/* 1 for a mod with good length */ +static size_t modlentest(unsigned char *buf, size_t bufsize, size_t filesize, + int header) +{ + int i; + int no_of_instr; + int smpl = 0; + int plist; + int maxpattern = 0; + + if (header > bufsize) + return -1; /* no mod */ + + if (header == S15_HEADER_LENGTH) { + no_of_instr = 15; + plist = header - 128; + } else if (header == S31_HEADER_LENGTH) { + no_of_instr = 31; + plist = header - 4 - 128; + } else { + return -1; + } + + for (i = 0; i < 128; i++) { + if (buf[plist + i] > maxpattern) + maxpattern = buf[plist + i]; + } + + if (maxpattern > 100) + return -1; + + for (i = 0; i < no_of_instr; i++) + smpl += 2 * read_be_u16(&buf[42 + i * 30]); /* add sample length in bytes*/ + + return header + (maxpattern + 1) * 1024 + smpl; +} + + +static void modparsing(unsigned char *buf, size_t bufsize, size_t header, int max_pattern, int pfx[], int pfxarg[]) +{ + int offset; + int i, j, fx; + unsigned char fxarg; + + for (i = 0; i < max_pattern; i++) { + for (j = 0; j < 256; j++) { + offset = header + i * 1024 + j * 4; + + if ((offset + 4) > bufsize) + return; + + fx = buf[offset + 2] & 0x0f; + fxarg = buf[offset + 3]; + + if (fx == 0) { + if (fxarg != 0 ) + pfx[fx] += 1; + pfxarg[fx] = (pfxarg[fx] > fxarg) ? pfxarg[fx] : fxarg; + + } else if (1 <= fx && fx <= 13) { + pfx[fx] +=1; + pfxarg[fx] = (pfxarg[fx] > fxarg) ? pfxarg[fx] : fxarg; + + } else if (fx == 14) { + pfx[((fxarg >> 4) & 0x0f) + 16] +=1; + + } else if (fx == 15) { + if (fxarg > 0x1f) + pfx[14] +=1; + else + pfx[15] +=1; + pfxarg[15] = (pfxarg[15] > fxarg) ? pfxarg[15] : fxarg; + } + } + } + +} + + +static int mod32check(unsigned char *buf, size_t bufsize, size_t realfilesize, + const char *path, int verbose) +{ + /* mod patterns at file offset 0x438 */ + char *mod_patterns[] = { "M.K.", ".M.K", NULL}; + /* startrekker patterns at file offset 0x438 */ + char *startrekker_patterns[] = { "FLT4", "FLT8", "EXO4", "EXO8", NULL}; + + int max_pattern = 0; + int i, j, t, ret; + int pfx[32]; + int pfxarg[32]; + + /* instrument var */ + int vol, slen, srep, sreplen; + + int has_slen_sreplen_zero = 0; /* sreplen empty of non looping instrument */ + int no_slen_sreplen_zero = 0; /* sreplen */ + + int has_slen_sreplen_one = 0; + int no_slen_sreplen_one = 0; + + int no_slen_has_volume = 0; + int finetune_used = 0; + + size_t calculated_size; + + /* returns: 0 for undefined */ + /* 1 for a Soundtracker2.5/Noisetracker 1.0 */ + /* 2 for a Noisetracker 1.2 */ + /* 3 for a Noisetracker 2.0 */ + /* 4 for a Startrekker 4ch */ + /* 5 for a Startrekker 8ch */ + /* 6 for Audiosculpture 4 ch/fm */ + /* 7 for Audiosculpture 8 ch/fm */ + /* 8 for a Protracker */ + /* 9 for a Fasttracker */ + /* 10 for a Noisetracker (M&K!) */ + /* 11 for a PTK Compatible */ + /* 12 for a Soundtracker 31instr. with repl in bytes */ + + /* Special cases first */ + if (patterntest(buf, "M&K!", (S31_HEADER_LENGTH - 4), 4, bufsize)) + return MOD_NOISETRACKER; /* Noisetracker (M&K!) */ + + if (patterntest(buf, "M!K!", (S31_HEADER_LENGTH - 4), 4, bufsize)) + return MOD_PROTRACKER; /* Protracker (100 patterns) */ + + if (patterntest(buf, "N.T.", (S31_HEADER_LENGTH - 4), 4, bufsize)) + return MOD_NOISETRACKER20; /* Noisetracker2.x */ + + for (i = 0; startrekker_patterns[i]; i++) { + if (patterntest(buf, startrekker_patterns[i], (S31_HEADER_LENGTH - 4), 4, bufsize)) { + t = 0; + for (j = 0; j < 30 * 0x1e; j = j + 0x1e) { + if (buf[0x2a + j] == 0 && buf[0x2b + j] == 0 && buf[0x2d + j] != 0) { + t = t + 1; /* no of AM instr. */ + } + } + if (t > 0) { + if (buf[0x43b] == '4'){ + ret = MOD_AUDIOSCULPTURE4; /* Startrekker 4 AM / ADSC */ + } else { + ret = MOD_AUDIOSCULPTURE8; /* Startrekker 8 AM / ADSC */ + } + } else { + if (buf[0x43b] == '4'){ + ret = MOD_STARTREKKER4; /* Startrekker 4ch */ + } else { + ret = MOD_STARTREKKER8; /* Startrekker 8ch */ + } + } + return ret; + } + } + + calculated_size = modlentest(buf, bufsize, realfilesize, S31_HEADER_LENGTH); + + if (calculated_size == -1) + return MOD_UNDEFINED; + + + for (i = 0; mod_patterns[i]; i++) { + if (patterntest(buf, mod_patterns[i], S31_HEADER_LENGTH - 4, 4, bufsize)) { + /* seems to be a generic M.K. MOD */ + /* only spam filesize message when it's a tracker module */ + + if (calculated_size != realfilesize) { + fprintf(stderr, "uade: file size is %zd but calculated size for a mod file is %zd (%s).\n", realfilesize, calculated_size, path); + } + + if (calculated_size > realfilesize) { + fprintf(stderr, "uade: file is truncated and won't get played (%s)\n", path); + return MOD_UNDEFINED; + } + + if (calculated_size < realfilesize) { + fprintf(stderr, "uade: file has trailing garbage behind the actual module data. Please fix it. (%s)\n", path); + } + + /* parse instruments */ + for (i = 0; i < 31; i++) { + vol = buf[45 + i * 30]; + slen = ((buf[42 + i * 30] << 8) + buf[43 + i * 30]) * 2; + srep = ((buf[46 + i * 30] << 8) + buf[47 + i * 30]) *2; + sreplen = ((buf[48 + i * 30] << 8) + buf[49 + i * 30]) * 2; + /* fprintf (stderr, "%d, slen: %d, %d (srep %d, sreplen %d), vol: %d\n",i, slen, srep+sreplen,srep, sreplen, vol); */ + + if (vol > 64) + return MOD_UNDEFINED; + + if (buf[44 + i * 30] != 0) { + if (buf[44+i*30] > 15) { + return MOD_UNDEFINED; + } else { + finetune_used++; + } + } + + if (slen > 0 && (srep + sreplen) > slen) { + /* Old Noisetracker /Soundtracker with repeat offset in bytes */ + return MOD_SOUNDTRACKER24; + } + + if (srep == 0) { + if (slen > 0) { + if (sreplen == 2){ + has_slen_sreplen_one++; + } + if (sreplen == 0){ + has_slen_sreplen_zero++; + } + } else { + if (sreplen > 0){ + no_slen_sreplen_one++; + } else { + no_slen_sreplen_zero++; + } + if (vol > 0) + no_slen_has_volume++; + } + } + } + + for (i = 0; i < 128; i++) { + if (buf[1080 - 130 + 2 + i] > max_pattern) + max_pattern = buf[1080 - 130 + 2 + i]; + } + + if (max_pattern > 100) { + /* pattern number can only be 0 <-> 100 for mod*/ + return MOD_UNDEFINED; + } + + memset (pfx, 0, sizeof (pfx)); + memset (pfxarg, 0, sizeof (pfxarg)); + modparsing(buf, bufsize, S31_HEADER_LENGTH-4, max_pattern, pfx, pfxarg); + + /* and now for let's see if we can spot the mod */ + + /* FX used: */ + /* DOC Soundtracker 2.x(2.5): 0,1,2(3,4) a,b,c,d,e,f */ + /* Noisetracker 1.x: 0,1,2,3,4 a,b,c,d,e,f */ + /* Noisetracker 2.x: 0,1,2,3,4 a,b,c,d,e,f */ + /* Protracker: 0,1,2,3,4,5,6,7 9,a,b,c,d,e,f +e## */ + /* PC tracker: 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f +e## */ + + for (j = 17; j <= 31; j++) { + if (pfx[j] != 0 || finetune_used >0) /* Extended fx used */ { + if (buf[0x3b7] != 0x7f && buf[0x3b7] != 0x78) { + return MOD_FASTTRACKER; /* Definetely Fasttracker*/ + } else { + return MOD_PROTRACKER; /* Protracker*/ + } + } + } + + if ((buf[0x3b7] == 0x7f) && + (has_slen_sreplen_zero <= has_slen_sreplen_one) && + (no_slen_sreplen_zero <=no_slen_sreplen_one)) + return MOD_PROTRACKER; /* Protracker */ + + if (buf[0x3b7] >0x7f) + return MOD_PTK_COMPATIBLE; /* Protracker compatible */ + + if ((buf[0x3b7] == 0) && + (has_slen_sreplen_zero > has_slen_sreplen_one) && + (no_slen_sreplen_zero > no_slen_sreplen_one)){ + if (pfx[0x10] == 0) { + /* probl. Fastracker or Protracker compatible */ + return MOD_PTK_COMPATIBLE; + } + /* FIXME: Investigate + else { + return MOD_PROTRACKER; // probl. Protracker + } */ + } + + if (pfx[0x05] != 0 || pfx[0x06] != 0 || pfx[0x07] != 0 || + pfx[0x09] != 0) { + /* Protracker compatible */ + return MOD_PTK_COMPATIBLE; + } + + if ((buf[0x3b7] >0 && buf[0x3b7] <= buf[0x3b6]) && + (has_slen_sreplen_zero <= has_slen_sreplen_one) && + (no_slen_sreplen_zero == 1) && + (no_slen_sreplen_zero <= no_slen_sreplen_one)) + return MOD_NOISETRACKER12; // Noisetracker 1.2 + + if ((buf[0x3b7] <0x80) && + (has_slen_sreplen_zero <= has_slen_sreplen_one) && + (no_slen_sreplen_zero <=no_slen_sreplen_one)) + return MOD_NOISETRACKER20; // Noisetracker 2.x + + if ((buf[0x3b7] <0x80) && + (pfx[0x0e] ==0) && + (has_slen_sreplen_zero <= has_slen_sreplen_one) && + (no_slen_sreplen_zero >=no_slen_sreplen_one)) + return MOD_SOUNDTRACKER25_NOISETRACKER10; // Noisetracker 1.x + + return MOD_PTK_COMPATIBLE; // Protracker compatible + } + } + + return MOD_UNDEFINED; +} + + +static int mod15check(unsigned char *buf, size_t bufsize, size_t realfilesize, + const char *path) +/* pattern parsing based on Sylvain 'Asle' Chipaux' */ +/* Modinfo-V2 */ +/* */ +/* returns: 0 for an undefined mod */ +/* 1 for a DOC Soundtracker mod */ +/* 2 for a Ultimate ST mod */ +/* 3 for a Mastersoundtracker */ +/* 4 for a SoundtrackerV2.0 -V4.0 */ +{ + int i = 0, j = 0; + int slen = 0; + int srep = 0; + int sreplen = 0; + int vol = 0; + + int noof_slen_zero_sreplen_zero = 0; + int noof_slen_zero_vol_zero = 0; + int srep_bigger_slen = 0; + int srep_bigger_ffff = 0; + int st_xy = 0; + + int max_pattern = 1; + int pfx[32]; + int pfxarg[32]; + + size_t calculated_size; + + /* sanity checks */ + if (bufsize < 0x1f3) + return 0; /* file too small */ + + if (bufsize < 2648+4 || realfilesize <2648+4) /* size 1 pattern + 1x 4 bytes Instrument :) */ + return 0; + + calculated_size = modlentest(buf, bufsize, realfilesize, S15_HEADER_LENGTH); + if (calculated_size == -1) + return 0; /* modlentest failed */ + + if (calculated_size != realfilesize) { + return 0 ; + } + + if (calculated_size > realfilesize) { + fprintf(stderr, "uade: file is truncated and won't get played (%s)\n", path); + return 0 ; + } + + + + /* check for 15 instruments */ + if (buf[0x1d6] != 0x00 && buf[0x1d6] < 0x81 && buf[0x1f3] !=1) { + for (i = 0; i < 128; i++) { /* pattern list table: 128 posbl. entries */ + max_pattern=(buf[600 - 130 + 2 + i] > max_pattern) ? buf[600 - 130 + 2 + i] : max_pattern; + } + if (max_pattern > 63) + return 0; /* pattern number can only be 0 <-> 63 for mod15 */ + } else { + return 0; + } + + /* parse instruments */ + for (i = 0; i < 15; i++) { + vol = buf[45 + i * 30]; + slen = ((buf[42 + i * 30] << 8) + buf[43 + i * 30]) * 2; + srep = ((buf[46 + i * 30] << 8) + buf[47 + i * 30]); + sreplen = ((buf[48 + i * 30] << 8) + buf[49 + i * 30]) * 2; + /* fprintf (stderr, "%d, slen: %d, %d (srep %d, sreplen %d), vol: %d\n",i, slen, srep+sreplen,srep, sreplen, vol); */ + + if (vol > 64 && buf[44+i*30] != 0) return 0; /* vol and finetune */ + + if (slen == 0) { + + if (vol == 0) + noof_slen_zero_vol_zero++; + + if (sreplen == 0 ) + noof_slen_zero_sreplen_zero++; + + } else { + if ((srep+sreplen) > slen) + srep_bigger_slen++; + } + + /* slen < 9999 */ + slen = (buf[42 + i * 30] << 8) + buf[43 + i * 30]; + if (slen <= 9999) { + /* repeat offset + repeat size*2 < word size */ + srep = ((buf[48 + i * 30] << 8) + buf[49 + i * 30]) * 2 + + ((buf[46 + i * 30] << 8) + buf[47 + i * 30]); + if (srep > 0xffff) srep_bigger_ffff++; + } + + if (buf[25+i*30] ==':' && buf [22+i*30] == '-' && + ((buf[20+i*30] =='S' && buf [21+i*30] == 'T') || + (buf[20+i*30] =='s' && buf [21+i*30] == 't'))) st_xy++; + } + + /* parse pattern data -> fill pfx[] with number of times fx being used*/ + memset (pfx, 0, sizeof (pfx)); + memset (pfxarg, 0, sizeof (pfxarg)); + + modparsing(buf, bufsize, S15_HEADER_LENGTH, max_pattern, pfx, pfxarg); + + /* and now for let's see if we can spot the mod */ + +/* FX used: */ +/* Ultimate ST: 0,1,2 */ +/* MasterSoundtracker: 0,1,2, c, e,f */ +/* DOC-Soundtracker V2.2: 0,1,2,a,b,c,d,e,f */ +/* Soundtracker I-VI 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f*/ + + + /* Check for fx used between 0x3 <-> 0xb for some weird ST II-IV mods */ + for (j = 0x5; j < 0xa; j++) { + if (pfx[j] != 0) + return 4; /* ST II-IV */ + } + + for (j = 0x0c; j < 0x11; j++) { + if (pfx[j] != 0) { + + if (pfx[0x0d] != 0 && pfxarg[0x0d] != 0) + return 4; /* ST II-IV */ + + if (pfx[0x0b] != 0 || pfx[0x0d] != 0 || pfx[0x0a]!= 0 ) { + return 1; /* DOC ST */ + } else { + if (pfxarg[1] > 0xe || pfxarg[2] > 0xe) + return 1; /* DOC ST */ + + return 3; /* Master ST */ + } + } + } + + /* pitchbend out of range ? */ + if ((pfxarg[1] > 0 && pfxarg[1] <0x1f) || + (pfxarg[2] > 0 && pfxarg [2] <0x1f) || + pfx [0] >2) return 1; // ST style Arpeggio, Pitchbends ??? + + if (pfx[1] > 0 || pfx[2] > 0) + return 2; /* nope UST like fx */ + + /* the rest of the files has no fx. so check instruments */ + if (st_xy!=0 && noof_slen_zero_vol_zero == 0 && + noof_slen_zero_sreplen_zero == 0 && buf[0x1d7] == 120) { + return 3; + } + + /* no fx, no loops... let's simply guess :)*/ + if (srep_bigger_slen == 0 && srep_bigger_ffff == 0 && + ((st_xy != 0 && buf[0x1d7] != 120 ) || st_xy==0)) + return 2; + + return 3; /* anything is played as normal soundtracker */ +} + +/* Reject WAV files so that uadefs doesn't cause bad behaviour */ +static int is_wav_file(unsigned char *buf, size_t size) +{ + if (size < WAV_HEADER_LEN) + return 0; + + if (memcmp(buf, "RIFF", 4)) + return 0; + + if (memcmp(buf + 8, "WAVEfmt ", 8)) + return 0; + + if (memcmp(buf + 36, "data", 4)) + return 0; + + return 1; +} + +void uade_filemagic(unsigned char *buf, size_t bufsize, char *pre, + size_t realfilesize, const char *path, int verbose) +{ + /* char filemagic(): + detects formats like e.g.: tfmx1.5, hip, hipc, fc13, fc1.4 + - tfmx 1.5 checking based on both tfmx DT and tfmxplay by jhp, + and the EP by Don Adan/WT. + - tfmx 7v checking based on info by don adan, the amore file + ripping description and jhp's desc of the tfmx format. + - other checks based on e.g. various player sources from Exotica + or by checking bytes with a hexeditor + by far not complete... + + NOTE: Those Magic ID checks are quite lame compared to the checks the + amiga replayer do... well, after all we are not ripping. so they + have to do at the moment :) + */ + + int i, modtype, t; + + struct modtype { + int e; + char *str; + }; + + struct modtype mod32types[] = { + {.e = MOD_SOUNDTRACKER25_NOISETRACKER10, .str = "MOD_NTK"}, + {.e = MOD_NOISETRACKER12, .str = "MOD_NTK1"}, + {.e = MOD_NOISETRACKER20, .str = "MOD_NTK2"}, + {.e = MOD_STARTREKKER4, .str = "MOD_FLT4"}, + {.e = MOD_STARTREKKER8, .str = "MOD_FLT8"}, + {.e = MOD_AUDIOSCULPTURE4, .str = "MOD_ADSC4"}, + {.e = MOD_AUDIOSCULPTURE8, .str = "MOD_ADSC8"}, + {.e = MOD_PROTRACKER, .str = "MOD"}, + {.e = MOD_FASTTRACKER, .str = "MOD_COMP"}, + {.e = MOD_NOISETRACKER, .str = "MOD_NTKAMP"}, + {.e = MOD_PTK_COMPATIBLE, .str = "MOD_COMP"}, + {.e = MOD_SOUNDTRACKER24, .str = "MOD_DOC"}, + {.str = NULL} + }; + + struct modtype mod15types[] = { + {.e = 1, .str = "MOD15"}, + {.e = 2, .str = "MOD15_UST"}, + {.e = 3, .str = "MOD15_MST"}, + {.e = 4, .str = "MOD15_ST-IV"}, + {.str = NULL} + }; + + /* Mark format unknown by default */ + pre[0] = 0; + + if (is_wav_file(buf, bufsize)) { + strcpy(pre, "reject"); + return; + } + + modtype = mod32check(buf, bufsize, realfilesize, path, verbose); + if (modtype != MOD_UNDEFINED) { + for (t = 0; mod32types[t].str != NULL; t++) { + if (modtype == mod32types[t].e) { + strcpy(pre, mod32types[t].str); + return; + } + } + } + + /* 0x438 == S31_HEADER_LENGTH - 4 */ + if (((buf[0x438] >= '1' && buf[0x438] <= '3') + && (buf[0x439] >= '0' && buf[0x439] <= '9') && buf[0x43a] == 'C' + && buf[0x43b] == 'H') || ((buf[0x438] >= '2' && buf[0x438] <= '8') + && buf[0x439] == 'C' && buf[0x43a] == 'H' + && buf[0x43b] == 'N') + || (buf[0x438] == 'T' && buf[0x439] == 'D' && buf[0x43a] == 'Z') + || (buf[0x438] == 'O' && buf[0x439] == 'C' && buf[0x43a] == 'T' + && buf[0x43b] == 'A') || (buf[0x438] == 'C' && buf[0x439] == 'D' + && buf[0x43a] == '8' + && buf[0x43b] == '1')) { + strcpy(pre, "MOD_PC"); /*Multichannel Tracker */ + + } else if (buf[0x2c] == 'S' && buf[0x2d] == 'C' && buf[0x2e] == 'R' + && buf[0x2f] == 'M') { + strcpy(pre, "S3M"); /*Scream Tracker */ + + } else if ((buf[0] == 0x60 && buf[2] == 0x60 && buf[4] == 0x48 + && buf[5] == 0xe7) || (buf[0] == 0x60 && buf[2] == 0x60 + && buf[4] == 0x41 && buf[5] == 0xfa) + || (buf[0] == 0x60 && buf[1] == 0x00 && buf[4] == 0x60 + && buf[5] == 0x00 && buf[8] == 0x48 && buf[9] == 0xe7) + || (buf[0] == 0x60 && buf[1] == 0x00 && buf[4] == 0x60 + && buf[5] == 0x00 && buf[8] == 0x60 && buf[9] == 0x00 + && buf[12] == 0x60 && buf[13] == 0x00 && buf[16] == 0x48 + && buf[17] == 0xe7)) { + strcpy(pre, "SOG"); /* Hippel */ + + } else if (buf[0x348] == '.' && buf[0x349] == 'Z' && buf[0x34A] == 'A' + && buf[0x34B] == 'D' && buf[0x34c] == 'S' && buf[0x34d] == '8' + && buf[0x34e] == '9' && buf[0x34f] == '.') { + strcpy(pre, "MKII"); /* Mark II */ + + } else if (read_be_u16(&buf[0x00]) == 0x2b7c && + read_be_u16(&buf[0x08]) == 0x2b7c && + read_be_u16(&buf[0x10]) == 0x2b7c && + read_be_u16(&buf[0x18]) == 0x2b7c && + read_be_u32(&buf[0x20]) == 0x303c00ff && + read_be_u32(&buf[0x24]) == 0x32004eb9 && + read_be_u16(&buf[0x2c]) == 0x4e75) { + strcpy(pre, "JPO"); /* Steve Turner*/ + + } else if (((buf[0] == 0x08 && buf[1] == 0xf9 && buf[2] == 0x00 + && buf[3] == 0x01) && (buf[4] == 0x00 && buf[5] == 0xbb + && buf[6] == 0x41 && buf[7] == 0xfa) + && ((buf[0x25c] == 0x4e && buf[0x25d] == 0x75) + || (buf[0x25c] == 0x4e && buf[0x25d] == 0xf9))) + || ((buf[0] == 0x41 && buf[1] == 0xfa) + && (buf[4] == 0xd1 && buf[5] == 0xe8) + && (((buf[0x230] == 0x4e && buf[0x231] == 0x75) + || (buf[0x230] == 0x4e && buf[0x231] == 0xf9)) + || ((buf[0x29c] == 0x4e && buf[0x29d] == 0x75) + || (buf[0x29c] == 0x4e && buf[0x29d] == 0xf9)) + ))) { + strcpy(pre, "SID1"); /* SidMon1 */ + + } else if (buf[0] == 0x4e && buf[1] == 0xfa && + buf[4] == 0x4e && buf[5] == 0xfa && + buf[8] == 0x4e && buf[9] == 0xfa && + buf[2] == 0x00 && buf[6] == 0x06 && buf[10] == 0x07) { + if (buf[3] == 0x2a && buf[7] == 0xfc && buf[11] == 0x7c) { + strcpy(pre, "SA_old"); + } else if (buf[3] == 0x1a && buf[7] == 0xc6 && buf[11] == 0x3a) { + strcpy(pre, "SA"); + } + + } else if (buf[0] == 0x4e && buf[1] == 0xfa && + buf[4] == 0x4e && buf[5] == 0xfa && + buf[8] == 0x4e && buf[9] == 0xfa && + buf[0xc] == 0x4e && buf[0xd] == 0xfa) { + for (i = 0x10; i < 256; i = i + 2) { + if (buf[i + 0] == 0x4e && buf[i + 1] == 0x75 && buf[i + 2] == 0x47 + && buf[i + 3] == 0xfa && buf[i + 12] == 0x4e && buf[i + 13] == 0x75) { + strcpy(pre, "FRED"); /* FRED */ + break; + } + } + + } else if (buf[0] == 0x60 && buf[1] == 0x00 && + buf[4] == 0x60 && buf[5] == 0x00 && + buf[8] == 0x60 && buf[9] == 0x00 && + buf[12] == 0x48 && buf[13] == 0xe7) { + strcpy(pre, "MA"); /*Music Assembler */ + + } else if (buf[0] == 0x00 && buf[1] == 0x00 && + buf[2] == 0x00 && buf[3] == 0x28 && + (buf[7] >= 0x34 && buf[7] <= 0x64) && + buf[0x20] == 0x21 && (buf[0x21] == 0x54 || buf[0x21] == 0x44) + && buf[0x22] == 0xff && buf[0x23] == 0xff) { + strcpy(pre, "SA-P"); /*SonicArranger Packed */ + + + } else if (buf[0] == 0x4e && buf[1] == 0xfa && + buf[4] == 0x4e && buf[5] == 0xfa && + buf[8] == 0x4e && buf[9] == 0xfa) { + t = ((buf[2] * 256) + buf[3]); + if (t < bufsize - 9) { + if (buf[2 + t] == 0x4b && buf[3 + t] == 0xfa && + buf[6 + t] == 0x08 && buf[7 + t] == 0xad && buf[8 + t] == 0x00 + && buf[9 + t] == 0x00) { + strcpy(pre, "MON"); /*M.O.N */ + } + } + + } else if (buf[0] == 0x02 && buf[1] == 0x39 && + buf[2] == 0x00 && buf[3] == 0x01 && + buf[8] == 0x66 && buf[9] == 0x02 && + buf[10] == 0x4e && buf[11] == 0x75 && + buf[12] == 0x78 && buf[13] == 0x00 && + buf[14] == 0x18 && buf[15] == 0x39) { + strcpy(pre, "MON_old"); /*M.O.N_old */ + + } else if (buf[0] == 0x48 && buf[1] == 0xe7 && buf[2] == 0xf1 + && buf[3] == 0xfe && buf[4] == 0x61 && buf[5] == 0x00) { + t = ((buf[6] * 256) + buf[7]); + if (t < (bufsize - 17)) { + for (i = 0; i < 10; i = i + 2) { + if (buf[6 + t + i] == 0x47 && buf[7 + t + i] == 0xfa) { + strcpy(pre, "DW"); /*Whittaker Type1... FIXME: incomplete */ + } + } + } + + } else if (buf[0] == 0x13 && buf[1] == 0xfc && + buf[2] == 0x00 && buf[3] == 0x40 && + buf[8] == 0x4e && buf[9] == 0x71 && + buf[10] == 0x04 && buf[11] == 0x39 && + buf[12] == 0x00 && buf[13] == 0x01 && + buf[18] == 0x66 && buf[19] == 0xf4 && + buf[20] == 0x4e && buf[21] == 0x75 && + buf[22] == 0x48 && buf[23] == 0xe7 && + buf[24] == 0xff && buf[25] == 0xfe) { + strcpy(pre, "EX"); /*Fashion Tracker */ + +/* Magic ID */ + } else if (buf[0x3a] == 'S' && buf[0x3b] == 'I' && buf[0x3c] == 'D' && + buf[0x3d] == 'M' && buf[0x3e] == 'O' && buf[0x3f] == 'N' && + buf[0x40] == ' ' && buf[0x41] == 'I' && buf[0x42] == 'I') { + strcpy(pre, "SID2"); /* SidMon II */ + + } else if (buf[0x28] == 'R' && buf[0x29] == 'O' && buf[0x2a] == 'N' && + buf[0x2b] == '_' && buf[0x2c] == 'K' && buf[0x2d] == 'L' && + buf[0x2e] == 'A' && buf[0x2f] == 'R' && buf[0x30] == 'E' && + buf[0x31] == 'N') { + strcpy(pre, "CM"); /* Ron Klaren (CustomMade) */ + + } else if (buf[0x3e] == 'A' && buf[0x3f] == 'C' && buf[0x40] == 'T' + && buf[0x41] == 'I' && buf[0x42] == 'O' && buf[0x43] == 'N' + && buf[0x44] == 'A' && buf[0x45] == 'M') { + strcpy(pre, "AST"); /*Actionanamics */ + + } else if (buf[26] == 'V' && buf[27] == '.' && buf[28] == '2') { + strcpy(pre, "BP"); /* Soundmon V2 */ + + } else if (buf[26] == 'V' && buf[27] == '.' && buf[28] == '3') { + strcpy(pre, "BP3"); /* Soundmon V2.2 */ + + } else if (buf[60] == 'S' && buf[61] == 'O' && buf[62] == 'N' + && buf[63] == 'G') { + strcpy(pre, "SFX13"); /* Sfx 1.3-1.8 */ + + } else if (buf[124] == 'S' && buf[125] == 'O' && buf[126] == '3' + && buf[127] == '1') { + strcpy(pre, "SFX20"); /* Sfx 2.0 */ + + } else if (buf[0x1a] == 'E' && buf[0x1b] == 'X' && buf[0x1c] == 'I' + && buf[0x1d] == 'T') { + strcpy(pre, "AAM"); /*Audio Arts & Magic */ + } else if (buf[8] == 'E' && buf[9] == 'M' && buf[10] == 'O' + && buf[11] == 'D' && buf[12] == 'E' && buf[13] == 'M' + && buf[14] == 'I' && buf[15] == 'C') { + strcpy(pre, "EMOD"); /* EMOD */ + + /* generic ID Check at offset 0x24 */ + + } else if (chk_id_offset(buf, bufsize, offset_0024_patterns, 0x24, pre)) { + + /* HIP7 ID Check at offset 0x04 */ + } else if (patterntest(buf, " **** Player by Jochen Hippel 1990 **** ", + 0x04, 40, bufsize)) { + strcpy(pre, "S7G"); /* HIP7 */ + + /* Magic ID at Offset 0x00 */ + } else if (buf[0] == 'M' && buf[1] == 'M' && buf[2] == 'D') { + if (buf[0x3] >= '0' && buf[0x3] < '3') { + /*move.l mmd_songinfo(a0),a1 */ + int s = (buf[8] << 24) + (buf[9] << 16) + (buf[0xa] << 8) + buf[0xb]; + if (((int) buf[s + 767]) & (1 << 6)) { /* btst #6, msng_flags(a1); */ + strcpy(pre, "OCTAMED"); + /*OCTAMED*/} else { + strcpy(pre, "MED"); + /*MED*/} + } else if (buf[0x3] != 'C') { + strcpy(pre, "MMD3"); /* mmd3 and above */ + } + + /* all TFMX format tests here */ + } else if (tfmxtest(buf, bufsize, pre)) { + /* is TFMX, nothing to do here ('pre' set in tfmxtest() */ + + } else if (buf[0] == 'T' && buf[1] == 'H' && buf[2] == 'X') { + if ((buf[3] == 0x00) || (buf[3] == 0x01)) { + strcpy(pre, "AHX"); /* AHX */ + } + + } else if (buf[1] == 'M' && buf[2] == 'U' && buf[3] == 'G' + && buf[4] == 'I' && buf[5] == 'C' && buf[6] == 'I' + && buf[7] == 'A' && buf[8] == 'N') { + if (buf[9] == '2') { + strcpy(pre, "MUG2"); /* Digimugi2 */ + } else { + strcpy(pre, "MUG"); /* Digimugi */ + } + + } else if (buf[0] == 'L' && buf[1] == 'M' && buf[2] == 'E' && buf[3] == 0x00) { + strcpy(pre, "LME"); /* LegLess */ + + } else if (buf[0] == 'P' && buf[1] == 'S' && buf[2] == 'A' && buf[3] == 0x00) { + strcpy(pre, "PSA"); /* PSA */ + + } else if ((buf[0] == 'S' && buf[1] == 'y' && buf[2] == 'n' && buf[3] == 't' + && buf[4] == 'h' && buf[6] == '.' && buf[8] == 0x00) + && (buf[5] > '1' && buf[5] < '4')) { + strcpy(pre, "SYN"); /* Synthesis */ + + } else if (buf[0xbc6] == '.' && buf[0xbc7] == 'F' && buf[0xbc8] == 'N' + && buf[0xbc9] == 'L') { + strcpy(pre, "DM2"); /* Delta 2.0 */ + + } else if (buf[0] == 'R' && buf[1] == 'J' && buf[2] == 'P') { + + if (buf[4] == 'S' && buf[5] == 'M' && buf[6] == 'O' && buf[7] == 'D') { + strcpy(pre, "RJP"); /* Vectordean (Richard Joseph Player) */ + } else { + strcpy(pre, ""); /* but don't play .ins files */ + } + } else if (buf[0] == 'F' && buf[1] == 'O' && buf[2] == 'R' && buf[3] == 'M') { + if (buf[8] == 'S' && buf[9] == 'M' && buf[10] == 'U' && buf[11] == 'S') { + strcpy(pre, "SMUS"); /* Sonix */ + } + // } else if (buf[0x00] == 0x00 && buf[0x01] == 0xfe && + // buf[0x30] == 0x00 && buf[0x31] ==0x00 && buf[0x32] ==0x01 && buf[0x33] ==0x40 && + // realfilesize > 332 ){ + // } + // strcpy (pre, "SMUS"); /* Tiny Sonix*/ + + } else if (tronictest(buf, bufsize)) { + strcpy(pre, "TRONIC"); /* Tronic */ + + /* generic ID Check at offset 0x00 */ + } else if (chk_id_offset(buf, bufsize, offset_0000_patterns, 0x00, pre)) { + + /*magic ids of some modpackers */ + } else if (buf[0x438] == 'P' && buf[0x439] == 'W' && buf[0x43a] == 'R' + && buf[0x43b] == 0x2e) { + strcpy(pre, "PPK"); /*Polkapacker */ + + } else if (buf[0x100] == 'S' && buf[0x101] == 'K' && buf[0x102] == 'Y' + && buf[0x103] == 'T') { + strcpy(pre, "SKT"); /*Skytpacker */ + + } else if ((buf[0x5b8] == 'I' && buf[0x5b9] == 'T' && buf[0x5ba] == '1' + && buf[0x5bb] == '0') || (buf[0x5b8] == 'M' && buf[0x5b9] == 'T' + && buf[0x5ba] == 'N' + && buf[0x5bb] == 0x00)) { + strcpy(pre, "ICE"); /*Ice/Soundtracker 2.6 */ + + } else if (buf[0x3b8] == 'K' && buf[0x3b9] == 'R' && buf[0x3ba] == 'I' + && buf[0x3bb] == 'S') { + strcpy(pre, "KRIS"); /*Kristracker */ + + } else if (buf[0] == 'X' && buf[1] == 'P' && buf[2] == 'K' && buf[3] == 'F'&& + read_be_u32(&buf[4]) + 8 == realfilesize && + buf[8] == 'S' && buf[9] == 'Q' && buf[10] == 'S' && buf[11] == 'H') { + fprintf(stderr, "uade: The file is SQSH packed. Please depack first.\n"); + strcpy(pre, "packed"); + + } else if ((modtype = mod15check(buf, bufsize, realfilesize, path)) != 0) { + for (t = 0; mod15types[t].str != NULL; t++) { + if (modtype == mod15types[t].e) { + strcpy(pre, mod15types[t].str); + return; + } + } + + /* Custom file check */ + } else if (buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x03 + && buf[3] == 0xf3) { + /*CUSTOM*/ i = (buf[0x0b] * 4) + 0x1c; /* beginning of first chunk */ + + if (i < bufsize - 0x42) { + + t = 0; + /* unfort. we can't always assume: moveq #-1,d0 rts before "delirium" */ + /* search 0x40 bytes from here, (enough?) */ + while ((buf[i + t + 0] != 'D' && buf[i + t + 1] != 'E' + && buf[i + t + 2] != 'L' && buf[i + t + 3] != 'I') + && (t < 0x40)) { + t++; + } + + if (t < 0x40) { + /* longword after Delirium is rel. offset from first chunk + where "hopefully" the delitags are */ + int s = (buf[i + t + 10] * 256) + buf[i + t + 11] + i; /* 64K */ + if (s < bufsize - 0x33) { + for (i = 0; i < 0x30; i = i + 4) { + if (buf[i + s + 0] == 0x80 && buf[i + s + 1] == 0x00 && + buf[i + s + 2] == 0x44 && buf[i + s + 3] == 0x55) { + strcpy(pre, "CUST"); /* CUSTOM */ + break; + } + } + } + } + } + + } else if (buf[12] == 0x00) { + int s = (buf[12] * 256 + buf[13] + 1) * 14; + if (s < (bufsize - 91)) { + if (buf[80 + s] == 'p' && buf[81 + s] == 'a' && buf[82 + s] == 't' + && buf[83 + s] == 't' && buf[87 + s] == 32 && buf[88 + s] == 'p' + && buf[89 + s] == 'a' && buf[90 + s] == 't' && buf[91 + s] == 't') { + strcpy(pre, "PUMA"); /* Pumatracker */ + } + } + } +} + + +/* We are currently stupid and check only for a few magic IDs at the offsets + * chk_id_offset returns 1 on success and sets the right prefix/extension + * in pre + * TODO: more and less easy check for the rest of the 52 trackerclones + */ +static int chk_id_offset(unsigned char *buf, int bufsize, + const char *patterns[], int offset, char *pre) +{ + int i; + for (i = 0; patterns[i]; i = i + 2) { + if (patterntest(buf, patterns[i], offset, strlen(patterns[i]), bufsize)) { + /* match found */ + strcpy(pre, patterns[i + 1]); + return 1; + } + } + return 0; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/amifilemagic.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/amifilemagic.h new file mode 100644 index 00000000..45e5cd48 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/amifilemagic.h @@ -0,0 +1,9 @@ +#ifndef _UADE_AMIFILEMAGIC_H_ +#define _UADE_AMIFILEMAGIC_H_ + +#include <stdio.h> + +void uade_filemagic(unsigned char *buf, size_t bufsize, char *pre, + size_t realfilesize, const char *path, int verbose); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/eagleplayer.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/eagleplayer.c new file mode 100644 index 00000000..7c8dfce2 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/eagleplayer.c @@ -0,0 +1,502 @@ +/* + * Loads contents of 'eagleplayer.conf'. The file formats are + * specified in doc/uade123.1. + * + * Copyright 2005-2007 Heikki Orsila <heikki.orsila@iki.fi> + * + * This source code module is dual licensed under GPL and Public Domain. + * Hence you may use _this_ module (not another code module) in any you + * want in your projects. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <stdint.h> + +#include <errno.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "eagleplayer.h" +#include "ossupport.h" +#include "amifilemagic.h" +#include "uadeconf.h" +#include "unixatomic.h" +#include "songdb.h" +#include "support.h" +#include "uadestate.h" + + +#define OPTION_DELIMITER "," + +#define MAX_SUFFIX_LENGTH 16 + +#define eperror(fmt, args...) do { uadeerror("Eagleplayer.conf error on line %zd: " fmt, lineno, ## args); } while (0) + + +/* Table for associating eagleplayer.conf, song.conf and uade.conf options + * together. + */ +const struct epconfattr epconf[] = { + {.s = "a500", .e = ES_A500, .o = UC_FILTER_TYPE, .c = "a500"}, + {.s = "a1200", .e = ES_A1200, .o = UC_FILTER_TYPE, .c = "a1200"}, + {.s = "always_ends", .e = ES_ALWAYS_ENDS, .o = UC_DISABLE_TIMEOUTS}, + {.s = "broken_song_end", .e = ES_BROKEN_SONG_END, .o = UC_NO_EP_END}, + {.s = "detect_format_by_content", .e = ES_CONTENT_DETECTION, .o = UC_CONTENT_DETECTION}, + {.s = "detect_format_by_name", .e = ES_NAME_DETECTION, .o = 0}, + {.s = "ignore_player_check",.e = ES_IGNORE_PLAYER_CHECK, .o = UC_IGNORE_PLAYER_CHECK}, + {.s = "led_off", .e = ES_LED_OFF, .o = UC_FORCE_LED_OFF}, + {.s = "led_on", .e = ES_LED_ON, .o = UC_FORCE_LED_ON}, + {.s = "never_ends", .e = ES_NEVER_ENDS, .o = 0}, + {.s = "no_ep_end_detect", .e = ES_BROKEN_SONG_END, .o = UC_NO_EP_END}, + {.s = "no_filter", .e = ES_NO_FILTER, .o = UC_NO_FILTER}, + {.s = "no_headphones", .e = ES_NO_HEADPHONES, .o = UC_NO_HEADPHONES}, + {.s = "no_panning", .e = ES_NO_PANNING, .o = UC_NO_PANNING}, + {.s = "no_postprocessing", .e = ES_NO_POSTPROCESSING, .o = UC_NO_POSTPROCESSING}, + {.s = "ntsc", .e = ES_NTSC, .o = UC_NTSC}, + {.s = "one_subsong", .e = ES_ONE_SUBSONG, .o = UC_ONE_SUBSONG}, + {.s = "pal", .e = ES_PAL, .o = UC_PAL}, + {.s = "reject", .e = ES_REJECT, .o = 0}, + {.s = "speed_hack", .e = ES_SPEED_HACK, .o = UC_SPEED_HACK}, + {.s = NULL} +}; + + +/* Variables for eagleplayer.conf and song.conf */ +static const struct epconfattr epconf_variables[] = { + {.s = "epopt", .t = UA_STRING, .e = ES_EP_OPTION}, + {.s = "gain", .t = UA_STRING, .e = ES_GAIN}, + {.s = "interpolator", .t = UA_STRING, .e = ES_RESAMPLER}, + {.s = "panning", .t = UA_STRING, .e = ES_PANNING}, + {.s = "player", .t = UA_STRING, .e = ES_PLAYER}, + {.s = "resampler", .t = UA_STRING, .e = ES_RESAMPLER}, + {.s = "silence_timeout", .t = UA_STRING, .e = ES_SILENCE_TIMEOUT}, + {.s = "subsong_timeout", .t = UA_STRING, .e = ES_SUBSONG_TIMEOUT}, + {.s = "subsongs", .t = UA_STRING, .e = ES_SUBSONGS}, + {.s = "timeout", .t = UA_STRING, .e = ES_TIMEOUT}, + {.s = NULL} +}; + + +static int ufcompare(const void *a, const void *b); +static struct eagleplayerstore *read_eagleplayer_conf(const char *filename); + + +static struct eagleplayer *get_eagleplayer(const char *extension, + struct eagleplayerstore *playerstore); + + +static int load_playerstore(struct uade_state *state) +{ + static int warnings = 1; + char formatsfile[PATH_MAX]; + + if (state->playerstore == NULL) { + snprintf(formatsfile, sizeof(formatsfile), + "%s/eagleplayer.conf", state->config.basedir.name); + + state->playerstore = read_eagleplayer_conf(formatsfile); + if (state->playerstore == NULL) { + if (warnings) { + fprintf(stderr, "Tried to load eagleplayer.conf from %s, but failed\n", formatsfile); + } + warnings = 0; + return 0; + } + + if (state->config.verbose) + fprintf(stderr, "Loaded eagleplayer.conf: %s\n", + formatsfile); + } + + return 1; +} + + +static struct eagleplayer *analyze_file_format(int *content, + const char *modulename, + struct uade_state *state) +{ + struct stat st; + char ext[MAX_SUFFIX_LENGTH]; + FILE *f; + struct eagleplayer *contentcandidate = NULL; + struct eagleplayer *namecandidate = NULL; + char *prefix, *postfix, *t; + size_t bufsize, bytesread; + uint8_t buf[8192]; + + *content = 0; + + if ((f = fopen(modulename, "rb")) == NULL) + return NULL; + + if (fstat(fileno(f), &st)) + uadeerror("Very weird stat error: %s (%s)\n", modulename, strerror(errno)); + + bufsize = sizeof buf; + bytesread = atomic_fread(buf, 1, bufsize, f); + fclose(f); + if (bytesread == 0) + return NULL; + memset(&buf[bytesread], 0, bufsize - bytesread); + + uade_filemagic(buf, bytesread, ext, st.st_size, modulename, state->config.verbose); + + if (strcmp(ext, "reject") == 0) + return NULL; + + if (ext[0] != 0 && state->config.verbose) + fprintf(stderr, "Content recognized: %s (%s)\n", ext, modulename); + + if (strcmp(ext, "packed") == 0) + return NULL; + + if (!load_playerstore(state)) + return NULL; + + /* First do filename detection (we'll later do content detection) */ + t = xbasename(modulename); + + if (strlcpy((char *) buf, t, sizeof buf) >= sizeof buf) + return NULL; + + t = strchr((char *) buf, '.'); + if (t == NULL) + return NULL; + + *t = 0; + prefix = (char *) buf; + + if (strlen(prefix) < MAX_SUFFIX_LENGTH) + namecandidate = get_eagleplayer(prefix, state->playerstore); + + if (namecandidate == NULL) { + /* Try postfix */ + t = xbasename(modulename); + strlcpy((char *) buf, t, sizeof buf); + postfix = strrchr((char *) buf, '.') + 1; /* postfix != NULL */ + + if (strlen(postfix) < MAX_SUFFIX_LENGTH) + namecandidate = get_eagleplayer(postfix, state->playerstore); + } + + /* If filemagic found a match, we'll use player plugins associated with + that extension */ + if (ext[0]) { + contentcandidate = get_eagleplayer(ext, state->playerstore); + if (contentcandidate != NULL) { + /* Do not recognize name detectable eagleplayers by + content */ + if (namecandidate == NULL || + (namecandidate->flags & ES_NAME_DETECTION) == 0) { + *content = 1; + return contentcandidate; + } + } else { + if (state->config.verbose) + fprintf(stderr, "%s not in eagleplayer.conf\n", ext); + } + } + + if (state->config.verbose) + fprintf(stderr, "Format detection by filename\n"); + + return namecandidate; +} + + +static void handle_attribute(struct uade_attribute **attributelist, + const struct epconfattr *attr, + char *item, size_t len, size_t lineno) +{ + struct uade_attribute *a; + char *str, *endptr; + int success = 0; + + if (item[len] != '=') { + fprintf(stderr, "Invalid song item: %s\n", item); + return; + } + str = item + len + 1; + + if ((a = calloc(1, sizeof *a)) == NULL) + eperror("No memory for song attribute.\n"); + + switch (attr->t) { + case UA_DOUBLE: + a->d = strtod(str, &endptr); + if (*endptr == 0) + success = 1; + break; + case UA_INT: + a->i = strtol(str, &endptr, 10); + if (*endptr == 0) + success = 1; + break; + case UA_STRING: + a->s = strdup(str); + if (a->s == NULL) + eperror("Out of memory allocating string option for song\n"); + success = 1; + break; + default: + fprintf(stderr, "Unknown song option: %s\n", + item); + break; + } + + if (success) { + a->type = attr->e; + a->next = *attributelist; + *attributelist = a; + } else { + fprintf(stderr, "Invalid song option: %s\n", item); + free(a); + } +} + + +int uade_song_and_player_attribute(struct uade_attribute **attributelist, + int *flags, char *item, size_t lineno) +{ + size_t i, len; + + for (i = 0; epconf[i].s != NULL; i++) { + if (strcasecmp(item, epconf[i].s) == 0) { + *flags |= epconf[i].e; + return 1; + } + } + + for (i = 0; epconf_variables[i].s != NULL; i++) { + len = strlen(epconf_variables[i].s); + if (strncasecmp(item, epconf_variables[i].s, len) != 0) + continue; + + handle_attribute(attributelist, &epconf_variables[i], + item, len, lineno); + return 1; + } + + return 0; +} + +/* Compare function for bsearch() and qsort() to sort eagleplayers with + respect to name extension. */ +static int ufcompare(const void *a, const void *b) +{ + const struct eagleplayermap *ua = a; + const struct eagleplayermap *ub = b; + + return strcasecmp(ua->extension, ub->extension); +} + +int uade_is_our_file(const char *modulename, int scanmode, + struct uade_state *state) +{ + int content; + struct eagleplayer *ep; + + ep = analyze_file_format(&content, modulename, state); + + if (!scanmode) + state->ep = ep; + + if (ep == NULL) + return 0; + + if (content) + return 1; + + if (state->config.content_detection && content == 0) + return 0; + + if ((ep->flags & ES_CONTENT_DETECTION) != 0) + return 0; + + return 1; +} + +static struct eagleplayer *get_eagleplayer(const char *extension, + struct eagleplayerstore *ps) +{ + struct eagleplayermap *uf = ps->map; + struct eagleplayermap *f; + struct eagleplayermap key = {.extension = (char *)extension }; + + f = bsearch(&key, uf, ps->nextensions, sizeof(uf[0]), ufcompare); + if (f == NULL) + return NULL; + + return f->player; +} + +/* Read eagleplayer.conf. */ +static struct eagleplayerstore *read_eagleplayer_conf(const char *filename) +{ + FILE *f; + struct eagleplayer *p; + size_t allocated; + size_t lineno = 0; + struct eagleplayerstore *ps = NULL; + size_t exti; + size_t i, j; + int epwarning; + + f = fopen(filename, "r"); + if (f == NULL) + goto error; + + ps = calloc(1, sizeof ps[0]); + if (ps == NULL) + eperror("No memory for ps."); + + allocated = 16; + if ((ps->players = malloc(allocated * sizeof(ps->players[0]))) == NULL) + eperror("No memory for eagleplayer.conf file.\n"); + + while (1) { + char **items; + size_t nitems; + + items = read_and_split_lines(&nitems, &lineno, f, UADE_WS_DELIMITERS); + if (items == NULL) + break; + + assert(nitems > 0); + + if (ps->nplayers == allocated) { + allocated *= 2; + ps->players = realloc(ps->players, allocated * sizeof(ps->players[0])); + if (ps->players == NULL) + eperror("No memory for players."); + } + + p = &ps->players[ps->nplayers]; + ps->nplayers++; + + memset(p, 0, sizeof p[0]); + + p->playername = strdup(items[0]); + if (p->playername == NULL) + uadeerror("No memory for playername.\n"); + + for (i = 1; i < nitems; i++) { + + if (strncasecmp(items[i], "prefixes=", 9) == 0) { + char prefixes[UADE_LINESIZE]; + char *prefixstart = items[i] + 9; + char *sp, *s; + size_t pos; + + assert(p->nextensions == 0 && p->extensions == NULL); + + p->nextensions = 0; + strlcpy(prefixes, prefixstart, + sizeof(prefixes)); + sp = prefixes; + while ((s = strsep(&sp, OPTION_DELIMITER)) != NULL) { + if (*s == 0) + continue; + p->nextensions++; + } + + p->extensions = + malloc((p->nextensions + + 1) * sizeof(p->extensions[0])); + if (p->extensions == NULL) + eperror("No memory for extensions."); + + pos = 0; + sp = prefixstart; + while ((s = strsep(&sp, OPTION_DELIMITER)) != NULL) { + if (*s == 0) + continue; + + p->extensions[pos] = strdup(s); + if (s == NULL) + eperror("No memory for prefix."); + pos++; + } + p->extensions[pos] = NULL; + assert(pos == p->nextensions); + + continue; + } + + if (strncasecmp(items[i], "comment:", 7) == 0) + break; + + if (uade_song_and_player_attribute(&p->attributelist, &p->flags, items[i], lineno)) + continue; + + fprintf(stderr, "Unrecognized option: %s\n", items[i]); + } + + for (i = 0; items[i] != NULL; i++) + free(items[i]); + + free(items); + } + + fclose(f); + + if (ps->nplayers == 0) { + free(ps->players); + free(ps); + return NULL; + } + + for (i = 0; i < ps->nplayers; i++) + ps->nextensions += ps->players[i].nextensions; + + ps->map = malloc(sizeof(ps->map[0]) * ps->nextensions); + if (ps->map == NULL) + eperror("No memory for extension map."); + + exti = 0; + epwarning = 0; + for (i = 0; i < ps->nplayers; i++) { + p = &ps->players[i]; + if (p->nextensions == 0) { + if (epwarning == 0) { + fprintf(stderr, + "uade warning: %s eagleplayer lacks prefixes in " + "eagleplayer.conf, which makes it unusable for any kind of " + "file type detection. If you don't want name based file type " + "detection for a particular format, use content_detection " + "option for the line in eagleplayer.conf.\n", + ps->players[i].playername); + epwarning = 1; + } + continue; + } + for (j = 0; j < p->nextensions; j++) { + assert(exti < ps->nextensions); + ps->map[exti].player = p; + ps->map[exti].extension = p->extensions[j]; + exti++; + } + } + + assert(exti == ps->nextensions); + + /* Make the extension map bsearch() ready */ + qsort(ps->map, ps->nextensions, sizeof(ps->map[0]), ufcompare); + + return ps; + + error: + if (ps) + free(ps->players); + free(ps); + if (f != NULL) + fclose(f); + return NULL; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/eagleplayer.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/eagleplayer.h new file mode 100644 index 00000000..fc3497b5 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/eagleplayer.h @@ -0,0 +1,127 @@ +#ifndef _UADE_EAGLEPLAYER_H_ +#define _UADE_EAGLEPLAYER_H_ + +#include <stdio.h> +#include <stdint.h> +#include <limits.h> + +#include "uadeconfstructure.h" + +/* We maintain alphabetical order even if that forces us to renumber bits + when a new option is added */ +#define ES_A1200 (1 << 0) +#define ES_A500 (1 << 1) +#define ES_ALWAYS_ENDS (1 << 2) +#define ES_BROKEN_SONG_END (1 << 3) +#define ES_CONTENT_DETECTION (1 << 4) +#define ES_EP_OPTION (1 << 5) +#define ES_GAIN (1 << 6) +#define ES_IGNORE_PLAYER_CHECK (1 << 7) +#define ES_LED_OFF (1 << 8) +#define ES_LED_ON (1 << 9) +#define ES_NAME_DETECTION (1 << 10) +#define ES_NEVER_ENDS (1 << 11) +#define ES_NO_FILTER (1 << 12) +#define ES_NO_HEADPHONES (1 << 13) +#define ES_NO_PANNING (1 << 14) +#define ES_NO_POSTPROCESSING (1 << 15) +#define ES_NTSC (1 << 16) +#define ES_ONE_SUBSONG (1 << 17) +#define ES_PAL (1 << 18) +#define ES_PANNING (1 << 19) +#define ES_PLAYER (1 << 20) +#define ES_REJECT (1 << 21) +#define ES_RESAMPLER (1 << 22) +#define ES_SILENCE_TIMEOUT (1 << 23) +#define ES_SPEED_HACK (1 << 24) +#define ES_SUBSONGS (1 << 25) +#define ES_SUBSONG_TIMEOUT (1 << 26) +#define ES_TIMEOUT (1 << 27) + +#define UADE_WS_DELIMITERS " \t\n" + +struct eagleplayer { + char *playername; + size_t nextensions; + char **extensions; + int flags; + struct uade_attribute *attributelist; +}; + +struct eagleplayermap { + char *extension; + struct eagleplayer *player; +}; + +struct eagleplayerstore { + size_t nplayers; + struct eagleplayer *players; + size_t nextensions; + struct eagleplayermap *map; +}; + +enum uade_attribute_type { + UA_STRING = 1, + UA_INT, + UA_DOUBLE +}; + +struct uade_attribute; + +struct uade_attribute { + struct uade_attribute *next; + enum uade_attribute_type type; + char *s; + int i; + double d; +}; + +struct uade_song { + char md5[33]; + + char module_filename[PATH_MAX]; + + char playername[256]; /* Eagleplayer name in players directory */ + char modulename[256]; /* From score */ + char formatname[256]; + + uint8_t *buf; + size_t bufsize; + + int min_subsong; + int max_subsong; + int cur_subsong; + + int playtime; + int flags; + int nsubsongs; + uint8_t *subsongs; + struct uade_attribute *songattributes; + struct uade_ep_options ep_options; + char *normalisation; + + int64_t out_bytes; + + int64_t silence_count; +}; + +struct epconfattr { + char *s; /* config file directive/variable name */ + int e; /* ES_* flags for eagleplayers and songs */ + int o; /* UC_* flag for uade.conf option */ + char *c; /* constant for an UC_* flag */ + enum uade_attribute_type t; /* if variable, its special type */ +}; + + +extern const struct epconfattr epconf[]; + + +/* FIX: A forward declaration to avoid circular dependency */ +struct uade_state; + +int uade_is_our_file(const char *modulename, int scanmode, struct uade_state *state); +int uade_song_and_player_attribute(struct uade_attribute **attributelist, + int *flags, char *item, size_t lineno); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/effects.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/effects.c new file mode 100644 index 00000000..c75c859d --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/effects.c @@ -0,0 +1,490 @@ +/* Effect module for UADE2 frontends. + + Copyright 2005 (C) Antti S. Lankila <alankila@bel.fi> + + This module is licensed under the GNU LGPL. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include <math.h> + +#include <compilersupport.h> + +#include "effects.h" + +/*** old headphone effect ***/ +#define UADE_EFFECT_HEADPHONES_DELAY_LENGTH 22 +#define UADE_EFFECT_HEADPHONES_DELAY_DIRECT 0.3 +#define UADE_EFFECT_HEADPHONES_CROSSMIX_VOL 0.80 + +static float headphones_ap_l[UADE_EFFECT_HEADPHONES_DELAY_LENGTH]; +static float headphones_ap_r[UADE_EFFECT_HEADPHONES_DELAY_LENGTH]; +static float headphones_rc_l[4]; +static float headphones_rc_r[4]; + +/*** new headphone effect ***/ + +/* delay time defines the width of the head. 0.5 ms gives us 15 cm virtual distance + * between sound arriving to either ear. */ +#define HEADPHONE2_DELAY_TIME 0.49e-3 +#define HEADPHONE2_DELAY_K 0.15 +/* head shadow frequency cutoff */ +#define HEADPHONE2_SHADOW_FREQ 8000.0 +/* high shelve keeps frequencies below cutoff intact and attenuates + * the rest in an uniform way. The effect is to make bass more "mono" than "stereo". */ +#define HEADPHONE2_SHELVE_FREQ 100.0 +#define HEADPHONE2_SHELVE_LEVEL -2.0 + +#define MAXIMUM_SAMPLING_RATE 96000 +#define HEADPHONE2_DELAY_MAX_LENGTH ((int)(MAXIMUM_SAMPLING_RATE*HEADPHONE2_DELAY_TIME+1)) +#define DENORMAL_OFFSET 1E-10 + +#define NORMALISE_RESOLUTION 10 /* in bits */ +#define NORMALISE_DEFAULT_GAIN 8.0 +#define NORMALISE_MAXIMUM_GAIN 8.0 + +/* Headphone variables */ +typedef struct { + float b0, b1, b2, a1, a2, x[2], y[2]; +} biquad_t; + +static float headphone2_ap_l[HEADPHONE2_DELAY_MAX_LENGTH]; +static float headphone2_ap_r[HEADPHONE2_DELAY_MAX_LENGTH]; +static int headphone2_delay_length; +static biquad_t headphone2_shelve_l; +static biquad_t headphone2_shelve_r; +static biquad_t headphone2_rc_l; +static biquad_t headphone2_rc_r; + +/* Normalise variables */ +static int normalise_peak_level; +static int normalise_historic_maximum_peak; +static int normalise_oldlevel; + +static void gain(int gain_amount, int16_t * sm, int frames); +static void pan(int pan_amount, int16_t * sm, int frames); +static void headphones(int16_t * sm, int frames); +static void headphones2(int16_t * sm, int frames); +static void normalise(int change_level, int16_t * sm, int frames); +static int normalise_compute_gain(int peak); + +static inline int sampleclip(int x) +{ + if (unlikely(x > 32767 || x < -32768)) { + if (x > 32767) + x = 32767; + else + x = -32768; + } + return x; +} + +/* calculate a high shelve filter */ +static void calculate_shelve(double fs, double fc, double g, biquad_t * bq) +{ + float A, omega, sn, cs, beta, b0, b1, b2, a0, a1, a2; + + A = powf(10, g / 40); + omega = 2 * M_PI * fc / fs; + omega = tan(omega / 2) * 2; + sn = sin(omega); + cs = cos(omega); + beta = sqrt(A + A); + + b0 = A * ((A + 1) + (A - 1) * cs + beta * sn); + b1 = -2 * A * ((A - 1) + (A + 1) * cs); + b2 = A * ((A + 1) + (A - 1) * cs - beta * sn); + a0 = (A + 1) - (A - 1) * cs + beta * sn; + a1 = 2 * ((A - 1) - (A + 1) * cs); + a2 = (A + 1) - (A - 1) * cs - beta * sn; + + bq->b0 = b0 / a0; + bq->b1 = b1 / a0; + bq->b2 = b2 / a0; + bq->a1 = a1 / a0; + bq->a2 = a2 / a0; +} + +/* calculate 1st order lowpass filter */ +static void calculate_rc(double fs, double fc, biquad_t * bq) +{ + float omega; + + if (fc >= fs / 2) { + bq->b0 = 1.0; + bq->b1 = 0.0; + bq->b2 = 0.0; + bq->a1 = 0.0; + bq->a2 = 0.0; + return; + } + omega = 2 * M_PI * fc / fs; + omega = tan(omega / 2) * 2; + + bq->b0 = 1 / (1 + 1 / omega); + bq->b1 = 0; + bq->b2 = 0; + bq->a1 = -1 + bq->b0; + bq->a2 = 0; +} + +static inline float evaluate_biquad(float input, biquad_t * bq) +{ + float output = DENORMAL_OFFSET; + + output += input * bq->b0 + bq->x[0] * bq->b1 + bq->x[1] * bq->b2; + output -= bq->y[0] * bq->a1 + bq->y[1] * bq->a2; + + bq->x[1] = bq->x[0]; + bq->x[0] = input; + + bq->y[1] = bq->y[0]; + bq->y[0] = output; + + return output; +} + +static void reset_biquad(biquad_t * bq) +{ + bq->x[0] = bq->x[1] = bq->y[0] = bq->y[1] = 0; +} + +/* Reset effects' state variables. + * Call this method between before starting playback */ +void uade_effect_reset_internals(void) +{ + /* old headphones */ + memset(headphones_ap_l, 0, sizeof(headphones_ap_l)); + memset(headphones_ap_r, 0, sizeof(headphones_ap_r)); + memset(headphones_rc_l, 0, sizeof(headphones_rc_l)); + memset(headphones_rc_r, 0, sizeof(headphones_rc_r)); + + /* new headphones */ + memset(headphone2_ap_l, 0, sizeof(headphone2_ap_l)); + memset(headphone2_ap_r, 0, sizeof(headphone2_ap_r)); + reset_biquad(&headphone2_shelve_l); + reset_biquad(&headphone2_shelve_r); + reset_biquad(&headphone2_rc_l); + reset_biquad(&headphone2_rc_r); + + normalise_peak_level = 0; + normalise_historic_maximum_peak = 0; + normalise_oldlevel = 1 << NORMALISE_RESOLUTION; +} + +void uade_effect_disable_all(struct uade_effect *ue) +{ + ue->enabled = 0; +} + +void uade_effect_disable(struct uade_effect *ue, uade_effect_t effect) +{ + ue->enabled &= ~(1 << effect); +} + +void uade_effect_enable(struct uade_effect *ue, uade_effect_t effect) +{ + ue->enabled |= 1 << effect; +} + +/* Returns 1 if effect is enabled, and zero otherwise. Ignores + UADE_EFFECT_ALLOW. */ +int uade_effect_is_enabled(struct uade_effect *ue, uade_effect_t effect) +{ + return (ue->enabled & (1 << effect)) != 0; +} + +void uade_effect_run(struct uade_effect *ue, int16_t * samples, int frames) +{ + if (ue->enabled & (1 << UADE_EFFECT_ALLOW)) { + normalise(ue->enabled & (1 << UADE_EFFECT_NORMALISE), samples, + frames); + if (ue->enabled & (1 << UADE_EFFECT_PAN)) + pan(ue->pan, samples, frames); + if (ue->enabled & (1 << UADE_EFFECT_HEADPHONES)) + headphones(samples, frames); + if (ue->enabled & (1 << UADE_EFFECT_HEADPHONES2) && ue->rate) + headphones2(samples, frames); + if (ue->enabled & (1 << UADE_EFFECT_GAIN)) + gain(ue->gain, samples, frames); + } +} + +void uade_effect_toggle(struct uade_effect *ue, uade_effect_t effect) +{ + ue->enabled ^= 1 << effect; +} + +void uade_effect_set_defaults(struct uade_effect *ue) +{ + memset(ue, 0, sizeof(*ue)); + uade_effect_disable_all(ue); + uade_effect_enable(ue, UADE_EFFECT_ALLOW); + uade_effect_gain_set_amount(ue, 1.0); + uade_effect_pan_set_amount(ue, 0.7); +} + +/* Rate of 0 means undefined. Effects that depend on sample rate must + self-check against this because they can not implemented properly */ +void uade_effect_set_sample_rate(struct uade_effect *ue, int rate) +{ + assert(rate >= 0); + ue->rate = rate; + + if (rate == 0) + return; + + calculate_shelve(rate, HEADPHONE2_SHELVE_FREQ, HEADPHONE2_SHELVE_LEVEL, + &headphone2_shelve_l); + calculate_shelve(rate, HEADPHONE2_SHELVE_FREQ, HEADPHONE2_SHELVE_LEVEL, + &headphone2_shelve_r); + calculate_rc(rate, HEADPHONE2_SHADOW_FREQ, &headphone2_rc_l); + calculate_rc(rate, HEADPHONE2_SHADOW_FREQ, &headphone2_rc_r); + headphone2_delay_length = HEADPHONE2_DELAY_TIME * rate + 0.5; + if (headphone2_delay_length > HEADPHONE2_DELAY_MAX_LENGTH) { + fprintf(stderr, "effects.c: truncating headphone delay line due to samplerate exceeding 96 kHz.\n"); + headphone2_delay_length = HEADPHONE2_DELAY_MAX_LENGTH; + } +} + +void uade_effect_gain_set_amount(struct uade_effect *ue, float amount) +{ + assert(amount >= 0.0 && amount <= 128.0); + ue->gain = amount * 256.0; +} + +void uade_effect_pan_set_amount(struct uade_effect *ue, float amount) +{ + assert(amount >= 0.0 && amount <= 2.0); + ue->pan = amount * 256.0 / 2.0; +} + +static int normalise_compute_gain(int peak) +{ + if (normalise_historic_maximum_peak == 0) { + /* if the peak is not known, we cap gain in an attempt to avoid + * boosting silent intros too much. */ + if (peak < 32768 / NORMALISE_DEFAULT_GAIN) + return NORMALISE_DEFAULT_GAIN * + (1 << NORMALISE_RESOLUTION); + else + return (32768 << NORMALISE_RESOLUTION) / peak; + } else { + int largerpeak; + if (peak < normalise_historic_maximum_peak) + largerpeak = normalise_historic_maximum_peak; + else + largerpeak = peak; + /* if the peak is known, we use the recorded value but adapt + if this rendition comes out louder for some reason (for + instance, updated UADE) */ + if (largerpeak < 32768 / NORMALISE_MAXIMUM_GAIN) + return NORMALISE_MAXIMUM_GAIN * + (1 << NORMALISE_RESOLUTION); + else + return (32768 << NORMALISE_RESOLUTION) / largerpeak; + } +} + +/* We save gain from maximum known level. This is an one-way street, + the gain can * only decrease with time. If the historic level is + known and larger, we prefer it. */ +void uade_effect_normalise_serialise(char *buf, size_t len) +{ + int peak = normalise_peak_level; + + assert(len > 0); + + if (normalise_historic_maximum_peak > normalise_peak_level) + peak = normalise_historic_maximum_peak; + + if (snprintf(buf, len, "v=1,p=%d", peak) >= len) { + fprintf(stderr, "normalise effect: buffer too short, gain would be truncated. This is a bug in UADE.\n"); + exit(-1); + } +} + +/* similarly, this should only be called if gain has a positive value, + * but we try to recover from misuse. */ +void uade_effect_normalise_unserialise(const char *buf) +{ + int version, readcount; + float peak; + + normalise_historic_maximum_peak = 0; + + if (buf == NULL) + return; + + readcount = sscanf(buf, "v=%d,p=%f", &version, &peak); + + if (readcount == 0) { + fprintf(stderr, "normalise effect: gain string invalid: '%s'\n", buf); + exit(-1); + } + + if (version != 1) { + fprintf(stderr, "normalise effect: unrecognized gain version: '%s'\n", buf); + exit(-1); + } + + if (readcount != 2) { + fprintf(stderr, "Could not read peak value for version 1: '%s'\n", buf); + exit(-1); + } + + if (peak >= 0.0 && peak <= 1.0) { + normalise_oldlevel = normalise_historic_maximum_peak = + 32768 * peak; + } else { + fprintf(stderr, "normalise effect: invalid peak level: '%s'\n", buf); + } +} + +static void normalise(int change_level, int16_t * sm, int frames) +{ + int i; + + /* Negative side is mirrored. but positive side gains by 1. + * This is to make both semiwaves have same max. */ + for (i = 0; i < 2 * frames; i += 1) { + int tmp = sm[i]; + tmp = (tmp >= 0) ? tmp + 1 : -tmp; + if (tmp > normalise_peak_level) + normalise_peak_level = tmp; + } + + /* Slight clipping may result in first playback while the system + * adjusts. With a bit of "advance warning" of clipping about to + * occur, the level begins to adjust as soon as the buffer + * begins. Typical adjustment times are not large -- a few hundred + * samples are to be expected -- and the clipping should only + * occur on the first rendition of the song, if at all. */ + if (change_level) { + int newlevel = normalise_compute_gain(normalise_peak_level); + + for (i = 0; i < 2 * frames; i += 1) { + /* same gain for the frame */ + if ((i & 1) == 0) { + if (normalise_oldlevel < newlevel) + normalise_oldlevel += 1; + if (normalise_oldlevel > newlevel) + normalise_oldlevel -= 1; + } + sm[i] = + sampleclip((sm[i] * + normalise_oldlevel) >> + NORMALISE_RESOLUTION); + } + } +} + +static void gain(int gain_amount, int16_t * sm, int frames) +{ + int i; + for (i = 0; i < 2 * frames; i += 1) + sm[i] = sampleclip((sm[i] * gain_amount) >> 8); +} + +/* Panning effect. Turns stereo into mono in a specific degree */ +static void pan(int pan_amount, int16_t * sm, int frames) +{ + int i, l, r, m; + for (i = 0; i < frames; i += 1) { + l = sm[0]; + r = sm[1]; + m = (r - l) * pan_amount; + sm[0] = ((l << 8) + m) >> 8; + sm[1] = ((r << 8) - m) >> 8; + sm += 2; + } +} + +/* All-pass delay. Its purpose is to confuse the phase of the sound a bit + * and also provide some delay to locate the source outside the head. This + * seems to work better than a pure delay line. */ +static float headphones_allpass_delay(float in, float *state) +{ + int i; + float tmp, output; + + tmp = in - UADE_EFFECT_HEADPHONES_DELAY_DIRECT * state[0]; + output = state[0] + UADE_EFFECT_HEADPHONES_DELAY_DIRECT * tmp; + + /* FIXME: use modulo and index */ + for (i = 1; i < UADE_EFFECT_HEADPHONES_DELAY_LENGTH; i += 1) + state[i - 1] = state[i]; + state[UADE_EFFECT_HEADPHONES_DELAY_LENGTH - 1] = tmp; + + return output; +} + +static float headphones_lpf(float in, float *state) +{ + float out = in * 0.53; + out += 0.47 * state[0]; + state[0] = out; + + return out; +} + +/* A real implementation would simply perform FIR with recorded HRTF data. */ +static void headphones(int16_t * sm, int frames) +{ + int i; + float ld, rd; + int l_final, r_final; + for (i = 0; i < frames; i += 1) { + ld = headphones_allpass_delay(sm[0], headphones_ap_l); + rd = headphones_allpass_delay(sm[1], headphones_ap_r); + ld = headphones_lpf(ld, headphones_rc_l); + rd = headphones_lpf(rd, headphones_rc_r); + + l_final = + (sm[0] + rd * UADE_EFFECT_HEADPHONES_CROSSMIX_VOL) / 2; + r_final = + (sm[1] + ld * UADE_EFFECT_HEADPHONES_CROSSMIX_VOL) / 2; + sm[0] = sampleclip(l_final); + sm[1] = sampleclip(r_final); + + sm += 2; + } +} + +static float headphone2_allpass_delay(float in, float *state) +{ + int i; + float tmp, output; + + tmp = in - HEADPHONE2_DELAY_K * state[0]; + output = state[0] + HEADPHONE2_DELAY_K * tmp; + + /* FIXME: use modulo and index */ + for (i = 1; i < headphone2_delay_length; i += 1) + state[i - 1] = state[i]; + state[headphone2_delay_length - 1] = tmp; + + return output; +} + +static void headphones2(int16_t * sm, int frames) +{ + int i; + for (i = 0; i < frames; i += 1) { + float ld, rd; + + ld = headphone2_allpass_delay(sm[0], headphone2_ap_l); + rd = headphone2_allpass_delay(sm[1], headphone2_ap_r); + ld = evaluate_biquad(ld, &headphone2_rc_l); + rd = evaluate_biquad(rd, &headphone2_rc_r); + ld = evaluate_biquad(ld, &headphone2_shelve_l); + rd = evaluate_biquad(rd, &headphone2_shelve_r); + + sm[0] = sampleclip((sm[0] + rd) / 2); + sm[1] = sampleclip((sm[1] + ld) / 2); + sm += 2; + } +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/effects.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/effects.h new file mode 100644 index 00000000..57a779df --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/effects.h @@ -0,0 +1,42 @@ +#ifndef _UADE2_EFFECTS_H_ +#define _UADE2_EFFECTS_H_ + +#include <stdint.h> + +typedef enum { + UADE_EFFECT_ALLOW, + UADE_EFFECT_GAIN, + UADE_EFFECT_HEADPHONES, + UADE_EFFECT_HEADPHONES2, + UADE_EFFECT_PAN, + UADE_EFFECT_NORMALISE, +} uade_effect_t; + +struct uade_effect { + uade_effect_t enabled; + int gain; + int pan; + int rate; +}; + +void uade_effect_disable(struct uade_effect *ue, uade_effect_t effect); +void uade_effect_disable_all(struct uade_effect *ue); +void uade_effect_enable(struct uade_effect *ue, uade_effect_t effect); +int uade_effect_is_enabled(struct uade_effect *ue, uade_effect_t effect); +void uade_effect_set_defaults(struct uade_effect *ue); +void uade_effect_set_sample_rate(struct uade_effect *ue, int rate); +void uade_effect_toggle(struct uade_effect *ue, uade_effect_t effect); + +/* effect-specific knobs */ +void uade_effect_gain_set_amount(struct uade_effect *ue, float amount); +void uade_effect_normalise_unserialise(const char *buf); +void uade_effect_normalise_serialise(char *buf, size_t len); +void uade_effect_pan_set_amount(struct uade_effect *ue, float amount); + +/* reset state at start of song */ +void uade_effect_reset_internals(void); + +/* process n frames of sample buffer */ +void uade_effect_run(struct uade_effect *ue, int16_t * sample, int frames); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.c new file mode 100644 index 00000000..7614ea48 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.c @@ -0,0 +1,247 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include <string.h> /* for memcpy() */ +#include "md5.h" + +#if __BYTE_ORDER == 1234 +#define byteReverse(buf, len) /* Nothing */ +#else +static void byteReverse(unsigned char *buf, unsigned longs); + +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse(unsigned char *buf, unsigned longs) +{ + uint32_t t; + do { + t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32_t *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(MD5_CTX *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) +{ + uint32_t t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], MD5_CTX *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32_t *) ctx->in)[14] = ctx->bits[0]; + ((uint32_t *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset((char *) ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32_t buf[4], uint32_t const in[16]) +{ + uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.copyright b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.copyright new file mode 100644 index 00000000..72b040b3 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.copyright @@ -0,0 +1,8 @@ +The algorithm is due to Ron Rivest. This code was written by Colin +Plumb in 1993, no copyright is claimed. This code is in the public +domain; do with it what you wish. +.Pp +Equivalent code is available from RSA Data Security, Inc. +This code has been tested against that, and is equivalent, +except that you don't need to include two pages of legalese +with every copy. diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.h new file mode 100644 index 00000000..6f471e3b --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.h @@ -0,0 +1,21 @@ +#ifndef _UADE_MD5_H_ +#define _UADE_MD5_H_ + +#include <sys/types.h> +#include <stdint.h> + +#define MD5_HASHBYTES 16 + +typedef struct MD5Context { + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +} MD5_CTX; + +void MD5Init(MD5_CTX *context); +void MD5Update(MD5_CTX *context, unsigned char const *buf, + unsigned len); +void MD5Final(unsigned char digest[MD5_HASHBYTES], MD5_CTX *context); +void MD5Transform(uint32_t buf[4], uint32_t const in[16]); + +#endif /* !_UADE_MD5_H_ */ diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songdb.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songdb.c new file mode 100644 index 00000000..b7d79165 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songdb.c @@ -0,0 +1,798 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include "songdb.h" +#include "uadeconf.h" +#include "md5.h" +#include "unixatomic.h" +#include "ossupport.h" +#include "uadeconfig.h" +#include "support.h" +#include "uadeconstants.h" + +#define NORM_ID "n=" +#define NORM_ID_LENGTH 2 + +#define eserror(fmt, args...) do { fprintf(stderr, "song.conf error on line %zd: " fmt "\n", lineno, ## args); exit(-1); } while (0) + + +struct eaglesong { + int flags; + char md5[33]; + struct uade_attribute *attributes; +}; + +struct persub { + int sub; + char *normalisation; +}; + +static struct uade_content *contentchecksums; +static size_t nccused; /* number of valid entries in content db */ +static size_t nccalloc; /* number of allocated entries for content db */ +static int ccmodified; +static int cccorrupted; + +static int nsongs; +static struct eaglesong *songstore; + +static int escompare(const void *a, const void *b); +static struct uade_content *get_content(const char *md5); + + +static void add_sub_normalisation(struct uade_content *n, char *normalisation) +{ + struct persub *subinfo; + char *endptr; + + subinfo = malloc(sizeof(*subinfo)); + if (subinfo == NULL) + uadeerror("Can't allocate memory for normalisation entry\n"); + + subinfo->sub = strtol(normalisation, &endptr, 10); + if (*endptr != ',' || subinfo->sub < 0) { + fprintf(stderr, "Invalid normalisation entry: %s\n", normalisation); + return; + } + + subinfo->normalisation = strdup(endptr + 1); + if (subinfo->normalisation == NULL) + uadeerror("Can't allocate memory for normalisation string\n"); + + vplist_append(n->subs, subinfo); +} + +/* Compare function for bsearch() and qsort() to sort songs with respect + to their md5sums */ +static int contentcompare(const void *a, const void *b) +{ + return strcasecmp(((struct uade_content *)a)->md5, + ((struct uade_content *)b)->md5); +} + +static int escompare(const void *a, const void *b) +{ + return strcasecmp(((struct eaglesong *)a)->md5, + ((struct eaglesong *)b)->md5); +} + +static struct uade_content *get_content(const char *md5) +{ + struct uade_content key; + + if (contentchecksums == NULL) + return NULL; + + memset(&key, 0, sizeof key); + strlcpy(key.md5, md5, sizeof key.md5); + + return bsearch(&key, contentchecksums, nccused, + sizeof contentchecksums[0], contentcompare); +} + +static struct uade_content *create_content_checksum(const char *md5, + uint32_t playtime) +{ + struct uade_content *n; + + if (nccused == nccalloc) { + nccalloc = MAX(nccalloc * 2, 16); + n = realloc(contentchecksums, + nccalloc * sizeof(struct uade_content)); + if (n == NULL) { + fprintf(stderr, + "uade: No memory for new content checksums.\n"); + return NULL; + } + contentchecksums = n; + } + + n = &contentchecksums[nccused]; + + if (md5 == NULL) + return n; + + nccused++; + + ccmodified = 1; + + memset(n, 0, sizeof(*n)); + strlcpy(n->md5, md5, sizeof(n->md5)); + n->playtime = playtime; + + n->subs = vplist_create(1); + + return n; +} + +static void md5_from_buffer(char *dest, size_t destlen, + uint8_t * buf, size_t bufsize) +{ + uint8_t md5[16]; + int ret; + MD5_CTX ctx; + MD5Init(&ctx); + MD5Update(&ctx, buf, bufsize); + MD5Final(md5, &ctx); + ret = + snprintf(dest, destlen, + "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", + md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], + md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], + md5[14], md5[15]); + if (ret >= destlen || ret != 32) { + fprintf(stderr, "md5 buffer error (%d/%zd)\n", ret, destlen); + exit(1); + } +} + +static void update_playtime(struct uade_content *n, uint32_t playtime) +{ + if (n->playtime != playtime) { + ccmodified = 1; + n->playtime = playtime; + } +} + +static void sort_content_checksums(void) +{ + if (contentchecksums == NULL) + return; + + qsort(contentchecksums, nccused, sizeof contentchecksums[0], + contentcompare); +} + +/* replace must be zero if content db is unsorted */ +struct uade_content *uade_add_playtime(const char *md5, uint32_t playtime) +{ + struct uade_content *n; + + /* If content db hasn't been read into memory already, it is not used */ + if (contentchecksums == NULL) + return NULL; + + /* Do not record song shorter than 3 secs */ + if (playtime < 3000) + return NULL; + + if (strlen(md5) != 32) + return NULL; + + n = get_content(md5); + if (n != NULL) { + update_playtime(n, playtime); + return n; + } + + n = create_content_checksum(md5, playtime); + + sort_content_checksums(); + + return n; +} + +void uade_lookup_volume_normalisation(struct uade_state *state) +{ + size_t i, nsubs; + struct uade_effect *ue = &state->effects; + struct uade_config *uc = &state->config; + struct uade_song *us = state->song; + struct uade_content *content = get_content(us->md5); + + if (content != NULL) { + + nsubs = vplist_len(content->subs); + + for (i = 0; i < nsubs; i++) { + + struct persub *subinfo = vplist_get(content->subs, i); + + if (subinfo->sub == us->cur_subsong) { + uade_set_config_option(uc, UC_NORMALISE, + subinfo->normalisation); + uade_effect_normalise_unserialise(uc-> + normalise_parameter); + uade_effect_enable(ue, UADE_EFFECT_NORMALISE); + break; + } + } + } +} + +static void get_song_flags_and_attributes_from_songstore(struct uade_song *us) +{ + struct eaglesong key; + struct eaglesong *es; + + if (songstore != NULL) { + /* Lookup md5 from the songdb */ + strlcpy(key.md5, us->md5, sizeof key.md5); + es = bsearch(&key, songstore, nsongs, sizeof songstore[0], escompare); + + if (es != NULL) { + /* Found -> copy flags and attributes from database */ + us->flags |= es->flags; + us->songattributes = es->attributes; + } + } +} + +int uade_alloc_song(struct uade_state *state, const char *filename) +{ + struct uade_song *us; + struct uade_content *content; + + state->song = NULL; + + us = calloc(1, sizeof *us); + if (us == NULL) + goto error; + + strlcpy(us->module_filename, filename, sizeof us->module_filename); + + us->buf = atomic_read_file(&us->bufsize, filename); + if (us->buf == NULL) + goto error; + + /* Compute an md5sum of the song */ + md5_from_buffer(us->md5, sizeof us->md5, us->buf, us->bufsize); + + /* Needs us->md5 sum */ + get_song_flags_and_attributes_from_songstore(us); + + /* Lookup playtime from content database */ + us->playtime = -1; + content = get_content(us->md5); + if (content != NULL && content->playtime > 0) + us->playtime = content->playtime; + + /* We can't know subsong numbers yet. The eagleplayer will report them + * in the playback state */ + us->min_subsong = us->max_subsong = us->cur_subsong = -1; + + state->song = us; + return 1; + + error: + if (us != NULL) { + free(us->buf); + free(us); + } + return 0; +} + +static int uade_open_and_lock(const char *filename, int create) +{ + int fd, ret; + fd = open(filename, O_RDWR); + if (fd < 0) { + if (errno == ENOENT && create) { + fd = open(filename, O_RDWR | O_CREAT, + S_IRUSR | S_IWUSR); + if (fd < 0) + return -1; + } else { + return -1; + } + } +#ifndef UADE_HAVE_CYGWIN + ret = lockf(fd, F_LOCK, 0); + if (ret) { + fprintf(stderr, "uade: Unable to lock song.conf: %s (%s)\n", + filename, strerror(errno)); + atomic_close(fd); + return -1; + } +#endif + + return fd; +} + + +static struct uade_content *store_playtime(const char *md5, long playtime, + int *newccmodified, + size_t oldnccused) +{ + struct uade_content *n = NULL; + + if (oldnccused > 0) { + struct uade_content key; + memset(&key, 0, sizeof key); + strlcpy(key.md5, md5, sizeof key.md5); + + /* We use "oldnccused" here as the length, while new entries + are added in unsorted manner to the end of the array */ + n = bsearch(&key, contentchecksums, oldnccused, + sizeof contentchecksums[0], contentcompare); + if (n == NULL) + /* new songs on disk db -> merge -> need saving */ + *newccmodified = 1; + } + + /* We value a playtime determined during run-time over + a database value */ + if (n == NULL) { + /* Note, create_content_checksum() makes "ccmodified" + true, which we work-around later with the "newccmodified" */ + n = create_content_checksum(md5, (uint32_t) playtime); + } + + if (n == NULL) { + /* No memory, fuck. We shouldn't save anything to + avoid losing data. */ + fprintf(stderr, + "uade: Warning, no memory for the song database\n"); + cccorrupted = 1; + } + + return n; +} + + + +int uade_read_content_db(const char *filename) +{ + char line[1024]; + FILE *f; + size_t lineno = 0; + long playtime; + int i, j, nexti; + char *id, *eptr; + char numberstr[1024]; + char *md5; + + /* We make backups of some variables because following loop will + make it always true, which is not what we want. The end result should + be that ccmodified is true in following cases only: + 1. the in-memory db is already dirty + 2. the in-memory db gets new data from disk db (merge operation) + Otherwise ccmodified should be false. */ + int newccmodified = ccmodified; + size_t oldnccused = nccused; + int fd; + struct uade_content *n; + + /* Try to create a database if it doesn't exist */ + if (contentchecksums == NULL + && create_content_checksum(NULL, 0) == NULL) + return 0; + + fd = uade_open_and_lock(filename, 0); + if (fd < 0) { + fprintf(stderr, "uade: Can not find %s\n", filename); + return 0; + } + + f = fdopen(fd, "r"); + if (f == NULL) { + fprintf(stderr, "uade: Can not create FILE structure for %s\n", + filename); + close(fd); + return 0; + } + + while (xfgets(line, sizeof line, f) != NULL) { + lineno++; + + if (line[0] == '#') + continue; + + md5 = line; + i = skip_and_terminate_word(line, 0); + if (i < 0) + continue; /* playtime doesn't exist */ + + for (j = 0; isxdigit(line[j]); j++); + + if (j != 32) + continue; /* is not a valid md5sum */ + + /* Grab and validate playtime (in milliseconds) */ + nexti = skip_and_terminate_word(line, i); + + playtime = strtol(&line[i], &eptr, 10); + if (*eptr != 0 || playtime < 0) { + fprintf(stderr, "Invalid playtime for md5 %s on contentdb line %zd: %s\n", md5, lineno, numberstr); + continue; + } + + n = store_playtime(md5, playtime, &newccmodified, oldnccused); + if (n == NULL) + continue; + + i = nexti; /* Note, it could be that i < 0 */ + + /* Get rest of the directives in a loop */ + while (i >= 0) { + id = &line[i]; + i = skip_and_terminate_word(line, i); + + /* Subsong volume normalisation: n=sub1,XXX */ + if (strncmp(id, NORM_ID, NORM_ID_LENGTH) == 0) { + id += NORM_ID_LENGTH; + add_sub_normalisation(n, id); + } else { + fprintf(stderr, "Unknown contentdb directive on line %zd: %s\n", lineno, id); + } + } + } + fclose(f); + + ccmodified = newccmodified; + + sort_content_checksums(); + + return 1; +} + +int uade_read_song_conf(const char *filename) +{ + FILE *f = NULL; + struct eaglesong *s; + size_t allocated; + size_t lineno = 0; + size_t i; + int fd; + + fd = uade_open_and_lock(filename, 1); + /* open_and_lock() may fail without harm (it's actually supposed to + fail if the process does not have lock (write) permissions to + the song.conf file */ + + f = fopen(filename, "r"); + if (f == NULL) + goto error; + + nsongs = 0; + allocated = 16; + songstore = calloc(allocated, sizeof songstore[0]); + if (songstore == NULL) + eserror("No memory for song store."); + + while (1) { + char **items; + size_t nitems; + + items = read_and_split_lines(&nitems, &lineno, f, + UADE_WS_DELIMITERS); + if (items == NULL) + break; + + assert(nitems > 0); + + if (nsongs == allocated) { + allocated *= 2; + songstore = realloc(songstore, allocated * sizeof(songstore[0])); + if (songstore == NULL) + eserror("No memory for players."); + } + + s = &songstore[nsongs]; + nsongs++; + + memset(s, 0, sizeof s[0]); + + if (strncasecmp(items[0], "md5=", 4) != 0) { + fprintf(stderr, "Line %zd must begin with md5= in %s\n", + lineno, filename); + free(items); + continue; + } + if (strlcpy(s->md5, items[0] + 4, sizeof s->md5) != + ((sizeof s->md5) - 1)) { + fprintf(stderr, + "Line %zd in %s has too long an md5sum.\n", + lineno, filename); + free(items); + continue; + } + + for (i = 1; i < nitems; i++) { + if (strncasecmp(items[i], "comment:", 7) == 0) + break; + if (uade_song_and_player_attribute(&s->attributes, &s->flags, items[i], lineno)) + continue; + fprintf(stderr, "song option %s is invalid\n", items[i]); + } + + for (i = 0; items[i] != NULL; i++) + free(items[i]); + + free(items); + } + + fclose(f); + + /* we may not have the file locked */ + if (fd >= 0) + atomic_close(fd); /* lock is closed too */ + + /* Sort MD5 sums for binary searching songs */ + qsort(songstore, nsongs, sizeof songstore[0], escompare); + return 1; + + error: + if (f) + fclose(f); + if (fd >= 0) + atomic_close(fd); + return 0; +} + +void uade_save_content_db(const char *filename) +{ + int fd; + FILE *f; + size_t i; + + if (ccmodified == 0 || cccorrupted) + return; + + fd = uade_open_and_lock(filename, 1); + if (fd < 0) { + fprintf(stderr, "uade: Can not write content db: %s\n", + filename); + return; + } + + f = fdopen(fd, "w"); + if (f == NULL) { + fprintf(stderr, + "uade: Can not create a FILE structure for content db: %s\n", + filename); + close(fd); + return; + } + + for (i = 0; i < nccused; i++) { + char str[1024]; + size_t subi, nsubs; + size_t bindex, bleft; + struct uade_content *n = &contentchecksums[i]; + + str[0] = 0; + + bindex = 0; + bleft = sizeof(str); + + nsubs = vplist_len(n->subs); + + for (subi = 0; subi < nsubs; subi++) { + struct persub *sub = vplist_get(n->subs, subi); + int ret; + ret = + snprintf(&str[bindex], bleft, NORM_ID "%s ", + sub->normalisation); + if (ret >= bleft) { + fprintf(stderr, + "Too much subsong infos for %s\n", + n->md5); + break; + } + bleft -= ret; + bindex += ret; + } + + fprintf(f, "%s %u %s\n", n->md5, (unsigned int)n->playtime, + str); + } + + ccmodified = 0; + + fclose(f); + fprintf(stderr, "uade: Saved %zd entries into content db.\n", nccused); +} + +int uade_test_silence(void *buf, size_t size, struct uade_state *state) +{ + int i, s, exceptioncount; + int16_t *sm; + int nsamples; + int64_t count = state->song->silence_count; + int end = 0; + + if (state->config.silence_timeout < 0) + return 0; + + exceptioncount = 0; + sm = buf; + nsamples = size / 2; + + for (i = 0; i < nsamples; i++) { + s = (sm[i] >= 0) ? sm[i] : -sm[i]; + if (s >= (32767 * 1 / 100)) { + exceptioncount++; + if (exceptioncount >= (size * 2 / 100)) { + count = 0; + break; + } + } + } + + if (i == nsamples) { + count += size; + if (count / (UADE_BYTES_PER_FRAME * state->config.frequency) >= state->config.silence_timeout) { + count = 0; + end = 1; + } + } + + state->song->silence_count = count; + + return end; +} + +void uade_unalloc_song(struct uade_state *state) +{ + free(state->song->buf); + state->song->buf = NULL; + + free(state->song); + state->song = NULL; +} + +int uade_update_song_conf(const char *songconfin, const char *songconfout, + const char *songname, const char *options) +{ + int ret; + int fd; + char md5[33]; + void *mem = NULL; + size_t filesize, newsize; + int found = 0; + size_t inputsize; + char *input, *inputptr, *outputptr; + size_t inputoffs; + char newline[256]; + size_t i; + int need_newline = 0; + + if (strlen(options) > 128) { + fprintf(stderr, "Too long song.conf options.\n"); + return 0; + } + + fd = uade_open_and_lock(songconfout, 1); + + input = atomic_read_file(&inputsize, songconfin); + if (input == NULL) { + fprintf(stderr, "Can not read song.conf: %s\n", songconfin); + atomic_close(fd); /* closes the lock too */ + return 0; + } + + newsize = inputsize + strlen(options) + strlen(songname) + 64; + mem = realloc(input, newsize); + if (mem == NULL) { + fprintf(stderr, + "Can not realloc the input file buffer for song.conf.\n"); + free(input); + atomic_close(fd); /* closes the lock too */ + return 0; + } + input = mem; + + mem = atomic_read_file(&filesize, songname); + if (mem == NULL) + goto error; + + md5_from_buffer(md5, sizeof md5, mem, filesize); + + inputptr = outputptr = input; + inputoffs = 0; + + while (inputoffs < inputsize) { + if (inputptr[0] == '#') + goto copyline; + + if ((inputoffs + 37) >= inputsize) + goto copyline; + + if (strncasecmp(inputptr, "md5=", 4) != 0) + goto copyline; + + if (strncasecmp(inputptr + 4, md5, 32) == 0) { + if (found) { + fprintf(stderr, + "Warning: dupe entry in song.conf: %s (%s)\n" + "Need manual resolving.\n", songname, + md5); + goto copyline; + } + found = 1; + snprintf(newline, sizeof newline, "md5=%s\t%s\n", md5, + options); + + /* Skip this line. It will be appended later to the end of the buffer */ + for (i = inputoffs; i < inputsize; i++) { + if (input[i] == '\n') { + i = i + 1 - inputoffs; + break; + } + } + if (i == inputsize) { + i = inputsize - inputoffs; + found = 0; + need_newline = 1; + } + inputoffs += i; + inputptr += i; + continue; + } + + copyline: + /* Copy the line */ + for (i = inputoffs; i < inputsize; i++) { + if (input[i] == '\n') { + i = i + 1 - inputoffs; + break; + } + } + if (i == inputsize) { + i = inputsize - inputoffs; + need_newline = 1; + } + memmove(outputptr, inputptr, i); + inputoffs += i; + inputptr += i; + outputptr += i; + } + + if (need_newline) { + snprintf(outputptr, 2, "\n"); + outputptr += 1; + } + + /* there is enough space */ + ret = snprintf(outputptr, PATH_MAX + 256, "md5=%s\t%s\tcomment %s\n", + md5, options, songname); + outputptr += ret; + + if (ftruncate(fd, 0)) { + fprintf(stderr, "Can not truncate the file.\n"); + goto error; + } + + /* Final file size */ + i = (size_t) (outputptr - input); + + if (atomic_write(fd, input, i) < i) + fprintf(stderr, + "Unable to write file contents back. Data loss happened. CRAP!\n"); + + error: + atomic_close(fd); /* Closes the lock too */ + free(input); + free(mem); + return 1; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songdb.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songdb.h new file mode 100644 index 00000000..8cbba160 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songdb.h @@ -0,0 +1,24 @@ +#ifndef _UADE_SONGDB_H_ +#define _UADE_SONGDB_H_ + +#include "uadestate.h" +#include "vplist.h" + +struct uade_content { + char md5[33]; + uint32_t playtime; /* in milliseconds */ + struct vplist *subs; +}; + +struct uade_content *uade_add_playtime(const char *md5, uint32_t playtime); +int uade_alloc_song(struct uade_state *state, const char *filename); +void uade_lookup_volume_normalisation(struct uade_state *state); +int uade_read_content_db(const char *filename); +int uade_read_song_conf(const char *filename); +void uade_save_content_db(const char *filename); +int uade_test_silence(void *buf, size_t size, struct uade_state *state); +void uade_unalloc_song(struct uade_state *state); +int uade_update_song_conf(const char *songconfin, const char *songconfout, + const char *songname, const char *options); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songinfo.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songinfo.c new file mode 100644 index 00000000..5997b183 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songinfo.c @@ -0,0 +1,721 @@ +#define _GNU_SOURCE +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <stdint.h> +#include <ctype.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "songinfo.h" +#include "uadeutils.h" +#include "ossupport.h" +#include "amifilemagic.h" +#include "support.h" + + +static void asciiline(char *dst, unsigned char *buf) +{ + int i, c; + for (i = 0; i < 16; i++) { + c = buf[i]; + if (isgraph(c) || c == ' ') { + dst[i] = c; + } else { + dst[i] = '.'; + } + } + dst[i] = 0; +} + +static int hexdump(char *info, size_t maxlen, char *filename, size_t toread) +{ + FILE *f; + size_t rb, ret; + uint8_t *buf; + + assert(maxlen >= 8192); + + f = fopen(filename, "rb"); + if (f == NULL) + return 0; + + buf = malloc(toread); + if (buf == NULL) + return 0; + + rb = 0; + while (rb < toread) { + ret = fread(&buf[rb], 1, toread - rb, f); + if (ret == 0) + break; + rb += ret; + } + + if (rb > 0) { + size_t roff = 0; + size_t woff = 0; + + while (roff < rb) { + int iret; + + if (woff >= maxlen) + break; + + if (woff + 32 >= maxlen) { + strcpy(&info[woff], "\nbuffer overflow...\n"); + woff += strlen(&info[woff]); + break; + } + + iret = snprintf(&info[woff], maxlen - woff, "%.3zx: ", + roff); + assert(iret > 0); + woff += iret; + + if (woff >= maxlen) + break; + + if (roff + 16 > rb) { + iret = snprintf(&info[woff], maxlen - woff, + "Aligned line "); + assert(iret > 0); + woff += iret; + + } else { + char dbuf[17]; + asciiline(dbuf, &buf[roff]); + iret = snprintf(&info[woff], maxlen - woff, + "%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x |%s|", + buf[roff + 0], buf[roff + 1], + buf[roff + 2], buf[roff + 3], + buf[roff + 4], buf[roff + 5], + buf[roff + 6], buf[roff + 7], + buf[roff + 8], buf[roff + 9], + buf[roff + 10], buf[roff + 11], + buf[roff + 12], buf[roff + 13], + buf[roff + 14], buf[roff + 15], + dbuf); + assert(iret > 0); + woff += iret; + } + + if (woff >= maxlen) + break; + + iret = snprintf(&info[woff], maxlen - woff, "\n"); + woff += iret; + + roff += 16; + } + + if (woff >= maxlen) + woff = maxlen - 1; + info[woff] = 0; + } + + fclose(f); + free(buf); + return rb == 0; +} + +static size_t find_tag(uint8_t * buf, size_t startoffset, size_t buflen, + uint8_t * tag, size_t taglen) +{ + uint8_t *treasure; + + if (startoffset >= buflen) + return -1; + + treasure = memmem(buf + startoffset, buflen - startoffset, tag, taglen); + if (treasure == NULL) + return -1; + + return (size_t) (treasure - buf); +} + +static int string_checker(unsigned char *str, size_t off, size_t maxoff) +{ + assert(maxoff > 0); + while (off < maxoff) { + if (*str == 0) + return 1; + off++; + str++; + } + return 0; +} + +/* Wanted Team's loadseg modules */ +static void process_WTWT_mod(char *credits, size_t credits_len, + unsigned char *buf, size_t len, char *lo, + char *hi, int rel) +{ + int offset, txt_offset, chunk; + char tmpstr[256]; + + /* check for Magic ID */ + offset = find_tag((uint8_t *) buf, 0, len, (uint8_t *) lo, 4); + if (offset == -1) + return; + + offset = + find_tag((uint8_t *) buf, offset + 4, offset + 8, (uint8_t *) hi, + 4); + if (offset == -1) + return; + + chunk = offset - 8; /* here's where our first chunk should be */ + offset = offset + rel; /* offset to our info pointers */ + + if (chunk < len && offset < len) { + txt_offset = read_be_u32(buf + offset) + chunk; + if (txt_offset < len && txt_offset != chunk) { + if (!string_checker(buf, txt_offset, len)) + return; + snprintf(tmpstr, sizeof tmpstr, "\nMODULENAME:\n %s\n", + buf + txt_offset); + strlcat(credits, tmpstr, credits_len); + + } + txt_offset = read_be_u32(buf + offset + 4) + chunk; + if (txt_offset < len && txt_offset != chunk) { + if (!string_checker(buf, txt_offset, len)) + return; + snprintf(tmpstr, sizeof tmpstr, "\nAUTHORNAME:\n %s\n", + buf + txt_offset); + strlcat(credits, tmpstr, credits_len); + } + + txt_offset = read_be_u32(buf + offset + 8) + chunk; + if (txt_offset < len && txt_offset != chunk) { + if (!string_checker(buf, txt_offset, len)) + return; + snprintf(tmpstr, sizeof tmpstr, "\nSPECIALINFO:\n %s", + buf + txt_offset); + strlcat(credits, tmpstr, credits_len); + } + } +} + +/* Get the info out of the AHX module data*/ +static void process_ahx_mod(char *credits, size_t credits_len, + unsigned char *buf, size_t len) +{ + int i; + size_t offset; + char tmpstr[256]; + + if (len < 13) + return; + + offset = read_be_u16(buf + 4); + + if (offset >= len) + return; + + if (!string_checker(buf, offset, len)) + return; + + snprintf(tmpstr, sizeof tmpstr, "\nSong title: %s\n", buf + offset); + strlcat(credits, tmpstr, credits_len); + + for (i = 0; i < buf[12]; i++) { + if (!string_checker(buf, offset, len)) + break; + offset = offset + 1 + strlen((char *)buf + offset); + if (offset < len) { + snprintf(tmpstr, 256, "\n %s", buf + offset); + strlcat(credits, tmpstr, credits_len); + } + } +} + +/* Get the info out of the protracker module data*/ +static void process_ptk_mod(char *credits, size_t credits_len, int inst, + uint8_t * buf, size_t len) +{ + int i; + char tmpstr[256]; + + if (!string_checker(buf, 0, len)) + return; + + snprintf(tmpstr, 35, "\nSong title: %s", buf); + strlcat(credits, tmpstr, credits_len); + + if (inst == 31) { + if (len >= 0x43c) { + snprintf(tmpstr, sizeof tmpstr, + "\nmax positions: %d\n", buf[0x3b6]); + strlcat(credits, tmpstr, credits_len); + } + } else { + if (len >= 0x1da) { + snprintf(tmpstr, sizeof tmpstr, + "\nmax positions: %d\n", buf[0x1d6]); + strlcat(credits, tmpstr, credits_len); + } + } + + snprintf(tmpstr, sizeof tmpstr, "\nINST - NAME SIZE VOL FINE LSTART LSIZE\n"); + strlcat(credits, tmpstr, credits_len); + if (len >= (0x14 + inst * 0x1e)) { + for (i = 0; i < inst; i++) { + if (!string_checker(buf, 0x14 + i * 0x1e, len)) + break; + snprintf(tmpstr, sizeof tmpstr, "[%2d] - ", i + 1); + strlcat(credits, tmpstr, credits_len); + snprintf(tmpstr, 23, "%-23s", buf + 0x14 + (i * 0x1e)); + strlcat(credits, tmpstr, credits_len); + snprintf(tmpstr, sizeof tmpstr, + " %6d %2d %2d %6d %6d\n", + read_be_u16(buf + 42 + i * 0x1e) * 2, + buf[45 + i * 0x1e], buf[44 + i * 0x1e], + read_be_u16(buf + 46 + i * 0x1e) * 2, + read_be_u16(buf + 48 + i * 0x1e) * 2); + strlcat(credits, tmpstr, credits_len); + } + } +} + +/* Get the info out of the digibooster module data*/ +static void process_digi_mod(char *credits, size_t credits_len, + uint8_t * buf, size_t len) +{ + int i; + char tmpstr[256]; + + if (len < (642 + 0x30 * 0x1e)) + return; + + if (!string_checker(buf, 610, len)) + return; + + snprintf(tmpstr, 0x2f, "\nSong title: %s \n", buf + 610); + strlcat(credits, tmpstr, credits_len); + + snprintf(tmpstr, sizeof tmpstr, "max positions: %d\n", buf[47]); + strlcat(credits, tmpstr, credits_len); + + snprintf(tmpstr, sizeof tmpstr, "\nINST - NAME SIZE VOL FINE LSTART LSIZE\n"); + strlcat(credits, tmpstr, credits_len); + if (len >= (642 + 0x1f * 0x1e)) { + for (i = 0; i < 0x1f; i++) { + if (!string_checker(buf, 642 + i * 0x1e, len)) + break; + snprintf(tmpstr, sizeof tmpstr, "[%2d] - ", i + 1); + strlcat(credits, tmpstr, credits_len); + snprintf(tmpstr, 30, "%-30s", buf + 642 + (i * 0x1e)); + strlcat(credits, tmpstr, credits_len); + snprintf(tmpstr, sizeof tmpstr, + " %11d %2d %3d %11d %11d\n", + read_be_u32(buf + 176 + i * 4), buf[548 + i], + buf[579 + i], read_be_u32(buf + 300 + i * 4), + read_be_u32(buf + 424 + i * 4)); + strlcat(credits, tmpstr, credits_len); + } + } +} + +/* Get the info out of custom song. FIX ME, clean this function. */ +static void process_custom(char *credits, size_t credits_len, + unsigned char *buf, size_t len) +{ + char tmpstr[1024]; + unsigned char *hunk; + unsigned char *tag_table; + int hunk_size; + int table_size; + + int i; + int offset; + unsigned int x, y; + unsigned char startpattern[4] = { 0x70, 0xff, 0x4e, 0x75 }; + + if (len < 4) + return; + + if (read_be_u32(buf) != 0x000003f3) + return; + + i = find_tag(buf, 0, len, startpattern, sizeof startpattern); + if (i == -1 || (i + 12) >= len) + return; + + if (strncmp((char *)buf + i + 4, "DELIRIUM", 8) != 0 && + strncmp((char *)buf + i + 4, "EPPLAYER", 8) != 0) { + return; + } + + /* Hunk found */ + hunk = buf + i; + hunk_size = len - i; + + if (16 + i + 5 >= hunk_size) + return; + + /* Check if $VER is available */ + if (!memcmp(&hunk[16], "$VER:", 5)) { + offset = 16 + 5; + while (offset < hunk_size) { + if (memcmp(&hunk[offset], " ", 1)) + break; + offset++; + } + if (offset >= hunk_size) + return; + + if ((offset + strlen((char *)hunk + offset) + 1) > + ((size_t) hunk_size)) + return; + + snprintf(tmpstr, sizeof tmpstr, "\nVERSION:\n%s\n\n", + hunk + offset); + strlcat(credits, tmpstr, credits_len); + } + + offset = read_be_u32(hunk + 12); + if (offset < 0) { + return; + } + + tag_table = hunk + offset; + + if (tag_table >= &buf[len]) + return; + + table_size = ((int)(&buf[len] - tag_table)) / 8; + + if (table_size <= 0) + return; + + /* check all tags in this loop */ + for (i = 0; i < table_size; i += 2) { + x = read_be_u32(tag_table + 4 * i); + y = read_be_u32(tag_table + 4 * (i + 1)); + + if (!x) + break; + + switch (x) { + case 0x8000445a: + if (y >= ((unsigned int)hunk_size)) + return; + if ((y + strlen((char *)hunk + y) + 1) > + ((size_t) hunk_size)) + return; + snprintf(tmpstr, sizeof tmpstr, "\nCREDITS:\n%s\n\n", + hunk + y); + strlcat(credits, tmpstr, credits_len); + break; + default: + break; + } + } +} + +/* + * Get the info out of the Deltamusic 2 module data + */ +static void process_dm2_mod(char *credits, size_t credits_len, + unsigned char *buf, size_t len) +{ + char tmpstr[256]; + if (!string_checker(buf, 0x148, len)) + return; + snprintf(tmpstr, sizeof tmpstr, "\nRemarks:\n%s", buf + 0x148); + strlcat(credits, tmpstr, credits_len); +} + +static int process_module(char *credits, size_t credits_len, char *filename) +{ + FILE *modfile; + struct stat st; + size_t modfilelen; + unsigned char *buf; + char pre[11]; + char tmpstr[256]; + size_t rb; + + if (!(modfile = fopen(filename, "rb"))) + return 0; + + if (fstat(fileno(modfile), &st)) + return 0; + + modfilelen = st.st_size; + + if ((buf = malloc(modfilelen)) == NULL) { + fprintf(stderr, "uade: can't allocate mem in process_module()"); + fclose(modfile); + return 0; + } + + rb = 0; + while (rb < modfilelen) { + size_t ret = fread(&buf[rb], 1, modfilelen - rb, modfile); + if (ret == 0) + break; + rb += ret; + } + + fclose(modfile); + + if (rb < modfilelen) { + fprintf(stderr, "uade: song info could not read %s fully\n", + filename); + free(buf); + return 0; + } + + snprintf(tmpstr, sizeof tmpstr, "UADE2 MODINFO:\n\nFile name: %s\nFile length: %zd bytes\n", filename, modfilelen); + strlcpy(credits, tmpstr, credits_len); + + /* Get filetype in pre */ + uade_filemagic(buf, modfilelen, pre, modfilelen, filename, 0); + + snprintf(tmpstr, sizeof tmpstr, "File prefix: %s.*\n", pre); + strlcat(credits, tmpstr, credits_len); + + if (strcasecmp(pre, "CUST") == 0) { + /* CUST */ + process_custom(credits, credits_len, buf, modfilelen); + + } else if (strcasecmp(pre, "DM2") == 0) { + /* DM2 */ + process_dm2_mod(credits, credits_len, buf, modfilelen); + + } else if (strcasecmp(pre, "DIGI") == 0) { + /* DIGIBooster */ + process_digi_mod(credits, credits_len, buf, modfilelen); + + } else if ((strcasecmp(pre, "AHX") == 0) || + (strcasecmp(pre, "THX") == 0)) { + /* AHX */ + process_ahx_mod(credits, credits_len, buf, modfilelen); + + } else if ((strcasecmp(pre, "MOD15") == 0) || + (strcasecmp(pre, "MOD15_UST") == 0) || + (strcasecmp(pre, "MOD15_MST") == 0) || + (strcasecmp(pre, "MOD15_ST-IV") == 0)) { + /*MOD15 */ + process_ptk_mod(credits, credits_len, 15, buf, modfilelen); + + } else if ((strcasecmp(pre, "MOD") == 0) || + (strcasecmp(pre, "MOD_DOC") == 0) || + (strcasecmp(pre, "MOD_NTK") == 0) || + (strcasecmp(pre, "MOD_NTK1") == 0) || + (strcasecmp(pre, "MOD_NTK2") == 0) || + (strcasecmp(pre, "MOD_FLT4") == 0) || + (strcasecmp(pre, "MOD_FLT8") == 0) || + (strcasecmp(pre, "MOD_ADSC4") == 0) || + (strcasecmp(pre, "MOD_ADSC8") == 0) || + (strcasecmp(pre, "MOD_COMP") == 0) || + (strcasecmp(pre, "MOD_NTKAMP") == 0) || + (strcasecmp(pre, "PPK") == 0) || + (strcasecmp(pre, "MOD_PC") == 0) || + (strcasecmp(pre, "ICE") == 0) || + (strcasecmp(pre, "ADSC") == 0)) { + /*MOD*/ + process_ptk_mod(credits, credits_len, 31, buf, modfilelen); + } else if (strcasecmp(pre, "DL") == 0) { + process_WTWT_mod(credits, credits_len, buf, modfilelen, "UNCL", + "EART", 0x28); + } else if (strcasecmp(pre, "BSS") == 0) { + process_WTWT_mod(credits, credits_len, buf, modfilelen, "BEAT", + "HOVE", 0x1c); + } else if (strcasecmp(pre, "GRAY") == 0) { + process_WTWT_mod(credits, credits_len, buf, modfilelen, "FRED", + "GRAY", 0x10); + } else if (strcasecmp(pre, "JMF") == 0) { + process_WTWT_mod(credits, credits_len, buf, modfilelen, "J.FL", + "OGEL", 0x14); + } else if (strcasecmp(pre, "SPL") == 0) { + process_WTWT_mod(credits, credits_len, buf, modfilelen, "!SOP", + "ROL!", 0x10); + } else if (strcasecmp(pre, "HD") == 0) { + process_WTWT_mod(credits, credits_len, buf, modfilelen, "H.DA", + "VIES", 24); + } else if (strcasecmp(pre, "RIFF") == 0) { + process_WTWT_mod(credits, credits_len, buf, modfilelen, "RIFF", + "RAFF", 0x14); + } else if (strcasecmp(pre, "FP") == 0) { + process_WTWT_mod(credits, credits_len, buf, modfilelen, "F.PL", + "AYER", 0x8); + } else if (strcasecmp(pre, "CORE") == 0) { + process_WTWT_mod(credits, credits_len, buf, modfilelen, "S.PH", + "IPPS", 0x20); + } else if (strcasecmp(pre, "BDS") == 0) { + process_WTWT_mod(credits, credits_len, buf, modfilelen, "DAGL", + "ISH!", 0x14); + } + + free(buf); + + return 0; +} + +int uade_generate_song_title(char *title, size_t dstlen, + struct uade_state *state) +{ + size_t srcoffs; + size_t dstoffs; + size_t srclen; + char *format; + char *bname; + char p[64]; + char *default_format = "%F %X [%P]"; + struct uade_song *us = state->song; + struct uade_config *uc = &state->config; + + /* %A min subsong + %B cur subsong + %C max subsong + %F file base name (us->module_filename) + %P player name + %T title + %X print subsong info if more than one subsong exist + */ + + format = uc->song_title; + + if (format == NULL) + format = default_format; + + if (strcmp("default", format) == 0) + format = default_format; + + if ((srclen = strlen(format)) == 0) { + fprintf(stderr, "Warning: empty song_title format string.\n"); + return 1; + } + + if (dstlen == 0) + return 1; + + if (strlen(us->module_filename) == 0) + return 1; + + bname = xbasename(us->module_filename); + + p[0] = 0; + if (us->formatname[0] == 0) { + if (us->playername[0] == 0) { + strlcpy(p, "Custom", sizeof p); + } else { + strlcpy(p, us->playername, sizeof p); + } + } else { + if (strncmp(us->formatname, "type: ", 6) == 0) { + strlcpy(p, us->formatname + 6, sizeof p); + } else { + strlcpy(p, us->formatname, sizeof p); + } + } + + srcoffs = dstoffs = 0; + + title[0] = 0; + + while (dstoffs < dstlen) { + char c; + if (srcoffs >= srclen) + break; + + if ((c = format[srcoffs]) == 0) + break; + + if (c != '%') { + title[dstoffs++] = format[srcoffs++]; + } else { + size_t inc; + char *dat = NULL; + char tmp[32]; + + if ((srcoffs + 1) >= srclen) { + fprintf(stderr, "Error: no identifier given in song title format: %s\n", format); + title[dstoffs] = 0; + return 1; + } + + c = format[srcoffs + 1]; + + switch (c) { + case 'A': + snprintf(tmp, sizeof tmp, "%d", + us->min_subsong); + dat = tmp; + break; + case 'B': + snprintf(tmp, sizeof tmp, "%d", + us->cur_subsong); + dat = tmp; + break; + case 'C': + snprintf(tmp, sizeof tmp, "%d", + us->max_subsong); + dat = tmp; + break; + case 'F': + dat = bname; + break; + case 'P': + dat = p; + break; + case 'T': + dat = us->modulename; + if (strcmp("<no songtitle>", dat) == 0) + dat[0] = 0; + if (dat[0] == 0) + dat = bname; + break; + case 'X': + if (us->min_subsong == us->max_subsong) { + tmp[0] = 0; + } else { + snprintf(tmp, sizeof tmp, "(%d/%d)", + us->cur_subsong, + us->max_subsong); + } + dat = tmp; + break; + default: + fprintf(stderr, + "Unknown identifier %%%c in song_title format: %s\n", + c, format); + title[dstoffs] = 0; + return 1; + } + inc = strlcpy(&title[dstoffs], dat, dstlen - dstoffs); + srcoffs += 2; + dstoffs += inc; + } + } + + if (dstoffs < dstlen) + title[dstoffs] = 0; + else + title[dstlen - 1] = 0; + + return 0; +} + +/* Returns zero on success, non-zero otherwise. */ +int uade_song_info(char *info, size_t maxlen, char *filename, + enum song_info_type type) +{ + switch (type) { + case UADE_MODULE_INFO: + return process_module(info, maxlen, filename); + case UADE_HEX_DUMP_INFO: + return hexdump(info, maxlen, filename, 2048); + default: + fprintf(stderr, "Illegal info requested.\n"); + exit(-1); + } + return 0; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songinfo.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songinfo.h new file mode 100644 index 00000000..e0abd059 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songinfo.h @@ -0,0 +1,19 @@ +#ifndef _UADE_SONG_INFO_ +#define _UADE_SONG_INFO_ + +#include <stdio.h> + +#include "uadestate.h" + +enum song_info_type { + UADE_MODULE_INFO = 0, + UADE_HEX_DUMP_INFO, + UADE_NUMBER_OF_INFOS +}; + +int uade_generate_song_title(char *title, size_t dstlen, + struct uade_state *state); +int uade_song_info(char *info, size_t maxlen, char *filename, + enum song_info_type type); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/support.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/support.c new file mode 100644 index 00000000..852d4c0e --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/support.c @@ -0,0 +1,183 @@ +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> + +#include "support.h" +#include "ossupport.h" + +/* Zero terminate the current word. Returns -1 is *s == 0 or the next word + does not exist. Otherwise returns offset to the beginning of next word. */ +int skip_and_terminate_word(char *s, int i) +{ + i = skipnws(s, i); + if (i < 0) + return -1; + + /* Zero terminate word */ + s[i] = 0; + + i = skipws(s, i + 1); + if (i < 0) + return -1; + + return i; +} + +char *xbasename(const char *s) +{ + char *t = strrchr(s, (int) '/'); + if (t == NULL) { + t = (char *) s; + } else { + t++; + } + return t; +} + +/* + * Split a string into 2 whitespace separated fields returned in "key" and + * "value". If more than 2 fields are found, they are cut off by zero + * terminating "key" and "value" inside the string. If "value" is not found, + * *value is set to NULL. If "key" is not found, *key is set to NULL. + * If something is found, both *key and *value become pointers inside the + * string s. + * + * Return values: + * - 0 if neither "key" nor "value" is found + * - 1 if only "key" is found + * - 2 if both "key" and "value" are found + */ +int get_two_ws_separated_fields(char **key, char **value, char *s) +{ + int i; + + *key = NULL; + *value = NULL; + + i = skipws(s, 0); /* Skip initial whitespace */ + + if (i < 0) + return 0; /* We got nothing */ + + *key = s + i; + + i = skip_and_terminate_word(s, i); + + if (i < 0) + return 1; /* We got a "key", but not a "value" */ + + *value = s + i; + + skip_and_terminate_word(s, i); + + return 2; /* We got both a "key" and a "value" */ +} + +/* + * Skip whitespace characters in string starting from offset i. Returns offset + * j >= i as the next non-whitespace character offset, or -1 if non-whitespace + * are not found. + */ +int skipws(const char *s, int i) +{ + while (isspace(s[i])) + i++; + + if (s[i] == 0) + return -1; + + return i; +} + +/* + * Skip non-whitespace characters in string starting from offset i. Returns + * offset j >= i as the next whitespace character offset, or -1 if no + * whitespace if found. + */ +int skipnws(const char *s, int i) +{ + while (!isspace(s[i]) && s[i] != 0) + i++; + + if (s[i] == 0) + return -1; + + return i; +} + + +/* Split line with respect to white space. */ +char **read_and_split_lines(size_t *nitems, size_t *lineno, FILE *f, + const char *delim) +{ + char line[UADE_LINESIZE], templine[UADE_LINESIZE]; + char **items = NULL; + size_t pos; + char *sp, *s; + + *nitems = 0; + + while (xfgets(line, sizeof line, f) != NULL) { + + if (lineno != NULL) + (*lineno)++; + + /* Skip, if a comment line */ + if (line[0] == '#') + continue; + + /* strsep() modifies line that it touches, so we make a copy + of it, and then count the number of items on the line */ + strlcpy(templine, line, sizeof(templine)); + sp = templine; + while ((s = strsep(&sp, delim)) != NULL) { + if (*s == 0) + continue; + (*nitems)++; + } + + if (*nitems > 0) + break; + } + + if (*nitems == 0) + return NULL; + + if ((items = malloc(sizeof(items[0]) * (*nitems + 1))) == NULL) + uadeerror("No memory for nws items.\n"); + + sp = line; + pos = 0; + while ((s = strsep(&sp, delim)) != NULL) { + if (*s == 0) + continue; + + if ((items[pos] = strdup(s)) == NULL) + uadeerror("No memory for an nws item.\n"); + + pos++; + } + items[pos] = NULL; + assert(pos == *nitems); + + return items; +} + + +char *xfgets(char *s, int size, FILE *stream) +{ + char *ret; + + while (1) { + ret = fgets(s, size, stream); + if (ret != NULL) + break; + + if (feof(stream)) + break; + } + + return ret; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/support.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/support.h new file mode 100644 index 00000000..1b32fe92 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/support.h @@ -0,0 +1,31 @@ +#ifndef _UADE_SUPPORT_H_ +#define _UADE_SUPPORT_H_ + +#include <stdio.h> + +#define UADE_LINESIZE 1024 + +#define uadeerror(fmt, args...) do { fprintf(stderr, "uade: " fmt, ## args); exit(1); } while (0) + +#define MAX(x, y) ((x) >= (y) ? (x) : (y)) +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + + +char *xbasename(const char *path); + +int get_two_ws_separated_fields(char **key, char **value, char *s); + +int skipnws(const char *s, int i); + +int skip_and_terminate_word(char *s, int i); + +int skipws(const char *s, int i); + +char **read_and_split_lines(size_t *nitems, size_t *lineno, FILE *f, + const char *delim); + +/* Same as fgets(), but guarantees that feof() or ferror() have happened + when xfgets() returns NULL */ +char *xfgets(char *s, int size, FILE *stream); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconf.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconf.c new file mode 100644 index 00000000..17300340 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconf.c @@ -0,0 +1,888 @@ +/* Handle uade.conf file + + Copyright (C) 2005 Heikki Orsila <heikki.orsila@iki.fi> + + This source code module is dual licensed under GPL and Public Domain. + Hence you may use _this_ module (not another code module) in any way you + want in your projects. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <limits.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "ossupport.h" +#include "uadeconf.h" +#include "uadeconfig.h" +#include "amigafilter.h" +#include "uadeconstants.h" +#include "songdb.h" +#include "uadeutils.h" +#include "support.h" + +static int uade_set_silence_timeout(struct uade_config *uc, const char *value); +static int uade_set_subsong_timeout(struct uade_config *uc, const char *value); +static int uade_set_timeout(struct uade_config *uc, const char *value); + + +struct uade_conf_opts { + char *str; + int l; + enum uade_option e; +}; + +/* List of uade.conf options. The list includes option name, minimum + string match length for the option name and its enum code. */ +static const struct uade_conf_opts uadeconfopts[] = { + {.str = "action_keys", .l = 2, .e = UC_ACTION_KEYS}, + {.str = "ao_option", .l = 2, .e = UC_AO_OPTION}, + {.str = "buffer_time", .l = 1, .e = UC_BUFFER_TIME}, + {.str = "cygwin", .l = 1, .e = UC_CYGWIN_DRIVE_WORKAROUND}, + {.str = "detect_format_by_detection", .l = 18, .e = UC_CONTENT_DETECTION}, + {.str = "disable_timeout", .l = 1, .e = UC_DISABLE_TIMEOUTS}, + {.str = "enable_timeout", .l = 2, .e = UC_ENABLE_TIMEOUTS}, + {.str = "ep_option", .l = 2, .e = UC_EAGLEPLAYER_OPTION}, + {.str = "filter_type", .l = 2, .e = UC_FILTER_TYPE}, + {.str = "force_led_off", .l = 12, .e = UC_FORCE_LED_OFF}, + {.str = "force_led_on", .l = 12, .e = UC_FORCE_LED_ON}, + {.str = "force_led", .l = 9, .e = UC_FORCE_LED}, + {.str = "frequency", .l = 2, .e = UC_FREQUENCY}, + {.str = "gain", .l = 1, .e = UC_GAIN}, + {.str = "headphones", .l = 11, .e = UC_HEADPHONES}, + {.str = "headphones2", .l = 11, .e = UC_HEADPHONES2}, + {.str = "headphone", .l = 11, .e = UC_HEADPHONES}, + {.str = "ignore_player_check", .l = 2, .e = UC_IGNORE_PLAYER_CHECK}, + {.str = "interpolator", .l = 2, .e = UC_RESAMPLER}, + {.str = "magic_detection", .l = 1, .e = UC_CONTENT_DETECTION}, + {.str = "no_ep_end_detect", .l = 4, .e = UC_NO_EP_END}, + {.str = "no_filter", .l = 4, .e = UC_NO_FILTER}, + {.str = "no_song_end", .l = 4, .e = UC_NO_EP_END}, + {.str = "normalise", .l = 1, .e = UC_NORMALISE}, + {.str = "ntsc", .l = 2, .e = UC_NTSC}, + {.str = "one_subsong", .l = 1, .e = UC_ONE_SUBSONG}, + {.str = "pal", .l = 3, .e = UC_PAL}, + {.str = "panning_value", .l = 3, .e = UC_PANNING_VALUE}, + {.str = "random_play", .l = 3, .e = UC_RANDOM_PLAY}, + {.str = "recursive_mode", .l = 3, .e = UC_RECURSIVE_MODE}, + {.str = "resampler", .l = 3, .e = UC_RESAMPLER}, + {.str = "silence_timeout_value", .l = 2, .e = UC_SILENCE_TIMEOUT_VALUE}, + {.str = "song_title", .l = 2, .e = UC_SONG_TITLE}, + {.str = "speed_hack", .l = 2, .e = UC_SPEED_HACK}, + {.str = "subsong_timeout_value", .l = 2, .e = UC_SUBSONG_TIMEOUT_VALUE}, + {.str = "timeout_value", .l = 1, .e = UC_TIMEOUT_VALUE}, + {.str = "verbose", .l = 1, .e = UC_VERBOSE}, + {.str = NULL} /* END OF LIST */ +}; + + +/* Map an uade.conf option to an enum */ +static enum uade_option map_str_to_option(const char *key) +{ + size_t i; + + for (i = 0; uadeconfopts[i].str != NULL; i++) { + if (strncmp(key, uadeconfopts[i].str, uadeconfopts[i].l) == 0) + return uadeconfopts[i].e; + } + + return 0; +} + +/* The function sets the default options. No *_set variables are set because + we don't want any option to become mergeable by default. See + uade_merge_configs(). */ +void uade_config_set_defaults(struct uade_config *uc) +{ + memset(uc, 0, sizeof(*uc)); + uc->action_keys = 1; + strlcpy(uc->basedir.name, UADE_CONFIG_BASE_DIR, sizeof uc->basedir.name); + uade_set_filter_type(uc, NULL); + uc->frequency = UADE_DEFAULT_FREQUENCY; + uc->gain = 1.0; + uc->panning = 0.7; + uc->silence_timeout = 20; + uc->subsong_timeout = 512; + uc->timeout = -1; + uc->use_timeouts = 1; +} + +double uade_convert_to_double(const char *value, double def, double low, + double high, const char *type) +{ + char *endptr, *newvalue; + char newseparator; + double v; + + if (value == NULL) + return def; + + v = strtod(value, &endptr); + + /* Decimal separator conversion, if needed */ + if (*endptr == ',' || *endptr == '.') { + newvalue = strdup(value); + if (newvalue == NULL) + uade_error("Out of memory\n"); + + newseparator = (*endptr == ',') ? '.' : ','; + + newvalue[(intptr_t) endptr - (intptr_t) value] = newseparator; + + v = strtod(newvalue, &endptr); + free(newvalue); + } + + if (*endptr != 0 || v < low || v > high) { + fprintf(stderr, "Invalid %s value: %s\n", type, value); + v = def; + } + + return v; +} + +static void uade_add_ep_option(struct uade_ep_options *opts, const char *s) +{ + size_t freespace = sizeof(opts->o) - opts->s; + + if (strlcpy(&opts->o[opts->s], s, freespace) >= freespace) { + fprintf(stderr, "Warning: uade eagleplayer option overflow: %s\n", s); + return; + } + + opts->s += strlen(s) + 1; +} + +static int handle_attributes(struct uade_config *uc, struct uade_song *us, + char *playername, size_t playernamelen, + int flags, struct uade_attribute *attributelist) +{ + struct uade_attribute *a; + size_t i; + + for (i = 0; epconf[i].s != NULL; i++) { + + if (epconf[i].o == 0) + continue; + + if ((flags & epconf[i].e) == 0) + continue; + + uade_set_config_option(uc, epconf[i].o, epconf[i].c); + } + + if (flags & ES_NEVER_ENDS) + fprintf(stderr, "uade: ES_NEVER_ENDS is not implemented. What should it do?\n"); + + if (flags & ES_REJECT) + return -1; + + a = attributelist; + + while (a != NULL) { + + switch (a->type) { + case ES_EP_OPTION: + if (uc->verbose) + fprintf(stderr, "Using eagleplayer option %s\n", a->s); + uade_add_ep_option(&us->ep_options, a->s); + break; + + case ES_GAIN: + uade_set_config_option(uc, UC_GAIN, a->s); + break; + + case ES_RESAMPLER: + uade_set_config_option(uc, UC_RESAMPLER, a->s); + break; + + case ES_PANNING: + uade_set_config_option(uc, UC_PANNING_VALUE, a->s); + break; + + case ES_PLAYER: + if (playername) { + snprintf(playername, playernamelen, "%s/players/%s", uc->basedir.name, a->s); + } else { + fprintf(stderr, "Error: attribute handling was given playername == NULL.\n"); + } + break; + + case ES_SILENCE_TIMEOUT: + uade_set_config_option(uc, UC_SILENCE_TIMEOUT_VALUE, a->s); + break; + + case ES_SUBSONGS: + fprintf(stderr, "Subsongs not implemented.\n"); + break; + + case ES_SUBSONG_TIMEOUT: + uade_set_config_option(uc, UC_SUBSONG_TIMEOUT_VALUE, a->s); + break; + + case ES_TIMEOUT: + uade_set_config_option(uc, UC_TIMEOUT_VALUE, a->s); + break; + + default: + fprintf(stderr, "Unknown song attribute integer: 0x%x\n", a->type); + break; + } + + a = a->next; + } + + return 0; +} + +int uade_set_song_attributes(struct uade_state *state, + char *playername, size_t playernamelen) +{ + struct uade_song *us = state->song; + struct uade_config *uc = &state->config; + + if (us->normalisation) + uade_set_config_option(uc, UC_NORMALISE, us->normalisation); + + return handle_attributes(uc, us, playername, playernamelen, + us->flags, us->songattributes); +} + +int uade_load_config(struct uade_config *uc, const char *filename) +{ + char line[256]; + FILE *f; + char *key, *value; + int linenumber = 0; + enum uade_option opt; + + if ((f = fopen(filename, "r")) == NULL) + return 0; + + uade_config_set_defaults(uc); + + while (xfgets(line, sizeof(line), f) != NULL) { + linenumber++; + + /* Skip comment lines */ + if (line[0] == '#') + continue; + + if (!get_two_ws_separated_fields(&key, &value, line)) + continue; /* Skip an empty line */ + + opt = map_str_to_option(key); + + if (opt) { + uade_set_config_option(uc, opt, value); + } else { + fprintf(stderr, "Unknown config key in %s on line %d: %s\n", filename, linenumber, key); + } + } + + fclose(f); + return 1; +} + +int uade_load_initial_config(char *uadeconfname, size_t maxlen, + struct uade_config *uc, struct uade_config *ucbase) +{ + int loaded; + char *home; + + assert(maxlen > 0); + uadeconfname[0] = 0; + + uade_config_set_defaults(uc); + + loaded = 0; + + /* First try to load from forced base dir (testing mode) */ + if (ucbase != NULL && ucbase->basedir_set) { + snprintf(uadeconfname, maxlen, "%s/uade.conf", + ucbase->basedir.name); + loaded = uade_load_config(uc, uadeconfname); + } + + home = uade_open_create_home(); + + /* Second, try to load config from ~/.uade2/uade.conf */ + if (loaded == 0 && home != NULL) { + snprintf(uadeconfname, maxlen, "%s/.uade2/uade.conf", home); + loaded = uade_load_config(uc, uadeconfname); + } + + /* Third, try to load from install path */ + if (loaded == 0) { + snprintf(uadeconfname, maxlen, "%s/uade.conf", + uc->basedir.name); + loaded = uade_load_config(uc, uadeconfname); + } + + return loaded; +} + +int uade_load_initial_song_conf(char *songconfname, size_t maxlen, + struct uade_config *uc, + struct uade_config *ucbase) +{ + int loaded = 0; + char *home; + + assert(maxlen > 0); + songconfname[0] = 0; + + /* Used for testing */ + if (ucbase != NULL && ucbase->basedir_set) { + snprintf(songconfname, maxlen, "%s/song.conf", + ucbase->basedir.name); + loaded = uade_read_song_conf(songconfname); + } + + /* Avoid unwanted home directory creation for test mode */ + if (loaded) + return loaded; + + home = uade_open_create_home(); + + /* Try to load from home dir */ + if (loaded == 0 && home != NULL) { + snprintf(songconfname, maxlen, "%s/.uade2/song.conf", home); + loaded = uade_read_song_conf(songconfname); + } + + /* No? Try install path */ + if (loaded == 0) { + snprintf(songconfname, maxlen, "%s/song.conf", + uc->basedir.name); + loaded = uade_read_song_conf(songconfname); + } + + return loaded; +} + +void uade_merge_configs(struct uade_config *ucd, const struct uade_config *ucs) +{ +#define MERGE_OPTION(y) do { if (ucs->y##_set) ucd->y = ucs->y; } while (0) + + MERGE_OPTION(action_keys); + MERGE_OPTION(ao_options); + MERGE_OPTION(basedir); + MERGE_OPTION(buffer_time); + MERGE_OPTION(content_detection); + MERGE_OPTION(cygwin_drive_workaround); + MERGE_OPTION(ep_options); + MERGE_OPTION(filter_type); + MERGE_OPTION(frequency); + MERGE_OPTION(gain); + MERGE_OPTION(gain_enable); + MERGE_OPTION(headphones); + MERGE_OPTION(headphones2); + MERGE_OPTION(ignore_player_check); + MERGE_OPTION(led_forced); + MERGE_OPTION(led_state); + MERGE_OPTION(no_ep_end); + MERGE_OPTION(no_filter); + MERGE_OPTION(no_postprocessing); + + /* Special merge -> don't use MERGE_OPTION macro */ + if (ucs->normalise_set && ucs->normalise) { + ucd->normalise = 1; + if (ucs->normalise_parameter != NULL) + ucd->normalise_parameter = ucs->normalise_parameter; + } + + MERGE_OPTION(one_subsong); + MERGE_OPTION(panning); + MERGE_OPTION(panning_enable); + MERGE_OPTION(random_play); + MERGE_OPTION(recursive_mode); + MERGE_OPTION(resampler); + MERGE_OPTION(silence_timeout); + MERGE_OPTION(song_title); + MERGE_OPTION(speed_hack); + MERGE_OPTION(subsong_timeout); + + MERGE_OPTION(timeout); + MERGE_OPTION(use_timeouts); + if (ucs->timeout_set) { + ucd->use_timeouts = 1; + ucd->use_timeouts_set = 1; + } + + MERGE_OPTION(use_text_scope); + MERGE_OPTION(use_ntsc); + MERGE_OPTION(verbose); +} + +char *uade_open_create_home(void) +{ + /* Create ~/.uade2 directory if it does not exist */ + char *home = getenv("HOME"); + if (home) { + char name[PATH_MAX]; + struct stat st; + snprintf(name, sizeof name, "%s/.uade2", home); + if (stat(name, &st) != 0) + mkdir(name, S_IRUSR | S_IWUSR | S_IXUSR); + } + + return home; +} + +int uade_parse_subsongs(int **subsongs, char *option) +{ + char substr[256]; + char *sp, *str; + size_t pos; + int nsubsongs; + + nsubsongs = 0; + *subsongs = NULL; + + if (strlcpy(substr, option, sizeof subsongs) >= sizeof subsongs) { + fprintf(stderr, "Too long a subsong option: %s\n", option); + return -1; + } + + sp = substr; + while ((str = strsep(&sp, ",")) != NULL) { + if (*str == 0) + continue; + nsubsongs++; + } + + *subsongs = malloc((nsubsongs + 1) * sizeof((*subsongs)[0])); + if (*subsongs == NULL) { + fprintf(stderr, "No memory for subsongs.\n"); + return -1; + } + + strlcpy(substr, option, sizeof subsongs); + + pos = 0; + sp = substr; + while ((str = strsep(&sp, ",")) != NULL) { + if (*str == 0) + continue; + (*subsongs)[pos] = atoi(str); + pos++; + } + + (*subsongs)[pos] = -1; + assert(pos == nsubsongs); + + return nsubsongs; +} + +void uade_set_effects(struct uade_state *state) +{ + struct uade_effect *effects = &state->effects; + struct uade_config *uc = &state->config; + + uade_effect_set_defaults(effects); + + if (uc->no_postprocessing) + uade_effect_disable(effects, UADE_EFFECT_ALLOW); + + if (uc->gain_enable) { + uade_effect_gain_set_amount(effects, uc->gain); + uade_effect_enable(effects, UADE_EFFECT_GAIN); + } + + if (uc->headphones) + uade_effect_enable(effects, UADE_EFFECT_HEADPHONES); + + if (uc->headphones2) + uade_effect_enable(effects, UADE_EFFECT_HEADPHONES2); + + if (uc->normalise) { + uade_effect_normalise_unserialise(uc->normalise_parameter); + uade_effect_enable(effects, UADE_EFFECT_NORMALISE); + } + + if (uc->panning_enable) { + uade_effect_pan_set_amount(effects, uc->panning); + uade_effect_enable(effects, UADE_EFFECT_PAN); + } + + uade_effect_set_sample_rate(effects, uc->frequency); +} + +void uade_set_config_option(struct uade_config *uc, enum uade_option opt, + const char *value) +{ + char *endptr; + long x; + +#define SET_OPTION(opt, value) do { uc->opt = (value); uc->opt##_set = 1; } while (0) + + switch (opt) { + case UC_ACTION_KEYS: + if (value != NULL) { + uc->action_keys_set = 1; + if (!strcasecmp(value, "on") || !strcmp(value, "1")) { + uc->action_keys = 1; + } else if (!strcasecmp(value, "off") || + !strcmp(value, "0")) { + uc->action_keys = 0; + } else { + fprintf(stderr, + "uade.conf: Unknown setting for action keys: %s\n", + value); + } + } + break; + + case UC_AO_OPTION: + strlcat(uc->ao_options.o, value, sizeof uc->ao_options.o); + strlcat(uc->ao_options.o, "\n", sizeof uc->ao_options.o); + uc->ao_options_set = 1; + break; + + case UC_BASE_DIR: + if (value != NULL) { + strlcpy(uc->basedir.name, value, + sizeof uc->basedir.name); + uc->basedir_set = 1; + } else { + fprintf(stderr, "uade: Passed NULL to UC_BASE_DIR.\n"); + } + break; + + case UC_BUFFER_TIME: + if (value != NULL) { + uc->buffer_time_set = 1; + uc->buffer_time = strtol(value, &endptr, 10); + if (uc->buffer_time <= 0 || *endptr != 0) { + fprintf(stderr, "Invalid buffer_time: %s\n", + value); + uc->buffer_time = 0; + } + } else { + fprintf(stderr, + "uade: Passed NULL to UC_BUFFER_TIME.\n"); + } + break; + + case UC_CONTENT_DETECTION: + SET_OPTION(content_detection, 1); + break; + + case UC_CYGWIN_DRIVE_WORKAROUND: + SET_OPTION(cygwin_drive_workaround, 1); + break; + + case UC_DISABLE_TIMEOUTS: + SET_OPTION(use_timeouts, 0); + break; + + case UC_ENABLE_TIMEOUTS: + SET_OPTION(use_timeouts, 1); + break; + + case UC_EAGLEPLAYER_OPTION: + if (value != NULL) { + uade_add_ep_option(&uc->ep_options, value); + uc->ep_options_set = 1; + } else { + fprintf(stderr, + "uade: Passed NULL to UC_EAGLEPLAYER_OPTION.\n"); + } + break; + + case UC_FILTER_TYPE: + SET_OPTION(no_filter, 0); + + if (value != NULL) { + if (strcasecmp(value, "none") != 0) { + /* Filter != NONE */ + uade_set_filter_type(uc, value); + uc->filter_type_set = 1; + } else { + /* Filter == NONE */ + uc->no_filter = 1; + } + } + break; + + case UC_FORCE_LED: + if (value == NULL) { + fprintf(stderr, "uade: UC_FORCE_LED value is NULL\n"); + break; + } + if (strcasecmp(value, "off") == 0 || strcmp(value, "0") == 0) { + uc->led_state = 0; + } else if (strcasecmp(value, "on") == 0 + || strcmp(value, "1") == 0) { + uc->led_state = 1; + } else { + fprintf(stderr, "Unknown force led argument: %s\n", + value); + break; + } + uc->led_state_set = 1; + + SET_OPTION(led_forced, 1); + break; + + case UC_FORCE_LED_OFF: + SET_OPTION(led_forced, 1); + SET_OPTION(led_state, 0); + break; + + case UC_FORCE_LED_ON: + SET_OPTION(led_forced, 1); + SET_OPTION(led_state, 1); + break; + + case UC_FREQUENCY: + if (value == NULL) { + fprintf(stderr, "uade: UC_FREQUENCY value is NULL\n"); + break; + } + x = strtol(value, &endptr, 10); + if (*endptr != 0) { + fprintf(stderr, "Invalid frequency number: %s\n", + value); + break; + } + /* The upper bound is NTSC Amigas bus freq */ + if (x < 1 || x > 3579545) { + fprintf(stderr, "Frequency out of bounds: %ld\n", x); + x = UADE_DEFAULT_FREQUENCY; + } + SET_OPTION(frequency, x); + break; + + case UC_GAIN: + if (value == NULL) { + fprintf(stderr, "uade: UC_GAIN value is NULL\n"); + break; + } + SET_OPTION(gain_enable, 1); + SET_OPTION(gain, uade_convert_to_double(value, 1.0, 0.0, 128.0, "gain")); + break; + + case UC_HEADPHONES: + SET_OPTION(headphones, 1); + break; + + case UC_HEADPHONES2: + SET_OPTION(headphones2, 1); + break; + + case UC_IGNORE_PLAYER_CHECK: + SET_OPTION(ignore_player_check, 1); + break; + + case UC_RESAMPLER: + if (value == NULL) { + fprintf(stderr, "uade.conf: No resampler given.\n"); + break; + } + uc->resampler = strdup(value); + if (uc->resampler != NULL) { + uc->resampler_set = 1; + } else { + fprintf(stderr, "uade.conf: no memory for resampler.\n"); + } + break; + + case UC_NO_EP_END: + SET_OPTION(no_ep_end, 1); + break; + + case UC_NO_FILTER: + SET_OPTION(no_filter, 1); + break; + + case UC_NO_HEADPHONES: + SET_OPTION(headphones, 0); + SET_OPTION(headphones2, 0); + break; + + case UC_NO_PANNING: + SET_OPTION(panning_enable, 0); + break; + + case UC_NO_POSTPROCESSING: + SET_OPTION(no_postprocessing, 1); + break; + + case UC_NORMALISE: + if (value == NULL) { + fprintf(stderr, "uade: UC_NORMALISE is NULL\n"); + break; + } + SET_OPTION(normalise, 1); + uc->normalise_parameter = (char *) value; + break; + + case UC_NTSC: + SET_OPTION(use_ntsc, 1); + break; + + case UC_ONE_SUBSONG: + SET_OPTION(one_subsong, 1); + break; + + case UC_PAL: + SET_OPTION(use_ntsc, 0); + break; + + case UC_PANNING_VALUE: + if (value == NULL) { + fprintf(stderr, "uade: UC_PANNING_VALUE is NULL\n"); + break; + } + SET_OPTION(panning_enable, 1); + SET_OPTION(panning, uade_convert_to_double(value, 0.0, 0.0, 2.0, "panning")); + break; + + case UC_RANDOM_PLAY: + SET_OPTION(random_play, 1); + break; + + case UC_RECURSIVE_MODE: + SET_OPTION(recursive_mode, 1); + break; + + case UC_SILENCE_TIMEOUT_VALUE: + if (value == NULL) { + fprintf(stderr, + "uade: UC_SILENCE_TIMEOUT_VALUE is NULL\n"); + break; + } + uade_set_silence_timeout(uc, value); + break; + + case UC_SONG_TITLE: + if (value == NULL) { + fprintf(stderr, "uade: No song_title format given.\n"); + break; + } + if ((uc->song_title = strdup(value)) == NULL) { + fprintf(stderr, "No memory for song title format\n"); + } else { + uc->song_title_set = 1; + } + break; + + case UC_SPEED_HACK: + SET_OPTION(speed_hack, 1); + break; + + case UC_SUBSONG_TIMEOUT_VALUE: + if (value == NULL) { + fprintf(stderr, + "uade: UC_SUBSONG_TIMEOUT_VALUE is NULL\n"); + break; + } + uade_set_subsong_timeout(uc, value); + break; + + case UC_TIMEOUT_VALUE: + if (value == NULL) { + fprintf(stderr, "uade: UC_TIMEOUT_VALUE is NULL\n"); + break; + } + uade_set_timeout(uc, value); + break; + + case UC_USE_TEXT_SCOPE: + SET_OPTION(use_text_scope, 1); + break; + + case UC_VERBOSE: + SET_OPTION(verbose, 1); + break; + + default: + fprintf(stderr, "uade_set_config_option(): unknown enum: %d\n", + opt); + exit(1); + } +} + +void uade_set_ep_attributes(struct uade_state *state) +{ + handle_attributes(&state->config, state->song, NULL, 0, state->ep->flags, state->ep->attributelist); +} + +void uade_set_filter_type(struct uade_config *uc, const char *model) +{ + uc->filter_type = FILTER_MODEL_A500; + + if (model == NULL) + return; + + /* a500 and a500e are the same */ + if (strncasecmp(model, "a500", 4) == 0) { + uc->filter_type = FILTER_MODEL_A500; + + /* a1200 and a1200e are the same */ + } else if (strncasecmp(model, "a1200", 5) == 0) { + uc->filter_type = FILTER_MODEL_A1200; + + } else { + fprintf(stderr, "Unknown filter model: %s\n", model); + } +} + +static int uade_set_silence_timeout(struct uade_config *uc, const char *value) +{ + char *endptr; + int t; + if (value == NULL) { + return -1; + } + t = strtol(value, &endptr, 10); + if (*endptr != 0 || t < -1) { + fprintf(stderr, "Invalid silence timeout value: %s\n", value); + return -1; + } + uc->silence_timeout = t; + uc->silence_timeout_set = 1; + return 0; +} + +static int uade_set_subsong_timeout(struct uade_config *uc, const char *value) +{ + char *endptr; + int t; + if (value == NULL) { + return -1; + } + t = strtol(value, &endptr, 10); + if (*endptr != 0 || t < -1) { + fprintf(stderr, "Invalid subsong timeout value: %s\n", value); + return -1; + } + uc->subsong_timeout = t; + uc->subsong_timeout_set = 1; + return 0; +} + +static int uade_set_timeout(struct uade_config *uc, const char *value) +{ + char *endptr; + int t; + if (value == NULL) { + return -1; + } + t = strtol(value, &endptr, 10); + if (*endptr != 0 || t < -1) { + fprintf(stderr, "Invalid timeout value: %s\n", value); + return -1; + } + uc->timeout = t; + uc->timeout_set = 1; + return 0; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconf.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconf.h new file mode 100644 index 00000000..62b11ef9 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconf.h @@ -0,0 +1,27 @@ +#ifndef _UADE_FRONTEND_CONFIG_H_ +#define _UADE_FRONTEND_CONFIG_H_ + +#include <uadestate.h> + +void uade_config_set_defaults(struct uade_config *uc); +double uade_convert_to_double(const char *value, double def, + double low, double high, const char *type); +int uade_load_config(struct uade_config *uc, const char *filename); +int uade_load_initial_config(char *uadeconfname, size_t maxlen, + struct uade_config *uc, + struct uade_config *ucbase); +int uade_load_initial_song_conf(char *songconfname, size_t maxlen, + struct uade_config *uc, + struct uade_config *ucbase); +void uade_merge_configs(struct uade_config *ucd, const struct uade_config *ucs); +char *uade_open_create_home(void); +int uade_parse_subsongs(int **subsongs, char *option); +void uade_set_config_option(struct uade_config *uc, enum uade_option opt, + const char *value); +void uade_set_effects(struct uade_state *state); +void uade_set_ep_attributes(struct uade_state *state); +int uade_set_song_attributes(struct uade_state *state, char *playername, + size_t playernamelen); +void uade_set_filter_type(struct uade_config *uc, const char *value); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconfstructure.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconfstructure.h new file mode 100644 index 00000000..d6cff1e0 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconfstructure.h @@ -0,0 +1,139 @@ +#ifndef _UADECONF_STRUCTURE_H_ +#define _UADECONF_STRUCTURE_H_ + +#include <limits.h> + +enum uade_option { + UC_ACTION_KEYS = 0x1000, + UC_AO_OPTION, + UC_BASE_DIR, + UC_BUFFER_TIME, + UC_CONTENT_DETECTION, + UC_CYGWIN_DRIVE_WORKAROUND, + UC_DISABLE_TIMEOUTS, + UC_ENABLE_TIMEOUTS, + UC_EAGLEPLAYER_OPTION, + UC_FILTER_TYPE, + UC_FORCE_LED_OFF, + UC_FORCE_LED_ON, + UC_FORCE_LED, + UC_FREQUENCY, + UC_GAIN, + UC_HEADPHONES, + UC_HEADPHONES2, + UC_IGNORE_PLAYER_CHECK, + UC_NO_FILTER, + UC_NO_HEADPHONES, + UC_NO_PANNING, + UC_NO_POSTPROCESSING, + UC_NO_EP_END, + UC_NORMALISE, + UC_NTSC, + UC_ONE_SUBSONG, + UC_PAL, + UC_PANNING_VALUE, + UC_RANDOM_PLAY, + UC_RECURSIVE_MODE, + UC_RESAMPLER, + UC_SILENCE_TIMEOUT_VALUE, + UC_SONG_TITLE, + UC_SPEED_HACK, + UC_SUBSONG_TIMEOUT_VALUE, + UC_TIMEOUT_VALUE, + UC_USE_TEXT_SCOPE, + UC_VERBOSE +}; + +struct uade_dir { + char name[PATH_MAX]; +}; + +struct uade_ep_options { + char o[256]; + size_t s; +}; + +struct uade_ao_options { + char o[256]; +}; + +#define UADE_CHAR_CONFIG(x) char x; char x##_set; +#define UADE_FLOAT_CONFIG(x) float x; char x##_set; +#define UADE_INT_CONFIG(x) int x; char x##_set; + +/* All the options are put into an instance of this structure. + * There can be many structures, one for uade.conf and the other for + * command line options. Then these structures are then merged together + * to know the complete behavior for each case. Note, these structures + * can be conflicting, so the options are merged in following order + * so that the last merge will determine true behavior: + * + * 1. set uade.conf options + * 2. set eagleplayer attributes + * 3. set song attributes + * 4. set command line options + * + * Merging works by looking at X_set members of this structure. X_set + * member indicates that feature X has explicitly been set, so the + * merge will notice the change in value. + */ +struct uade_config { + UADE_CHAR_CONFIG(action_keys); + + struct uade_ao_options ao_options; + char ao_options_set; + + struct uade_dir basedir; + char basedir_set; + + UADE_INT_CONFIG(buffer_time); + UADE_CHAR_CONFIG(content_detection); + UADE_CHAR_CONFIG(cygwin_drive_workaround); + + struct uade_ep_options ep_options; + char ep_options_set; + + UADE_CHAR_CONFIG(filter_type); + UADE_INT_CONFIG(frequency); + UADE_CHAR_CONFIG(led_forced); + UADE_CHAR_CONFIG(led_state); + + UADE_CHAR_CONFIG(gain_enable); + /* should be removed of uade_effect integrated */ + UADE_FLOAT_CONFIG(gain); + + UADE_CHAR_CONFIG(headphones); + UADE_CHAR_CONFIG(headphones2); + UADE_CHAR_CONFIG(ignore_player_check); + + char *resampler; + char resampler_set; + + UADE_CHAR_CONFIG(no_ep_end); + UADE_CHAR_CONFIG(no_filter); + UADE_CHAR_CONFIG(no_postprocessing); + + UADE_CHAR_CONFIG(normalise); + /* no normalise_parameter_set entry, use manual merging code */ + char *normalise_parameter; + + UADE_CHAR_CONFIG(one_subsong); + UADE_FLOAT_CONFIG(panning); /* should be removed */ + UADE_CHAR_CONFIG(panning_enable); + UADE_CHAR_CONFIG(random_play); + UADE_CHAR_CONFIG(recursive_mode); + UADE_INT_CONFIG(silence_timeout); + + char *song_title; + char song_title_set; + + UADE_CHAR_CONFIG(speed_hack); + UADE_INT_CONFIG(subsong_timeout); + UADE_INT_CONFIG(timeout); + UADE_CHAR_CONFIG(use_text_scope); + UADE_CHAR_CONFIG(use_timeouts); + UADE_CHAR_CONFIG(use_ntsc); + UADE_CHAR_CONFIG(verbose); +}; + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadecontrol.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadecontrol.c new file mode 100644 index 00000000..66e3eac8 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadecontrol.c @@ -0,0 +1,249 @@ +/* uadecontrol.c is a helper module to control uade core through IPC: + + Copyright (C) 2005 Heikki Orsila <heikki.orsila@iki.fi> + + This source code module is dual licensed under GPL and Public Domain. + Hence you may use _this_ module (not another code module) in any way you + want in your projects. +*/ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/socket.h> + +#include "uadecontrol.h" +#include "ossupport.h" +#include "sysincludes.h" +#include "uadeconstants.h" +#include "songdb.h" + +static void subsong_control(int subsong, int command, struct uade_ipc *ipc); + +void uade_change_subsong(struct uade_state *state) +{ + state->song->silence_count = 0; + + uade_lookup_volume_normalisation(state); + + subsong_control(state->song->cur_subsong, UADE_COMMAND_CHANGE_SUBSONG, &state->ipc); +} + +int uade_read_request(struct uade_ipc *ipc) +{ + uint32_t left = UADE_MAX_MESSAGE_SIZE - sizeof(struct uade_msg); + if (uade_send_u32(UADE_COMMAND_READ, left, ipc)) { + fprintf(stderr, "\ncan not send read command\n"); + return 0; + } + return left; +} + +static int send_ep_options(struct uade_ep_options *eo, struct uade_ipc *ipc) +{ + if (eo->s > 0) { + size_t i = 0; + while (i < eo->s) { + char *s = &eo->o[i]; + size_t l = strlen(s) + 1; + assert((i + l) <= eo->s); + if (uade_send_string + (UADE_COMMAND_SET_PLAYER_OPTION, s, ipc)) { + fprintf(stderr, + "Can not send eagleplayer option.\n"); + return -1; + } + i += l; + } + } + return 0; +} + +void uade_send_filter_command(struct uade_state *state) +{ + struct uade_config *uadeconf = &state->config; + struct uade_ipc *ipc = &state->ipc; + + int filter_type = uadeconf->filter_type; + int filter_state = uadeconf->led_state; + int force_filter = uadeconf->led_forced; + + if (uadeconf->no_filter) + filter_type = 0; + + /* Note that filter state is not normally forced */ + filter_state = force_filter ? (2 + (filter_state & 1)) : 0; + + if (uade_send_two_u32s + (UADE_COMMAND_FILTER, filter_type, filter_state, ipc)) { + fprintf(stderr, "Can not setup filters.\n"); + exit(-1); + } +} + +static void send_resampling_command(struct uade_ipc *ipc, + struct uade_config *uadeconf) +{ + char *mode = uadeconf->resampler; + if (mode != NULL) { + if (strlen(mode) == 0) { + fprintf(stderr, "Resampling mode may not be empty.\n"); + exit(-1); + } + if (uade_send_string + (UADE_COMMAND_SET_RESAMPLING_MODE, mode, ipc)) { + fprintf(stderr, "Can not set resampling mode.\n"); + exit(-1); + } + } +} + +static void subsong_control(int subsong, int command, struct uade_ipc *ipc) +{ + assert(subsong >= 0 && subsong < 256); + if (uade_send_u32(command, (uint32_t) subsong, ipc) < 0) { + fprintf(stderr, "Could not changet subsong\n"); + exit(-1); + } +} + +void uade_set_subsong(int subsong, struct uade_ipc *ipc) +{ + subsong_control(subsong, UADE_COMMAND_SET_SUBSONG, ipc); +} + +int uade_song_initialization(const char *scorename, + const char *playername, + const char *modulename, + struct uade_state *state) +{ + uint8_t space[UADE_MAX_MESSAGE_SIZE]; + struct uade_msg *um = (struct uade_msg *)space; + struct uade_ipc *ipc = &state->ipc; + struct uade_config *uc = &state->config; + struct uade_song *us = state->song; + + if (uade_send_string(UADE_COMMAND_SCORE, scorename, ipc)) { + fprintf(stderr, "Can not send score name.\n"); + goto cleanup; + } + + if (uade_send_string(UADE_COMMAND_PLAYER, playername, ipc)) { + fprintf(stderr, "Can not send player name.\n"); + goto cleanup; + } + + if (uade_send_string(UADE_COMMAND_MODULE, modulename, ipc)) { + fprintf(stderr, "Can not send module name.\n"); + goto cleanup; + } + + if (uade_send_short_message(UADE_COMMAND_TOKEN, ipc)) { + fprintf(stderr, "Can not send token after module.\n"); + goto cleanup; + } + + printf ("uade_song_initialization: receive message\n"); + if (uade_receive_message(um, sizeof(space), ipc) <= 0) { + fprintf(stderr, "Can not receive acknowledgement.\n"); + goto cleanup; + } + + if (um->msgtype == UADE_REPLY_CANT_PLAY) { + if (uade_receive_short_message(UADE_COMMAND_TOKEN, ipc)) { + fprintf(stderr, + "Can not receive token in main loop.\n"); + exit(-1); + } + return UADECORE_CANT_PLAY; + } + + if (um->msgtype != UADE_REPLY_CAN_PLAY) { + fprintf(stderr, "Unexpected reply from uade: %u\n", + (unsigned int)um->msgtype); + goto cleanup; + } + + if (uade_receive_short_message(UADE_COMMAND_TOKEN, ipc) < 0) { + fprintf(stderr, "Can not receive token after play ack.\n"); + goto cleanup; + } + + if (uc->ignore_player_check) { + if (uade_send_short_message(UADE_COMMAND_IGNORE_CHECK, ipc) < 0) { + fprintf(stderr, "Can not send ignore check message.\n"); + goto cleanup; + } + } + + if (uc->no_ep_end) { + if (uade_send_short_message + (UADE_COMMAND_SONG_END_NOT_POSSIBLE, ipc) < 0) { + fprintf(stderr, + "Can not send 'song end not possible'.\n"); + goto cleanup; + } + } + + uade_send_filter_command(state); + + send_resampling_command(ipc, uc); + + if (uc->speed_hack) { + if (uade_send_short_message(UADE_COMMAND_SPEED_HACK, ipc)) { + fprintf(stderr, "Can not send speed hack command.\n"); + goto cleanup; + } + } + + if (uc->use_ntsc) { + if (uade_send_short_message(UADE_COMMAND_SET_NTSC, ipc)) { + fprintf(stderr, "Can not send ntsc command.\n"); + goto cleanup; + } + } + + if (uc->frequency != UADE_DEFAULT_FREQUENCY) { + if (uade_send_u32 + (UADE_COMMAND_SET_FREQUENCY, uc->frequency, ipc)) { + fprintf(stderr, "Can not send frequency.\n"); + goto cleanup; + } + } + + if (uc->use_text_scope) { + if (uade_send_short_message(UADE_COMMAND_USE_TEXT_SCOPE, ipc)) { + fprintf(stderr, "Can not send use text scope command.\n"); + goto cleanup; + } + } + + if (send_ep_options(&us->ep_options, ipc) || + send_ep_options(&uc->ep_options, ipc)) + goto cleanup; + + printf ("uade_song_initialization: success\n"); + + return 0; + + cleanup: + return UADECORE_INIT_ERROR; +} + +void uade_spawn(struct uade_state *state, const char *uadename, + const char *configname) +{ + uade_arch_spawn(&state->ipc, &state->pid, uadename); + + if (uade_send_string(UADE_COMMAND_CONFIG, configname, &state->ipc)) { + fprintf(stderr, "Can not send config name: %s\n", + strerror(errno)); + kill(state->pid, SIGTERM); + state->pid = 0; + abort(); + } +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadecontrol.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadecontrol.h new file mode 100644 index 00000000..769521a9 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadecontrol.h @@ -0,0 +1,24 @@ +#ifndef _UADE_CONTROL_ +#define _UADE_CONTROL_ + +#include <sys/types.h> + +#include <uadestate.h> + +enum { + UADECORE_INIT_OK = 0, + UADECORE_INIT_ERROR, + UADECORE_CANT_PLAY +}; + +void uade_change_subsong(struct uade_state *state); +int uade_read_request(struct uade_ipc *ipc); +void uade_send_filter_command(struct uade_state *state); +void uade_set_subsong(int subsong, struct uade_ipc *ipc); +int uade_song_initialization(const char *scorename, const char *playername, + const char *modulename, + struct uade_state *state); +void uade_spawn(struct uade_state *state, const char *uadename, + const char *configname); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadestate.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadestate.h new file mode 100644 index 00000000..7014a30a --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadestate.h @@ -0,0 +1,25 @@ +#ifndef _UADE_STATE_H_ +#define _UADE_STATE_H_ + +#include <sys/types.h> +#include <unistd.h> + +#include <eagleplayer.h> +#include <effects.h> +#include <uadeipc.h> + +struct uade_state { + /* Per song members */ + struct uade_config config; + struct uade_song *song; + struct uade_effect effects; + struct eagleplayer *ep; + + /* Permanent members */ + int validconfig; + struct eagleplayerstore *playerstore; + struct uade_ipc ipc; + pid_t pid; +}; + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/unixwalkdir.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/unixwalkdir.c new file mode 100644 index 00000000..292976d7 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/unixwalkdir.c @@ -0,0 +1,69 @@ +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +#include <unixwalkdir.h> + +void *uade_walk_directories(const char *dirname, + void *(*fn) (const char *file, + enum uade_wtype wtype, void *opaque), + void *opaque) +{ + char *dename; + DIR *dir; + size_t namelen; + struct dirent *de; + void *ret = NULL; + struct stat st; + enum uade_wtype wtype; + + namelen = strlen(dirname) + 256 + 2; + if ((dename = malloc(namelen)) == NULL) + return NULL; + + if ((dir = opendir(dirname)) == NULL) + return NULL; + + while ((de = readdir(dir)) != NULL) { + + if (strcmp(de->d_name, ".") == 0 + || strcmp(de->d_name, "..") == 0) + continue; + + if (snprintf(dename, namelen, "%s/%s", dirname, de->d_name) >= + namelen) { + fprintf(stderr, "interesting: too long a filename\n"); + continue; + } + + if (lstat(dename, &st)) + continue; + + if (S_ISREG(st.st_mode)) + wtype = UADE_WALK_REGULAR_FILE; + else if (S_ISDIR(st.st_mode)) + wtype = UADE_WALK_DIRECTORY; + else if (S_ISLNK(st.st_mode)) + wtype = UADE_WALK_SYMLINK; + else + wtype = UADE_WALK_SPECIAL; + + if ((ret = fn(dename, wtype, opaque)) != NULL) + break; + + if (wtype == UADE_WALK_DIRECTORY) { + if ((ret = + uade_walk_directories(dename, fn, opaque)) != NULL) + break; + } + } + + closedir(dir); + free(dename); + + return ret; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/unixwalkdir.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/unixwalkdir.h new file mode 100644 index 00000000..69844f47 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/unixwalkdir.h @@ -0,0 +1,16 @@ +#ifndef _UADE_UNIXWALKDIR_H_ +#define _UADE_UNIXWALKDIR_H_ + +enum uade_wtype { + UADE_WALK_REGULAR_FILE = 1, + UADE_WALK_DIRECTORY, + UADE_WALK_SYMLINK, + UADE_WALK_SPECIAL +}; + +void *uade_walk_directories(const char *dirname, + void *(*fn) (const char *file, + enum uade_wtype wtype, void *opaque), + void *opaque); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/vplist.c b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/vplist.c new file mode 100644 index 00000000..5546f54d --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/vplist.c @@ -0,0 +1,115 @@ +#include <stdlib.h> +#include <string.h> + +#include "vplist.h" + + +#define VPLIST_BASIC_LENGTH 5 + + +static void shrink_vplist(struct vplist *v, size_t newsize) +{ + size_t ncopied = v->tail - v->head; + void **newl; + if (newsize >= v->allocated) { + fprintf(stderr, "vplist not shrinked.\n"); + return; + } + memmove(v->l, &v->l[v->head], ncopied * sizeof(v->l[0])); + v->head = 0; + v->tail = ncopied; + v->allocated = newsize; + if ((newl = realloc(v->l, v->allocated * sizeof(v->l[0]))) == NULL) { + fprintf(stderr, "Not enough memory for shrinking vplist.\n"); + exit(-1); + } + v->l = newl; +} + + +void vplist_grow(struct vplist *v) +{ + size_t newsize = v->allocated * 2; + void **newl; + if (newsize == 0) + newsize = VPLIST_BASIC_LENGTH; + newl = realloc(v->l, newsize * sizeof(v->l[0])); + if (newl == NULL) { + fprintf(stderr, "Not enough memory for growing vplist.\n"); + exit(-1); + } + v->l = newl; + v->allocated = newsize; +} + + +struct vplist *vplist_create(size_t initial_length) +{ + struct vplist *v; + if ((v = calloc(1, sizeof(*v))) == NULL) { + fprintf(stderr, "No memory for vplist.\n"); + exit(-1); + } + if (initial_length == 0) + initial_length = VPLIST_BASIC_LENGTH; + v->allocated = initial_length; + if ((v->l = malloc(v->allocated * sizeof(v->l[0]))) == NULL) { + fprintf(stderr, "Can not create a vplist.\n"); + exit(-1); + } + return v; +} + + +void vplist_flush(struct vplist *v) +{ + v->head = v->tail = 0; + if (v->allocated >= (2 * VPLIST_BASIC_LENGTH)) + shrink_vplist(v, VPLIST_BASIC_LENGTH); +} + + +void vplist_free(struct vplist *v) +{ + free(v->l); + memset(v, 0, sizeof(*v)); + free(v); +} + + +void *vplist_pop_head(struct vplist *v) +{ + void *item; + + if (v->head == v->tail) { + fprintf(stderr, "Error: can not pop head from an empty vplist.\n"); + exit(-1); + } + + item = v->l[v->head++]; + + /* If 3/4 of a list is unused, free half the list */ + if (v->allocated >= VPLIST_BASIC_LENGTH && v->head >= ((v->allocated / 4) * 3)) + shrink_vplist(v, v->allocated / 2); + + return item; +} + + +void *vplist_pop_tail(struct vplist *v) +{ + void *item; + + if (v->head == v->tail) { + fprintf(stderr, "Error: can not pop tail from an empty vplist.\n"); + exit(-1); + } + + item = v->l[v->tail--]; + + /* If 3/4 of a list is unused, free half the list */ + if (v->allocated >= VPLIST_BASIC_LENGTH && v->tail < (v->allocated / 4)) + shrink_vplist(v, v->allocated / 2); + + return item; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/vplist.h b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/vplist.h new file mode 100644 index 00000000..ef79f5bd --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/frontends/common/vplist.h @@ -0,0 +1,44 @@ +#ifndef _SHD_VPLIST_H_ +#define _SHD_VPLIST_H_ + +#include <stdio.h> +#include <assert.h> + + +struct vplist { + size_t head; + size_t tail; + size_t allocated; + void **l; +}; + + +struct vplist *vplist_create(size_t initial_length); +void vplist_flush(struct vplist *v); +void vplist_free(struct vplist *v); +void vplist_grow(struct vplist *v); +void *vplist_pop_head(struct vplist *v); +void *vplist_pop_tail(struct vplist *v); + + +static inline void vplist_append(struct vplist *v, void *item) +{ + if (v->tail == v->allocated) + vplist_grow(v); + v->l[v->tail++] = item; +} + + +static inline void *vplist_get(struct vplist *v, size_t i) +{ + assert(i < (v->tail - v->head)); + return v->l[v->head + i]; +} + + +static inline size_t vplist_len(struct vplist *v) +{ + return v->tail - v->head; +} + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/.gitignore b/plugins/ddb_input_uade2/uade-2.13/src/include/.gitignore new file mode 100644 index 00000000..c74efa80 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/.gitignore @@ -0,0 +1,4 @@ +compilersupport.h +ossupport.h +sysincludes.h +uadeconfig.h diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/amigafilter.h b/plugins/ddb_input_uade2/uade-2.13/src/include/amigafilter.h new file mode 100644 index 00000000..761fd33f --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/amigafilter.h @@ -0,0 +1,10 @@ +#ifndef _UADE_AMIGA_FILTER_H_ +#define _UADE_AMIGA_FILTER_H_ + +enum { + FILTER_MODEL_A500 = 1, + FILTER_MODEL_A1200, + FILTER_MODEL_UPPER_BOUND +}; + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/amigamsg.h b/plugins/ddb_input_uade2/uade-2.13/src/include/amigamsg.h new file mode 100644 index 00000000..457529c3 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/amigamsg.h @@ -0,0 +1,24 @@ +#ifndef _AMIGAMSG_H_ +#define _AMIGAMSG_H_ + +enum amigamsg { + AMIGAMSG_SETSUBSONG = 1, + AMIGAMSG_SONG_END, + AMIGAMSG_PLAYERNAME, + AMIGAMSG_MODULENAME, + AMIGAMSG_SUBSINFO, + AMIGAMSG_CHECKERROR, + AMIGAMSG_SCORECRASH, + AMIGAMSG_SCOREDEAD, + AMIGAMSG_GENERALMSG, + AMIGAMSG_NTSC, + AMIGAMSG_FORMATNAME, + AMIGAMSG_LOADFILE, + AMIGAMSG_READ, + AMIGAMSG_FILESIZE, + AMIGAMSG_TIME_CRITICAL, + AMIGAMSG_GET_INFO, + AMIGAMSG_START_OUTPUT +}; + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/audio.h b/plugins/ddb_input_uade2/uade-2.13/src/include/audio.h new file mode 100644 index 00000000..5716f5f9 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/audio.h @@ -0,0 +1,57 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Sound emulation stuff + * + * Copyright 1995, 1996, 1997 Bernd Schmidt + */ + +#ifndef _UADE_AUDIO_H_ +#define _UADE_AUDIO_H_ + +#include "sinctable.h" + +#define AUDIO_DEBUG 0 +/* Queue length 256 implies minimum emulated period of 8. This should be + * sufficient for all imaginable purposes. This must be power of two. */ +#define SINC_QUEUE_LENGTH 256 + +typedef struct { + int time, output; +} sinc_queue_t; + +extern struct audio_channel_data { + unsigned long adk_mask; + unsigned long evtime; + unsigned char dmaen, intreq2, data_written; + uaecptr lc, pt; + + int state, wper, wlen; + int current_sample; + int sample_accum, sample_accum_time; + int output_state; + sinc_queue_t sinc_queue[SINC_QUEUE_LENGTH]; + int sinc_queue_time; + int sinc_queue_head; + int vol; + uae_u16 dat, nextdat, per, len; + + /* Debug variables */ + uaecptr ptend, nextdatpt, nextdatptend, datpt, datptend; +} audio_channel[4]; + +extern void AUDxDAT (int nr, uae_u16 value); +extern void AUDxVOL (int nr, uae_u16 value); +extern void AUDxPER (int nr, uae_u16 value); +extern void AUDxLCH (int nr, uae_u16 value); +extern void AUDxLCL (int nr, uae_u16 value); +extern void AUDxLEN (int nr, uae_u16 value); + +void audio_reset (void); +void audio_set_filter(int filter_type, int filter_force); +void audio_set_rate (int rate); +void audio_set_resampler(char *name); +void audio_use_text_scope(void); +void update_audio (void); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/cia.h b/plugins/ddb_input_uade2/uade-2.13/src/include/cia.h new file mode 100644 index 00000000..558b11c0 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/cia.h @@ -0,0 +1,26 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * CIA chip support + * + * (c) 1995 Bernd Schmidt + */ + +extern void CIA_reset(void); +extern void CIA_vsync_handler(void); +extern void CIA_hsync_handler(void); +extern void CIA_handler(void); + +extern void diskindex_handler(void); + +extern void dumpcia(void); + +extern unsigned int ciaaicr,ciaaimask,ciabicr,ciabimask; +extern unsigned int ciaacra,ciaacrb,ciabcra,ciabcrb; +extern unsigned int ciaapra, ciabpra; +extern unsigned long ciaata,ciaatb,ciabta,ciabtb; +extern unsigned long ciaatod,ciabtod,ciaatol,ciabtol,ciaaalarm,ciabalarm; +extern int ciaatlatch,ciabtlatch; + +extern unsigned int gui_ledstate; +extern int gui_ledstate_forced; diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/commpipe.h b/plugins/ddb_input_uade2/uade-2.13/src/include/commpipe.h new file mode 100644 index 00000000..c7f4d814 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/commpipe.h @@ -0,0 +1,155 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Communication between threads + * + * Copyright 1997, 2001 Bernd Schmidt + */ + +typedef union { + int i; + uae_u32 u32; + void *pv; +} uae_pt; + +/* These currently require the maximum size to be known at initialization + * time, but it wouldn't be hard to use a "normal" pipe as an extension once the + * user-level one gets full. + * We queue up to chunks pieces of data before signalling the other thread to + * avoid overhead. */ + +typedef struct { + uae_sem_t lock; + uae_sem_t reader_wait; + uae_sem_t writer_wait; + uae_pt *data; + int size, chunks; + volatile int rdp, wrp; + volatile int writer_waiting; + volatile int reader_waiting; +} smp_comm_pipe; + +static inline void init_comm_pipe (smp_comm_pipe *p, int size, int chunks) +{ + p->data = (uae_pt *)malloc (size*sizeof (uae_pt)); + p->size = size; + p->chunks = chunks; + p->rdp = p->wrp = 0; + p->reader_waiting = 0; + p->writer_waiting = 0; + uae_sem_init (&p->lock, 0, 1); + uae_sem_init (&p->reader_wait, 0, 0); + uae_sem_init (&p->writer_wait, 0, 0); +} + +static inline void destroy_comm_pipe (smp_comm_pipe *p) +{ + uae_sem_destroy (&p->lock); + uae_sem_destroy (&p->reader_wait); + uae_sem_destroy (&p->writer_wait); +} + +static inline void maybe_wake_reader (smp_comm_pipe *p, int no_buffer) +{ + if (p->reader_waiting + && (no_buffer || ((p->wrp - p->rdp + p->size) % p->size) >= p->chunks)) + { + p->reader_waiting = 0; + uae_sem_post (&p->reader_wait); + } +} + +static inline void write_comm_pipe_pt (smp_comm_pipe *p, uae_pt data, int no_buffer) +{ + int nxwrp = (p->wrp + 1) % p->size; + + if (p->reader_waiting) { + /* No need to do all the locking */ + p->data[p->wrp] = data; + p->wrp = nxwrp; + maybe_wake_reader (p, no_buffer); + return; + } + + uae_sem_wait (&p->lock); + if (nxwrp == p->rdp) { + /* Pipe full! */ + p->writer_waiting = 1; + uae_sem_post (&p->lock); + /* Note that the reader could get in between here and do a + * sem_post on writer_wait before we wait on it. That's harmless. + * There's a similar case in read_comm_pipe_int_blocking. */ + uae_sem_wait (&p->writer_wait); + uae_sem_wait (&p->lock); + } + p->data[p->wrp] = data; + p->wrp = nxwrp; + maybe_wake_reader (p, no_buffer); + uae_sem_post (&p->lock); +} + +static inline uae_pt read_comm_pipe_pt_blocking (smp_comm_pipe *p) +{ + uae_pt data; + + uae_sem_wait (&p->lock); + if (p->rdp == p->wrp) { + p->reader_waiting = 1; + uae_sem_post (&p->lock); + uae_sem_wait (&p->reader_wait); + uae_sem_wait (&p->lock); + } + data = p->data[p->rdp]; + p->rdp = (p->rdp + 1) % p->size; + + /* We ignore chunks here. If this is a problem, make the size bigger in the init call. */ + if (p->writer_waiting) { + p->writer_waiting = 0; + uae_sem_post (&p->writer_wait); + } + uae_sem_post (&p->lock); + return data; +} + +static inline int comm_pipe_has_data (smp_comm_pipe *p) +{ + return p->rdp != p->wrp; +} + +static inline int read_comm_pipe_int_blocking (smp_comm_pipe *p) +{ + uae_pt foo = read_comm_pipe_pt_blocking (p); + return foo.i; +} +static inline uae_u32 read_comm_pipe_u32_blocking (smp_comm_pipe *p) +{ + uae_pt foo = read_comm_pipe_pt_blocking (p); + return foo.u32; +} + +static inline void *read_comm_pipe_pvoid_blocking (smp_comm_pipe *p) +{ + uae_pt foo = read_comm_pipe_pt_blocking (p); + return foo.pv; +} + +static inline void write_comm_pipe_int (smp_comm_pipe *p, int data, int no_buffer) +{ + uae_pt foo; + foo.i = data; + write_comm_pipe_pt (p, foo, no_buffer); +} + +static inline void write_comm_pipe_u32 (smp_comm_pipe *p, int data, int no_buffer) +{ + uae_pt foo; + foo.u32 = data; + write_comm_pipe_pt (p, foo, no_buffer); +} + +static inline void write_comm_pipe_pvoid (smp_comm_pipe *p, void *data, int no_buffer) +{ + uae_pt foo; + foo.pv = data; + write_comm_pipe_pt (p, foo, no_buffer); +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/compiler.h b/plugins/ddb_input_uade2/uade-2.13/src/include/compiler.h new file mode 100644 index 00000000..545dd6a4 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/compiler.h @@ -0,0 +1,111 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * m68k -> i386 compiler + * + * (c) 1995 Bernd Schmidt + */ + +typedef uaecptr (*code_execfunc)(void); + +struct code_page { + struct code_page *next; + uae_u32 allocmask; +}; + +struct hash_block { + struct hash_block *lru_next, *lru_prev; + struct hash_entry *he_first; + + struct code_page *cpage; + int alloclen; + uae_u32 page_allocmask; + char *compile_start; + + int nrefs; + + int translated:1; + int untranslatable:1; + int allocfailed:1; +}; + +struct hash_entry { + code_execfunc execute; /* For the sake of the stubs in X86.S */ + struct hash_entry *next,*prev; + struct hash_entry *next_same_block, *lru_next, *lru_prev; + struct hash_block *block; + + uaecptr addr; + uae_u32 matchword; + int ncalls:8; + int locked:1; + int cacheflush:1; +}; + +extern int nr_bbs_start; +extern uae_u8 nr_bbs_to_run; +extern code_execfunc exec_me; + +#ifdef USE_COMPILER +static inline void run_compiled_code(void) +{ + + /*if (regs.spcflags == SPCFLAG_EXEC && may_run_compiled) {*/ + while (regs.spcflags == SPCFLAG_EXEC) { + uaecptr newpc; + regs.spcflags = 0; + /* newpc = (*exec_me)();*/ + __asm__ __volatile__ ("pushl %%ebp; call *%1; popl %%ebp" : "=a" (newpc) : "r" (exec_me) : + "%eax", "%edx", "%ecx", "%ebx", + "%edi", "%esi", "memory", "cc"); + if (nr_bbs_to_run == 0) { + struct hash_entry *h = (struct hash_entry *)newpc; + regs.spcflags = SPCFLAG_EXEC; + exec_me = h->execute; + regs.pc = h->addr; + regs.pc_p = regs.pc_oldp = get_real_address(h->addr); + nr_bbs_to_run = nr_bbs_start; + } else + m68k_setpc_fast(newpc); + do_cycles(); + } +/*} else */ + regs.spcflags &= ~SPCFLAG_EXEC; +} + +extern void compiler_init(void); +extern void possible_loadseg(void); + +extern void m68k_do_rts(void); +extern void m68k_do_bsr(uaecptr, uae_s32); +extern void m68k_do_jsr(uaecptr, uaecptr); +extern void compiler_flush_jsr_stack(void); + +#else + +#define run_compiled_code() do { ; } while (0) +#define compiler_init() do { ; } while (0) +#define possible_loadseg() do { ; } while (0) +#define compiler_flush_jsr_stack() do { ; } while (0) + +static inline void m68k_do_rts(void) +{ + m68k_setpc(get_long(m68k_areg(regs, 7))); + m68k_areg(regs, 7) += 4; +} + +static inline void m68k_do_bsr(uaecptr oldpc, uae_s32 offset) +{ + m68k_areg(regs, 7) -= 4; + put_long(m68k_areg(regs, 7), oldpc); + m68k_incpc(offset); +} + +static inline void m68k_do_jsr(uaecptr oldpc, uaecptr dest) +{ + m68k_areg(regs, 7) -= 4; + put_long(m68k_areg(regs, 7), oldpc); + m68k_setpc(dest); +} + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/custom.h b/plugins/ddb_input_uade2/uade-2.13/src/include/custom.h new file mode 100644 index 00000000..15e3d689 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/custom.h @@ -0,0 +1,115 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * custom chip support + * + * (c) 1995 Bernd Schmidt + */ + +/* These are the masks that are ORed together in the chipset_mask option. + * If CSMASK_AGA is set, the ECS bits are guaranteed to be set as well. */ +#define CSMASK_ECS_AGNUS 1 +#define CSMASK_ECS_DENISE 2 +#define CSMASK_AGA 4 + +extern void custom_init (void); +extern void customreset (void); +extern int intlev (void); +extern void dumpcustom (void); + +extern void do_disk (void); + +extern void notice_new_xcolors (void); +extern void notice_screen_contents_lost (void); +extern void init_row_map (void); + +extern int picasso_requested_on; +extern int picasso_on; + +/* Set to 1 to leave out the current frame in average frame time calculation. + * Useful if the debugger was active. */ +extern int bogusframe; + +extern uae_u16 dmacon; +extern uae_u16 intena,intreq; + +extern int current_hpos (void); + +static inline int dmaen (unsigned int dmamask) +{ + return (dmamask & dmacon) && (dmacon & 0x200); +} + +#define SPCFLAG_STOP 2 +#define SPCFLAG_DISK 4 +#define SPCFLAG_INT 8 +#define SPCFLAG_BRK 16 +#define SPCFLAG_EXTRA_CYCLES 32 +#define SPCFLAG_TRACE 64 +#define SPCFLAG_DOTRACE 128 +#define SPCFLAG_DOINT 256 +#define SPCFLAG_BLTNASTY 512 +#define SPCFLAG_EXEC 1024 +#define SPCFLAG_MODE_CHANGE 8192 + +extern int dskdmaen; +extern uae_u16 adkcon; + +extern unsigned int joy0dir, joy1dir; +extern int joy0button, joy1button; + +extern void INTREQ (uae_u16); +extern uae_u16 INTREQR (void); + +/* maximums for statically allocated tables */ + +/* PAL/NTSC values */ + +/* The HRM says: The vertical blanking area (PAL) ranges from line 0 to line 29, + * and no data can be displayed there. Nevertheless, we lose some overscan data + * if minfirstline is set to 29. */ + +#define MAXHPOS_PAL 227 +#define MAXHPOS_NTSC 227 +#define MAXVPOS_PAL 312 +#define MAXVPOS_NTSC 262 +#define MINFIRSTLINE_PAL 21 +#define MINFIRSTLINE_NTSC 18 +#define VBLANK_ENDLINE_PAL 29 +#define VBLANK_ENDLINE_NTSC 24 +#define VBLANK_HZ_PAL 50 +#define VBLANK_HZ_NTSC 60 + +#define SOUNDTICKS_PAL 3546895 +#define SOUNDTICKS_NTSC 3579545 + +#define MAXHPOS (MAXHPOS_PAL) +#define MAXVPOS (MAXVPOS_PAL) +#define SOUNDTICKS (SOUNDTICKS_PAL) + +extern int maxhpos, maxvpos, minfirstline, vblank_endline, numscrlines, vblank_hz; +extern unsigned long syncbase; +#define NUMSCRLINES (maxvpos+1-minfirstline+1) + +#define DMA_AUD0 0x0001 +#define DMA_AUD1 0x0002 +#define DMA_AUD2 0x0004 +#define DMA_AUD3 0x0008 +#define DMA_DISK 0x0010 +#define DMA_SPRITE 0x0020 +#define DMA_BLITTER 0x0040 +#define DMA_COPPER 0x0080 +#define DMA_BITPLANE 0x0100 +#define DMA_BLITPRI 0x0400 + +extern unsigned long frametime, timeframes; + +/* 50 words give you 800 horizontal pixels. An A500 can't do that, so it ought + * to be enough. Don't forget to update the definition in genp2c.c as well. */ +#define MAX_WORDS_PER_LINE 50 + +extern uae_u32 hirestab_h[256][2]; +extern uae_u32 lorestab_h[256][4]; + +extern uae_u32 hirestab_l[256][1]; +extern uae_u32 lorestab_l[256][2]; diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/debug.h b/plugins/ddb_input_uade2/uade-2.13/src/include/debug.h new file mode 100644 index 00000000..8ca10ab5 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/debug.h @@ -0,0 +1,25 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Debugger + * + * (c) 1995 Bernd Schmidt + * + */ + +#define MAX_HIST 10000 + +extern int firsthist; +extern int lasthist; +extern int debugging; +extern int debug_interrupt_happened; + +#ifdef NEED_TO_DEBUG_BADLY +extern struct regstruct history[MAX_HIST]; +extern union flagu historyf[MAX_HIST]; +#else +extern uaecptr history[MAX_HIST]; +#endif + +extern void debug(void); +extern void activate_debugger(void); diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/events.h b/plugins/ddb_input_uade2/uade-2.13/src/include/events.h new file mode 100644 index 00000000..4b692650 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/events.h @@ -0,0 +1,83 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Events + * These are best for low-frequency events. Having too many of them, + * or using them for events that occur too frequently, can cause massive + * slowdown. + * + * Copyright 1995-1998 Bernd Schmidt + */ + +extern void reset_frame_rate_hack (void); +extern int rpt_available; + +extern unsigned long int cycles, nextevent, is_lastline; +extern unsigned long int sample_evtime; +typedef void (*evfunc)(void); + +struct ev +{ + int active; + unsigned long int evtime, oldcycles; + evfunc handler; +}; + +enum { + ev_hsync, ev_copper, ev_cia, + ev_blitter, ev_diskblk, ev_diskindex, + ev_max +}; + +extern struct ev eventtab[ev_max]; + +static void events_schedule (void) +{ + unsigned long int mintime = ~0L; + unsigned long int eventtime; + /* HSYNC */ + if(eventtab[ev_hsync].active) { + eventtime = eventtab[ev_hsync].evtime - cycles; + if (eventtime < mintime) mintime = eventtime; + } + /* AUDIO */ +#if 0 + if(eventtab[ev_audio].active) { + eventtime = eventtab[ev_audio].evtime - cycles; + if (eventtime < mintime) mintime = eventtime; + } +#endif + /* CIA */ + if(eventtab[ev_cia].active) { + eventtime = eventtab[ev_cia].evtime - cycles; + if (eventtime < mintime) mintime = eventtime; + } + nextevent = cycles + mintime; +} + +static void do_cycles_slow (unsigned long cycles_to_add) { + if ((nextevent - cycles) <= cycles_to_add) { + for (; cycles_to_add != 0; cycles_to_add--) { + if (++cycles == nextevent) { + /* HSYNC */ + if(eventtab[ev_hsync].active && eventtab[ev_hsync].evtime == cycles) { + (*eventtab[ev_hsync].handler)(); + } + /* AUDIO */ +#if 0 + if(eventtab[ev_audio].active && eventtab[ev_audio].evtime == cycles) { + (*eventtab[ev_audio].handler)(); + } +#endif + /* CIA */ + if(eventtab[ev_cia].active && eventtab[ev_cia].evtime == cycles) { + (*eventtab[ev_cia].handler)(); + } + events_schedule(); + } + } + } + cycles += cycles_to_add; +} + +#define do_cycles do_cycles_slow diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/execlib.h b/plugins/ddb_input_uade2/uade-2.13/src/include/execlib.h new file mode 100644 index 00000000..c0777221 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/execlib.h @@ -0,0 +1,40 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Miscellaneous bits for exec emulation + * + * Copyright 1996 Bernd Schmidt + */ + +#define CMD_INVALID 0 +#define CMD_RESET 1 +#define CMD_READ 2 +#define CMD_WRITE 3 +#define CMD_UPDATE 4 +#define CMD_CLEAR 5 +#define CMD_STOP 6 +#define CMD_START 7 +#define CMD_FLUSH 8 +#define CMD_NONSTD 9 + +#define NT_TASK 1 +#define NT_DEVICE 3 +#define NT_MSGPORT 4 +#define NT_MESSAGE 5 +#define NT_FREEMSG 6 +#define NT_REPLYMSG 7 +#define NT_RESOURCE 8 +#define NT_LIBRARY 9 +#define NT_SIGNALSEM 15 + +#ifndef MEMF_PUBLIC /* protection for AmigaDOS */ +#define MEMF_PUBLIC 1 +#define MEMF_CHIP 2 +#define MEMF_FAST 4 +#define MEMF_LOCAL 256 +#define MEMF_24BITDMA 512 +#define MEMF_CLEAR (1<<16) +#define MEMF_LARGEST (1<<17) +#define MEMF_REVERSE (1<<18) +#define MEMF_TOTAL (1<<19) +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/gensound.h b/plugins/ddb_input_uade2/uade-2.13/src/include/gensound.h new file mode 100644 index 00000000..63daeb04 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/gensound.h @@ -0,0 +1,19 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Prototypes for general sound related functions + * This use to be called sound.h, but that causes confusion + * + * Copyright 1997 Bernd Schmidt + */ + +extern int sound_available; + +/* Determine if we can produce any sound at all. This can be only a guess; + * if unsure, say yes. Any call to init_sound may change the value. */ +extern int setup_sound (void); + +extern void set_sound_freq (int x); +extern void init_sound (void); +extern void flush_sound (void); +extern void close_sound (void); diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/memory.h b/plugins/ddb_input_uade2/uade-2.13/src/include/memory.h new file mode 100644 index 00000000..96a967b5 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/memory.h @@ -0,0 +1,181 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * memory management + * + * Copyright 1995 Bernd Schmidt + */ + +/* Enabling this adds one additional native memory reference per 68k memory + * access, but saves one shift (on the x86). Enabling this is probably + * better for the cache. My favourite benchmark (PP2) doesn't show a + * difference, so I leave this enabled. */ + +#if 1 || defined SAVE_MEMORY +#define SAVE_MEMORY_BANKS +#endif + +#ifndef REGPARAM +#define REGPARAM +#endif + +typedef uae_u32 (*mem_get_func)(uaecptr) REGPARAM; +typedef void (*mem_put_func)(uaecptr, uae_u32) REGPARAM; +typedef uae_u8 *(*xlate_func)(uaecptr) REGPARAM; +typedef int (*check_func)(uaecptr, uae_u32) REGPARAM; + +extern char *address_space, *good_address_map; +extern uae_u8 *chipmemory; + +extern uae_u32 allocated_chipmem; +extern uae_u32 allocated_fastmem; +extern uae_u32 allocated_bogomem; +extern uae_u32 allocated_gfxmem; +extern uae_u32 allocated_z3fastmem; +extern uae_u32 allocated_a3000mem; + +#undef DIRECT_MEMFUNCS_SUCCESSFUL +#include "machdep/maccess.h" + +#ifndef CAN_MAP_MEMORY +#undef USE_COMPILER +#endif + +#if defined(USE_COMPILER) && !defined(USE_MAPPED_MEMORY) +#define USE_MAPPED_MEMORY +#endif + +#define kickmem_size 0x080000 + +#define chipmem_start 0x00000000 +#define bogomem_start 0x00C00000 +#define a3000mem_start 0x07000000 +#define kickmem_start 0x00F80000 + +extern int ersatzkickfile; + +typedef struct { + /* These ones should be self-explanatory... */ + mem_get_func lget, wget, bget; + mem_put_func lput, wput, bput; + /* Use xlateaddr to translate an Amiga address to a uae_u8 * that can + * be used to address memory without calling the wget/wput functions. + * This doesn't work for all memory banks, so this function may call + * abort(). */ + xlate_func xlateaddr; + /* To prevent calls to abort(), use check before calling xlateaddr. + * It checks not only that the memory bank can do xlateaddr, but also + * that the pointer points to an area of at least the specified size. + * This is used for example to translate bitplane pointers in custom.c */ + check_func check; +} addrbank; + +extern uae_u8 filesysory[65536]; + +extern addrbank chipmem_bank; +extern addrbank kickmem_bank; +extern addrbank custom_bank; +extern addrbank clock_bank; +extern addrbank cia_bank; +extern addrbank rtarea_bank; +extern addrbank expamem_bank; +extern addrbank fastmem_bank; +extern addrbank gfxmem_bank; + +extern void rtarea_init (void); +extern void rtarea_setup (void); +extern void expamem_init (void); +extern void expamem_reset (void); + +extern uae_u32 gfxmem_start; +extern uae_u8 *gfxmemory; +extern uae_u32 gfxmem_mask; +extern int address_space_24; + +/* Default memory access functions */ + +extern int default_check(uaecptr addr, uae_u32 size) REGPARAM; +extern uae_u8 *default_xlate(uaecptr addr) REGPARAM; + +#define bankindex(addr) (((uaecptr)(addr)) >> 16) + +#ifdef SAVE_MEMORY_BANKS +extern addrbank *mem_banks[65536]; +#define get_mem_bank(addr) (*mem_banks[bankindex(addr)]) +#define put_mem_bank(addr, b) (mem_banks[bankindex(addr)] = (b)) +#else +extern addrbank mem_banks[65536]; +#define get_mem_bank(addr) (mem_banks[bankindex(addr)]) +#define put_mem_bank(addr, b) (mem_banks[bankindex(addr)] = *(b)) +#endif + +extern void memory_init(void); +extern void map_banks(addrbank *bank, int first, int count); + +#ifndef NO_INLINE_MEMORY_ACCESS + +#define longget(addr) (call_mem_get_func(get_mem_bank(addr).lget, addr)) +#define wordget(addr) (call_mem_get_func(get_mem_bank(addr).wget, addr)) +#define byteget(addr) (call_mem_get_func(get_mem_bank(addr).bget, addr)) +#define longput(addr,l) (call_mem_put_func(get_mem_bank(addr).lput, addr, l)) +#define wordput(addr,w) (call_mem_put_func(get_mem_bank(addr).wput, addr, w)) +#define byteput(addr,b) (call_mem_put_func(get_mem_bank(addr).bput, addr, b)) + +#else + +extern uae_u32 alongget(uaecptr addr); +extern uae_u32 awordget(uaecptr addr); +extern uae_u32 longget(uaecptr addr); +extern uae_u32 wordget(uaecptr addr); +extern uae_u32 byteget(uaecptr addr); +extern void longput(uaecptr addr, uae_u32 l); +extern void wordput(uaecptr addr, uae_u32 w); +extern void byteput(uaecptr addr, uae_u32 b); + +#endif + +#ifndef MD_HAVE_MEM_1_FUNCS + +#define longget_1 longget +#define wordget_1 wordget +#define byteget_1 byteget +#define longput_1 longput +#define wordput_1 wordput +#define byteput_1 byteput + +#endif + +static inline uae_u32 get_long(uaecptr addr) +{ + return longget_1(addr); +} +static inline uae_u32 get_word(uaecptr addr) +{ + return wordget_1(addr); +} +static inline uae_u32 get_byte(uaecptr addr) +{ + return byteget_1(addr); +} +static inline void put_long(uaecptr addr, uae_u32 l) +{ + longput_1(addr, l); +} +static inline void put_word(uaecptr addr, uae_u32 w) +{ + wordput_1(addr, w); +} +static inline void put_byte(uaecptr addr, uae_u32 b) +{ + byteput_1(addr, b); +} + +static inline uae_u8 *get_real_address(uaecptr addr) +{ + return get_mem_bank(addr).xlateaddr(addr); +} + +static inline int valid_address(uaecptr addr, uae_u32 size) +{ + return get_mem_bank(addr).check(addr, size); +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/newcpu.h b/plugins/ddb_input_uade2/uade-2.13/src/include/newcpu.h new file mode 100644 index 00000000..84732f10 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/newcpu.h @@ -0,0 +1,275 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * MC68000 emulation + * + * Copyright 1995 Bernd Schmidt + */ + +#include <machdep/m68k.h> + +void m68k_run_1 (void); + +#ifndef SET_CFLG + +#define SET_CFLG(x) (CFLG = (x)) +#define SET_NFLG(x) (NFLG = (x)) +#define SET_VFLG(x) (VFLG = (x)) +#define SET_ZFLG(x) (ZFLG = (x)) +#define SET_XFLG(x) (XFLG = (x)) + +#define GET_CFLG CFLG +#define GET_NFLG NFLG +#define GET_VFLG VFLG +#define GET_ZFLG ZFLG +#define GET_XFLG XFLG + +#define CLEAR_CZNV do { \ + SET_CFLG (0); \ + SET_ZFLG (0); \ + SET_NFLG (0); \ + SET_VFLG (0); \ +while (0) + +#define COPY_CARRY (SET_XFLG (GET_CFLG)) +#endif + +extern int areg_byteinc[]; +extern int imm8_table[]; + +extern int movem_index1[256]; +extern int movem_index2[256]; +extern int movem_next[256]; + +extern int fpp_movem_index1[256]; +extern int fpp_movem_index2[256]; +extern int fpp_movem_next[256]; + +extern int broken_in; + +typedef unsigned long cpuop_func (uae_u32) REGPARAM; + +struct cputbl { + cpuop_func *handler; + int specific; + uae_u16 opcode; +}; + +extern unsigned long op_illg (uae_u32) REGPARAM; + +typedef char flagtype; + +extern struct regstruct +{ + uae_u32 regs[16]; + uaecptr usp,isp,msp; + uae_u16 sr; + flagtype t1; + flagtype t0; + flagtype s; + flagtype m; + flagtype x; + flagtype stopped; + int intmask; + + uae_u32 pc; + uae_u8 *pc_p; + uae_u8 *pc_oldp; + + uae_u32 vbr,sfc,dfc; + + double fp[8]; + uae_u32 fpcr,fpsr,fpiar; + + uae_u32 spcflags; + uae_u32 kick_mask; + + /* Fellow sources say this is 4 longwords. That's impossible. It needs + * to be at least a longword. The HRM has some cryptic comment about two + * instructions being on the same longword boundary. + * The way this is implemented now seems like a good compromise. + */ + uae_u32 prefetch; +} regs, lastint_regs; + +#define m68k_dreg(r,num) ((r).regs[(num)]) +#define m68k_areg(r,num) (((r).regs + 8)[(num)]) + +#define get_ibyte(o) do_get_mem_byte((uae_u8 *)(regs.pc_p + (o) + 1)) +#define get_iword(o) do_get_mem_word((uae_u16 *)(regs.pc_p + (o))) +#define get_ilong(o) do_get_mem_long((uae_u32 *)(regs.pc_p + (o))) + +#ifdef HAVE_GET_WORD_UNSWAPPED +#define GET_OPCODE (do_get_mem_word_unswapped (regs.pc_p)) +#else +#define GET_OPCODE (get_iword (0)) +#endif + +static inline uae_u32 get_ibyte_prefetch (uae_s32 o) +{ + if (o > 3 || o < 0) + return do_get_mem_byte((uae_u8 *)(regs.pc_p + o + 1)); + + return do_get_mem_byte((uae_u8 *)(((uae_u8 *)®s.prefetch) + o + 1)); +} +static inline uae_u32 get_iword_prefetch (uae_s32 o) +{ + if (o > 3 || o < 0) + return do_get_mem_word((uae_u16 *)(regs.pc_p + o)); + + return do_get_mem_word((uae_u16 *)(((uae_u8 *)®s.prefetch) + o)); +} +static inline uae_u32 get_ilong_prefetch (uae_s32 o) +{ + union { + uae_u32 *u32; + uae_u16 *u16; + } prefetch_u; + + if (o > 3 || o < 0) + return do_get_mem_long((uae_u32 *)(regs.pc_p + o)); + if (o == 0) + return do_get_mem_long(®s.prefetch); + + prefetch_u.u32 = ®s.prefetch; + + return (do_get_mem_word (prefetch_u.u16 + 1) << 16) | do_get_mem_word ((uae_u16 *)(regs.pc_p + 4)); +} + +#define m68k_incpc(o) (regs.pc_p += (o)) + +static inline void fill_prefetch_0 (void) +{ + uae_u32 r; +#ifdef UNALIGNED_PROFITABLE + r = *(uae_u32 *)regs.pc_p; + regs.prefetch = r; +#else + r = do_get_mem_long ((uae_u32 *)regs.pc_p); + do_put_mem_long (®s.prefetch, r); +#endif +} + +#if 0 +static inline void fill_prefetch_2 (void) +{ + uae_u32 r = do_get_mem_long (®s.prefetch) << 16; + uae_u32 r2 = do_get_mem_word (((uae_u16 *)regs.pc_p) + 1); + r |= r2; + do_put_mem_long (®s.prefetch, r); +} +#else +#define fill_prefetch_2 fill_prefetch_0 +#endif + +/* These are only used by the 68020/68881 code, and therefore don't + * need to handle prefetch. */ +static inline uae_u32 next_ibyte (void) +{ + uae_u32 r = get_ibyte (0); + m68k_incpc (2); + return r; +} + +static inline uae_u32 next_iword (void) +{ + uae_u32 r = get_iword (0); + m68k_incpc (2); + return r; +} + +static inline uae_u32 next_ilong (void) +{ + uae_u32 r = get_ilong (0); + m68k_incpc (4); + return r; +} + +#if !defined USE_COMPILER +static inline void m68k_setpc (uaecptr newpc) +{ + regs.pc_p = regs.pc_oldp = get_real_address(newpc); + regs.pc = newpc; +} +#else +extern void m68k_setpc (uaecptr newpc); +#endif + +static inline uaecptr m68k_getpc (void) +{ + return regs.pc + ((char *)regs.pc_p - (char *)regs.pc_oldp); +} + +static inline uaecptr m68k_getpc_p (uae_u8 *p) +{ + return regs.pc + ((char *)p - (char *)regs.pc_oldp); +} + +#ifdef USE_COMPILER +extern void m68k_setpc_fast (uaecptr newpc); +extern void m68k_setpc_bcc (uaecptr newpc); +extern void m68k_setpc_rte (uaecptr newpc); +#else +#define m68k_setpc_fast m68k_setpc +#define m68k_setpc_bcc m68k_setpc +#define m68k_setpc_rte m68k_setpc +#endif + +static inline void m68k_setstopped (int stop) +{ + regs.stopped = stop; + if (stop) + regs.spcflags |= SPCFLAG_STOP; +} + +extern uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp); +extern uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp); + +extern uae_s32 ShowEA (int reg, amodes mode, wordsizes size, char *buf); + +extern void MakeSR (void); +extern void MakeFromSR (void); +extern void Exception (int, uaecptr); +extern void dump_counts (void); +extern void m68k_move2c (int, uae_u32 *); +extern void m68k_movec2 (int, uae_u32 *); +extern void m68k_divl (uae_u32, uae_u32, uae_u16, uaecptr); +extern void m68k_mull (uae_u32, uae_u32, uae_u16); +extern void init_m68k (void); +extern void m68k_go (void); +extern void m68k_dumpstate (uaecptr *); +extern void m68k_disasm (uaecptr, uaecptr *, int); +extern void m68k_reset (void); + +extern void mmu_op (uae_u32, uae_u16); + +extern void fpp_opp (uae_u32, uae_u16); +extern void fdbcc_opp (uae_u32, uae_u16); +extern void fscc_opp (uae_u32, uae_u16); +extern void ftrapcc_opp (uae_u32,uaecptr); +extern void fbcc_opp (uae_u32, uaecptr, uae_u32); +extern void fsave_opp (uae_u32); +extern void frestore_opp (uae_u32); + +/* Opcode of faulting instruction */ +extern uae_u16 last_op_for_exception_3; +/* PC at fault time */ +extern uaecptr last_addr_for_exception_3; +/* Address that generated the exception */ +extern uaecptr last_fault_for_exception_3; + +#define CPU_OP_NAME(a) op ## a + +/* 68020 + 68881 */ +extern struct cputbl op_smalltbl_0[]; +/* 68020 */ +extern struct cputbl op_smalltbl_1[]; +/* 68010 */ +extern struct cputbl op_smalltbl_2[]; +/* 68000 */ +extern struct cputbl op_smalltbl_3[]; +/* 68000 slow but compatible. */ +extern struct cputbl op_smalltbl_4[]; + +extern cpuop_func *cpufunctbl[65536]; + diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/options.h b/plugins/ddb_input_uade2/uade-2.13/src/include/options.h new file mode 100644 index 00000000..2ec4befc --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/options.h @@ -0,0 +1,262 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Stuff + * + * Copyright 1995, 1996 Ed Hanway + * Copyright 1995-98 Bernd Schmidt + */ + +#define UAEMAJOR 0 +#define UAEMINOR 8 +#define UAESUBREV 9 + +typedef enum { KBD_LANG_US, KBD_LANG_DE, KBD_LANG_SE, KBD_LANG_FR, KBD_LANG_IT, KBD_LANG_ES } KbdLang; + +extern long int version; + +struct uaedev_mount_info; + +struct strlist { + struct strlist *next; + char *str; +}; + +struct uae_prefs { + struct strlist *unknown_lines; + + char description[256]; + + int illegal_mem; + int no_xhair; + int use_serial; + int serial_demand; + int parallel_demand; + int automount_uaedev; + int use_gfxlib; + int socket_emu; + + int start_debugger; + int start_gui; + + int jport0; + int jport1; + KbdLang keyboard_lang; + int allow_save; + int emul_accuracy; + int test_drawing_speed; + + int produce_sound; + int stereo; + int sound_bits; + int sound_freq; + int sound_minbsiz; + int sound_maxbsiz; + int sound_pri_time; + int sound_pri_cutoff; + int sound_interpol; + + int gfx_framerate; + int gfx_width; + int gfx_height; + int gfx_lores; + int gfx_linedbl; + int gfx_correct_aspect; + int gfx_afullscreen; + int gfx_pfullscreen; + int gfx_xcenter; + int gfx_ycenter; + int color_mode; + + int blits_32bit_enabled; + int immediate_blits; + unsigned int chipset_mask; + int ntscmode; + + char df[4][256]; + char romfile[256]; + char keyfile[256]; + char prtname[256]; + + char path_floppy[256]; + char path_hardfile[256]; + char path_rom[256]; + + int m68k_speed; + int cpu_level; + int cpu_compatible; + int address_space_24; + + uae_u32 z3fastmem_size; + uae_u32 fastmem_size; + uae_u32 chipmem_size; + uae_u32 bogomem_size; + uae_u32 a3000mem_size; + uae_u32 gfxmem_size; + + struct uaedev_mount_info *mountinfo; + + /* Target specific options */ + int x11_use_low_bandwidth; + int x11_use_mitshm; + int x11_use_dgamode; + int x11_hide_cursor; + int svga_no_linear; + int win32_middle_mouse; + int win32_sound_style; + int win32_sound_tweak; + int win32_logfile; + int win32_iconified_nospeed; + int win32_iconified_nosound; +}; + +extern void save_options (FILE *, struct uae_prefs *); + +extern void default_prefs (struct uae_prefs *); +extern void discard_prefs (struct uae_prefs *); + +extern int cfgfile_yesno (char *option, char *value, char *name, int *location); +extern int cfgfile_intval (char *option, char *value, char *name, int *location, int scale); +extern int cfgfile_strval (char *option, char *value, char *name, int *location, const char *table[], int more); +extern int cfgfile_string (char *option, char *value, char *name, char *location, int maxsz); +extern char *cfgfile_subst_path (const char *path, const char *subst, const char *file); + +extern int target_parse_option (struct uae_prefs *, char *option, char *value); +extern void target_save_options (FILE *, struct uae_prefs *); + +extern int cfgfile_load (struct uae_prefs *, const char *filename); +extern int cfgfile_save (struct uae_prefs *, const char *filename); +extern void cfgfile_parse_line (struct uae_prefs *p, char *); +extern int cfgfile_parse_option (struct uae_prefs *p, char *option, char *value); +extern int cfgfile_get_description (const char *filename, char *description); +extern void cfgfile_show_usage (void); + +extern void fixup_prefs_dimensions (struct uae_prefs *prefs); + +extern void check_prefs_changed_custom (void); +extern void check_prefs_changed_cpu (void); +extern int check_prefs_changed_gfx (void); + +#define JSEM_DECODEVAL(n,v) ((n) == 0 ? (v)->jport0 : (v)->jport1) +/* Determine how port n is configured */ +#define JSEM_ISJOY0(n,v) (JSEM_DECODEVAL(n,v) == 0) +#define JSEM_ISJOY1(n,v) (JSEM_DECODEVAL(n,v) == 1) +#define JSEM_ISMOUSE(n,v) (JSEM_DECODEVAL(n,v) == 2) +#define JSEM_ISNUMPAD(n,v) (JSEM_DECODEVAL(n,v) == 3) +#define JSEM_ISCURSOR(n,v) (JSEM_DECODEVAL(n,v) == 4) +#define JSEM_ISSOMEWHEREELSE(n,v) (JSEM_DECODEVAL(n,v) == 5) +extern const char *gameport_state (int n); + +extern struct uae_prefs currprefs, changed_prefs; + +#if __GNUC__ - 1 > 1 || __GNUC_MINOR__ - 1 > 6 +extern void write_log (const char *, ...) __attribute__ ((format (printf, 1, 2))); +#else +extern void write_log (const char *, ...); +#endif + +extern void machdep_init (void); + +/* AIX doesn't think it is Unix. Neither do I. */ +#if defined(_ALL_SOURCE) || defined(_AIX) +#undef __unix +#define __unix +#endif + +extern char romfile[], keyfile[], prtname[], sername[]; + +extern int cloanto_rom; + +#define MAX_COLOR_MODES 5 + +extern int fast_memcmp(const void *foo, const void *bar, int len); +extern int memcmpy(void *foo, const void *bar, int len); + +/* + * You can specify numbers from 0 to 5 here. It is possible that higher + * numbers will make the CPU emulation slightly faster, but if the setting + * is too high, you will run out of memory while compiling. + * Best to leave this as it is. + */ +#define CPU_EMU_SIZE 0 + +/* #define NEED_TO_DEBUG_BADLY */ + +#if !defined(USER_PROGRAMS_BEHAVE) +#define USER_PROGRAMS_BEHAVE 0 +#endif + +/* Some memsets which know that they can safely overwrite some more memory + * at both ends and use that knowledge to align the pointers. */ + +#define QUADRUPLIFY(c) (((c) | ((c) << 8)) | (((c) | ((c) << 8)) << 16)) + +/* When you call this routine, bear in mind that it rounds the bounds and + * may need some padding for the array. */ + +#define fuzzy_memset(p, c, o, l) fuzzy_memset_1 ((p), QUADRUPLIFY (c), (o) & ~3, ((l) + 4) >> 2) +static inline void fuzzy_memset_1 (void *p, uae_u32 c, int offset, int len) +{ + uae_u32 *p2 = (uae_u32 *)((char *)p + offset); + int a = len & 7; + len >>= 3; + switch (a) { + case 7: p2--; goto l1; + case 6: p2-=2; goto l2; + case 5: p2-=3; goto l3; + case 4: p2-=4; goto l4; + case 3: p2-=5; goto l5; + case 2: p2-=6; goto l6; + case 1: p2-=7; goto l7; + case 0: if (!--len) return; break; + } + + for (;;) { + p2[0] = c; + l1: + p2[1] = c; + l2: + p2[2] = c; + l3: + p2[3] = c; + l4: + p2[4] = c; + l5: + p2[5] = c; + l6: + p2[6] = c; + l7: + p2[7] = c; + + if (!len) + break; + len--; + p2 += 8; + } +} + +/* This one knows it will never be asked to clear more than 32 bytes. Make sure you call this with a + constant for the length. */ +#define fuzzy_memset_le32(p, c, o, l) fuzzy_memset_le32_1 ((p), QUADRUPLIFY (c), (o) & ~3, ((l) + 7) >> 2) +static inline void fuzzy_memset_le32_1 (void *p, uae_u32 c, int offset, int len) +{ + uae_u32 *p2 = (uae_u32 *)((char *)p + offset); + + switch (len) { + case 9: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; p2[7] = c; p2[8] = c; break; + case 8: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; p2[7] = c; break; + case 7: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; break; + case 6: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; break; + case 5: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; break; + case 4: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; break; + case 3: p2[0] = c; p2[1] = c; p2[2] = c; break; + case 2: p2[0] = c; p2[1] = c; break; + case 1: p2[0] = c; break; + case 0: break; + default: printf("Hit the programmer.\n"); break; + } +} + +#if defined(AMIGA) && defined(__GNUC__) +/* #include "od-amiga/amiga-kludges.h" */ +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/osemu.h b/plugins/ddb_input_uade2/uade-2.13/src/include/osemu.h new file mode 100644 index 00000000..817c5c9b --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/osemu.h @@ -0,0 +1,19 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * OS emulation prototypes + * + * Copyright 1996 Bernd Schmidt + */ + +static inline char *raddr(uaecptr p) +{ + return p == 0 ? NULL : (char *)get_real_address(p); +} + +extern void gfxlib_install(void); + +/* graphics.library */ + +extern int GFX_WritePixel(uaecptr rp, int x, int y); + diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/readcpu.h b/plugins/ddb_input_uade2/uade-2.13/src/include/readcpu.h new file mode 100644 index 00000000..62a81c6a --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/readcpu.h @@ -0,0 +1,99 @@ +ENUMDECL { + Dreg, Areg, Aind, Aipi, Apdi, Ad16, Ad8r, + absw, absl, PC16, PC8r, imm, imm0, imm1, imm2, immi, am_unknown, am_illg +} ENUMNAME (amodes); + +ENUMDECL { + i_ILLG, + + i_OR, i_AND, i_EOR, i_ORSR, i_ANDSR, i_EORSR, + i_SUB, i_SUBA, i_SUBX, i_SBCD, + i_ADD, i_ADDA, i_ADDX, i_ABCD, + i_NEG, i_NEGX, i_NBCD, i_CLR, i_NOT, i_TST, + i_BTST, i_BCHG, i_BCLR, i_BSET, + i_CMP, i_CMPM, i_CMPA, + i_MVPRM, i_MVPMR, i_MOVE, i_MOVEA, i_MVSR2, i_MV2SR, + i_SWAP, i_EXG, i_EXT, i_MVMEL, i_MVMLE, + i_TRAP, i_MVR2USP, i_MVUSP2R, i_RESET, i_NOP, i_STOP, i_RTE, i_RTD, + i_LINK, i_UNLK, + i_RTS, i_TRAPV, i_RTR, + i_JSR, i_JMP, i_BSR, i_Bcc, + i_LEA, i_PEA, i_DBcc, i_Scc, + i_DIVU, i_DIVS, i_MULU, i_MULS, + i_ASR, i_ASL, i_LSR, i_LSL, i_ROL, i_ROR, i_ROXL, i_ROXR, + i_ASRW, i_ASLW, i_LSRW, i_LSLW, i_ROLW, i_RORW, i_ROXLW, i_ROXRW, + i_CHK,i_CHK2, + i_MOVEC2, i_MOVE2C, i_CAS, i_CAS2, i_DIVL, i_MULL, + i_BFTST,i_BFEXTU,i_BFCHG,i_BFEXTS,i_BFCLR,i_BFFFO,i_BFSET,i_BFINS, + i_PACK, i_UNPK, i_TAS, i_BKPT, i_CALLM, i_RTM, i_TRAPcc, i_MOVES, + i_FPP, i_FDBcc, i_FScc, i_FTRAPcc, i_FBcc, i_FSAVE, i_FRESTORE, + i_MMUOP +} ENUMNAME (instrmnem); + +extern struct mnemolookup { + instrmnem mnemo; + const char *name; +} lookuptab[]; + +ENUMDECL { + sz_byte, sz_word, sz_long +} ENUMNAME (wordsizes); + +ENUMDECL { + fa_set, fa_unset, fa_zero, fa_one, fa_dontcare, fa_unknown, fa_isjmp +} ENUMNAME (flagaffect); + +ENUMDECL { + fu_used, fu_unused, fu_maybecc, fu_unknown, fu_isjmp +} ENUMNAME (flaguse); + +ENUMDECL { + bit0, bit1, bitc, bitC, bitf, biti, bitI, bitj, bitJ, bitk, bitK, + bits, bitS, bitd, bitD, bitr, bitR, bitz, lastbit +} ENUMNAME (bitvals); + +struct instr_def { + unsigned int bits; + int n_variable; + char bitpos[16]; + unsigned int mask; + int cpulevel; + int plevel; + struct { + unsigned int flaguse:3; + unsigned int flagset:3; + } flaginfo[5]; + unsigned char sduse; + const char *opcstr; +}; + +extern struct instr_def defs68k[]; +extern int n_defs68k; + +extern struct instr { + long int handler; + unsigned char dreg; + unsigned char sreg; + signed char dpos; + signed char spos; + unsigned char sduse; + int flagdead:8, flaglive:8; + unsigned int mnemo:8; + unsigned int cc:4; + unsigned int plev:2; + unsigned int size:2; + unsigned int smode:5; + unsigned int stype:3; + unsigned int dmode:5; + unsigned int suse:1; + unsigned int duse:1; + unsigned int unused1:1; + unsigned int clev:3; + unsigned int unused2:5; +} *table68k; + +extern void read_table68k (void); +extern void do_merges (void); +extern int get_no_mismatches (void); +extern int nr_cpuop_funcs; + diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/sinctable.h b/plugins/ddb_input_uade2/uade-2.13/src/include/sinctable.h new file mode 100644 index 00000000..56fb62d7 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/sinctable.h @@ -0,0 +1,7 @@ +#ifndef _SINCTABLE_H_ +#define _SINCTABLE_H_ + +#define SINC_QUEUE_MAX_AGE 2048 +extern const int winsinc_integral[5][SINC_QUEUE_MAX_AGE]; + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/sysdeps.h b/plugins/ddb_input_uade2/uade-2.13/src/include/sysdeps.h new file mode 100644 index 00000000..5d407b2d --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/sysdeps.h @@ -0,0 +1,347 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Try to include the right system headers and get other system-specific + * stuff right & other collected kludges. + * + * If you think about modifying this, think twice. Some systems rely on + * the exact order of the #include statements. That's also the reason + * why everything gets included unconditionally regardless of whether + * it's actually needed by the .c file. + * + * Copyright 1996, 1997 Bernd Schmidt + */ + +/* MODIF PMO */ +#ifndef _H_SYSDEPS +#define _H_SYSDEPS +/* ENDOF MODIF PMO */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <assert.h> +#include <limits.h> + +#ifndef __STDC__ +#error "Your compiler is not ANSI. Get a real one." +#endif + +#include <stdarg.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_VALUES_H +#include <values.h> +#endif + +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#if HAVE_DIRENT_H +# include <dirent.h> +#else +# define dirent direct +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + +#ifdef HAVE_SYS_UTIME_H +# include <sys/utime.h> +#endif + +#include <errno.h> +#include <assert.h> + +#if EEXIST == ENOTEMPTY +#define BROKEN_OS_PROBABLY_AIX +#endif + +#ifdef __NeXT__ +#define S_IRUSR S_IREAD +#define S_IWUSR S_IWRITE +#define S_IXUSR S_IEXEC +#define S_ISDIR(val) (S_IFDIR & val) +struct utimbuf +{ + time_t actime; + time_t modtime; +}; +#endif + +#define REGPARAM2 + +#ifdef __DOS__ +#include <pc.h> +#include <io.h> +#endif + +/* MODIF PMO */ +/* WIN32/UNIX compatibility */ +#ifdef WINDOWS_VCPP + #define COMP_SEPARATOR '\\' + #define COMP_S_SEPARATOR "\\" +#else + #define COMP_SEPARATOR '/' + #define COMP_S_SEPARATOR "/" +#endif +/* ENDOF MODIF PMO */ + +/* Acorn specific stuff */ +#ifdef ACORN + +#define S_IRUSR S_IREAD +#define S_IWUSR S_IWRITE +#define S_IXUSR S_IEXEC + +#define strcasecmp stricmp + +#endif + +#ifndef L_tmpnam +#define L_tmpnam 128 /* ought to be safe */ +#endif + +/* If char has more then 8 bits, good night. */ +typedef unsigned char uae_u8; +typedef signed char uae_s8; + +typedef struct { uae_u8 RGB[3]; } RGB; + +#if SIZEOF_SHORT == 2 +typedef unsigned short uae_u16; +typedef short uae_s16; +#elif SIZEOF_INT == 2 +typedef unsigned int uae_u16; +typedef int uae_s16; +#else +#error No 2 byte type, you lose. +#endif + +#if SIZEOF_INT == 4 +typedef unsigned int uae_u32; +typedef int uae_s32; +#elif SIZEOF_LONG == 4 +typedef unsigned long uae_u32; +typedef long uae_s32; +#else +#error No 4 byte type, you lose. +#endif + +typedef uae_u32 uaecptr; + +#undef uae_s64 +#undef uae_u64 + +#if SIZEOF_LONG_LONG == 8 +#define uae_s64 long long +#define uae_u64 long long +#define VAL64(a) (a ## LL) +#define UVAL64(a) (a ## uLL) +#elif SIZEOF___INT64 == 8 +#define uae_s64 __int64 +#define uae_u64 unsigned __int64 +#define VAL64(a) (a) +#define UVAL64(a) (a) +#elif SIZEOF_LONG == 8 +#define uae_s64 long; +#define uae_u64 unsigned long; +#define VAL64(a) (a ## l) +#define UVAL64(a) (a ## ul) +#endif + +#ifdef HAVE_STRDUP +#define my_strdup strdup +#else +extern char *my_strdup (const char*s); +#endif +extern void *xmalloc(size_t); + +/* We can only rely on GNU C getting enums right. Mickeysoft VSC++ is known + * to have problems, and it's likely that other compilers choke too. */ +#ifdef __GNUC__ +#define ENUMDECL typedef enum +#define ENUMNAME(name) name +#else +#define ENUMDECL enum +#define ENUMNAME(name) ; typedef int name +#endif + +/* + * Porters to weird systems, look! This is the preferred way to get + * filesys.c (and other stuff) running on your system. Define the + * appropriate macros and implement wrappers in a machine-specific file. + * + * I guess the Mac port could use this (Ernesto?) + */ + +#undef DONT_HAVE_POSIX +#undef DONT_HAVE_REAL_POSIX /* define if open+delete doesn't do what it should */ +#undef DONT_HAVE_STDIO +#undef DONT_HAVE_MALLOC + +#if defined _WIN32 + +#if defined __WATCOMC__ + +#define O_NDELAY 0 +#include <direct.h> +#define dirent direct +#define mkdir(a,b) mkdir(a) +#define strcasecmp stricmp + +#elif defined __MINGW32__ + +#define O_NDELAY 0 +#define mkdir(a,b) mkdir(a) + +#endif + +#endif /* _WIN32 */ + +#ifdef DONT_HAVE_POSIX + +#define access posixemu_access +extern int posixemu_access (const char *, int); +#define open posixemu_open +extern int posixemu_open (const char *, int, int); +#define close posixemu_close +extern void posixemu_close (int); +#define read posixemu_read +extern int posixemu_read (int, char *, int); +#define write posixemu_write +extern int posixemu_write (int, const char *, int); +#undef lseek +#define lseek posixemu_seek +extern int posixemu_seek (int, int, int); +#define stat(a,b) posixemu_stat ((a), (b)) +extern int posixemu_stat (const char *, STAT *); +#define mkdir posixemu_mkdir +extern int mkdir (const char *, int); +#define rmdir posixemu_rmdir +extern int posixemu_rmdir (const char *); +#define unlink posixemu_unlink +extern int posixemu_unlink (const char *); +#define truncate posixemu_truncate +extern int posixemu_truncate (const char *, long int); +#define rename posixemu_rename +extern int posixemu_rename (const char *, const char *); +#define chmod posixemu_chmod +extern int posixemu_chmod (const char *, int); +#define tmpnam posixemu_tmpnam +extern void posixemu_tmpnam (char *); +#define utime posixemu_utime +extern int posixemu_utime (const char *, struct utimbuf *); +#define opendir posixemu_opendir +extern DIR * posixemu_opendir (const char *); +#define readdir posixemu_readdir +extern struct dirent* readdir (DIR *); +#define closedir posixemu_closedir +extern void closedir (DIR *); + +/* This isn't the best place for this, but it fits reasonably well. The logic + * is that you probably don't have POSIX errnos if you don't have the above + * functions. */ +extern long dos_errno (void); + +#endif + +#ifdef DONT_HAVE_STDIO + +extern FILE *stdioemu_fopen (const char *, const char *); +#define fopen(a,b) stdioemu_fopen(a, b) +extern int stdioemu_fseek (FILE *, int, int); +#define fseek(a,b,c) stdioemu_fseek(a, b, c) +extern int stdioemu_fread (char *, int, int, FILE *); +#define fread(a,b,c,d) stdioemu_fread(a, b, c, d) +extern int stdioemu_fwrite (const char *, int, int, FILE *); +#define fwrite(a,b,c,d) stdioemu_fwrite(a, b, c, d) +extern int stdioemu_ftell (FILE *); +#define ftell(a) stdioemu_ftell(a) +extern int stdioemu_fclose (FILE *); +#define fclose(a) stdioemu_fclose(a) + +#endif + +#ifdef DONT_HAVE_MALLOC + +#define malloc(a) mallocemu_malloc(a) +extern void *mallocemu_malloc (int size); +#define free(a) mallocemu_free(a) +extern void mallocemu_free (void *ptr); + +#endif + +#ifdef X86_ASSEMBLY +#define ASM_SYM_FOR_FUNC(a) __asm__(a) +#else +#define ASM_SYM_FOR_FUNC(a) +#endif + +#if defined USE_COMPILER +#undef NO_PREFETCH_BUFFER +#undef NO_EXCEPTION_3 +#define NO_EXCEPTION_3 +#define NO_PREFETCH_BUFFER +#endif + +#include "target.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* Every Amiga hardware clock cycle takes this many "virtual" cycles. This + used to be hardcoded as 1, but using higher values allows us to time some + stuff more precisely. + 512 is the official value from now on - it can't change, unless we want + _another_ config option "finegrain2_m68k_speed". + + We define this value here rather than in events.h so that gencpu.c sees + it. */ +#define CYCLE_UNIT 512 + +/* MODIF PMO */ +#endif + +/* ENDOF MODIF PMO */ + diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/text_scope.h b/plugins/ddb_input_uade2/uade-2.13/src/include/text_scope.h new file mode 100644 index 00000000..7bc9d206 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/text_scope.h @@ -0,0 +1,21 @@ +#ifndef _TEXT_SCOPE_H_ +#define _TEXT_SCOPE_H_ + +#include "uadeconfig.h" + +#ifdef UADE_CONFIG_TEXT_SCOPE +#define TEXT_SCOPE(cycles, voice, e, value) \ + do { \ + if (use_text_scope) \ + text_scope(cycles, voice, e, value); \ + } while (0) +#else +#define TEXT_SCOPE(cycles, voice, e, value) do {} while (0) +#endif + +enum PaulaEventType {PET_VOL, PET_PER, PET_DAT, PET_LEN, PET_LCH, PET_LCL}; + +void text_scope(unsigned long cycles, int voice, enum PaulaEventType e, + int value); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/uade.h b/plugins/ddb_input_uade2/uade-2.13/src/include/uade.h new file mode 100644 index 00000000..91f590fe --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/uade.h @@ -0,0 +1,43 @@ +#ifndef _UADE_MAIN_H_ +#define _UADE_MAIN_H_ + +#include <limits.h> +#include <stdlib.h> + +#include "uadeipc.h" + +struct uade_song { + char playername[PATH_MAX]; /* filename of eagleplayer */ + char modulename[PATH_MAX]; /* filename of song */ + char scorename[PATH_MAX]; /* filename of score file */ + + int min_subsong; + int max_subsong; + int cur_subsong; +}; + + +void uade_change_subsong(int subs); +void uade_check_sound_buffers(int bytes); +void uade_send_debug(const char *fmt, ...); +void uade_get_amiga_message(void); +void uade_handle_r_state(void); +void uade_option(int, char**); /* handles command line parameters */ +void uade_reset(void); +void uade_send_amiga_message(int msgtype); +void uade_set_automatic_song_end(int song_end_possible); +void uade_set_ntsc(int usentsc); +void uade_song_end(char *reason, int kill_it); +void uade_swap_buffer_bytes(void *data, int bytes); + +extern int uade_audio_output; +extern int uade_audio_skip; +extern int uade_debug; +extern int uade_local_sound; +extern int uade_read_size; +extern int uade_reboot; +extern int uade_time_critical; + +extern struct uade_ipc uadeipc; + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/uadeconstants.h b/plugins/ddb_input_uade2/uade-2.13/src/include/uadeconstants.h new file mode 100644 index 00000000..5a69953a --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/uadeconstants.h @@ -0,0 +1,10 @@ +#ifndef _UADE_CONSTANTS_H_ +#define _UADE_CONSTANTS_H_ + +/* You must not change anything */ +#define UADE_CHANNELS (2) +#define UADE_DEFAULT_FREQUENCY (44100) +#define UADE_BYTES_PER_SAMPLE (2) +#define UADE_BYTES_PER_FRAME (UADE_CHANNELS * UADE_BYTES_PER_SAMPLE) + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/uadeipc.h b/plugins/ddb_input_uade2/uade-2.13/src/include/uadeipc.h new file mode 100644 index 00000000..3bad980b --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/uadeipc.h @@ -0,0 +1,77 @@ +#ifndef _UADEIPC_H_ +#define _UADEIPC_H_ + +#include <stdlib.h> +#include <stdint.h> + +#include "uadeutils.h" + +#define UADE_MAX_MESSAGE_SIZE (4096) + +enum uade_msgtype { + UADE_MSG_FIRST = 0, + UADE_COMMAND_ACTIVATE_DEBUGGER, + UADE_COMMAND_CHANGE_SUBSONG, + UADE_COMMAND_CONFIG, + UADE_COMMAND_SCORE, + UADE_COMMAND_PLAYER, + UADE_COMMAND_MODULE, + UADE_COMMAND_READ, + UADE_COMMAND_REBOOT, + UADE_COMMAND_SET_SUBSONG, + UADE_COMMAND_IGNORE_CHECK, + UADE_COMMAND_SONG_END_NOT_POSSIBLE, + UADE_COMMAND_SET_NTSC, + UADE_COMMAND_FILTER, + UADE_COMMAND_SET_FREQUENCY, + UADE_COMMAND_SET_PLAYER_OPTION, + UADE_COMMAND_SET_RESAMPLING_MODE, + UADE_COMMAND_SPEED_HACK, + UADE_COMMAND_TOKEN, + UADE_COMMAND_USE_TEXT_SCOPE, + UADE_REPLY_MSG, + UADE_REPLY_CANT_PLAY, + UADE_REPLY_CAN_PLAY, + UADE_REPLY_SONG_END, + UADE_REPLY_SUBSONG_INFO, + UADE_REPLY_PLAYERNAME, + UADE_REPLY_MODULENAME, + UADE_REPLY_FORMATNAME, + UADE_REPLY_DATA, + UADE_MSG_LAST +}; + +struct uade_msg { + uint32_t msgtype; + uint32_t size; + uint8_t data[0]; +} __attribute__((packed)); + +enum uade_control_state { + UADE_INITIAL_STATE = 0, + UADE_R_STATE, + UADE_S_STATE +}; + +struct uade_ipc { + void *input; + void *output; + unsigned int inputbytes; + char inputbuffer[UADE_MAX_MESSAGE_SIZE]; + enum uade_control_state state; +}; + +void uade_check_fix_string(struct uade_msg *um, size_t maxlen); +int uade_parse_u32_message(uint32_t *u1, struct uade_msg *um); +int uade_parse_two_u32s_message(uint32_t *u1, uint32_t *u2, struct uade_msg *um); +int uade_receive_message(struct uade_msg *um, size_t maxbytes, struct uade_ipc *ipc); +int uade_receive_short_message(enum uade_msgtype msgtype, struct uade_ipc *ipc); +int uade_receive_string(char *s, enum uade_msgtype msgtype, size_t maxlen, struct uade_ipc *ipc); +int uade_send_message(struct uade_msg *um, struct uade_ipc *ipc); +int uade_send_short_message(enum uade_msgtype msgtype, struct uade_ipc *ipc); +int uade_send_string(enum uade_msgtype msgtype, const char *str, struct uade_ipc *ipc); +int uade_send_u32(enum uade_msgtype com, uint32_t u, struct uade_ipc *ipc); +int uade_send_two_u32s(enum uade_msgtype com, uint32_t u1, uint32_t u2, struct uade_ipc *ipc); +void uade_set_peer(struct uade_ipc *ipc, int peer_is_client, const char *input, const char *output); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/uadeutils.h b/plugins/ddb_input_uade2/uade-2.13/src/include/uadeutils.h new file mode 100644 index 00000000..fcd24233 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/uadeutils.h @@ -0,0 +1,27 @@ +#ifndef _UADE_UTILS_H_ +#define _UADE_UTILS_H_ + +#include <stdint.h> + +#define uade_error(fmt, args...) do { \ + fprintf(stderr, "%s:%d: %s: " fmt, __FILE__, __LINE__, __func__, ## args); \ + abort(); \ + } while (0) + +static inline uint16_t read_be_u16(void *s) +{ + uint16_t x; + uint8_t *ptr = (uint8_t *) s; + x = ptr[1] + (ptr[0] << 8); + return x; +} + +static inline uint32_t read_be_u32(void *s) +{ + uint32_t x; + uint8_t *ptr = (uint8_t *) s; + x = (ptr[0] << 24) + (ptr[1] << 16) + (ptr[2] << 8) + ptr[3]; + return x; +} + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/uae.h b/plugins/ddb_input_uade2/uade-2.13/src/include/uae.h new file mode 100644 index 00000000..1ab9d75f --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/uae.h @@ -0,0 +1,30 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Prototypes for main.c + * + * Copyright 1996 Bernd Schmidt + */ + +extern int uade_main (int argc, char **argv); +extern void uae_quit (void); + +extern int quit_program; + +extern char warning_buffer[256]; + +/* This structure is used to define menus. The val field can hold key + * shortcuts, or one of these special codes: + * -4: deleted entry, not displayed, not selectable, but does count in + * select value + * -3: end of table + * -2: line that is displayed, but not selectable + * -1: line that is selectable, but has no keyboard shortcut + * 0: Menu title + */ +struct bstring { + const char *data; + int val; +}; + +extern char *colormodes[]; diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/unixatomic.h b/plugins/ddb_input_uade2/uade-2.13/src/include/unixatomic.h new file mode 100644 index 00000000..565cf864 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/unixatomic.h @@ -0,0 +1,15 @@ +#ifndef _UNIXATOMIC_H_ +#define _UNIXATOMIC_H_ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +int atomic_close(int fd); +int atomic_dup2(int oldfd, int newfd); +size_t atomic_fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +ssize_t atomic_read(int fd, const void *buf, size_t count); +void *atomic_read_file(size_t *fs, const char *filename); +ssize_t atomic_write(int fd, const void *buf, size_t count); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/include/unixsupport.h b/plugins/ddb_input_uade2/uade-2.13/src/include/unixsupport.h new file mode 100644 index 00000000..dc7d545e --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/include/unixsupport.h @@ -0,0 +1,32 @@ +#ifndef _UADE_UNIXSUPPORT_H_ +#define _UADE_UNIXSUPPORT_H_ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <string.h> +#include <errno.h> + +#include "uadeipc.h" + + +#define die(fmt, args...) do { fprintf(stderr, "uade: " fmt, ## args); exit(1); } while(0) + +#define dieerror(fmt, args...) do { fprintf(stderr, "uade: " fmt ": %s\n", ## args, strerror(errno)); exit(1); } while(0) + + +char *uade_dirname(char *dst, char *src, size_t maxlen); +FILE *uade_open_amiga_file(char *aname, const char *playerdir); +void uade_portable_initializations(void); +void uade_arch_spawn(struct uade_ipc *ipc, pid_t *uadepid, const char *uadename); + +/* These read and write functions MUST read and write the full size_t amount + if they are able to. */ +ssize_t uade_ipc_read(void *f, const void *buf, size_t count); +ssize_t uade_ipc_write(void *f, const void *buf, size_t count); +void *uade_ipc_set_input(const char *input); +void *uade_ipc_set_output(const char *output); + +char *windows_to_cygwin_path(const char *path); + +#endif diff --git a/plugins/ddb_input_uade2/uade-2.13/src/uadeipc.c b/plugins/ddb_input_uade2/uade-2.13/src/uadeipc.c new file mode 100644 index 00000000..cba45ce0 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/uadeipc.c @@ -0,0 +1,291 @@ +/* UADE + * + * Copyright 2005 Heikki Orsila <heikki.orsila@iki.fi> + * + * This source code module is dual licensed under GPL and Public Domain. + * Hence you may use _this_ module (not another code module) in any way you + * want in your projects. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> +#include <string.h> + +#include "uadeipc.h" +#include "ossupport.h" +#include "sysincludes.h" + + +static int valid_message(struct uade_msg *uc); + + +void uade_check_fix_string(struct uade_msg *um, size_t maxlen) +{ + uint8_t *s = (uint8_t *) um->data; + size_t safelen; + if (um->size == 0) { + s[0] = 0; + fprintf(stderr, "zero string detected\n"); + } + safelen = 0; + while (s[safelen] != 0 && safelen < maxlen) + safelen++; + if (safelen == maxlen) { + safelen--; + fprintf(stderr, "too long a string\n"); + s[safelen] = 0; + } + if (um->size != (safelen + 1)) { + fprintf(stderr, "string size does not match\n"); + um->size = safelen + 1; + s[safelen] = 0; + } +} + + +static ssize_t get_more(size_t bytes, struct uade_ipc *ipc) +{ + if (ipc->inputbytes < bytes) { + ssize_t s = uade_ipc_read(ipc->input, &ipc->inputbuffer[ipc->inputbytes], bytes - ipc->inputbytes); + if (s <= 0) + return -1; + ipc->inputbytes += s; + } + return 0; +} + + +static void copy_from_inputbuffer(void *dst, int bytes, struct uade_ipc *ipc) +{ + if (ipc->inputbytes < bytes) { + fprintf(stderr, "not enough bytes in input buffer\n"); + exit(-1); + } + memcpy(dst, ipc->inputbuffer, bytes); + memmove(ipc->inputbuffer, &ipc->inputbuffer[bytes], ipc->inputbytes - bytes); + ipc->inputbytes -= bytes; +} + + +int uade_parse_u32_message(uint32_t *u1, struct uade_msg *um) +{ + if (um->size != 4) + return -1; + *u1 = ntohl(* (uint32_t *) um->data); + return 0; +} + + +int uade_parse_two_u32s_message(uint32_t *u1, uint32_t *u2, + struct uade_msg *um) +{ + if (um->size != 8) + return -1; + *u1 = ntohl(((uint32_t *) um->data)[0]); + *u2 = ntohl(((uint32_t *) um->data)[1]); + return 0; +} + + +int uade_receive_message(struct uade_msg *um, size_t maxbytes, + struct uade_ipc *ipc) +{ + size_t fullsize; + + if (ipc->state == UADE_INITIAL_STATE) { + ipc->state = UADE_R_STATE; + } else if (ipc->state == UADE_S_STATE) { + fprintf(stderr, "protocol error: receiving in S state is forbidden\n"); + return -1; + } + + if (ipc->inputbytes < sizeof(*um)) { + if (get_more(sizeof(*um), ipc)) + return 0; + } + + copy_from_inputbuffer(um, sizeof(*um), ipc); + + um->msgtype = ntohl(um->msgtype); + um->size = ntohl(um->size); + + if (!valid_message(um)) + return -1; + + fullsize = um->size + sizeof(*um); + if (fullsize > maxbytes) { + fprintf(stderr, "too big a command: %zu\n", fullsize); + return -1; + } + if (ipc->inputbytes < um->size) { + if (get_more(um->size, ipc)) + return -1; + } + copy_from_inputbuffer(&um->data, um->size, ipc); + + if (um->msgtype == UADE_COMMAND_TOKEN) + ipc->state = UADE_S_STATE; + + return 1; +} + + +int uade_receive_short_message(enum uade_msgtype msgtype, struct uade_ipc *ipc) +{ + struct uade_msg um; + + if (ipc->state == UADE_INITIAL_STATE) { + ipc->state = UADE_R_STATE; + } else if (ipc->state == UADE_S_STATE) { + fprintf(stderr, "protocol error: receiving (%d) in S state is forbidden\n", msgtype); + return -1; + } + + if (uade_receive_message(&um, sizeof(um), ipc) <= 0) { + fprintf(stderr, "can not receive short message: %d\n", msgtype); + return -1; + } + return (um.msgtype == msgtype) ? 0 : -1; +} + + +int uade_receive_string(char *s, enum uade_msgtype com, + size_t maxlen, struct uade_ipc *ipc) +{ + uint8_t commandbuf[UADE_MAX_MESSAGE_SIZE]; + struct uade_msg *um = (struct uade_msg *) commandbuf; + int ret; + + if (ipc->state == UADE_INITIAL_STATE) { + ipc->state = UADE_R_STATE; + } else if (ipc->state == UADE_S_STATE) { + fprintf(stderr, "protocol error: receiving in S state is forbidden\n"); + return -1; + } + + ret = uade_receive_message(um, UADE_MAX_MESSAGE_SIZE, ipc); + if (ret <= 0) + return ret; + if (um->msgtype != com) + return -1; + if (um->size == 0) + return -1; + if (um->size != (strlen((char *) um->data) + 1)) + return -1; + strlcpy(s, (char *) um->data, maxlen); + return 1; +} + + +int uade_send_message(struct uade_msg *um, struct uade_ipc *ipc) +{ + uint32_t size = um->size; + + if (ipc->state == UADE_INITIAL_STATE) { + ipc->state = UADE_S_STATE; + } else if (ipc->state == UADE_R_STATE) { + fprintf(stderr, "protocol error: sending in R state is forbidden\n"); + return -1; + } + + if (!valid_message(um)) + return -1; + if (um->msgtype == UADE_COMMAND_TOKEN) + ipc->state = UADE_R_STATE; + um->msgtype = htonl(um->msgtype); + um->size = htonl(um->size); + if (uade_ipc_write(ipc->output, um, sizeof(*um) + size) < 0) + return -1; + + return 0; +} + + +int uade_send_short_message(enum uade_msgtype msgtype, struct uade_ipc *ipc) +{ + struct uade_msg msg = {.msgtype = msgtype}; + + if (uade_send_message(&msg, ipc)) { + fprintf(stderr, "can not send short message: %d\n", msgtype); + return -1; + } + return 0; +} + + +int uade_send_string(enum uade_msgtype com, const char *str, struct uade_ipc *ipc) +{ + uint32_t size = strlen(str) + 1; + struct uade_msg um = {.msgtype = ntohl(com), .size = ntohl(size)}; + + if (ipc->state == UADE_INITIAL_STATE) { + ipc->state = UADE_S_STATE; + } else if (ipc->state == UADE_R_STATE) { + fprintf(stderr, "protocol error: sending in R state is forbidden\n"); + return -1; + } + + if ((sizeof(um) + size) > UADE_MAX_MESSAGE_SIZE) + return -1; + if (uade_ipc_write(ipc->output, &um, sizeof(um)) < 0) + return -1; + if (uade_ipc_write(ipc->output, str, size) < 0) + return -1; + + return 0; +} + + +int uade_send_u32(enum uade_msgtype com, uint32_t u, struct uade_ipc *ipc) +{ + uint8_t space[UADE_MAX_MESSAGE_SIZE]; + struct uade_msg *um = (struct uade_msg *) space; + um->msgtype = com; + um->size = 4; + * (uint32_t *) um->data = htonl(u); + return uade_send_message(um, ipc); +} + + +int uade_send_two_u32s(enum uade_msgtype com, uint32_t u1, uint32_t u2, + struct uade_ipc *ipc) +{ + uint8_t space[UADE_MAX_MESSAGE_SIZE]; + struct uade_msg *um = (struct uade_msg *) space; + um->msgtype = com; + um->size = 8; + ((uint32_t *) um->data)[0] = htonl(u1); + ((uint32_t *) um->data)[1] = htonl(u2); + return uade_send_message(um, ipc); +} + + +void uade_set_peer(struct uade_ipc *ipc, int peer_is_client, const char *input, const char *output) +{ + assert(peer_is_client == 0 || peer_is_client == 1); + assert(input != NULL); + assert(output != NULL); + + *ipc = (struct uade_ipc) {.state = UADE_INITIAL_STATE, + .input= uade_ipc_set_input(input), + .output = uade_ipc_set_output(output)}; +} + + +static int valid_message(struct uade_msg *um) +{ + size_t len; + if (um->msgtype <= UADE_MSG_FIRST || um->msgtype >= UADE_MSG_LAST) { + fprintf(stderr, "unknown command: %u\n", (unsigned int) um->msgtype); + return 0; + } + len = sizeof(*um) + um->size; + if (len > UADE_MAX_MESSAGE_SIZE) { + fprintf(stderr, "too long a message: %zu\n", len); + return 0; + } + return 1; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/unixatomic.c b/plugins/ddb_input_uade2/uade-2.13/src/unixatomic.c new file mode 100644 index 00000000..1adbe27a --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/unixatomic.c @@ -0,0 +1,149 @@ +#include <errno.h> +#include <stdint.h> +#include <assert.h> + +#include "unixatomic.h" +#include "sysincludes.h" + +int atomic_close(int fd) +{ + while (1) { + if (close(fd) < 0) { + if (errno == EINTR) + continue; + return -1; + } + break; + } + return 0; +} + + +int atomic_dup2(int oldfd, int newfd) +{ + while (1) { + if (dup2(oldfd, newfd) < 0) { + if (errno == EINTR) + continue; + return -1; + } + break; + } + return newfd; +} + + +size_t atomic_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + uint8_t *dest = ptr; + size_t readmembers = 0; + size_t ret; + + while (readmembers < nmemb) { + ret = fread(dest + size * readmembers, size, nmemb - readmembers, stream); + if (ret == 0) + break; + readmembers += ret; + } + + assert(readmembers <= nmemb); + + return readmembers; +} + + +ssize_t atomic_read(int fd, const void *buf, size_t count) +{ + char *b = (char *) buf; + ssize_t bytes_read = 0; + ssize_t ret; + while (bytes_read < count) { + ret = read(fd, &b[bytes_read], count - bytes_read); + if (ret < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) { + fd_set s; + FD_ZERO(&s); + FD_SET(fd, &s); + if (select(fd + 1, &s, NULL, NULL, NULL) == 0) + fprintf(stderr, "atomic_read: very strange. infinite select() returned 0. report this!\n"); + continue; + } + return -1; + } else if (ret == 0) { + return 0; + } + bytes_read += ret; + } + return bytes_read; +} + + +void *atomic_read_file(size_t *fs, const char *filename) +{ + FILE *f; + size_t off; + void *mem = NULL; + size_t msize; + long pos; + + if ((f = fopen(filename, "rb")) == NULL) + goto error; + + if (fseek(f, 0, SEEK_END)) + goto error; + pos = ftell(f); + if (pos < 0) + goto error; + if (fseek(f, 0, SEEK_SET)) + goto error; + + *fs = pos; + msize = (pos > 0) ? pos : 1; + + if ((mem = malloc(msize)) == NULL) + goto error; + + off = atomic_fread(mem, 1, *fs, f); + if (off < *fs) { + fprintf(stderr, "Not able to read the whole file %s\n", filename); + goto error; + } + + fclose(f); + return mem; + + error: + if (f) + fclose(f); + free(mem); + *fs = 0; + return NULL; +} + + +ssize_t atomic_write(int fd, const void *buf, size_t count) +{ + char *b = (char *) buf; + ssize_t bytes_written = 0; + ssize_t ret; + while (bytes_written < count) { + ret = write(fd, &b[bytes_written], count - bytes_written); + if (ret < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) { + fd_set s; + FD_ZERO(&s); + FD_SET(fd, &s); + if (select(fd + 1, NULL, &s, NULL, NULL) == 0) + fprintf(stderr, "atomic_write: very strange. infinite select() returned 0. report this!\n"); + continue; + } + return -1; + } + bytes_written += ret; + } + return bytes_written; +} diff --git a/plugins/ddb_input_uade2/uade-2.13/src/unixsupport.c b/plugins/ddb_input_uade2/uade-2.13/src/unixsupport.c new file mode 100644 index 00000000..d6131bc2 --- /dev/null +++ b/plugins/ddb_input_uade2/uade-2.13/src/unixsupport.c @@ -0,0 +1,350 @@ +/* UNIX support tools for uadecore. + + Copyright 2000 - 2005 (C) Heikki Orsila <heikki.orsila@iki.fi> + + This module is licensed under the GNU GPL. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <libgen.h> +#include <sys/socket.h> +#include <unistd.h> +#include <limits.h> +#include <ctype.h> + +#include "uade.h" +#include "unixatomic.h" + + +static int url_to_fd(const char *url, int flags, mode_t mode) +{ + int fd; + if (strncmp(url, "fd://", 5) == 0) { + char *endptr; + if (url[5] == 0) + return -1; + fd = strtol(&url[5], &endptr, 10); + if (*endptr != 0) + return -1; + } else { + if (flags & O_WRONLY) { + fd = open(url, flags, mode); + } else { + fd = open(url, flags); + } + } + if (fd < 0) + fd = -1; + return fd; +} + + +/* This must read the full size_t count if it can, and therefore we use + atomic_read() */ +ssize_t uade_ipc_read(void *f, const void *buf, size_t count) +{ + int fd = (intptr_t) f; + return atomic_read(fd, buf, count); +} + + +/* This must write the full size_t count if it can, and therefore we use + atomic_write() */ +ssize_t uade_ipc_write(void *f, const void *buf, size_t count) +{ + int fd = (intptr_t) f; + return atomic_write(fd, buf, count); +} + + +void *uade_ipc_set_input(const char *input) +{ + int fd; + if ((fd = url_to_fd(input, O_RDONLY, 0)) < 0) { + fprintf(stderr, "can not open input file %s: %s\n", input, strerror(errno)); + exit(-1); + } + return (void *) ((intptr_t) fd); +} + + +void *uade_ipc_set_output(const char *output) +{ + int fd; + if ((fd = url_to_fd(output, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { + fprintf(stderr, "can not open output file %s: %s\n", output, strerror(errno)); + exit(-1); + } + return (void *) ((intptr_t) fd); +} + + +static int uade_amiga_scandir(char *real, char *dirname, char *fake, int ml) +{ + DIR *dir; + struct dirent *direntry; + if (!(dir = opendir(dirname))) { + fprintf(stderr, "uade: can't open dir (%s) (amiga scandir)\n", dirname); + return 0; + } + while ((direntry = readdir(dir))) { + if (!strcmp(fake, direntry->d_name)) { + if (((int) strlcpy(real, direntry->d_name, ml)) >= ml) { + fprintf(stderr, "uade: %s does not fit real", direntry->d_name); + closedir(dir); + return 0; + } + break; + } + } + if (direntry) { + closedir(dir); + return 1; + } + rewinddir(dir); + while ((direntry = readdir(dir))) { + if (!strcasecmp(fake, direntry->d_name)) { + if (((int) strlcpy(real, direntry->d_name, ml)) >= ml) { + fprintf(stderr, "uade: %s does not fit real", direntry->d_name); + closedir(dir); + return 0; + } + break; + } + } + closedir(dir); + return direntry ? 1 : 0; +} + + +char *uade_dirname(char *dst, char *src, size_t maxlen) +{ + char *srctemp = strdup(src); + if (srctemp == NULL) + return NULL; + strlcpy(dst, dirname(srctemp), maxlen); + free(srctemp); + return dst; +} + + +/* opens file in amiga namespace */ +FILE *uade_open_amiga_file(char *aname, const char *playerdir) +{ + char *separator; + char *ptr; + char copy[PATH_MAX]; + char dirname[PATH_MAX]; + char fake[PATH_MAX]; + char real[PATH_MAX]; + int len; + DIR *dir; + FILE *file; + + if (strlcpy(copy, aname, sizeof(copy)) >= sizeof(copy)) { + fprintf(stderr, "uade: error: amiga tried to open a very long filename\nplease REPORT THIS!\n"); + return NULL; + } + ptr = copy; + /* fprintf(stderr, "uade: opening %s\n", ptr); */ + if ((separator = strchr(ptr, (int) ':'))) { + len = (int) (separator - ptr); + memcpy(dirname, ptr, len); + dirname[len] = 0; + if (!strcasecmp(dirname, "ENV")) { + snprintf(dirname, sizeof(dirname), "%s/ENV/", playerdir); + } else if (!strcasecmp(dirname, "S")) { + snprintf(dirname, sizeof(dirname), "%s/S/", playerdir); + } else { + fprintf(stderr, "uade: open_amiga_file: unknown amiga volume (%s)\n", aname); + return NULL; + } + if (!(dir = opendir(dirname))) { + fprintf(stderr, "uade: can't open dir (%s) (volume parsing)\n", dirname); + return NULL; + } + closedir(dir); + /* fprintf(stderr, "uade: opening from dir %s\n", dirname); */ + ptr = separator + 1; + } else { + if (*ptr == '/') { + /* absolute path */ + strlcpy(dirname, "/", sizeof(dirname)); + ptr++; + } else { + /* relative path */ + strlcpy(dirname, "./", sizeof(dirname)); + } + } + + while ((separator = strchr(ptr, (int) '/'))) { + len = (int) (separator - ptr); + if (!len) { + ptr++; + continue; + } + memcpy(fake, ptr, len); + fake[len] = 0; + if (uade_amiga_scandir(real, dirname, fake, sizeof(real))) { + /* found matching entry */ + if (strlcat(dirname, real, sizeof(dirname)) >= sizeof(dirname)) { + fprintf(stderr, "uade: too long dir path (%s + %s)\n", dirname, real); + return NULL; + } + if (strlcat(dirname, "/", sizeof(dirname)) >= sizeof(dirname)) { + fprintf(stderr, "uade: too long dir path (%s + %s)\n", dirname, "/"); + return NULL; + } + } else { + /* didn't find entry */ + /* fprintf (stderr, "uade: %s not found from (%s) (dir scanning)\n", fake, dirname); */ + return NULL; + } + ptr = separator + 1; + } + /* fprintf(stderr, "uade: pass 3: (%s) (%s)\n", dirname, ptr); */ + + if (!(dir = opendir(dirname))) { + fprintf(stderr, "can't open dir (%s) (after dir scanning)\n", dirname); + return NULL; + } + closedir(dir); + + if (uade_amiga_scandir(real, dirname, ptr, sizeof(real))) { + /* found matching entry */ + if (strlcat(dirname, real, sizeof(dirname)) >= sizeof(dirname)) { + fprintf(stderr, "uade: too long dir path (%s + %s)\n", dirname, real); + return NULL; + } + } else { + /* didn't find entry */ + /* fprintf (stderr, "uade: %s not found from %s\n", ptr, dirname); */ + return NULL; + } + if (!(file = fopen(dirname, "r"))) { + fprintf (stderr, "uade: couldn't open file (%s) induced by (%s)\n", dirname, aname); + } + return file; +} + + +void uade_portable_initializations(void) +{ + int signals[] = {SIGINT, -1}; + int *signum = signals; + struct sigaction act; + memset(&act, 0, sizeof act); + act.sa_handler = SIG_IGN; + + while (*signum != -1) { + while (1) { + if ((sigaction(*signum, &act, NULL)) < 0) { + if (errno == EINTR) + continue; + fprintf(stderr, "can not ignore signal %d: %s\n", *signum, strerror(errno)); + exit(-1); + } + break; + } + signum++; + } +} + + +void uade_arch_spawn(struct uade_ipc *ipc, pid_t *uadepid, + const char *uadename) +{ + int fds[2]; + char input[32], output[32]; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { + fprintf(stderr, "Can not create socketpair: %s\n", strerror(errno)); + abort(); + } + + *uadepid = fork(); + if (*uadepid < 0) { + fprintf(stderr, "Fork failed: %s\n", strerror(errno)); + abort(); + } + + /* The child (*uadepid == 0) will execute uadecore */ + if (*uadepid == 0) { + int fd; + int maxfds; + + if ((maxfds = sysconf(_SC_OPEN_MAX)) < 0) { + maxfds = 1024; + fprintf(stderr, "Getting max fds failed. Using %d.\n", maxfds); + } + + /* close everything else but stdin, stdout, stderr, and in/out fds */ + for (fd = 3; fd < maxfds; fd++) { + if (fd != fds[1]) + atomic_close(fd); + } + + /* give in/out fds as command line parameters to the uade process */ + snprintf(input, sizeof(input), "fd://%d", fds[1]); + snprintf(output, sizeof(output), "fd://%d", fds[1]); + + execlp(uadename, uadename, "-i", input, "-o", output, (char *) NULL); + fprintf(stderr, "uade execlp failed: %s\n", strerror(errno)); + abort(); + } + + /* Close fds that the uadecore uses */ + if (atomic_close(fds[1]) < 0) { + fprintf(stderr, "Could not close uadecore fds: %s\n", strerror(errno)); + kill (*uadepid, SIGTERM); + abort(); + } + + do { + snprintf(output, sizeof output, "fd://%d", fds[0]); + snprintf(input, sizeof input, "fd://%d", fds[0]); + uade_set_peer(ipc, 1, input, output); + } while (0); +} + +/* + * A hack that converts X:\something style windows names into cygwin style name + * /cygdrive/X/something. All '\\' characters are converted into '/' + * characters. + */ +char *windows_to_cygwin_path(const char *path) +{ + size_t i; + char *s; + size_t len = strlen(path); + + if (len == 0) + return calloc(1, 1); + + if (len >= 2 && isalpha(path[0]) && path[1] == ':') { + /* uses windows drive names */ + size_t newlen = len + 32; + s = malloc(newlen); + if (s != NULL) + snprintf(s, newlen, "/cygdrive/%c/%s", path[0], &path[2]); + } else { + s = strdup(path); + } + if (s == NULL) + return NULL; + + for (i = 0; s[i] != 0; i++) { + if (s[i] == '\\') + s[i] = '/'; + } + + return s; +} |