summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorGravatar waker <wakeroid@gmail.com>2010-12-05 16:06:29 +0100
committerGravatar waker <wakeroid@gmail.com>2010-12-05 16:06:29 +0100
commit4a04da22d9faf432962e98dbc8dae2e3df9b16c3 (patch)
tree8a43fa66cace8de729d4c8bcaa95d23a684c6174 /plugins
parentad085a1661d4a46eefb4a8d7359ea1b58bf8cc08 (diff)
added UADE2 plugin
Diffstat (limited to 'plugins')
-rw-r--r--plugins/ddb_input_uade2/plugin.c692
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/AUTHORS59
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/COPYING12
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/COPYING.GPL340
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/COPYING.LGPL504
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/ChangeLog1907
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/README53
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/amifilemagic.c1168
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/amifilemagic.h9
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/eagleplayer.c502
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/eagleplayer.h127
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/effects.c490
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/effects.h42
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.c247
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.copyright8
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/md5.h21
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songdb.c798
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songdb.h24
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songinfo.c721
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/songinfo.h19
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/support.c183
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/support.h31
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconf.c888
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconf.h27
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadeconfstructure.h139
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadecontrol.c249
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadecontrol.h24
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/uadestate.h25
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/unixwalkdir.c69
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/unixwalkdir.h16
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/vplist.c115
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/frontends/common/vplist.h44
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/.gitignore4
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/amigafilter.h10
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/amigamsg.h24
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/audio.h57
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/cia.h26
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/commpipe.h155
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/compiler.h111
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/custom.h115
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/debug.h25
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/events.h83
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/execlib.h40
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/gensound.h19
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/memory.h181
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/newcpu.h275
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/options.h262
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/osemu.h19
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/readcpu.h99
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/sinctable.h7
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/sysdeps.h347
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/text_scope.h21
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/uade.h43
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/uadeconstants.h10
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/uadeipc.h77
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/uadeutils.h27
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/uae.h30
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/unixatomic.h15
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/include/unixsupport.h32
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/uadeipc.c291
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/unixatomic.c149
-rw-r--r--plugins/ddb_input_uade2/uade-2.13/src/unixsupport.c350
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 *)&regs.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 *)&regs.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(&regs.prefetch);
+
+ prefetch_u.u32 = &regs.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 (&regs.prefetch, r);
+#endif
+}
+
+#if 0
+static inline void fill_prefetch_2 (void)
+{
+ uae_u32 r = do_get_mem_long (&regs.prefetch) << 16;
+ uae_u32 r2 = do_get_mem_word (((uae_u16 *)regs.pc_p) + 1);
+ r |= r2;
+ do_put_mem_long (&regs.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;
+}