# HG changeset patch # User chainsaw # Date 1135989099 28800 # Node ID 8df427a314a86a141d8ac01e090464676181f03e # Parent 70075730e18709c742772ed53686a1f0cc4204c5 [svn] Adlib synthesizer (AdPlug) support. diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/Makefile.am --- a/Plugins/Input/Makefile.am Fri Dec 30 14:17:35 2005 -0800 +++ b/Plugins/Input/Makefile.am Fri Dec 30 16:31:39 2005 -0800 @@ -1,2 +1,2 @@ -ALL_PLUGINS = mpg123 aac modplug vorbis tonegen cdaudio sid wav flac console wma timidity musepack sexypsf +ALL_PLUGINS = mpg123 aac modplug vorbis tonegen cdaudio sid wav flac console wma timidity musepack sexypsf adplug SUBDIRS = $(INPUT_PLUGINS) diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/Makefile.am Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,14 @@ +if HAVE_ADPLUG + +SUBDIRS = core +lib_LTLIBRARIES = libadplug.la + +endif + +libdir = $(plugindir)/$(INPUT_PLUGIN_DIR) + +libadplug_la_LDFLAGS = -lstdc++ -lbinio $(PLUGIN_LDFLAGS) ./core/libadplugcore.la + +libadplug_la_SOURCES = adplug-xmms.cc + +INCLUDES = $(GTK_CFLAGS) -I$(top_builddir)/intl -I$(top_srcdir) -I./core diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/adplug-xmms.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/adplug-xmms.cc Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,937 @@ +/* + AdPlug/XMMS - AdPlug XMMS Plugin + Copyright (C) 2002, 2003 Simon Peter + + AdPlug/XMMS 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 plugin 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 plugin; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include "adplug.h" +#include "emuopl.h" +#include "silentopl.h" +#include "players.h" +#include "audacious/plugin.h" +#include "libaudacious/util.h" +#include "libaudacious/configdb.h" + +/***** Defines *****/ + +// Version string +#define ADPLUG_NAME "AdPlug" + +// Sound buffer size in samples +#define SNDBUFSIZE 512 + +// AdPlug's 8 and 16 bit audio formats +#define FORMAT_8 FMT_U8 +#define FORMAT_16 FMT_S16_NE + +// Default file name of AdPlug's database file +#define ADPLUGDB_FILE "adplug.db" + +// Default AdPlug user's configuration subdirectory +#define ADPLUG_CONFDIR ".adplug" + +/***** Global variables *****/ + +extern "C" InputPlugin adplug_ip; +static gboolean audio_error = FALSE; + +// Configuration (and defaults) +static struct { + gint freq; + gboolean bit16, stereo, endless, quickdetect; + CPlayers players; +} cfg = { 44100l, true, false, false, true, CAdPlug::players }; + +// Player variables +static struct { + CPlayer *p; + CAdPlugDatabase *db; + unsigned int subsong, songlength; + int seek; + char filename[PATH_MAX]; + char *songtitle; + float time_ms; + bool playing; + GThread *play_thread; + GtkLabel *infobox; + GtkDialog *infodlg; +} plr = { 0, 0, 0, 0, -1, "", NULL, 0.0f, false, 0, NULL, NULL }; + +/***** Debugging *****/ + +#ifdef DEBUG + +#include + +static void dbg_printf(const char *fmt, ...) +{ + va_list argptr; + + va_start(argptr, fmt); + vfprintf(stderr, fmt, argptr); + va_end(argptr); +} + +#else + +static void dbg_printf(const char *fmt, ...) +{ } + +#endif + +/***** [Dialog]: Utility functions *****/ + +static GtkWidget *make_framed(GtkWidget *what, const gchar *label) +{ + GtkWidget *framebox = gtk_frame_new(label); + + gtk_container_add(GTK_CONTAINER(framebox), what); + return framebox; +} + +static GtkWidget *print_left(const gchar *text) +{ + GtkLabel *label = GTK_LABEL(gtk_label_new(text)); + + gtk_label_set_justify(label, GTK_JUSTIFY_LEFT); + gtk_misc_set_padding(GTK_MISC(label), 2, 2); + return GTK_WIDGET(label); +} + +static void MessageBox(const char *title, const char *text, const char *button) +{ + char *tmptitle = (char *)malloc(strlen(title) + 1), + *tmptxt = (char *)malloc(strlen(text) + 1), + *tmpbutton = (char *)malloc(strlen(button) + 1); + + strcpy(tmptitle, title); strcpy(tmptxt, text); strcpy(tmpbutton, button); + + GtkWidget *msgbox = xmms_show_message(tmptitle, tmptxt, tmpbutton, FALSE, + GTK_SIGNAL_FUNC(gtk_widget_destroyed), &msgbox); + + free(tmptitle); free(tmptxt); free(tmpbutton); +} + +/***** Dialog boxes *****/ + +static void adplug_about(void) +{ + std::ostringstream text; + + text << ADPLUG_NAME "\n" + "Copyright (C) 2002, 2003 Simon Peter \n\n" + "This plugin is released under the terms and conditions of the GNU LGPL.\n" + "See http://www.gnu.org/licenses/lgpl.html for details." + "\n\nThis plugin uses the AdPlug library, which is copyright (C) Simon Peter, et al.\n" + "Linked AdPlug library version: " << CAdPlug::get_version() << std::ends; + + MessageBox("About " ADPLUG_NAME, text.str().c_str(), "Ugh!"); +} + +static void close_config_box_ok(GtkButton *button, GPtrArray *rblist) +{ + // Apply configuration settings + cfg.bit16 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_ptr_array_index(rblist, 0))); + cfg.stereo = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_ptr_array_index(rblist, 1))); + + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_ptr_array_index(rblist, 2)))) cfg.freq = 11025; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_ptr_array_index(rblist, 3)))) cfg.freq = 22050; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_ptr_array_index(rblist, 4)))) cfg.freq = 44100; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_ptr_array_index(rblist, 5)))) cfg.freq = 48000; + + cfg.endless = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_ptr_array_index(rblist, 6))); + cfg.quickdetect = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_ptr_array_index(rblist, 7))); + + cfg.players = *(CPlayers *)g_ptr_array_index(rblist, 8); + delete (CPlayers *)g_ptr_array_index(rblist, 8); + + g_ptr_array_free(rblist, FALSE); +} + +static void close_config_box_cancel(GtkButton *button, GPtrArray *rblist) +{ + delete (CPlayers *)g_ptr_array_index(rblist, 8); + g_ptr_array_free(rblist, FALSE); +} + +static void config_fl_row_select(GtkCList *fl, gint row, gint col, + GdkEventButton *event, CPlayers *pl) +{ + pl->push_back((CPlayerDesc *)gtk_clist_get_row_data(fl, row)); + pl->unique(); +} + +static void config_fl_row_unselect(GtkCList *fl, gint row, gint col, + GdkEventButton *event, CPlayers *pl) +{ + pl->remove((CPlayerDesc *)gtk_clist_get_row_data(fl, row)); +} + +static void adplug_config(void) +{ + GtkDialog *config_dlg = GTK_DIALOG(gtk_dialog_new()); + GtkNotebook *notebook = GTK_NOTEBOOK(gtk_notebook_new()); + GtkTable *table; + GtkTooltips *tooltips = gtk_tooltips_new(); + GPtrArray *rblist = g_ptr_array_new(); + + gtk_window_set_title(GTK_WINDOW(config_dlg), "AdPlug :: Configuration"); + gtk_window_set_policy(GTK_WINDOW(config_dlg), FALSE, FALSE, TRUE); // Window is auto sized + gtk_window_set_modal(GTK_WINDOW(config_dlg), TRUE); + gtk_container_add(GTK_CONTAINER(config_dlg->vbox), GTK_WIDGET(notebook)); + + // Add Ok & Cancel buttons + { + GtkWidget *button; + + button = gtk_button_new_with_label("Ok"); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(close_config_box_ok), + (gpointer)rblist); + gtk_signal_connect_object_after(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT(config_dlg)); + gtk_container_add(GTK_CONTAINER(config_dlg->action_area), button); + + button = gtk_button_new_with_label("Cancel"); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(close_config_box_cancel), + (gpointer)rblist); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT(config_dlg)); + gtk_container_add(GTK_CONTAINER(config_dlg->action_area), button); + } + + /***** Page 1: General *****/ + + table = GTK_TABLE(gtk_table_new(1, 2, TRUE)); + gtk_table_set_row_spacings(table, 5); gtk_table_set_col_spacings(table, 5); + gtk_notebook_append_page(notebook, GTK_WIDGET(table), print_left("General")); + + // Add "Sound quality" section + { + GtkTable *sqt = GTK_TABLE(gtk_table_new(2, 2, FALSE)); + GtkVBox *fvb; + GtkRadioButton *rb; + + gtk_table_set_row_spacings(sqt, 5); + gtk_table_set_col_spacings(sqt, 5); + gtk_table_attach_defaults(table, make_framed(GTK_WIDGET(sqt), "Sound quality"), + 0, 1, 0, 1); + + // Add "Resolution" section + fvb = GTK_VBOX(gtk_vbox_new(TRUE, 0)); + gtk_table_attach_defaults(sqt, make_framed(GTK_WIDGET(fvb), "Resolution"), + 0, 1, 0, 1); + rb = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label(NULL, "8bit")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), !cfg.bit16); + gtk_container_add(GTK_CONTAINER(fvb), GTK_WIDGET(rb)); + rb = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label_from_widget(rb, "16bit")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), cfg.bit16); + gtk_container_add(GTK_CONTAINER(fvb), GTK_WIDGET(rb)); + g_ptr_array_add(rblist, (gpointer)rb); + + // Add "Channels" section + fvb = GTK_VBOX(gtk_vbox_new(TRUE, 0)); + gtk_table_attach_defaults(sqt, make_framed(GTK_WIDGET(fvb), "Channels"), + 0, 1, 1, 2); + rb = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label(NULL, "Mono")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), !cfg.stereo); + gtk_container_add(GTK_CONTAINER(fvb), GTK_WIDGET(rb)); + rb = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label_from_widget(rb, "Stereo")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), cfg.stereo); + gtk_container_add(GTK_CONTAINER(fvb), GTK_WIDGET(rb)); + gtk_tooltips_set_tip(tooltips, GTK_WIDGET(rb), + "Setting stereo is not recommended, unless you need to. " + "This won't add any stereo effects to the sound - OPL2 " + "is just mono - but eats up more CPU power!", NULL); + g_ptr_array_add(rblist, (gpointer)rb); + + // Add "Frequency" section + fvb = GTK_VBOX(gtk_vbox_new(TRUE, 0)); + gtk_table_attach_defaults(sqt, make_framed(GTK_WIDGET(fvb), "Frequency"), + 1, 2, 0, 2); + rb = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label(NULL, "11025")); + if(cfg.freq == 11025) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), TRUE); + gtk_container_add(GTK_CONTAINER(fvb), GTK_WIDGET(rb)); + g_ptr_array_add(rblist, (gpointer)rb); + rb = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label_from_widget(rb, "22050")); + if(cfg.freq == 22050) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), TRUE); + gtk_container_add(GTK_CONTAINER(fvb), GTK_WIDGET(rb)); + g_ptr_array_add(rblist, (gpointer)rb); + rb = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label_from_widget(rb, "44100")); + if(cfg.freq == 44100) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), TRUE); + gtk_container_add(GTK_CONTAINER(fvb), GTK_WIDGET(rb)); + g_ptr_array_add(rblist, (gpointer)rb); + rb = GTK_RADIO_BUTTON(gtk_radio_button_new_with_label_from_widget(rb, "48000")); + if(cfg.freq == 48000) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb), TRUE); + gtk_container_add(GTK_CONTAINER(fvb), GTK_WIDGET(rb)); + g_ptr_array_add(rblist, (gpointer)rb); + } + + // Add "Playback" section + { + GtkVBox *vb = GTK_VBOX(gtk_vbox_new(FALSE, 0)); + GtkCheckButton *cb; + + gtk_table_attach_defaults(table, make_framed(GTK_WIDGET(vb), "Playback"), + 1, 2, 0, 1); + + cb = GTK_CHECK_BUTTON(gtk_check_button_new_with_label("Detect songend")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb), !cfg.endless); + gtk_container_add(GTK_CONTAINER(vb), GTK_WIDGET(cb)); + gtk_tooltips_set_tip(tooltips, GTK_WIDGET(cb), + "If enabled, XMMS will detect a song's ending, stop " + "it and advance in the playlist. If disabled, XMMS " + "won't take notice of a song's ending and loop it all " + "over again and again.", NULL); + g_ptr_array_add(rblist, (gpointer)cb); + + cb = GTK_CHECK_BUTTON(gtk_check_button_new_with_label("Quick file detection")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb), cfg.quickdetect); + gtk_container_add(GTK_CONTAINER(vb), GTK_WIDGET(cb)); + gtk_tooltips_set_tip(tooltips, GTK_WIDGET(cb), + "If enabled, we'll try to determine a file's type by " + "only looking at the file extension, instead of " + "processing the file's contents. This speeds up the " + "load time of files a lot, but can be inaccurate if " + "the file has the wrong extension.", NULL); + g_ptr_array_add(rblist, (gpointer)cb); + } + + /***** Page 2: Formats *****/ + + table = GTK_TABLE(gtk_table_new(1, 1, TRUE)); + gtk_notebook_append_page(notebook, GTK_WIDGET(table), print_left("Formats")); + + // Add "Format selection" section + { + GtkHBox *vb = GTK_HBOX(gtk_hbox_new(FALSE, 0)); + gtk_table_attach_defaults(table, make_framed(GTK_WIDGET(vb), "Format selection"), + 0, 1, 0, 1); + // Add scrollable list + { + gchar *rowstr[] = {"Format", "Extension"}; + GtkEventBox *eventbox = GTK_EVENT_BOX(gtk_event_box_new()); + GtkScrolledWindow *formatswnd = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); + GtkCList *fl = GTK_CLIST(gtk_clist_new_with_titles(2, rowstr)); + CPlayers::const_iterator i; + unsigned int j; + gtk_clist_set_selection_mode(fl, GTK_SELECTION_MULTIPLE); + + // Build list + for(i = CAdPlug::players.begin(); i != CAdPlug::players.end(); i++) { + gint rownum; + + gchar *rws[2]; + rws[0] = g_strdup((*i)->filetype.c_str()); + rws[1] = g_strdup((*i)->get_extension(0)); + for(j = 1; (*i)->get_extension(j); j++) + rws[1] = g_strjoin(", ", rws[1], (*i)->get_extension(j), NULL); + rownum = gtk_clist_append(fl, rws); + g_free(rws[0]); g_free(rws[1]); + gtk_clist_set_row_data(fl, rownum, (gpointer)(*i)); + if(find(cfg.players.begin(), cfg.players.end(), *i) != cfg.players.end()) + gtk_clist_select_row(fl, rownum, 0); + } + + gtk_clist_columns_autosize(fl); + gtk_scrolled_window_set_policy(formatswnd, GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gpointer pl = (gpointer)new CPlayers(cfg.players); + gtk_signal_connect(GTK_OBJECT(fl), "select-row", + GTK_SIGNAL_FUNC(config_fl_row_select), pl); + gtk_signal_connect(GTK_OBJECT(fl), "unselect-row", + GTK_SIGNAL_FUNC(config_fl_row_unselect), pl); + gtk_container_add(GTK_CONTAINER(formatswnd), GTK_WIDGET(fl)); + gtk_container_add(GTK_CONTAINER(eventbox), GTK_WIDGET(formatswnd)); + gtk_container_add(GTK_CONTAINER(vb), GTK_WIDGET(eventbox)); + gtk_tooltips_set_tip(tooltips, GTK_WIDGET(eventbox), + "Selected file types will be recognized and played " + "back by this plugin. Deselected types will be " + "ignored to make room for other plugins to play " + "these files.", NULL); + g_ptr_array_add(rblist, pl); + } + } + + // Show window + gtk_widget_show_all(GTK_WIDGET(config_dlg)); +} + +static void add_instlist(GtkCList *instlist, const char *t1, const char *t2) +{ + gchar *rowstr[2]; + + rowstr[0] = g_strdup(t1); rowstr[1] = g_strdup(t2); + gtk_clist_append(instlist, rowstr); + g_free(rowstr[0]); g_free(rowstr[1]); +} + +static CPlayer *factory(const std::string &filename, Copl *newopl) +/* Wrapper factory method that implements the "quick detect" feature. */ +{ + CPlayer *p; + CPlayers::const_iterator i; + unsigned int j; + + dbg_printf("factory(\"%s\",opl): ", filename.c_str()); + if(cfg.quickdetect) { + // Quick detect! Just check according to file extensions. + dbg_printf("quick detect: "); + for(i = cfg.players.begin(); i != cfg.players.end(); i++) + for(j = 0; (*i)->get_extension(j); j++) + if(CFileProvider::extension(filename, (*i)->get_extension(j))) + if((p = (*i)->factory(newopl))) + if(p->load(filename)) { + dbg_printf("%s\n", (*i)->filetype.c_str()); + return p; + } else + delete p; + + dbg_printf("failed!\n"); + return 0; // quick detect failed. + } else { // just call AdPlug's original factory() + dbg_printf("asking AdPlug...\n"); + return CAdPlug::factory(filename, newopl, cfg.players); + } +} + +static void adplug_stop(void); +static void adplug_play(char *filename); + +static void subsong_slider(GtkAdjustment *adj) +{ + adplug_stop(); + plr.subsong = (unsigned int)adj->value - 1; + adplug_play(plr.filename); +} + +#if 0 +static void close_infobox(GtkDialog *infodlg) +{ + // Forget our references to the instance of the "currently playing song" info + // box. But only if we're really destroying that one... ;) + if(infodlg == plr.infodlg) { + plr.infobox = NULL; + plr.infodlg = NULL; + } +} + +static void adplug_info_box(char *filename) +{ + CSilentopl tmpopl; + CPlayer *p = (strcmp(filename, plr.filename) || !plr.p) ? + factory(filename, &tmpopl) : plr.p; + + if(!p) return; // bail out if no player could be created + if(p == plr.p && plr.infodlg) return; // only one info box for active song + + std::ostringstream infotext; + unsigned int i; + GtkDialog *infobox = GTK_DIALOG(gtk_dialog_new()); + GtkButton *okay_button = GTK_BUTTON(gtk_button_new_with_label("Ok")); + GtkPacker *packer = GTK_PACKER(gtk_packer_new()); + GtkHBox *hbox = GTK_HBOX(gtk_hbox_new(TRUE, 2)); + + // Build file info box + gtk_window_set_title(GTK_WINDOW(infobox), "AdPlug :: File Info"); + gtk_window_set_policy(GTK_WINDOW(infobox), FALSE, FALSE, TRUE); // Window is auto sized + gtk_container_add(GTK_CONTAINER(infobox->vbox), GTK_WIDGET(packer)); + gtk_packer_set_default_border_width(packer, 2); + gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE); + gtk_signal_connect_object(GTK_OBJECT(okay_button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT(infobox)); + gtk_signal_connect(GTK_OBJECT(infobox), "destroy", + GTK_SIGNAL_FUNC(close_infobox), 0); + gtk_container_add(GTK_CONTAINER(infobox->action_area), GTK_WIDGET(okay_button)); + + // Add filename section + gtk_packer_add_defaults(packer, make_framed(print_left(filename), "Filename"), + GTK_SIDE_TOP, GTK_ANCHOR_CENTER, GTK_FILL_X); + + // Add "Song info" section + infotext << "Title: " << p->gettitle() << std::endl << + "Author: " << p->getauthor() << std::endl << + "File Type: " << p->gettype() << std::endl << + "Subsongs: " << p->getsubsongs() << std::endl << + "Instruments: " << p->getinstruments(); + if(plr.p == p) + infotext << std::ends; + else { + infotext << std::endl << "Orders: " << p->getorders() << std::endl << + "Patterns: " << p->getpatterns() << std::ends; + } + gtk_container_add(GTK_CONTAINER(hbox), + make_framed(print_left(infotext.str().c_str()), "Song")); + + // Add "Playback info" section if currently playing + if(plr.p == p) { + plr.infobox = GTK_LABEL(gtk_label_new("")); + gtk_label_set_justify(plr.infobox, GTK_JUSTIFY_LEFT); + gtk_misc_set_padding(GTK_MISC(plr.infobox), 2, 2); + gtk_container_add(GTK_CONTAINER(hbox), + make_framed(GTK_WIDGET(plr.infobox), "Playback")); + } + gtk_packer_add_defaults(packer, GTK_WIDGET(hbox), GTK_SIDE_TOP, + GTK_ANCHOR_CENTER, GTK_FILL_X); + + // Add instrument names section + if(p->getinstruments()) { + GtkScrolledWindow *instwnd = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); + GtkCList *instnames; + gchar tmpstr[10]; + + { + gchar *rowstr[] = {"#","Instrument name"}; + instnames = GTK_CLIST(gtk_clist_new_with_titles(2, rowstr)); + } + gtk_clist_set_column_justification(instnames, 0, GTK_JUSTIFY_RIGHT); + + for(i=0;igetinstruments();i++) { + sprintf(tmpstr, "%d", i + 1); + add_instlist(instnames, tmpstr, p->getinstrument(i).c_str()); + } + + gtk_clist_columns_autosize(instnames); + gtk_scrolled_window_set_policy(instwnd, GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(instwnd), GTK_WIDGET(instnames)); + gtk_packer_add(packer, GTK_WIDGET(instwnd), GTK_SIDE_TOP, + GTK_ANCHOR_CENTER, GTK_FILL_X, 0, 0, 0, 0, 50); + } + + // Add "Song message" section + if(!p->getdesc().empty()) { + GtkScrolledWindow *msgwnd = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); + GtkText *msg = GTK_TEXT(gtk_text_new(NULL, NULL)); + gint pos = 0; + + gtk_scrolled_window_set_policy(msgwnd, GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_text_set_editable(msg, FALSE); + gtk_text_set_word_wrap(msg, TRUE); + // gtk_text_set_line_wrap(msg, TRUE); + gtk_editable_insert_text(GTK_EDITABLE(msg), p->getdesc().c_str(), + p->getdesc().length(), &pos); + + gtk_container_add(GTK_CONTAINER(msgwnd), GTK_WIDGET(msg)); + gtk_packer_add(packer, make_framed(GTK_WIDGET(msgwnd), "Song message"), + GTK_SIDE_TOP, GTK_ANCHOR_CENTER, GTK_FILL_X, 2, 0, 0, 200, 50); + } + + // Add subsong slider section + if(p == plr.p && p->getsubsongs() > 1) { + GtkAdjustment *adj = GTK_ADJUSTMENT(gtk_adjustment_new(plr.subsong + 1, 1, + p->getsubsongs() + 1, + 1, 5, 1)); + GtkHScale *slider = GTK_HSCALE(gtk_hscale_new(adj)); + + gtk_signal_connect(GTK_OBJECT(adj), "value_changed", + GTK_SIGNAL_FUNC(subsong_slider), NULL); + gtk_range_set_update_policy(GTK_RANGE(slider), GTK_UPDATE_DISCONTINUOUS); + gtk_scale_set_digits(GTK_SCALE(slider), 0); + gtk_packer_add_defaults(packer, make_framed(GTK_WIDGET(slider), "Subsong selection"), + GTK_SIDE_TOP, GTK_ANCHOR_CENTER, GTK_FILL_X); + } + + // Show dialog box + gtk_widget_show_all(GTK_WIDGET(infobox)); + if(p == plr.p) { // Remember widget, so we could destroy it later + plr.infodlg = infobox; + } else // Delete temporary player + delete p; +} + +/***** Main player (!! threaded !!) *****/ + +static void update_infobox(void) +{ + std::ostringstream infotext; + + // Recreate info string + infotext << "Order: " << plr.p->getorder() << " / " << plr.p->getorders() << + std::endl << "Pattern: " << plr.p->getpattern() << " / " << + plr.p->getpatterns() << std::endl << "Row: " << plr.p->getrow() << + std::endl << "Speed: " << plr.p->getspeed() << std::endl << "Timer: " << + plr.p->getrefresh() << "Hz" << std::ends; + + GDK_THREADS_ENTER(); + gtk_label_set_text(plr.infobox, infotext.str().c_str()); + GDK_THREADS_LEAVE(); +} +#endif + +// Define sampsize macro (only usable inside play_loop()!) +#define sampsize ((bit16 ? 2 : 1) * (stereo ? 2 : 1)) + +static void *play_loop(void *filename) +/* Main playback thread. Takes the filename to play as argument. */ +{ + dbg_printf("play_loop(\"%s\"): ", (char *)filename); + CEmuopl opl(cfg.freq, cfg.bit16, cfg.stereo); + long toadd = 0, i, towrite; + char *sndbuf, *sndbufpos; + bool playing = true, // Song self-end indicator. + bit16 = cfg.bit16, // Duplicate config, so it doesn't affect us if + stereo = cfg.stereo; // the user changes it while we're playing. + unsigned long freq = cfg.freq; + + // Try to load module + dbg_printf("factory, "); + if(!(plr.p = factory((char *)filename, &opl))) { + dbg_printf("error!\n"); + MessageBox("AdPlug :: Error", "File could not be opened!", "Ok"); + plr.playing = false; + g_thread_exit(NULL); + } + + // Cache song length + dbg_printf("length, "); + plr.songlength = plr.p->songlength(plr.subsong); + + // cache song title + dbg_printf("title, "); + if(!plr.p->gettitle().empty()) { + plr.songtitle = (char *)malloc(plr.p->gettitle().length() + 1); + strcpy(plr.songtitle, plr.p->gettitle().c_str()); + } + + // reset to first subsong on new file + dbg_printf("subsong, "); + if(strcmp((char *)filename, plr.filename)) { + strcpy(plr.filename, (char *)filename); + plr.subsong = 0; + } + + // Allocate audio buffer + dbg_printf("buffer, "); + sndbuf = (char *)malloc(SNDBUFSIZE * sampsize); + + // Set XMMS main window information + dbg_printf("xmms, "); + adplug_ip.set_info(plr.songtitle, plr.songlength, freq * sampsize * 8, + freq, stereo ? 2 : 1); + + // Rewind player to right subsong + dbg_printf("rewind, "); + plr.p->rewind(plr.subsong); + + // main playback loop + dbg_printf("loop.\n"); + while((playing || cfg.endless) && plr.playing) { + // seek requested ? + if(plr.seek != -1) { + // backward seek ? + if(plr.seek < plr.time_ms) { + plr.p->rewind(plr.subsong); + plr.time_ms = 0.0f; + } + + // seek to requested position + while((plr.time_ms < plr.seek) && plr.p->update()) + plr.time_ms += 1000 / plr.p->getrefresh(); + + // Reset output plugin and some values + adplug_ip.output->flush((int)plr.time_ms); + plr.seek = -1; + } + + // fill sound buffer + towrite = SNDBUFSIZE; sndbufpos = sndbuf; + while (towrite > 0) { + while (toadd < 0) { + toadd += freq; + playing = plr.p->update(); + plr.time_ms += 1000 / plr.p->getrefresh(); + } + i = MIN(towrite, (long)(toadd / plr.p->getrefresh() + 4) & ~3); + opl.update((short *)sndbufpos, i); + sndbufpos += i * sampsize; towrite -= i; + toadd -= (long)(plr.p->getrefresh() * i); + } + + // write sound buffer and update vis + adplug_ip.add_vis_pcm(adplug_ip.output->written_time(), + bit16 ? FORMAT_16 : FORMAT_8, + stereo ? 2 : 1, SNDBUFSIZE * sampsize, sndbuf); + while(adplug_ip.output->buffer_free() < SNDBUFSIZE * sampsize) xmms_usleep(10000); + adplug_ip.output->write_audio(sndbuf, SNDBUFSIZE * sampsize); + +#if 0 + // update infobox, if necessary + if(plr.infobox && plr.playing) update_infobox(); +#endif + } + + // playback finished - deinit + dbg_printf("play_loop(\"%s\"): ", (char *)filename); + if(!playing) { // wait for output plugin to finish if song has self-ended + dbg_printf("wait, "); + while(adplug_ip.output->buffer_playing()) xmms_usleep(10000); + } else { // or else, flush its output buffers + dbg_printf("flush, "); + adplug_ip.output->buffer_free(); adplug_ip.output->buffer_free(); + } + + // free everything and exit + dbg_printf("free"); + delete plr.p; plr.p = 0; + if(plr.songtitle) { free(plr.songtitle); plr.songtitle = NULL; } + free(sndbuf); + plr.playing = false; // important! XMMS won't get a self-ended song without it. + dbg_printf(".\n"); + g_thread_exit(NULL); +} + +// sampsize macro not useful anymore. +#undef sampsize + +/***** Informational *****/ + +static int adplug_is_our_file(char *filename) +{ + CSilentopl tmpopl; + CPlayer *p = factory(filename,&tmpopl); + + dbg_printf("adplug_is_our_file(\"%s\"): returned ",filename); + + if(p) { + delete p; + dbg_printf("TRUE\n"); + return TRUE; + } + + dbg_printf("FALSE\n"); + return FALSE; +} + +static int adplug_get_time(void) +{ + if(audio_error) { dbg_printf("adplug_get_time(): returned -2\n"); return -2; } + if(!plr.playing) { dbg_printf("adplug_get_time(): returned -1\n"); return -1; } + return adplug_ip.output->output_time(); +} + +static void adplug_song_info(char *filename, char **title, int *length) +{ + CSilentopl tmpopl; + CPlayer *p = factory(filename, &tmpopl); + + dbg_printf("adplug_song_info(\"%s\", \"%s\", %d): ", filename, *title, *length); + + if(p) { + // allocate and set title string + if(p->gettitle().empty()) + *title = 0; + else { + *title = (char *)malloc(p->gettitle().length() + 1); + strcpy(*title, p->gettitle().c_str()); + } + + // get song length + *length = p->songlength(plr.subsong); + + // delete temporary player object + delete p; + } + + dbg_printf("title = \"%s\", length = %d\n", *title, *length); +} + +/***** Player control *****/ + +static void adplug_play(char *filename) +{ + dbg_printf("adplug_play(\"%s\"): ", filename); + audio_error = FALSE; + +#if 0 + // On new song, re-open "Song info" dialog, if open + dbg_printf("dialog, "); + if(plr.infobox && strcmp(filename, plr.filename)) + gtk_widget_destroy(GTK_WIDGET(plr.infodlg)); +#endif + + // open output plugin + dbg_printf("open, "); + if (!adplug_ip.output->open_audio(cfg.bit16 ? FORMAT_16 : FORMAT_8, cfg.freq, cfg.stereo ? 2 : 1)) { + audio_error = TRUE; + return; + } + + // Initialize global player data (this is here to prevent a race condition + // between adplug_get_time() returning the playback state and adplug_loop() + // initializing the playback state) + dbg_printf("init, "); + plr.playing = true; plr.time_ms = 0.0f; plr.seek = -1; + + // start player thread + dbg_printf("create"); + plr.play_thread = g_thread_create(play_loop, filename, TRUE, NULL); + dbg_printf(".\n"); +} + +static void adplug_stop(void) +{ + dbg_printf("adplug_stop(): join, "); + plr.playing = false; g_thread_join(plr.play_thread); // stop player thread + dbg_printf("close"); adplug_ip.output->close_audio(); + dbg_printf(".\n"); +} + +static void adplug_pause(short paused) +{ + dbg_printf("adplug_pause(%d)\n", paused); + adplug_ip.output->pause(paused); +} + +static void adplug_seek(int time) +{ + dbg_printf("adplug_seek(%d)\n", time); + plr.seek = time * 1000; // time is in seconds, but we count in ms +} + +/***** Configuration file handling *****/ + +#define CFG_VERSION "AdPlug" + +static void adplug_init(void) +{ + dbg_printf("adplug_init(): open, "); + ConfigDb *db = bmp_cfg_db_open(); + + // Read configuration + dbg_printf("read, "); + bmp_cfg_db_get_bool(db, CFG_VERSION, "16bit", (gboolean *)&cfg.bit16); + bmp_cfg_db_get_bool(db, CFG_VERSION, "Stereo", (gboolean *)&cfg.stereo); + bmp_cfg_db_get_int(db, CFG_VERSION, "Frequency", (gint *)&cfg.freq); + bmp_cfg_db_get_bool(db, CFG_VERSION, "Endless", (gboolean *)&cfg.endless); + bmp_cfg_db_get_bool(db, CFG_VERSION, "QuickDetect", (gboolean *)&cfg.quickdetect); + + // Read file type exclusion list + dbg_printf("exclusion, "); + { + gchar *cfgstr = "", *exclude; + gboolean cfgread; + + cfgread = bmp_cfg_db_get_string(db, CFG_VERSION, "Exclude", &cfgstr); + exclude = (char *)malloc(strlen(cfgstr) + 2); strcpy(exclude, cfgstr); + exclude[strlen(exclude) + 1] = '\0'; + if(cfgread) free(cfgstr); + g_strdelimit(exclude, ":", '\0'); + for(gchar *p = exclude; *p; p += strlen(p) + 1) + cfg.players.remove(cfg.players.lookup_filetype(p)); + free(exclude); + } + bmp_cfg_db_close(db); + + // Load database from disk and hand it to AdPlug + dbg_printf("database"); + plr.db = new CAdPlugDatabase; + + { + const char *homedir = getenv("HOME"); + + if(homedir) { + char *userdb = (char *)malloc(strlen(homedir) + strlen(ADPLUG_CONFDIR) + + strlen(ADPLUGDB_FILE) + 3); + strcpy(userdb, homedir); strcat(userdb, "/" ADPLUG_CONFDIR "/"); + strcat(userdb, ADPLUGDB_FILE); + plr.db->load(userdb); // load user's database + dbg_printf(" (userdb=\"%s\")", userdb); + } + } + CAdPlug::set_database(plr.db); + dbg_printf(".\n"); +} + +static void adplug_quit(void) +{ + dbg_printf("adplug_quit(): open, "); + ConfigDb *db = bmp_cfg_db_open(); + + // Close database + dbg_printf("db, "); + if(plr.db) delete plr.db; + + // Write configuration + dbg_printf("write, "); + bmp_cfg_db_set_bool(db, CFG_VERSION, "16bit", cfg.bit16); + bmp_cfg_db_set_bool(db, CFG_VERSION, "Stereo", cfg.stereo); + bmp_cfg_db_set_int(db, CFG_VERSION, "Frequency", cfg.freq); + bmp_cfg_db_set_bool(db, CFG_VERSION, "Endless", cfg.endless); + bmp_cfg_db_set_bool(db, CFG_VERSION, "QuickDetect", cfg.quickdetect); + + dbg_printf("exclude, "); + std::string exclude; + for(CPlayers::const_iterator i = CAdPlug::players.begin(); + i != CAdPlug::players.end(); i++) + if(find(cfg.players.begin(), cfg.players.end(), *i) == cfg.players.end()) { + if(!exclude.empty()) exclude += ":"; + exclude += (*i)->filetype; + } + gchar *cfgval = g_strdup(exclude.c_str()); + bmp_cfg_db_set_string(db, CFG_VERSION, "Exclude", cfgval); + free(cfgval); + + dbg_printf("close"); + bmp_cfg_db_close(db); + dbg_printf(".\n"); +} + +/***** Plugin (exported) *****/ + +InputPlugin adplug_ip = + { + NULL, // handle (filled by XMMS) + NULL, // filename (filled by XMMS) + ADPLUG_NAME, // plugin description + adplug_init, // plugin functions... + adplug_about, + adplug_config, + adplug_is_our_file, + NULL, // scan_dir (look in Input/cdaudio/cdaudio.c) + adplug_play, + adplug_stop, + adplug_pause, + adplug_seek, + NULL, // set_eq + adplug_get_time, + NULL, // get_volume (handled by output plugin) + NULL, // set_volume (...) + adplug_quit, + NULL, // OBSOLETE - DO NOT USE! + NULL, // add_vis_pcm (filled by XMMS) + NULL, // set_info (filled by XMMS) + NULL, // set_info_text (filled by XMMS) + adplug_song_info, + NULL, // adplug_info_box was here (but it used deprecated GTK+ functions) + NULL // output plugin (filled by XMMS) + }; + +extern "C" InputPlugin *get_iplugin_info(void) +{ + return &adplug_ip; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/Makefile.am Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,21 @@ +noinst_LTLIBRARIES = libadplugcore.la + +libadplugcore_la_SOURCES = adplug.cpp emuopl.cpp fmopl.c diskopl.cpp debug.c \ +debug.h fprovide.cpp player.cpp database.cpp hsc.cpp sng.cpp imf.cpp \ +players.cpp protrack.cpp a2m.cpp adtrack.cpp amd.cpp bam.cpp d00.cpp dfm.cpp \ +hsp.cpp ksm.cpp mad.cpp mid.cpp mkj.cpp cff.cpp dmo.cpp s3m.cpp dtm.cpp \ +fmc.cpp mtk.cpp rad.cpp raw.cpp sa2.cpp xad.cpp flash.cpp bmf.cpp hybrid.cpp \ +hyp.cpp psi.cpp rat.cpp u6m.cpp rol.cpp mididata.h xsm.cpp adlibemu.c dro.cpp \ +lds.cpp + +# This is a hack. Throughout AdPlug, stricmp() is used to do caseless string +# comparations. UNIX libc's don't support stricmp(), but do support the BSD +# strcasecmp(), so we have to replace every occurance of stricmp() into +# strcasecmp(). stricmp() seems to be Windows, but maybe also POSIX... +AM_CPPFLAGS = -Dstricmp=strcasecmp + +noinst_HEADERS = adplug.h emuopl.h fmopl.h silentopl.h opl.h diskopl.h \ +a2m.h amd.h bam.h d00.h dfm.h hsc.h hsp.h imf.h ksm.h lds.h mid.h mkj.h \ +mtk.h protrack.h rad.h raw.h s3m.h sa2.h sng.h u6m.h player.h fmc.h mad.h \ +xad.h bmf.h flash.h hyp.h psi.h rat.h hybrid.h rol.h adtrack.h cff.h dtm.h \ +dmo.h fprovide.h database.h players.h xsm.h adlibemu.h kemuopl.h dro.h diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/Makefile.bt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/Makefile.bt Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,26 @@ +# AdPlug Makefile for Watcom and OpenWatcom +# Copyright (c) 2001 - 2004 Simon Peter + +# This flag is set to work around a bug in the Watcom 11.0c compiler in +# conjunction with the STLport library. Without it, the compiler will crash +# during compilation of some files and create very fragile code for others. +CXXFLAGS = -oi+ + +OUTPUT = adplug.lib + +OBJS = debug.obj adplug.obj emuopl.obj fmopl.obj realopl.obj analopl.obj & +diskopl.obj database.obj player.obj players.obj fprovide.obj protrack.obj & +a2m.obj hsc.obj imf.obj sng.obj amd.obj d00.obj dfm.obj hsp.obj ksm.obj & +mid.obj mkj.obj mtk.obj rad.obj raw.obj s3m.obj sa2.obj bam.obj xad.obj & +mad.obj fmc.obj bmf.obj flash.obj hybrid.obj hyp.obj psi.obj rat.obj lds.obj & +adtrack.obj cff.obj dtm.obj dmo.obj u6m.obj rol.obj xsm.obj dro.obj + +include_INST = protrack.h a2m.h amd.h d00.h dfm.h hsc.h hsp.h imf.h ksm.h & +mid.h mkj.h mtk.h rad.h raw.h s3m.h sa2.h sng.h bam.h xad.h mad.h fmc.h & +bmf.h flash.h hybrid.h hyp.h psi.h rat.h adplug.h emuopl.h fmopl.h realopl.h & +analopl.h diskopl.h player.h opl.h silentopl.h lds.h adtrack.h cff.h dtm.h & +dmo.h u6m.h rol.h database.h fprovide.h players.h xsm.h dro.h + +lib_INST = adplug.lib + +includesubdir = adplug diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/a2m.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/a2m.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,449 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * a2m.cpp - A2M Loader by Simon Peter + * + * NOTES: + * This loader detects and loads version 1, 4, 5 & 8 files. + * + * version 1-4 files: + * Following commands are ignored: + * FF1 - FF9, FAx - FEx + * + * version 5-8 files: + * Instrument panning is ignored. Flags byte is ignored. + * Following commands are ignored: + * Gxy, Hxy, Kxy - &xy + */ + +#include "a2m.h" + +const unsigned int Ca2mLoader::MAXFREQ = 2000, +Ca2mLoader::MINCOPY = ADPLUG_A2M_MINCOPY, +Ca2mLoader::MAXCOPY = ADPLUG_A2M_MAXCOPY, +Ca2mLoader::COPYRANGES = ADPLUG_A2M_COPYRANGES, +Ca2mLoader::CODESPERRANGE = ADPLUG_A2M_CODESPERRANGE, +Ca2mLoader::TERMINATE = 256, +Ca2mLoader::FIRSTCODE = ADPLUG_A2M_FIRSTCODE, +Ca2mLoader::MAXCHAR = FIRSTCODE + COPYRANGES * CODESPERRANGE - 1, +Ca2mLoader::SUCCMAX = MAXCHAR + 1, +Ca2mLoader::TWICEMAX = ADPLUG_A2M_TWICEMAX, +Ca2mLoader::ROOT = 1, Ca2mLoader::MAXBUF = 42 * 1024, +Ca2mLoader::MAXDISTANCE = 21389, Ca2mLoader::MAXSIZE = 21389 + MAXCOPY; + +const unsigned short Ca2mLoader::bitvalue[14] = + {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192}; + +const signed short Ca2mLoader::copybits[COPYRANGES] = + {4, 6, 8, 10, 12, 14}; + +const signed short Ca2mLoader::copymin[COPYRANGES] = + {0, 16, 80, 336, 1360, 5456}; + +CPlayer *Ca2mLoader::factory(Copl *newopl) +{ + return new Ca2mLoader(newopl); +} + +bool Ca2mLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + struct { + char id[10]; + unsigned long crc; + unsigned char version,numpats; + } ch; + int i,j,k,t; + unsigned int l; + unsigned char *org, *orgptr; + unsigned long alength; + unsigned short len[9], *secdata, *secptr; + const unsigned char convfx[16] = {0,1,2,23,24,3,5,4,6,9,17,13,11,19,7,14}; + const unsigned char convinf1[16] = {0,1,2,6,7,8,9,4,5,3,10,11,12,13,14,15}; + const unsigned char newconvfx[] = {0,1,2,3,4,5,6,23,24,21,10,11,17,13,7,19, + 255,255,22,25,255,15,255,255,255,255,255, + 255,255,255,255,255,255,255,255,14,255}; + + // read header + f->readString(ch.id, 10); ch.crc = f->readInt(4); + ch.version = f->readInt(1); ch.numpats = f->readInt(1); + + // file validation section + if(strncmp(ch.id,"_A2module_",10) || (ch.version != 1 && ch.version != 5 && + ch.version != 4 && ch.version != 8)) { + fp.close(f); + return false; + } + + // load, depack & convert section + nop = ch.numpats; length = 128; restartpos = 0; activechan = 0xffff; + if(ch.version == 1 || ch.version == 4) { + for(i=0;i<5;i++) len[i] = f->readInt(2); + t = 9; + } else { + for(i=0;i<9;i++) len[i] = f->readInt(2); + t = 18; + } + + // block 0 + secdata = new unsigned short [len[0] / 2]; + if(ch.version == 1 || ch.version == 5) { + for(i=0;ireadInt(2); + org = new unsigned char [MAXBUF]; orgptr = org; + sixdepak(secdata,org,len[0]); + } else { + orgptr = (unsigned char *)secdata; + for(i=0;ireadInt(1); + } + memcpy(songname,orgptr,43); orgptr += 43; + memcpy(author,orgptr,43); orgptr += 43; + memcpy(instname,orgptr,250*33); orgptr += 250*33; + for(i=0;i<250;i++) { // instruments + inst[i].data[0] = *(orgptr+i*13+10); + inst[i].data[1] = *(orgptr+i*13); + inst[i].data[2] = *(orgptr+i*13+1); + inst[i].data[3] = *(orgptr+i*13+4); + inst[i].data[4] = *(orgptr+i*13+5); + inst[i].data[5] = *(orgptr+i*13+6); + inst[i].data[6] = *(orgptr+i*13+7); + inst[i].data[7] = *(orgptr+i*13+8); + inst[i].data[8] = *(orgptr+i*13+9); + inst[i].data[9] = *(orgptr+i*13+2); + inst[i].data[10] = *(orgptr+i*13+3); + if(ch.version == 1 || ch.version == 4) + inst[i].misc = *(orgptr+i*13+11); + else + inst[i].misc = 0; + inst[i].slide = *(orgptr+i*13+12); + } + + orgptr += 250*13; + memcpy(order,orgptr,128); orgptr += 128; + bpm = *orgptr; orgptr += 1; + initspeed = *orgptr; + // v5-8 files have an additional flag byte here + if(ch.version == 1 || ch.version == 5) + delete [] org; + delete [] secdata; + + // blocks 1-4 or 1-8 + alength = len[1]; + for(i=0;i<(ch.version == 1 || ch.version == 4 ? ch.numpats/16 : ch.numpats/8);i++) + alength += len[i+2]; + + secdata = new unsigned short [alength / 2]; + if(ch.version == 1 || ch.version == 5) { + for(l=0;lreadInt(2); + org = new unsigned char [MAXBUF * (ch.numpats / (ch.version == 1 ? 16 : 8) + 1)]; + orgptr = org; secptr = secdata; + orgptr += sixdepak(secptr,orgptr,len[1]); secptr += len[1] / 2; + if(ch.version == 1) { + if(ch.numpats > 16) + orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2; + if(ch.numpats > 32) + orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2; + if(ch.numpats > 48) + sixdepak(secptr,orgptr,len[4]); + } else { + if(ch.numpats > 8) + orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2; + if(ch.numpats > 16) + orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2; + if(ch.numpats > 24) + orgptr += sixdepak(secptr,orgptr,len[4]); secptr += len[4] / 2; + if(ch.numpats > 32) + orgptr += sixdepak(secptr,orgptr,len[5]); secptr += len[5] / 2; + if(ch.numpats > 40) + orgptr += sixdepak(secptr,orgptr,len[6]); secptr += len[6] / 2; + if(ch.numpats > 48) + orgptr += sixdepak(secptr,orgptr,len[7]); secptr += len[7] / 2; + if(ch.numpats > 56) + sixdepak(secptr,orgptr,len[8]); + } + delete [] secdata; + } else { + org = (unsigned char *)secdata; + for(l=0;lreadInt(1); + } + + for(i=0;i<64*9;i++) // patterns + trackord[i/9][i%9] = i+1; + + if(ch.version == 1 || ch.version == 4) { + for(i=0;i> 4; + else { + tracks[i*9+k][j].param1 = convinf1[org[i*64*t*4+j*t*4+k*4+3] >> 4]; + if(tracks[i*9+k][j].param1 == 15 && !tracks[i*9+k][j].param2) { // convert key-off + tracks[i*9+k][j].command = 8; + tracks[i*9+k][j].param1 = 0; + tracks[i*9+k][j].param2 = 0; + } + } + if(tracks[i*9+k][j].command == 14) { + switch(tracks[i*9+k][j].param1) { + case 2: // convert define waveform + tracks[i*9+k][j].command = 25; + tracks[i*9+k][j].param1 = tracks[i*9+k][j].param2; + tracks[i*9+k][j].param2 = 0xf; + break; + case 8: // convert volume slide up + tracks[i*9+k][j].command = 26; + tracks[i*9+k][j].param1 = tracks[i*9+k][j].param2; + tracks[i*9+k][j].param2 = 0; + break; + case 9: // convert volume slide down + tracks[i*9+k][j].command = 26; + tracks[i*9+k][j].param1 = 0; + break; + } + } + } + } else { + for(i=0;i> 4; + tracks[i*9+j][k].param2 = org[i*64*t*4+j*64*4+k*4+3] & 0x0f; + } + } + + if(ch.version == 1 || ch.version == 5) + delete [] org; + else + delete [] secdata; + fp.close(f); + rewind(0); + return true; +} + +float Ca2mLoader::getrefresh() +{ + if(tempo != 18) + return (float) (tempo); + else + return 18.2f; +} + +/*** private methods *************************************/ + +void Ca2mLoader::inittree() +{ + unsigned short i; + + for(i=2;i<=TWICEMAX;i++) { + dad[i] = i / 2; + freq[i] = 1; + } + + for(i=1;i<=MAXCHAR;i++) { + leftc[i] = 2 * i; + rghtc[i] = 2 * i + 1; + } +} + +void Ca2mLoader::updatefreq(unsigned short a,unsigned short b) +{ + do { + freq[dad[a]] = freq[a] + freq[b]; + a = dad[a]; + if(a != ROOT) + if(leftc[dad[a]] == a) + b = rghtc[dad[a]]; + else + b = leftc[dad[a]]; + } while(a != ROOT); + + if(freq[ROOT] == MAXFREQ) + for(a=1;a<=TWICEMAX;a++) + freq[a] >>= 1; +} + +void Ca2mLoader::updatemodel(unsigned short code) +{ + unsigned short a=code+SUCCMAX,b,c,code1,code2; + + freq[a]++; + if(dad[a] != ROOT) { + code1 = dad[a]; + if(leftc[code1] == a) + updatefreq(a,rghtc[code1]); + else + updatefreq(a,leftc[code1]); + + do { + code2 = dad[code1]; + if(leftc[code2] == code1) + b = rghtc[code2]; + else + b = leftc[code2]; + + if(freq[a] > freq[b]) { + if(leftc[code2] == code1) + rghtc[code2] = a; + else + leftc[code2] = a; + + if(leftc[code1] == a) { + leftc[code1] = b; + c = rghtc[code1]; + } else { + rghtc[code1] = b; + c = leftc[code1]; + } + + dad[b] = code1; + dad[a] = code2; + updatefreq(b,c); + a = b; + } + + a = dad[a]; + code1 = dad[a]; + } while(code1 != ROOT); + } +} + +unsigned short Ca2mLoader::inputcode(unsigned short bits) +{ + unsigned short i,code=0; + + for(i=1;i<=bits;i++) { + if(!ibitcount) { + if(ibitcount == MAXBUF) + ibufcount = 0; + ibitbuffer = wdbuf[ibufcount]; + ibufcount++; + ibitcount = 15; + } else + ibitcount--; + + if(ibitbuffer > 0x7fff) + code |= bitvalue[i-1]; + ibitbuffer <<= 1; + } + + return code; +} + +unsigned short Ca2mLoader::uncompress() +{ + unsigned short a=1; + + do { + if(!ibitcount) { + if(ibufcount == MAXBUF) + ibufcount = 0; + ibitbuffer = wdbuf[ibufcount]; + ibufcount++; + ibitcount = 15; + } else + ibitcount--; + + if(ibitbuffer > 0x7fff) + a = rghtc[a]; + else + a = leftc[a]; + ibitbuffer <<= 1; + } while(a <= MAXCHAR); + + a -= SUCCMAX; + updatemodel(a); + return a; +} + +void Ca2mLoader::decode() +{ + unsigned short i,j,k,t,c,count=0,dist,len,index; + + inittree(); + c = uncompress(); + + while(c != TERMINATE) { + if(c < 256) { + obuf[obufcount] = (unsigned char)c; + obufcount++; + if(obufcount == MAXBUF) { + output_size = MAXBUF; + obufcount = 0; + } + + buf[count] = (unsigned char)c; + count++; + if(count == MAXSIZE) + count = 0; + } else { + t = c - FIRSTCODE; + index = t / CODESPERRANGE; + len = t + MINCOPY - index * CODESPERRANGE; + dist = inputcode(copybits[index]) + len + copymin[index]; + + j = count; + k = count - dist; + if(count < dist) + k += MAXSIZE; + + for(i=0;i<=len-1;i++) { + obuf[obufcount] = buf[k]; + obufcount++; + if(obufcount == MAXBUF) { + output_size = MAXBUF; + obufcount = 0; + } + + buf[j] = buf[k]; + j++; k++; + if(j == MAXSIZE) j = 0; + if(k == MAXSIZE) k = 0; + } + + count += len; + if(count >= MAXSIZE) + count -= MAXSIZE; + } + c = uncompress(); + } + output_size = obufcount; +} + +unsigned short Ca2mLoader::sixdepak(unsigned short *source, unsigned char *dest, + unsigned short size) +{ + if((unsigned int)size + 4096 > MAXBUF) + return 0; + + buf = new unsigned char [MAXSIZE]; + input_size = size; + ibitcount = 0; ibitbuffer = 0; + obufcount = 0; ibufcount = 0; + wdbuf = source; obuf = dest; + + decode(); + delete [] buf; + return output_size; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/a2m.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/a2m.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,80 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * a2m.h - A2M Loader by Simon Peter + */ + +#include "protrack.h" + +class Ca2mLoader: public CmodPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + Ca2mLoader(Copl *newopl) + : CmodPlayer(newopl) + { }; + + bool load(const std::string &filename, const CFileProvider &fp); + float getrefresh(); + + std::string gettype() + { return std::string("AdLib Tracker 2"); }; + std::string gettitle() + { if(*songname) return std::string(songname,1,*songname); else return std::string(); }; + std::string getauthor() + { if(*author) return std::string(author,1,*author); else return std::string(); }; + unsigned int getinstruments() + { return 250; }; + std::string getinstrument(unsigned int n) + { return std::string(instname[n],1,*instname[n]); }; + +private: + +#define ADPLUG_A2M_COPYRANGES 6 +#define ADPLUG_A2M_FIRSTCODE 257 +#define ADPLUG_A2M_MINCOPY 3 +#define ADPLUG_A2M_MAXCOPY 255 +#define ADPLUG_A2M_CODESPERRANGE (ADPLUG_A2M_MAXCOPY - ADPLUG_A2M_MINCOPY + 1) +#define ADPLUG_A2M_MAXCHAR (ADPLUG_A2M_FIRSTCODE + \ + ADPLUG_A2M_COPYRANGES * ADPLUG_A2M_CODESPERRANGE - 1) +#define ADPLUG_A2M_TWICEMAX (2 * ADPLUG_A2M_MAXCHAR + 1) + + static const unsigned int MAXFREQ, MINCOPY, MAXCOPY, COPYRANGES, + CODESPERRANGE, TERMINATE, FIRSTCODE, MAXCHAR, SUCCMAX, TWICEMAX, ROOT, + MAXBUF, MAXDISTANCE, MAXSIZE; + + static const unsigned short bitvalue[14]; + static const signed short copybits[ADPLUG_A2M_COPYRANGES], + copymin[ADPLUG_A2M_COPYRANGES]; + + void inittree(); + void updatefreq(unsigned short a,unsigned short b); + void updatemodel(unsigned short code); + unsigned short inputcode(unsigned short bits); + unsigned short uncompress(); + void decode(); + unsigned short sixdepak(unsigned short *source,unsigned char *dest,unsigned short size); + + char songname[43], author[43], instname[250][33]; + + unsigned short ibitcount, ibitbuffer, ibufcount, obufcount, input_size, + output_size, leftc[ADPLUG_A2M_MAXCHAR+1], rghtc[ADPLUG_A2M_MAXCHAR+1], + dad[ADPLUG_A2M_TWICEMAX+1], freq[ADPLUG_A2M_TWICEMAX+1], *wdbuf; + unsigned char *obuf, *buf; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/adlibemu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/adlibemu.c Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,600 @@ +/* + * ADLIBEMU.C + * Copyright (C) 1998-2001 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* +This file is a digital Adlib emulator for OPL2 and possibly OPL3 + +Features that could be added in a future version: +- Amplitude and Frequency Vibrato Bits (not hard, but a big speed hit) +- Global Keyboard Split Number Bit (need to research this one some more) +- 2nd Adlib chip for OPL3 (simply need to make my cell array bigger) +- Advanced connection modes of OPL3 (Just need to add more "docell" cases) +- L/R Stereo bits of OPL3 (Need adlibgetsample to return stereo) + +Features that aren't worth supporting: +- Anything related to adlib timers&interrupts (Sorry - I always used IRQ0) +- Composite sine wave mode (CSM) (Supported only on ancient cards) + +I'm not sure about a few things in my code: +- Attack curve. What function is this anyway? I chose to use an order-3 + polynomial to approximate but this doesn't seem right. +- Attack/Decay/Release constants - my constants may not be exact +- What should ADJUSTSPEED be? +- Haven't verified that Global Keyboard Split Number Bit works yet +- Some of the drums don't always sound right. It's pretty hard to guess + the exact waveform of drums when you look at random data which is + slightly randomized due to digital ADC recording. +- Adlib seems to have a lot more treble than my emulator does. I'm not + sure if this is simply unfixable due to the sound blaster's different + filtering on FM and digital playback or if it's a serious bug in my + code. +*/ + +#include +#include + +#if !defined(max) && !defined(__cplusplus) +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#if !defined(min) && !defined(__cplusplus) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define PI 3.141592653589793 +#define MAXCELLS 18 +#define WAVPREC 2048 + +static float AMPSCALE=(8192.0); +#define FRQSCALE (49716/512.0) + +//Constants for Ken's Awe32, on a PII-266 (Ken says: Use these for KSM's!) +#define MODFACTOR 4.0 //How much of modulator cell goes into carrier +#define MFBFACTOR 1.0 //How much feedback goes back into modulator +#define ADJUSTSPEED 0.75 //0<=x<=1 Simulate finite rate of change of state + +//Constants for Ken's Awe64G, on a P-133 +//#define MODFACTOR 4.25 //How much of modulator cell goes into carrier +//#define MFBFACTOR 0.5 //How much feedback goes back into modulator +//#define ADJUSTSPEED 0.85 //0<=x<=1 Simulate finite rate of change of state + +typedef struct +{ + float val, t, tinc, vol, sustain, amp, mfb; + float a0, a1, a2, a3, decaymul, releasemul; + short *waveform; + long wavemask; + void (*cellfunc)(void *, float); + unsigned char flags, dum0, dum1, dum2; +} celltype; + +static long numspeakers, bytespersample; +static float recipsamp; +static celltype cell[MAXCELLS]; +static signed short wavtable[WAVPREC*3]; +static float kslmul[4] = {0.0,0.5,0.25,1.0}; +static float frqmul[16] = {.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15}, nfrqmul[16]; +static unsigned char adlibreg[256], ksl[8][16]; +static unsigned char modulatorbase[9] = {0,1,2,8,9,10,16,17,18}; +static unsigned char odrumstat = 0; +static unsigned char base2cell[22] = {0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8}; + +float lvol[9] = {1,1,1,1,1,1,1,1,1}; //Volume multiplier on left speaker +float rvol[9] = {1,1,1,1,1,1,1,1,1}; //Volume multiplier on right speaker +long lplc[9] = {0,0,0,0,0,0,0,0,0}; //Samples to delay on left speaker +long rplc[9] = {0,0,0,0,0,0,0,0,0}; //Samples to delay on right speaker + +long nlvol[9], nrvol[9]; +long nlplc[9], nrplc[9]; +long rend = 0; +#define FIFOSIZ 256 +static float *rptr[9], *nrptr[9]; +static float rbuf[9][FIFOSIZ*2]; +static float snd[FIFOSIZ*2]; + +#ifndef USING_ASM +#define _inline +#endif + +#ifdef USING_ASM +static _inline void ftol (float f, long *a) +{ + _asm + { + mov eax, a + fld f + fistp dword ptr [eax] + } +} +#else +static void ftol(float f, long *a) { + *a=f; +} +#endif + +#define ctc ((celltype *)c) //A rare attempt to make code easier to read! +void docell4 (void *c, float modulator) { } +void docell3 (void *c, float modulator) +{ + long i; + + ftol(ctc->t+modulator,&i); + ctc->t += ctc->tinc; + ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED; +} +void docell2 (void *c, float modulator) +{ + long i; + + ftol(ctc->t+modulator,&i); + + if (*(long *)&ctc->amp <= 0x37800000) + { + ctc->amp = 0; + ctc->cellfunc = docell4; + } + ctc->amp *= ctc->releasemul; + + ctc->t += ctc->tinc; + ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED; +} +void docell1 (void *c, float modulator) +{ + long i; + + ftol(ctc->t+modulator,&i); + + if ((*(long *)&ctc->amp) <= (*(long *)&ctc->sustain)) + { + if (ctc->flags&32) + { + ctc->amp = ctc->sustain; + ctc->cellfunc = docell3; + } + else + ctc->cellfunc = docell2; + } + else + ctc->amp *= ctc->decaymul; + + ctc->t += ctc->tinc; + ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED; +} +void docell0 (void *c, float modulator) +{ + long i; + + ftol(ctc->t+modulator,&i); + + ctc->amp = ((ctc->a3*ctc->amp + ctc->a2)*ctc->amp + ctc->a1)*ctc->amp + ctc->a0; + if ((*(long *)&ctc->amp) > 0x3f800000) + { + ctc->amp = 1; + ctc->cellfunc = docell1; + } + + ctc->t += ctc->tinc; + ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED; +} + + +static long waveform[8] = {WAVPREC,WAVPREC>>1,WAVPREC,(WAVPREC*3)>>2,0,0,(WAVPREC*5)>>2,WAVPREC<<1}; +static long wavemask[8] = {WAVPREC-1,WAVPREC-1,(WAVPREC>>1)-1,(WAVPREC>>1)-1,WAVPREC-1,((WAVPREC*3)>>2)-1,WAVPREC>>1,WAVPREC-1}; +static long wavestart[8] = {0,WAVPREC>>1,0,WAVPREC>>2,0,0,0,WAVPREC>>3}; +static float attackconst[4] = {1/2.82624,1/2.25280,1/1.88416,1/1.59744}; +static float decrelconst[4] = {1/39.28064,1/31.41608,1/26.17344,1/22.44608}; +void cellon (long i, long j, celltype *c, unsigned char iscarrier) +{ + long frn, oct, toff; + float f; + + frn = ((((long)adlibreg[i+0xb0])&3)<<8) + (long)adlibreg[i+0xa0]; + oct = ((((long)adlibreg[i+0xb0])>>2)&7); + toff = (oct<<1) + ((frn>>9)&((frn>>8)|(((adlibreg[8]>>6)&1)^1))); + if (!(adlibreg[j+0x20]&16)) toff >>= 2; + + f = pow(2.0,(adlibreg[j+0x60]>>4)+(toff>>2)-1)*attackconst[toff&3]*recipsamp; + c->a0 = .0377*f; c->a1 = 10.73*f+1; c->a2 = -17.57*f; c->a3 = 7.42*f; + f = -7.4493*decrelconst[toff&3]*recipsamp; + c->decaymul = pow(2.0,f*pow(2.0,(adlibreg[j+0x60]&15)+(toff>>2))); + c->releasemul = pow(2.0,f*pow(2.0,(adlibreg[j+0x80]&15)+(toff>>2))); + c->wavemask = wavemask[adlibreg[j+0xe0]&7]; + c->waveform = &wavtable[waveform[adlibreg[j+0xe0]&7]]; + if (!(adlibreg[1]&0x20)) c->waveform = &wavtable[WAVPREC]; + c->t = wavestart[adlibreg[j+0xe0]&7]; + c->flags = adlibreg[j+0x20]; + c->cellfunc = docell0; + c->tinc = (float)(frn<vol = pow(2.0,((float)(adlibreg[j+0x40]&63) + + (float)kslmul[adlibreg[j+0x40]>>6]*ksl[oct][frn>>6]) * -.125 - 14); + c->sustain = pow(2.0,(float)(adlibreg[j+0x80]>>4) * -.5); + if (!iscarrier) c->amp = 0; + c->mfb = pow(2.0,((adlibreg[i+0xc0]>>1)&7)+5)*(WAVPREC/2048.0)*MFBFACTOR; + if (!(adlibreg[i+0xc0]&14)) c->mfb = 0; + c->val = 0; +} + +//This function (and bug fix) written by Chris Moeller +void cellfreq (signed long i, signed long j, celltype *c) +{ + long frn, oct; + + frn = ((((long)adlibreg[i+0xb0])&3)<<8) + (long)adlibreg[i+0xa0]; + oct = ((((long)adlibreg[i+0xb0])>>2)&7); + + c->tinc = (float)(frn<vol = pow(2.0,((float)(adlibreg[j+0x40]&63) + + (float)kslmul[adlibreg[j+0x40]>>6]*ksl[oct][frn>>6]) * -.125 - 14); +} + +static long initfirstime = 0; +void adlibinit (long dasamplerate, long danumspeakers, long dabytespersample) +{ + long i, j, frn, oct; + + memset((void *)adlibreg,0,sizeof(adlibreg)); + memset((void *)cell,0,sizeof(celltype)*MAXCELLS); + memset((void *)rbuf,0,sizeof(rbuf)); + rend = 0; odrumstat = 0; + + for(i=0;i=0;i--) nfrqmul[i] = frqmul[i]*recipsamp*FRQSCALE*(WAVPREC/2048.0); + + if (!initfirstime) + { + initfirstime = 1; + + for(i=0;i<(WAVPREC>>1);i++) + { + wavtable[i] = + wavtable[(i<<1) +WAVPREC] = (signed short)(16384*sin((float)((i<<1) )*PI*2/WAVPREC)); + wavtable[(i<<1)+1+WAVPREC] = (signed short)(16384*sin((float)((i<<1)+1)*PI*2/WAVPREC)); + } + for(i=0;i<(WAVPREC>>3);i++) + { + wavtable[i+(WAVPREC<<1)] = wavtable[i+(WAVPREC>>3)]-16384; + wavtable[i+((WAVPREC*17)>>3)] = wavtable[i+(WAVPREC>>2)]+16384; + } + + //[table in book]*8/3 + ksl[7][0] = 0; ksl[7][1] = 24; ksl[7][2] = 32; ksl[7][3] = 37; + ksl[7][4] = 40; ksl[7][5] = 43; ksl[7][6] = 45; ksl[7][7] = 47; + ksl[7][8] = 48; for(i=9;i<16;i++) ksl[7][i] = i+41; + for(j=6;j>=0;j--) + for(i=0;i<16;i++) + { + oct = (long)ksl[j+1][i]-8; if (oct < 0) oct = 0; + ksl[j][i] = (unsigned char)oct; + } + } + else + { + for(i=0;i<9;i++) + { + frn = ((((long)adlibreg[i+0xb0])&3)<<8) + (long)adlibreg[i+0xa0]; + oct = ((((long)adlibreg[i+0xb0])>>2)&7); + cell[i].tinc = (float)(frn< (odrumstat&16)) //BassDrum + { + cellon(6,16,&cell[6],0); + cellon(6,19,&cell[15],1); + cell[15].vol *= 2; + } + if ((v&8) > (odrumstat&8)) //Snare + { + cellon(16,20,&cell[16],0); + cell[16].tinc *= 2*(nfrqmul[adlibreg[17+0x20]&15] / nfrqmul[adlibreg[20+0x20]&15]); + if (((adlibreg[20+0xe0]&7) >= 3) && ((adlibreg[20+0xe0]&7) <= 5)) cell[16].vol = 0; + cell[16].vol *= 2; + } + if ((v&4) > (odrumstat&4)) //TomTom + { + cellon(8,18,&cell[8],0); + cell[8].vol *= 2; + } + if ((v&2) > (odrumstat&2)) //Cymbal + { + cellon(17,21,&cell[17],0); + + cell[17].wavemask = wavemask[5]; + cell[17].waveform = &wavtable[waveform[5]]; + cell[17].tinc *= 16; cell[17].vol *= 2; + + //cell[17].waveform = &wavtable[WAVPREC]; cell[17].wavemask = 0; + //if (((adlibreg[21+0xe0]&7) == 0) || ((adlibreg[21+0xe0]&7) == 6)) + // cell[17].waveform = &wavtable[(WAVPREC*7)>>2]; + //if (((adlibreg[21+0xe0]&7) == 2) || ((adlibreg[21+0xe0]&7) == 3)) + // cell[17].waveform = &wavtable[(WAVPREC*5)>>2]; + } + if ((v&1) > (odrumstat&1)) //Hihat + { + cellon(7,17,&cell[7],0); + if (((adlibreg[17+0xe0]&7) == 1) || ((adlibreg[17+0xe0]&7) == 4) || + ((adlibreg[17+0xe0]&7) == 5) || ((adlibreg[17+0xe0]&7) == 7)) cell[7].vol = 0; + if ((adlibreg[17+0xe0]&7) == 6) { cell[7].wavemask = 0; cell[7].waveform = &wavtable[(WAVPREC*7)>>2]; } + } + + odrumstat = v; + } + else if (((unsigned)(i-0x40) < (unsigned)22) && ((i&7) < 6)) + { + if ((i&7) < 3) // Modulator + cellfreq(base2cell[i-0x40],i-0x40,&cell[base2cell[i-0x40]]); + else // Carrier + cellfreq(base2cell[i-0x40],i-0x40,&cell[base2cell[i-0x40]+9]); + } + else if ((unsigned)(i-0xa0) < (unsigned)9) + { + cellfreq(i-0xa0,modulatorbase[i-0xa0],&cell[i-0xa0]); + cellfreq(i-0xa0,modulatorbase[i-0xa0]+3,&cell[i-0xa0+9]); + } + else if ((unsigned)(i-0xb0) < (unsigned)9) + { + if ((v&32) > (tmp&32)) + { + cellon(i-0xb0,modulatorbase[i-0xb0],&cell[i-0xb0],0); + cellon(i-0xb0,modulatorbase[i-0xb0]+3,&cell[i-0xb0+9],1); + } + else if ((v&32) < (tmp&32)) + cell[i-0xb0].cellfunc = cell[i-0xb0+9].cellfunc = docell2; + cellfreq(i-0xb0,modulatorbase[i-0xb0],&cell[i-0xb0]); + cellfreq(i-0xb0,modulatorbase[i-0xb0]+3,&cell[i-0xb0+9]); + } + + //outdata(i,v); +} + +#ifdef USING_ASM +static long fpuasm; +static float fakeadd = 8388608.0+128.0; +static _inline void clipit8 (float f, long a) +{ + _asm + { + mov edi, a + fld dword ptr f + fadd dword ptr fakeadd + fstp dword ptr fpuasm + mov eax, fpuasm + test eax, 0x007fff00 + jz short skipit + shr eax, 16 + xor eax, -1 + skipit: mov byte ptr [edi], al + } +} + +static _inline void clipit16 (float f, long a) +{ + _asm + { + mov eax, a + fld dword ptr f + fist word ptr [eax] + cmp word ptr [eax], 0x8000 + jne short skipit2 + fst dword ptr [fpuasm] + cmp fpuasm, 0x80000000 + sbb word ptr [eax], 0 + skipit2: fstp st + } +} +#else +static void clipit8(float f,unsigned char *a) { + f/=256.0; + f+=128.0; + if (f>254.5) *a=255; + else if (f<0.5) *a=0; + else *a=f; +} + +static void clipit16(float f,short *a) { + if (f>32766.5) *a=32767; + else if (f<-32767.5) *a=-32768; + else *a=f; +} +#endif + +void adlibsetvolume(int i) { + AMPSCALE=i; +} + +void adlibgetsample (unsigned char *sndptr, long numbytes) +{ + long i, j, k=0, ns, endsamples, rptrs, numsamples; + celltype *cptr; + float f; + short *sndptr2=(short *)sndptr; + + numsamples = (numbytes>>(numspeakers+bytespersample-2)); + + if (bytespersample == 1) f = AMPSCALE/256.0; else f = AMPSCALE; + if (numspeakers == 1) + { + nlvol[0] = lvol[0]*f; + for(i=0;i<9;i++) rptr[i] = &rbuf[0][0]; + rptrs = 1; + } + else + { + rptrs = 0; + for(i=0;i<9;i++) + { + if ((!i) || (lvol[i] != lvol[i-1]) || (rvol[i] != rvol[i-1]) || + (lplc[i] != lplc[i-1]) || (rplc[i] != rplc[i-1])) + { + nlvol[rptrs] = lvol[i]*f; + nrvol[rptrs] = rvol[i]*f; + nlplc[rptrs] = rend-min(max(lplc[i],0),FIFOSIZ); + nrplc[rptrs] = rend-min(max(rplc[i],0),FIFOSIZ); + rptrs++; + } + rptr[i] = &rbuf[rptrs-1][0]; + } + } + + + //CPU time used to be somewhat less when emulator was only mono! + // Because of no delay fifos! + + for(ns=0;ns>1)-1)); //Snare + (cell[7].cellfunc)((void *)&cell[7],k&(WAVPREC-1)); //Hihat + (cell[17].cellfunc)((void *)&cell[17],k&((WAVPREC>>3)-1)); //Cymbal + (cell[8].cellfunc)((void *)&cell[8],0.0); //TomTom + nrptr[7][i] += cell[7].val + cell[16].val; + nrptr[8][i] += cell[8].val + cell[17].val; + } + } + } + for(j=9-1;j>=0;j--) + { + if ((adlibreg[0xbd]&0x20) && (j >= 6) && (j < 9)) continue; + + cptr = &cell[j]; k = j; + if (adlibreg[0xc0+k]&1) + { + if ((cptr[9].cellfunc == docell4) && (cptr->cellfunc == docell4)) continue; + for(i=0;icellfunc)((void *)cptr,cptr->val*cptr->mfb); + (cptr->cellfunc)((void *)&cptr[9],0); + nrptr[j][i] += cptr[9].val + cptr->val; + } + } + else + { + if (cptr[9].cellfunc == docell4) continue; + for(i=0;icellfunc)((void *)cptr,cptr->val*cptr->mfb); + (cptr[9].cellfunc)((void *)&cptr[9],cptr->val*WAVPREC*MODFACTOR); + nrptr[j][i] += cptr[9].val; + } + } + } + + if (numspeakers == 1) + { + if (bytespersample == 1) + { + for(i=endsamples-1;i>=0;i--) + clipit8(nrptr[0][i]*nlvol[0],sndptr+1); + } + else + { + for(i=endsamples-1;i>=0;i--) + clipit16(nrptr[0][i]*nlvol[0],sndptr2+i); + } + } + else + { + memset((void *)snd,0,endsamples*sizeof(float)*2); + for(j=0;j=0;i--) + clipit8(snd[i],sndptr+i); + } + else + { + for(i=(endsamples<<1)-1;i>=0;i--) + clipit16(snd[i],sndptr2+i); + } + } + + sndptr = sndptr+(numspeakers*endsamples); + sndptr2 = sndptr2+(numspeakers*endsamples); + rend = ((rend+endsamples)&(FIFOSIZ*2-1)); + } +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/adlibemu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/adlibemu.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,26 @@ +/* + * ADLIBEMU.H + * Copyright (C) 1998-2001 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void adlibinit(long dasamplerate,long danumspeakers,long dabytespersample); +void adlib0(long i,long v); +void adlibgetsample(void *sndptr,long numbytes); +void adlibsetvolume(int i); +void randoinsts(); +extern float lvol[9],rvol[9],lplc[9],rplc[9]; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/adplug.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/adplug.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,179 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2005 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * adplug.cpp - CAdPlug utility class, by Simon Peter + */ + +#include +#include + +#include "adplug.h" +#include "debug.h" + +/***** Replayer includes *****/ + +#include "hsc.h" +#include "amd.h" +#include "a2m.h" +#include "imf.h" +#include "sng.h" +#include "adtrack.h" +#include "bam.h" +#include "d00.h" +#include "dfm.h" +#include "hsp.h" +#include "ksm.h" +#include "mad.h" +#include "mid.h" +#include "mkj.h" +#include "cff.h" +#include "dmo.h" +#include "s3m.h" +#include "dtm.h" +#include "fmc.h" +#include "mtk.h" +#include "rad.h" +#include "raw.h" +#include "sa2.h" +#include "bmf.h" +#include "flash.h" +#include "hybrid.h" +#include "hyp.h" +#include "psi.h" +#include "rat.h" +#include "lds.h" +#include "u6m.h" +#include "rol.h" +#include "xsm.h" +#include "dro.h" + +/***** Defines *****/ + +#define VERSION "1.5.1" // AdPlug library version string + +/***** CAdPlug *****/ + +// List of all players that come with the standard AdPlug distribution +const CPlayerDesc CAdPlug::allplayers[] = { + CPlayerDesc(ChscPlayer::factory, "HSC-Tracker", ".hsc\0"), + CPlayerDesc(CsngPlayer::factory, "SNGPlay", ".sng\0"), + CPlayerDesc(CimfPlayer::factory, "Apogee IMF", ".imf\0.wlf\0.adlib\0"), + CPlayerDesc(Ca2mLoader::factory, "Adlib Tracker 2", ".a2m\0"), + CPlayerDesc(CadtrackLoader::factory, "Adlib Tracker", ".sng\0"), + CPlayerDesc(CamdLoader::factory, "AMUSIC", ".amd\0"), + CPlayerDesc(CbamPlayer::factory, "Bob's Adlib Music", ".bam\0"), + CPlayerDesc(Cd00Player::factory, "Packed EdLib", ".d00\0"), + CPlayerDesc(CdfmLoader::factory, "Digital-FM", ".dfm\0"), + CPlayerDesc(ChspLoader::factory, "HSC Packed", ".hsp\0"), + CPlayerDesc(CksmPlayer::factory, "Ken Silverman Music", ".ksm\0"), + CPlayerDesc(CmadLoader::factory, "Mlat Adlib Tracker", ".mad\0"), + CPlayerDesc(CmidPlayer::factory, "MIDI", ".mid\0.cmf\0.sci\0.laa\0"), + CPlayerDesc(CmkjPlayer::factory, "MKJamz", ".mkj\0"), + CPlayerDesc(CcffLoader::factory, "Boomtracker", ".cff\0"), + CPlayerDesc(CdmoLoader::factory, "TwinTeam", ".dmo\0"), + CPlayerDesc(Cs3mPlayer::factory, "Scream Tracker 3", ".s3m\0"), + CPlayerDesc(CdtmLoader::factory, "DeFy Adlib Tracker", ".dtm\0"), + CPlayerDesc(CfmcLoader::factory, "Faust Music Creator", ".sng\0"), + CPlayerDesc(CmtkLoader::factory, "MPU-401 Trakker", ".mtk\0"), + CPlayerDesc(CradLoader::factory, "Reality Adlib Tracker", ".rad\0"), + CPlayerDesc(CrawPlayer::factory, "RdosPlay RAW", ".raw\0"), + CPlayerDesc(Csa2Loader::factory, "Surprise! Adlib Tracker", ".sat\0.sa2\0"), + CPlayerDesc(CxadbmfPlayer::factory, "BMF Adlib Tracker", ".xad\0"), + CPlayerDesc(CxadflashPlayer::factory, "Flash", ".xad\0"), + CPlayerDesc(CxadhybridPlayer::factory, "Hybrid", ".xad\0"), + CPlayerDesc(CxadhypPlayer::factory, "Hypnosis", ".xad\0"), + CPlayerDesc(CxadpsiPlayer::factory, "PSI", ".xad\0"), + CPlayerDesc(CxadratPlayer::factory, "rat", ".xad\0"), + CPlayerDesc(CldsPlayer::factory, "LOUDNESS Sound System", ".lds\0"), + CPlayerDesc(Cu6mPlayer::factory, "Ultima 6 Music", ".m\0"), + CPlayerDesc(CrolPlayer::factory, "Adlib Visual Composer", ".rol\0"), + CPlayerDesc(CxsmPlayer::factory, "eXtra Simple Music", ".xsm\0"), + CPlayerDesc(CdroPlayer::factory, "DOSBox Raw OPL", ".dro\0"), + CPlayerDesc() +}; + +const CPlayers &CAdPlug::init_players(const CPlayerDesc pd[]) +{ + static CPlayers initplayers; + unsigned int i; + + for(i = 0; pd[i].factory; i++) + initplayers.push_back(&pd[i]); + + return initplayers; +} + +const CPlayers CAdPlug::players = CAdPlug::init_players(CAdPlug::allplayers); +CAdPlugDatabase *CAdPlug::database = 0; + +CPlayer *CAdPlug::factory(const std::string &fn, Copl *opl, const CPlayers &pl, + const CFileProvider &fp) +{ + CPlayer *p; + CPlayers::const_iterator i; + unsigned int j; + + AdPlug_LogWrite("*** CAdPlug::factory(\"%s\",opl,fp) ***\n", fn.c_str()); + + // Try a direct hit by file extension + for(i = pl.begin(); i != pl.end(); i++) + for(j = 0; (*i)->get_extension(j); j++) + if(fp.extension(fn, (*i)->get_extension(j))) { + AdPlug_LogWrite("Trying direct hit: %s\n", (*i)->filetype.c_str()); + if((p = (*i)->factory(opl))) + if(p->load(fn, fp)) { + AdPlug_LogWrite("got it!\n"); + AdPlug_LogWrite("--- CAdPlug::factory ---\n"); + return p; + } else + delete p; + } + + // Try all players, one by one + for(i = pl.begin(); i != pl.end(); i++) { + AdPlug_LogWrite("Trying: %s\n", (*i)->filetype.c_str()); + if((p = (*i)->factory(opl))) + if(p->load(fn, fp)) { + AdPlug_LogWrite("got it!\n"); + AdPlug_LogWrite("--- CAdPlug::factory ---\n"); + return p; + } else + delete p; + } + + // Unknown file + AdPlug_LogWrite("End of list!\n"); + AdPlug_LogWrite("--- CAdPlug::factory ---\n"); + return 0; +} + +void CAdPlug::set_database(CAdPlugDatabase *db) +{ + database = db; +} + +std::string CAdPlug::get_version() +{ + return std::string(VERSION); +} + +void CAdPlug::debug_output(const std::string &filename) +{ + AdPlug_LogFile(filename.c_str()); + AdPlug_LogWrite("CAdPlug::debug_output(\"%s\"): Redirected.\n",filename.c_str()); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/adplug.dsp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/adplug.dsp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,509 @@ +# Microsoft Developer Studio Project File - Name="adplug" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=adplug - Win32 Debug +!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "adplug.mak". +!MESSAGE +!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "adplug.mak" CFG="adplug - Win32 Debug" +!MESSAGE +!MESSAGE Für die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "adplug - Win32 Release" (basierend auf "Win32 (x86) Static Library") +!MESSAGE "adplug - Win32 Debug" (basierend auf "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "adplug - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Installing library and headers... +PostBuild_Cmds=call vc6inst l "Release\adplug.lib" call vc6inst i *.h adplug +# End Special Build Tool + +!ELSEIF "$(CFG)" == "adplug - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug\adplugd.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Installing library and headers... +PostBuild_Cmds=call vc6inst l "Debug\adplugd.lib" call vc6inst i *.h adplug +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "adplug - Win32 Release" +# Name "adplug - Win32 Debug" +# Begin Group "Quellcodedateien" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\a2m.cpp +# End Source File +# Begin Source File + +SOURCE=.\adlibemu.c +# End Source File +# Begin Source File + +SOURCE=.\adplug.cpp +# End Source File +# Begin Source File + +SOURCE=.\adtrack.cpp +# End Source File +# Begin Source File + +SOURCE=.\amd.cpp +# End Source File +# Begin Source File + +SOURCE=.\analopl.cpp +# End Source File +# Begin Source File + +SOURCE=.\bam.cpp +# End Source File +# Begin Source File + +SOURCE=.\bmf.cpp +# End Source File +# Begin Source File + +SOURCE=.\cff.cpp +# End Source File +# Begin Source File + +SOURCE=.\d00.cpp +# End Source File +# Begin Source File + +SOURCE=.\database.cpp +# End Source File +# Begin Source File + +SOURCE=.\debug.c +# End Source File +# Begin Source File + +SOURCE=.\dfm.cpp +# End Source File +# Begin Source File + +SOURCE=.\diskopl.cpp +# End Source File +# Begin Source File + +SOURCE=.\dmo.cpp +# End Source File +# Begin Source File + +SOURCE=.\dro.cpp +# End Source File +# Begin Source File + +SOURCE=.\dtm.cpp +# End Source File +# Begin Source File + +SOURCE=.\emuopl.cpp +# End Source File +# Begin Source File + +SOURCE=.\flash.cpp +# End Source File +# Begin Source File + +SOURCE=.\fmc.cpp +# End Source File +# Begin Source File + +SOURCE=.\fmopl.c +# ADD CPP /W1 +# End Source File +# Begin Source File + +SOURCE=.\fprovide.cpp +# End Source File +# Begin Source File + +SOURCE=.\hsc.cpp +# End Source File +# Begin Source File + +SOURCE=.\hsp.cpp +# End Source File +# Begin Source File + +SOURCE=.\hybrid.cpp +# End Source File +# Begin Source File + +SOURCE=.\hyp.cpp +# End Source File +# Begin Source File + +SOURCE=.\imf.cpp +# End Source File +# Begin Source File + +SOURCE=.\ksm.cpp +# End Source File +# Begin Source File + +SOURCE=.\lds.cpp +# End Source File +# Begin Source File + +SOURCE=.\mad.cpp +# End Source File +# Begin Source File + +SOURCE=.\mid.cpp +# End Source File +# Begin Source File + +SOURCE=.\mkj.cpp +# End Source File +# Begin Source File + +SOURCE=.\mtk.cpp +# End Source File +# Begin Source File + +SOURCE=.\player.cpp +# End Source File +# Begin Source File + +SOURCE=.\players.cpp +# End Source File +# Begin Source File + +SOURCE=.\protrack.cpp +# End Source File +# Begin Source File + +SOURCE=.\psi.cpp +# End Source File +# Begin Source File + +SOURCE=.\rad.cpp +# End Source File +# Begin Source File + +SOURCE=.\rat.cpp +# End Source File +# Begin Source File + +SOURCE=.\raw.cpp +# End Source File +# Begin Source File + +SOURCE=.\realopl.cpp +# End Source File +# Begin Source File + +SOURCE=.\rol.cpp +# End Source File +# Begin Source File + +SOURCE=.\s3m.cpp +# End Source File +# Begin Source File + +SOURCE=.\sa2.cpp +# End Source File +# Begin Source File + +SOURCE=.\sng.cpp +# End Source File +# Begin Source File + +SOURCE=.\u6m.cpp +# End Source File +# Begin Source File + +SOURCE=.\xad.cpp +# End Source File +# Begin Source File + +SOURCE=.\xsm.cpp +# End Source File +# End Group +# Begin Group "Header-Dateien" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\a2m.h +# End Source File +# Begin Source File + +SOURCE=.\adlibemu.h +# End Source File +# Begin Source File + +SOURCE=.\adplug.h +# End Source File +# Begin Source File + +SOURCE=.\adtrack.h +# End Source File +# Begin Source File + +SOURCE=.\amd.h +# End Source File +# Begin Source File + +SOURCE=.\analopl.h +# End Source File +# Begin Source File + +SOURCE=.\bam.h +# End Source File +# Begin Source File + +SOURCE=.\bmf.h +# End Source File +# Begin Source File + +SOURCE=.\cff.h +# End Source File +# Begin Source File + +SOURCE=.\d00.h +# End Source File +# Begin Source File + +SOURCE=.\database.h +# End Source File +# Begin Source File + +SOURCE=.\debug.h +# End Source File +# Begin Source File + +SOURCE=.\dfm.h +# End Source File +# Begin Source File + +SOURCE=.\diskopl.h +# End Source File +# Begin Source File + +SOURCE=.\dmo.h +# End Source File +# Begin Source File + +SOURCE=.\dro.h +# End Source File +# Begin Source File + +SOURCE=.\dtm.h +# End Source File +# Begin Source File + +SOURCE=.\emuopl.h +# End Source File +# Begin Source File + +SOURCE=.\flash.h +# End Source File +# Begin Source File + +SOURCE=.\fmc.h +# End Source File +# Begin Source File + +SOURCE=.\fmopl.h +# End Source File +# Begin Source File + +SOURCE=.\fprovide.h +# End Source File +# Begin Source File + +SOURCE=.\hsc.h +# End Source File +# Begin Source File + +SOURCE=.\hsp.h +# End Source File +# Begin Source File + +SOURCE=.\hybrid.h +# End Source File +# Begin Source File + +SOURCE=.\hyp.h +# End Source File +# Begin Source File + +SOURCE=.\imf.h +# End Source File +# Begin Source File + +SOURCE=.\imfcrc.h +# End Source File +# Begin Source File + +SOURCE=.\kemuopl.h +# End Source File +# Begin Source File + +SOURCE=.\ksm.h +# End Source File +# Begin Source File + +SOURCE=.\lds.h +# End Source File +# Begin Source File + +SOURCE=.\mad.h +# End Source File +# Begin Source File + +SOURCE=.\mid.h +# End Source File +# Begin Source File + +SOURCE=.\mididata.h +# End Source File +# Begin Source File + +SOURCE=.\mkj.h +# End Source File +# Begin Source File + +SOURCE=.\mtk.h +# End Source File +# Begin Source File + +SOURCE=.\opl.h +# End Source File +# Begin Source File + +SOURCE=.\player.h +# End Source File +# Begin Source File + +SOURCE=.\players.h +# End Source File +# Begin Source File + +SOURCE=.\protrack.h +# End Source File +# Begin Source File + +SOURCE=.\psi.h +# End Source File +# Begin Source File + +SOURCE=.\rad.h +# End Source File +# Begin Source File + +SOURCE=.\rat.h +# End Source File +# Begin Source File + +SOURCE=.\raw.h +# End Source File +# Begin Source File + +SOURCE=.\realopl.h +# End Source File +# Begin Source File + +SOURCE=.\rol.h +# End Source File +# Begin Source File + +SOURCE=.\s3m.h +# End Source File +# Begin Source File + +SOURCE=.\sa2.h +# End Source File +# Begin Source File + +SOURCE=.\silentopl.h +# End Source File +# Begin Source File + +SOURCE=.\sng.h +# End Source File +# Begin Source File + +SOURCE=.\u6m.h +# End Source File +# Begin Source File + +SOURCE=.\xad.h +# End Source File +# Begin Source File + +SOURCE=.\xsm.h +# End Source File +# End Group +# End Target +# End Project diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/adplug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/adplug.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,55 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * adplug.h - AdPlug main header file, by Simon Peter + */ + +#ifndef H_ADPLUG_ADPLUG +#define H_ADPLUG_ADPLUG + +#include + +#include "player.h" +#include "opl.h" +#include "fprovide.h" +#include "players.h" +#include "database.h" + +class CAdPlug +{ + friend CPlayer::CPlayer(Copl *newopl); + +public: + static const CPlayers players; + + static CPlayer *factory(const std::string &fn, Copl *opl, + const CPlayers &pl = players, + const CFileProvider &fp = CProvider_Filesystem()); + + static void set_database(CAdPlugDatabase *db); + static std::string get_version(); + static void debug_output(const std::string &filename); + +private: + static CAdPlugDatabase *database; + static const CPlayerDesc allplayers[]; + + static const CPlayers &init_players(const CPlayerDesc pd[]); +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/adtrack.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/adtrack.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,176 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * adtrack.cpp - Adlib Tracker 1.0 Loader by Simon Peter + * + * NOTES: + * The original Adlib Tracker 1.0 is behaving a little different from the + * official spec: The 'octave' integer from the instrument file is stored + * "minus 1" from the actual value, underflowing from 0 to 0xffff. + * + * I also noticed that my player is playing everything transposed a few tones + * higher than the original tracker. As far as i can see, my player perfectly + * follows the official spec, so it "must" be the tracker that does something + * wrong here... + */ + +#include +#include + +#include "adtrack.h" +#include "debug.h" + +/*** Public methods ***/ + +CPlayer *CadtrackLoader::factory(Copl *newopl) +{ + return new CadtrackLoader(newopl); +} + +bool CadtrackLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + binistream *instf; + char note[2]; + unsigned short rwp; + unsigned char chp, octave, pnote = 0; + int i,j; + AdTrackInst myinst; + + // file validation + if(!fp.extension(filename, ".sng") || fp.filesize(f) != 36000) + { fp.close(f); return false; } + + // check for instruments file + std::string instfilename(filename, 0, filename.find_last_of('.')); + instfilename += ".ins"; + AdPlug_LogWrite("CadtrackLoader::load(,\"%s\"): Checking for \"%s\"...\n", + filename.c_str(), instfilename.c_str()); + instf = fp.open(instfilename); + if(!instf || fp.filesize(instf) != 468) { fp.close(f); return false; } + + // give CmodPlayer a hint on what we're up to + realloc_patterns(1,1000,9); realloc_instruments(9); realloc_order(1); + init_trackord(); flags = NoKeyOn; + (*order) = 0; length = 1; restartpos = 0; bpm = 120; initspeed = 3; + + // load instruments from instruments file + for(i=0;i<9;i++) { + for(j=0;j<2;j++) { + myinst.op[j].appampmod = instf->readInt(2); + myinst.op[j].appvib = instf->readInt(2); + myinst.op[j].maintsuslvl = instf->readInt(2); + myinst.op[j].keybscale = instf->readInt(2); + myinst.op[j].octave = instf->readInt(2); + myinst.op[j].freqrisevollvldn = instf->readInt(2); + myinst.op[j].softness = instf->readInt(2); + myinst.op[j].attack = instf->readInt(2); + myinst.op[j].decay = instf->readInt(2); + myinst.op[j].release = instf->readInt(2); + myinst.op[j].sustain = instf->readInt(2); + myinst.op[j].feedback = instf->readInt(2); + myinst.op[j].waveform = instf->readInt(2); + } + convert_instrument(i, &myinst); + } + fp.close(instf); + + // load file + for(rwp=0;rwp<1000;rwp++) + for(chp=0;chp<9;chp++) { + // read next record + f->readString(note, 2); octave = f->readInt(1); f->ignore(); + switch(*note) { + case 'C': if(note[1] == '#') pnote = 2; else pnote = 1; break; + case 'D': if(note[1] == '#') pnote = 4; else pnote = 3; break; + case 'E': pnote = 5; break; + case 'F': if(note[1] == '#') pnote = 7; else pnote = 6; break; + case 'G': if(note[1] == '#') pnote = 9; else pnote = 8; break; + case 'A': if(note[1] == '#') pnote = 11; else pnote = 10; break; + case 'B': pnote = 12; break; + case '\0': + if(note[1] == '\0') + tracks[chp][rwp].note = 127; + else { + fp.close(f); + return false; + } + break; + default: fp.close(f); return false; + } + if((*note) != '\0') { + tracks[chp][rwp].note = pnote + (octave * 12); + tracks[chp][rwp].inst = chp + 1; + } + } + + fp.close(f); + rewind(0); + return true; +} + +float CadtrackLoader::getrefresh() +{ + return 18.2f; +} + +/*** Private methods ***/ + +void CadtrackLoader::convert_instrument(unsigned int n, AdTrackInst *i) +{ + // Carrier "Amp Mod / Vib / Env Type / KSR / Multiple" register + inst[n].data[2] = i->op[Carrier].appampmod ? 1 << 7 : 0; + inst[n].data[2] += i->op[Carrier].appvib ? 1 << 6 : 0; + inst[n].data[2] += i->op[Carrier].maintsuslvl ? 1 << 5 : 0; + inst[n].data[2] += i->op[Carrier].keybscale ? 1 << 4 : 0; + inst[n].data[2] += (i->op[Carrier].octave + 1) & 0xffff; // Bug in original tracker + // Modulator... + inst[n].data[1] = i->op[Modulator].appampmod ? 1 << 7 : 0; + inst[n].data[1] += i->op[Modulator].appvib ? 1 << 6 : 0; + inst[n].data[1] += i->op[Modulator].maintsuslvl ? 1 << 5 : 0; + inst[n].data[1] += i->op[Modulator].keybscale ? 1 << 4 : 0; + inst[n].data[1] += (i->op[Modulator].octave + 1) & 0xffff; // Bug in original tracker + + // Carrier "Key Scaling / Level" register + inst[n].data[10] = (i->op[Carrier].freqrisevollvldn & 3) << 6; + inst[n].data[10] += i->op[Carrier].softness & 63; + // Modulator... + inst[n].data[9] = (i->op[Modulator].freqrisevollvldn & 3) << 6; + inst[n].data[9] += i->op[Modulator].softness & 63; + + // Carrier "Attack / Decay" register + inst[n].data[4] = (i->op[Carrier].attack & 0x0f) << 4; + inst[n].data[4] += i->op[Carrier].decay & 0x0f; + // Modulator... + inst[n].data[3] = (i->op[Modulator].attack & 0x0f) << 4; + inst[n].data[3] += i->op[Modulator].decay & 0x0f; + + // Carrier "Release / Sustain" register + inst[n].data[6] = (i->op[Carrier].release & 0x0f) << 4; + inst[n].data[6] += i->op[Carrier].sustain & 0x0f; + // Modulator... + inst[n].data[5] = (i->op[Modulator].release & 0x0f) << 4; + inst[n].data[5] += i->op[Modulator].sustain & 0x0f; + + // Channel "Feedback / Connection" register + inst[n].data[0] = (i->op[Carrier].feedback & 7) << 1; + + // Carrier/Modulator "Wave Select" registers + inst[n].data[8] = i->op[Carrier].waveform & 3; + inst[n].data[7] = i->op[Modulator].waveform & 3; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/adtrack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/adtrack.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,53 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * adtrack.h - Adlib Tracker 1.0 Loader by Simon Peter + */ + +#include "protrack.h" + +class CadtrackLoader: public CmodPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CadtrackLoader(Copl *newopl) + : CmodPlayer(newopl) + { }; + + bool load(const std::string &filename, const CFileProvider &fp); + float getrefresh(); + + std::string gettype() + { return std::string("Adlib Tracker 1.0"); }; + unsigned int getinstruments() + { return 9; }; + +private: + enum Operators {Carrier = 1, Modulator = 0}; + + typedef struct { + struct { + unsigned short appampmod, appvib, maintsuslvl, keybscale, octave, + freqrisevollvldn, softness, attack, decay, release, sustain, + feedback, waveform; + } op[2]; + } AdTrackInst; + + void convert_instrument(unsigned int n, AdTrackInst *i); +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/amd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/amd.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,173 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * amd.cpp - AMD Loader by Simon Peter + */ + +#include + +#include "amd.h" +#include "debug.h" + +CPlayer *CamdLoader::factory(Copl *newopl) +{ + return new CamdLoader(newopl); +} + +bool CamdLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + struct { + char id[9]; + unsigned char version; + } header; + int i, j, k, t, numtrax; + unsigned char buf, buf2, buf3; + const unsigned char convfx[10] = {0,1,2,9,17,11,13,18,3,14}; + + // file validation section + if(fp.filesize(f) < 1072) { fp.close(f); return false; } + f->seek(1062); f->readString(header.id, 9); + header.version = f->readInt(1); + if(strncmp(header.id, "seek(0); + f->readString(songname, sizeof(songname)); + f->readString(author, sizeof(author)); + for(i = 0; i < 26; i++) { + f->readString(instname[i], 23); + for(j = 0; j < 11; j++) inst[i].data[j] = f->readInt(1); + } + length = f->readInt(1); nop = f->readInt(1) + 1; + for(i=0;i<128;i++) order[i] = f->readInt(1); + f->seek(10, binio::Add); + if(header.version == 0x10) { // unpacked module + for(i=0;i<64*9;i++) + trackord[i/9][i%9] = i+1; + t = 0; + while(!f->ateof()) { + for(j=0;j<64;j++) + for(i=t;ireadInt(1); + tracks[i][j].param2 = (buf&127) % 10; + tracks[i][j].param1 = (buf&127) / 10; + buf = f->readInt(1); + tracks[i][j].inst = buf >> 4; + tracks[i][j].command = buf & 0x0f; + buf = f->readInt(1); + if(buf >> 4) // fix bug in AMD save routine + tracks[i][j].note = ((buf & 14) >> 1) * 12 + (buf >> 4); + else + tracks[i][j].note = 0; + tracks[i][j].inst += (buf & 1) << 4; + } + t += 9; + } + } else { // packed module + for(i=0;ireadInt(2) + 1; + numtrax = f->readInt(2); + for(k=0;kreadInt(2); + if(i > 575) i = 575; // fix corrupted modules + j = 0; + do { + buf = f->readInt(1); + if(buf & 128) { + for(t = j; t < j + (buf & 127) && t < 64; t++) { + tracks[i][t].command = 0; + tracks[i][t].inst = 0; + tracks[i][t].note = 0; + tracks[i][t].param1 = 0; + tracks[i][t].param2 = 0; + } + j += buf & 127; + continue; + } + tracks[i][j].param2 = buf % 10; + tracks[i][j].param1 = buf / 10; + buf = f->readInt(1); + tracks[i][j].inst = buf >> 4; + tracks[i][j].command = buf & 0x0f; + buf = f->readInt(1); + if(buf >> 4) // fix bug in AMD save routine + tracks[i][j].note = ((buf & 14) >> 1) * 12 + (buf >> 4); + else + tracks[i][j].note = 0; + tracks[i][j].inst += (buf & 1) << 4; + j++; + } while(j<64); + } + } + fp.close(f); + + // convert to protracker replay data + bpm = 50; restartpos = 0; activechan = 0xffff; flags = Decimal; + for(i=0;i<26;i++) { // convert instruments + buf = inst[i].data[0]; + buf2 = inst[i].data[1]; + inst[i].data[0] = inst[i].data[10]; + inst[i].data[1] = buf; + buf = inst[i].data[2]; + inst[i].data[2] = inst[i].data[5]; + buf3 = inst[i].data[3]; + inst[i].data[3] = buf; + buf = inst[i].data[4]; + inst[i].data[4] = inst[i].data[7]; + inst[i].data[5] = buf3; + buf3 = inst[i].data[6]; + inst[i].data[6] = inst[i].data[8]; + inst[i].data[7] = buf; + inst[i].data[8] = inst[i].data[9]; + inst[i].data[9] = buf2; + inst[i].data[10] = buf3; + for(j=0;j<23;j++) // convert names + if(instname[i][j] == '\xff') + instname[i][j] = '\x20'; + } + for(i=0;i, et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * amd.h - AMD Loader by Simon Peter + */ + +#include "protrack.h" + +class CamdLoader: public CmodPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CamdLoader(Copl *newopl) + : CmodPlayer(newopl) + { }; + + bool load(const std::string &filename, const CFileProvider &fp); + float getrefresh(); + + std::string gettype() + { return std::string("AMUSIC Adlib Tracker"); }; + std::string gettitle() + { return std::string(songname,0,24); }; + std::string getauthor() + { return std::string(author,0,24); }; + unsigned int getinstruments() + { return 26; }; + std::string getinstrument(unsigned int n) + { return std::string(instname[n],0,23); }; + +private: + char songname[24],author[24],instname[26][23]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/analopl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/analopl.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,167 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999, 2000, 2001 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * analopl.cpp - Spectrum analyzing hardware OPL, by Simon Peter (dn.tlp@gmx.net) + */ + +#include +#include "analopl.h" + +#ifdef _MSC_VER + #define INP _inp + #define OUTP _outp +#elif defined(__WATCOMC__) + #define INP inp + #define OUTP outp +#endif + +#define SHORTDELAY 6 // short delay in I/O port-reads after OPL hardware output +#define LONGDELAY 35 // long delay in I/O port-reads after OPL hardware output + +// the 9 operators as expected by the OPL2 +static const unsigned char op_table[9] = {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12}; + +CAnalopl::CAnalopl(unsigned short initport): adlport(initport), hardvol(0), bequiet(false), nowrite(false) +{ + int i; + + for(i=0;i<22;i++) { + hardvols[i][0] = 0; + hardvols[i][1] = 0; + } + for(i=0;i<9;i++) { + keyregs[i][0] = 0; + keyregs[i][1] = 0; + } +} + +bool CAnalopl::detect() +{ + unsigned char stat1,stat2,i; + + hardwrite(4,0x60); hardwrite(4,0x80); + stat1 = INP(adlport); + hardwrite(2,0xff); hardwrite(4,0x21); + for(i=0;i<80;i++) // wait for adlib + INP(adlport); + stat2 = INP(adlport); + hardwrite(4,0x60); hardwrite(4,0x80); + + if(((stat1 & 0xe0) == 0) && ((stat2 & 0xe0) == 0xc0)) + return true; + else + return false; +} + +void CAnalopl::setvolume(int volume) +{ + int i; + + hardvol = volume; + for(i=0;i<9;i++) { + hardwrite(0x43+op_table[i],((hardvols[op_table[i]+3][0] & 63) + volume) > 63 ? 63 : hardvols[op_table[i]+3][0] + volume); + if(hardvols[i][1] & 1) // modulator too? + hardwrite(0x40+op_table[i],((hardvols[op_table[i]][0] & 63) + volume) > 63 ? 63 : hardvols[op_table[i]][0] + volume); + } +} + +void CAnalopl::setquiet(bool quiet) +{ + bequiet = quiet; + + if(quiet) { + oldvol = hardvol; + setvolume(63); + } else + setvolume(oldvol); +} + +void CAnalopl::hardwrite(int reg, int val) +{ + int i; + + OUTP(adlport,reg); // set register + for(i=0;i= 0xb0 && reg <= 0xb8) { + if(!keyregs[reg - 0xb0][0] && (val & 32)) + keyregs[reg - 0xb0][1] = 1; + else + keyregs[reg - 0xb0][1] = 0; + keyregs[reg - 0xb0][0] = val & 32; + if(bequiet) // filter all key-on commands + val &= ~32; + } + if(reg >= 0x40 && reg <= 0x55) // cache volumes + hardvols[reg-0x40][0] = val; + if(reg >= 0xc0 && reg <= 0xc8) + hardvols[reg-0xc0][1] = val; + if(hardvol) // reduce volume + for(i=0;i<9;i++) { + if(reg == 0x43 + op_table[i]) + val = ((val & 63) + hardvol) > 63 ? 63 : val + hardvol; + else + if((reg == 0x40 + op_table[i]) && (hardvols[i][1] & 1)) + val = ((val & 63) + hardvol) > 63 ? 63 : val + hardvol; + } + + hardwrite(reg,val); +} + +void CAnalopl::init() +{ + int i; + + for (i=0;i<9;i++) { // stop instruments + hardwrite(0xb0 + i,0); // key off + hardwrite(0x80 + op_table[i],0xff); // fastest release + } + hardwrite(0xbd,0); // clear misc. register +} + +int CAnalopl::getcarriervol(unsigned int v) +{ + return (hardvols[op_table[v]+3][0] & 63); +} + +int CAnalopl::getmodulatorvol(unsigned int v) +{ + return (hardvols[op_table[v]][0] & 63); +} + +bool CAnalopl::getkeyon(unsigned int v) +{ + if(keyregs[v][1]) { + keyregs[v][1] = 0; + return true; + } else + return false; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/analopl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/analopl.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,64 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999, 2000, 2001 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * analopl.h - Spectrum analyzing hardware OPL, by Simon Peter (dn.tlp@gmx.net) + */ + +#ifndef H_ANALOPL_DEFINED +#define H_ANALOPL_DEFINED + +#include "opl.h" + +#define DFL_ADLIBPORT 0x388 // default adlib baseport + +class CAnalopl: public Copl +{ +public: + CAnalopl(unsigned short initport = DFL_ADLIBPORT); // initport = OPL2 hardware baseport + + bool detect(); // returns true if adlib compatible board is found, else false + void setvolume(int volume); // set adlib master volume (0 - 63) 0 = loudest, 63 = softest + void setquiet(bool quiet = true); // sets the OPL2 quiet, while still writing to the registers + void setport(unsigned short port) // set new OPL2 hardware baseport + { adlport = port; }; + void setnowrite(bool nw = true) // set hardware write status + { nowrite = nw; }; + + int getvolume() // get adlib master volume + { return hardvol; }; + int getcarriervol(unsigned int v); // get carrier volume of adlib voice v + int getmodulatorvol(unsigned int v); // get modulator volume of adlib voice v + bool getkeyon(unsigned int v); + + // template methods + void write(int reg, int val); + void init(); + +private: + void hardwrite(int reg, int val); // write to OPL2 hardware registers + + unsigned short adlport; // adlib hardware baseport + int hardvol,oldvol; // hardware master volume + bool bequiet; // quiet status cache + char hardvols[22][2]; // volume cache + unsigned char keyregs[9][2]; // shadow key register + bool nowrite; // don't write to hardware, if true +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/bam.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/bam.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,203 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * bam.cpp - Bob's Adlib Music Player, by Simon Peter + * + * NOTES: + * In my player, the loop counter is stored with the label. This can be + * dangerous for some situations (see below), but there shouldn't be any BAM + * files triggering this situation. + * + * From SourceForge Bug #476088: + * ----------------------------- + * Using just one loop counter for each label, my player can't + * handle files that loop twice to the same label (if that's at + * all possible with BAM). Imagine the following situation: + * + * ... [*] ---- [<- *] ---- [<- *] ... + * ^ ^ ^ ^ ^ ^ ^ + * | | | | | | | + * +---|----+-----|-----+-----|----+--- normal song data + * +----------|-----------|-------- label 1 + * +-----------+-------- loop points to label 1 + * + * both loop points loop to the same label. Storing the loop + * count with the label would cause chaos with the counter, + * when the player executes the inner jump. + * ------------------ + * Not to worry. my reference implementation of BAM does not + * support the multiple loop situation you describe, and + * neither do any BAM-creation programs. Then both loops point + * to the same label, the inner loop's counter is just allowed + * to clobber the outer loop's counter. No stack is neccisary. + */ + +#include +#include "bam.h" + +const unsigned short CbamPlayer::freq[] = {172,182,193,205,217,230,243,258,274, +290,307,326,345,365,387,410,435,460,489,517,547,580,614,651,1369,1389,1411, +1434,1459,1484,1513,1541,1571,1604,1638,1675,2393,2413,2435,2458,2483,2508, +2537,2565,2595,2628,2662,2699,3417,3437,3459,3482,3507,3532,3561,3589,3619, +3652,3686,3723,4441,4461,4483,4506,4531,4556,4585,4613,4643,4676,4710,4747, +5465,5485,5507,5530,5555,5580,5609,5637,5667,5700,5734,5771,6489,6509,6531, +6554,6579,6604,6633,6661,6691,6724,6758,6795,7513,7533,7555,7578,7603,7628, +7657,7685,7715,7748,7782,7819,7858,7898,7942,7988,8037,8089,8143,8191,8191, +8191,8191,8191,8191,8191,8191,8191,8191,8191,8191}; + +CPlayer *CbamPlayer::factory(Copl *newopl) +{ + return new CbamPlayer(newopl); +} + +bool CbamPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[4]; + unsigned int i; + + size = fp.filesize(f) - 4; // filesize minus header + f->readString(id, 4); + if(strncmp(id,"CBMF",4)) { fp.close(f); return false; } + + song = new unsigned char [size]; + for(i = 0; i < size; i++) song[i] = f->readInt(1); + + fp.close(f); + rewind(0); + return true; +} + +bool CbamPlayer::update() +{ + unsigned char cmd,c; + + if(del) { + del--; + return !songend; + } + + if(pos >= size) { // EOF detection + pos = 0; + songend = true; + } + + while(song[pos] < 128) { + cmd = song[pos] & 240; + c = song[pos] & 15; + switch(cmd) { + case 0: // stop song + pos = 0; + songend = true; + break; + case 16: // start note + if(c < 9) { + opl->write(0xa0 + c, freq[song[++pos]] & 255); + opl->write(0xb0 + c, (freq[song[pos]] >> 8) + 32); + } else + pos++; + pos++; + break; + case 32: // stop note + if(c < 9) + opl->write(0xb0 + c, 0); + pos++; + break; + case 48: // define instrument + if(c < 9) { + opl->write(0x20 + op_table[c],song[pos+1]); + opl->write(0x23 + op_table[c],song[pos+2]); + opl->write(0x40 + op_table[c],song[pos+3]); + opl->write(0x43 + op_table[c],song[pos+4]); + opl->write(0x60 + op_table[c],song[pos+5]); + opl->write(0x63 + op_table[c],song[pos+6]); + opl->write(0x80 + op_table[c],song[pos+7]); + opl->write(0x83 + op_table[c],song[pos+8]); + opl->write(0xe0 + op_table[c],song[pos+9]); + opl->write(0xe3 + op_table[c],song[pos+10]); + opl->write(0xc0 + c,song[pos+11]); + } + pos += 12; + break; + case 80: // set label + label[c].target = ++pos; + label[c].defined = true; + break; + case 96: // jump + if(label[c].defined) + switch(song[pos+1]) { + case 254: // infinite loop + if(label[c].defined) { + pos = label[c].target; + songend = true; + break; + } + // fall through... + case 255: // chorus + if(!chorus && label[c].defined) { + chorus = true; + gosub = pos + 2; + pos = label[c].target; + break; + } + // fall through... + case 0: // end of loop + pos += 2; + break; + default: // finite loop + if(!label[c].count) { // loop elapsed + label[c].count = 255; + pos += 2; + break; + } + if(label[c].count < 255) // loop defined + label[c].count--; + else // loop undefined + label[c].count = song[pos+1] - 1; + pos = label[c].target; + break; + } + break; + case 112: // end of chorus + if(chorus) { + pos = gosub; + chorus = false; + } else + pos++; + break; + default: // reserved command (skip) + pos++; + break; + } + } + if(song[pos] >= 128) { // wait + del = song[pos] - 127; + pos++; + } + return !songend; +} + +void CbamPlayer::rewind(int subsong) +{ + int i; + + pos = 0; songend = false; del = 0; gosub = 0; chorus = false; + memset(label, 0, sizeof(label)); label[0].defined = true; + for(i = 0; i < 16; i++) label[i].count = 255; // 255 = undefined + opl->init(); opl->write(1,32); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/bam.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/bam.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,56 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * bam.h - Bob's Adlib Music Player, by Simon Peter + */ + +#include "player.h" + +class CbamPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CbamPlayer(Copl *newopl) + : CPlayer(newopl), song(0) + { }; + ~CbamPlayer() + { if(song) delete [] song; }; + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh() + { return 25.0f; }; + + std::string gettype() + { return std::string("Bob's Adlib Music"); }; + +private: + static const unsigned short freq[]; + + unsigned char *song, del; + unsigned long pos, size, gosub; + bool songend, chorus; + + struct { + unsigned long target; + bool defined; + unsigned char count; + } label[16]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/bmf.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/bmf.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,594 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] BMF player, by Riven the Mage + */ + +/* + - discovery - + + file(s) : GAMESNET.COM + type : GamesNet advertising intro + tune : by (?)The Brain [Razor 1911] + player : ver.0.9b by Hammer + + file(s) : 2FAST4U.COM + type : Ford Knox BBStro + tune : by The Brain [Razor 1911] + player : ver.1.1 by ? + comment : in original player at 9th channel the feedback adlib register is not C8 but C6. + + file(s) : DATURA.COM + type : Datura BBStro + tune : by The Brain [Razor 1911] + player : ver.1.2 by ? + comment : inaccurate replaying, because constant outport; in original player it can be 380 or 382. +*/ + +#include "bmf.h" +#include "debug.h" + +const unsigned char CxadbmfPlayer::bmf_adlib_registers[117] = +{ + 0x20, 0x23, 0x40, 0x43, 0x60, 0x63, 0x80, 0x83, 0xA0, 0xB0, 0xC0, 0xE0, 0xE3, + 0x21, 0x24, 0x41, 0x44, 0x61, 0x64, 0x81, 0x84, 0xA1, 0xB1, 0xC1, 0xE1, 0xE4, + 0x22, 0x25, 0x42, 0x45, 0x62, 0x65, 0x82, 0x85, 0xA2, 0xB2, 0xC2, 0xE2, 0xE5, + 0x28, 0x2B, 0x48, 0x4B, 0x68, 0x6B, 0x88, 0x8B, 0xA3, 0xB3, 0xC3, 0xE8, 0xEB, + 0x29, 0x2C, 0x49, 0x4C, 0x69, 0x6C, 0x89, 0x8C, 0xA4, 0xB4, 0xC4, 0xE9, 0xEC, + 0x2A, 0x2D, 0x4A, 0x4D, 0x6A, 0x6D, 0x8A, 0x8D, 0xA5, 0xB5, 0xC5, 0xEA, 0xED, + 0x30, 0x33, 0x50, 0x53, 0x70, 0x73, 0x90, 0x93, 0xA6, 0xB6, 0xC6, 0xF0, 0xF3, + 0x31, 0x34, 0x51, 0x54, 0x71, 0x74, 0x91, 0x94, 0xA7, 0xB7, 0xC7, 0xF1, 0xF4, + 0x32, 0x35, 0x52, 0x55, 0x72, 0x75, 0x92, 0x95, 0xA8, 0xB8, 0xC8, 0xF2, 0xF5 +}; + +const unsigned short CxadbmfPlayer::bmf_notes[12] = +{ + 0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287 +}; + +/* for 1.1 */ +const unsigned short CxadbmfPlayer::bmf_notes_2[12] = +{ + 0x159, 0x16D, 0x183, 0x19A, 0x1B2, 0x1CC, 0x1E8, 0x205, 0x223, 0x244, 0x267, 0x28B +}; + +const unsigned char CxadbmfPlayer::bmf_default_instrument[13] = +{ + 0x01, 0x01, 0x3F, 0x3F, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +CPlayer *CxadbmfPlayer::factory(Copl *newopl) +{ + return new CxadbmfPlayer(newopl); +} + +bool CxadbmfPlayer::xadplayer_load() +{ + unsigned short ptr = 0; + int i; + + if(xad.fmt != BMF) + return false; + +#ifdef DEBUG + AdPlug_LogWrite("\nbmf_load():\n\n"); +#endif + if (!strncmp((char *)&tune[0],"BMF1.2",6)) + { + bmf.version = BMF1_2; + bmf.timer = 70.0f; + } + else if (!strncmp((char *)&tune[0],"BMF1.1",6)) + { + bmf.version = BMF1_1; + bmf.timer = 60.0f; + } + else + { + bmf.version = BMF0_9B; + bmf.timer = 18.2f; + } + + // copy title & author + if (bmf.version > BMF0_9B) + { + ptr = 6; + + strncpy(bmf.title,(char *)&tune[ptr],36); + + while (tune[ptr]) { ptr++; } + ptr++; + + strncpy(bmf.author,(char *)&tune[ptr],36); + + while (tune[ptr]) { ptr++; } + ptr++; + } + else + { + strncpy(bmf.title,xad.title,36); + strncpy(bmf.author,xad.author,36); + } + + // speed + if (bmf.version > BMF0_9B) + bmf.speed = tune[ptr++]; + else + bmf.speed = ((tune[ptr++] << 8) / 3) >> 8; // strange, yeh ? + + // load instruments + if (bmf.version > BMF0_9B) + { + unsigned long iflags = (tune[ptr] << 24) | (tune[ptr+1] << 16) | (tune[ptr+2] << 8) | tune[ptr+3]; + ptr+=4; + + for(i=0;i<32;i++) + if (iflags & (1 << (31-i))) + { + strcpy(bmf.instruments[i].name, (char *)&tune[ptr]); + memcpy(bmf.instruments[i].data, &tune[ptr+11], 13); + ptr += 24; + } + else + { + bmf.instruments[i].name[0] = 0; + + if (bmf.version == BMF1_1) + for(int j=0;j<13;j++) + bmf.instruments[i].data[j] = bmf_default_instrument[j]; + else + for(int j=0;j<13;j++) + bmf.instruments[i].data[j] = 0; + } + } + else + { + ptr = 6; + + for(i=0;i<32;i++) + { + bmf.instruments[i].name[0] = 0; + memcpy(bmf.instruments[tune[ptr]].data, &tune[ptr+2],13); // bug no.1 (no instrument-table-end detection) + ptr+=15; + } + } + + // load streams + if (bmf.version > BMF0_9B) + { + unsigned long sflags = (tune[ptr] << 24) | (tune[ptr+1] << 16) | (tune[ptr+2] << 8) | tune[ptr+3]; + ptr+=4; + + for(i=0;i<9;i++) + if (sflags & (1 << (31-i))) + ptr+=__bmf_convert_stream(&tune[ptr],i); + else + bmf.streams[i][0].cmd = 0xFF; + } + else + { + for(i=0;i BMF0_9B) + { + opl_write(0x01, 0x20); + + /* 1.1 */ + if (bmf.version == BMF1_1) + for(i=0;i<9;i++) + for(j=0;j<13;j++) + opl_write(bmf_adlib_registers[13*i+j], bmf_default_instrument[j]); + /* 1.2 */ + else if (bmf.version == BMF1_2) + for(i=0x20; i<0x100; i++) + opl_write(i,0xFF); // very interesting, really! + } + + /* ALL */ + + opl_write(0x08, 0x00); + opl_write(0xBD, 0xC0); +} + +void CxadbmfPlayer::xadplayer_update() +{ + for(int i=0;i<9;i++) + if (bmf.channel[i].stream_position != 0xFFFF) + if (bmf.channel[i].delay) + bmf.channel[i].delay--; + else + { +#ifdef DEBUG + AdPlug_LogWrite("channel %02X:\n", i); +#endif + bmf_event event; + + // process so-called cross-events + while (true) + { + memcpy(&event, &bmf.streams[i][bmf.channel[i].stream_position], sizeof(bmf_event)); +#ifdef DEBUG + AdPlug_LogWrite("%02X %02X %02X %02X %02X %02X\n",event.note,event.delay,event.volume,event.instrument,event.cmd,event.cmd_data ); +#endif + + if (event.cmd == 0xFF) + { + bmf.channel[i].stream_position = 0xFFFF; + bmf.active_streams--; + break; + } + else if (event.cmd == 0xFE) + { + bmf.channel[i].loop_position = bmf.channel[i].stream_position+1; + bmf.channel[i].loop_counter = event.cmd_data; + } + else if (event.cmd == 0xFD) + { + if (bmf.channel[i].loop_counter) + { + bmf.channel[i].stream_position = bmf.channel[i].loop_position-1; + bmf.channel[i].loop_counter--; + } + } + else + break; + + bmf.channel[i].stream_position++; + } // while (true) + + // process normal event + unsigned short pos = bmf.channel[i].stream_position; + + if (pos != 0xFFFF) + { + bmf.channel[i].delay = bmf.streams[i][pos].delay; + + // command ? + if (bmf.streams[i][pos].cmd) + { + unsigned char cmd = bmf.streams[i][pos].cmd; + + // 0x01: Set Modulator Volume + if (cmd == 0x01) + { + unsigned char reg = bmf_adlib_registers[13*i+2]; + + opl_write(reg, (adlib[reg] | 0x3F) - bmf.streams[i][pos].cmd_data); + } + // 0x10: Set Speed + else if (cmd == 0x10) + { + plr.speed = bmf.streams[i][pos].cmd_data; + plr.speed_counter = plr.speed; + } + } // if (bmf.streams[i][pos].cmd) + + // instrument ? + if (bmf.streams[i][pos].instrument) + { + unsigned char ins = bmf.streams[i][pos].instrument-1; + + if (bmf.version != BMF1_1) + opl_write(0xB0+i, adlib[0xB0+i] & 0xDF); + + for(int j=0;j<13;j++) + opl_write(bmf_adlib_registers[i*13+j], bmf.instruments[ins].data[j]); + } // if (bmf.streams[i][pos].instrument) + + // volume ? + if (bmf.streams[i][pos].volume) + { + unsigned char vol = bmf.streams[i][pos].volume-1; + unsigned char reg = bmf_adlib_registers[13*i+3]; + + opl_write(reg, (adlib[reg] | 0x3F) - vol); + } // if (bmf.streams[i][pos].volume) + + // note ? + if (bmf.streams[i][pos].note) + { + unsigned short note = bmf.streams[i][pos].note; + unsigned short freq = 0; + + // mute channel + opl_write(0xB0+i, adlib[0xB0+i] & 0xDF); + + // get frequency + if (bmf.version == BMF1_1) + { + if (note <= 0x60) + freq = bmf_notes_2[--note % 12]; + } + else + { + if (note != 0x7F) + freq = bmf_notes[--note % 12]; + } + + // play note + if (freq) + { + opl_write(0xB0+i, (freq >> 8) | ((note / 12) << 2) | 0x20); + opl_write(0xA0+i, freq & 0xFF); + } + } // if (bmf.streams[i][pos].note) + + bmf.channel[i].stream_position++; + } // if (pos != 0xFFFF) + + } // if (!bmf.channel[i].delay) + + // is module loop ? + if (!bmf.active_streams) + { + for(int j=0;j<9;j++) + bmf.channel[j].stream_position = 0; + + bmf.active_streams = 9; + + plr.looping = 1; + } +} + +float CxadbmfPlayer::xadplayer_getrefresh() +{ + return bmf.timer; +} + +std::string CxadbmfPlayer::xadplayer_gettype() +{ + return std::string("xad: BMF Adlib Tracker"); +} + +std::string CxadbmfPlayer::xadplayer_gettitle() +{ + return std::string(bmf.title); +} + +std::string CxadbmfPlayer::xadplayer_getauthor() +{ + return std::string(bmf.author); +} + +unsigned int CxadbmfPlayer::xadplayer_getinstruments() +{ + return 32; +} + +std::string CxadbmfPlayer::xadplayer_getinstrument(unsigned int i) +{ + return std::string(bmf.instruments[i].name); +} + +/* -------- Internal Functions ---------------------------- */ + +int CxadbmfPlayer::__bmf_convert_stream(unsigned char *stream, int channel) +{ +#ifdef DEBUG + AdPlug_LogWrite("channel %02X (note,delay,volume,instrument,command,command_data):\n",channel); + unsigned char *last = stream; +#endif + unsigned char *stream_start = stream; + + int pos = 0; + + while (true) + { + memset(&bmf.streams[channel][pos], 0, sizeof(bmf_event)); + + bool is_cmd = false; + + if (*stream == 0xFE) + { + // 0xFE -> 0xFF: End of Stream + bmf.streams[channel][pos].cmd = 0xFF; + + stream++; + + break; + } + else if (*stream == 0xFC) + { + // 0xFC -> 0xFE xx: Save Loop Position + bmf.streams[channel][pos].cmd = 0xFE; + bmf.streams[channel][pos].cmd_data = (*(stream+1) & ((bmf.version == BMF0_9B) ? 0x7F : 0x3F)) - 1; + + stream+=2; + } + else if (*stream == 0x7D) + { + // 0x7D -> 0xFD: Loop Saved Position + bmf.streams[channel][pos].cmd = 0xFD; + + stream++; + } + else + { + if (*stream & 0x80) + { + if (*(stream+1) & 0x80) + { + if (*(stream+1) & 0x40) + { + // byte0: 1aaaaaaa = NOTE + bmf.streams[channel][pos].note = *stream & 0x7F; + // byte1: 11bbbbbb = DELAY + bmf.streams[channel][pos].delay = *(stream+1) & 0x3F; + // byte2: cccccccc = COMMAND + + stream+=2; + + is_cmd = true; + } + else + { + // byte0: 1aaaaaaa = NOTE + bmf.streams[channel][pos].note = *stream & 0x7F; + // byte1: 11bbbbbb = DELAY + bmf.streams[channel][pos].delay = *(stream+1) & 0x3F; + + stream+=2; + } // if (*(stream+1) & 0x40) + } + else + { + // byte0: 1aaaaaaa = NOTE + bmf.streams[channel][pos].note = *stream & 0x7F; + // byte1: 0bbbbbbb = COMMAND + + stream++; + + is_cmd = true; + } // if (*(stream+1) & 0x80) + } + else + { + // byte0: 0aaaaaaa = NOTE + bmf.streams[channel][pos].note = *stream & 0x7F; + + stream++; + } // if (*stream & 0x80) + } // if (*stream == 0xFE) + + // is command ? + if (is_cmd) + { + + /* ALL */ + + if ((0x20 <= *stream) && (*stream <= 0x3F)) + { + // 0x20 or higher; 0x3F or lower: Set Instrument + bmf.streams[channel][pos].instrument = *stream - 0x20 + 1; + + stream++; + } + else if (0x40 <= *stream) + { + // 0x40 or higher: Set Volume + bmf.streams[channel][pos].volume = *stream - 0x40 + 1; + + stream++; + } + else + { + + /* 0.9b */ + + if (bmf.version == BMF0_9B) + if (*stream < 0x20) + { + // 0x1F or lower: ? + stream++; + } + + /* 1.2 */ + + if (bmf.version == BMF1_2) + if (*stream == 0x01) + { + // 0x01: Set Modulator Volume -> 0x01 + bmf.streams[channel][pos].cmd = 0x01; + bmf.streams[channel][pos].cmd_data = *(stream+1); + + stream+=2; + } + else if (*stream == 0x02) + { + // 0x02: ? + stream+=2; + } + else if (*stream == 0x03) + { + // 0x03: ? + stream+=2; + } + else if (*stream == 0x04) + { + // 0x04: Set Speed -> 0x10 + bmf.streams[channel][pos].cmd = 0x10; + bmf.streams[channel][pos].cmd_data = *(stream+1); + + stream+=2; + } + else if (*stream == 0x05) + { + // 0x05: Set Carrier Volume (port 380) + bmf.streams[channel][pos].volume = *(stream+1) + 1; + + stream+=2; + } + else if (*stream == 0x06) + { + // 0x06: Set Carrier Volume (port 382) + bmf.streams[channel][pos].volume = *(stream+1) + 1; + + stream+=2; + } // if (bmf.version == BMF1_2) + + } // if ((0x20 <= *stream) && (*stream <= 0x3F)) + + } // if (is_cmd) + +#ifdef DEBUG + AdPlug_LogWrite("%02X %02X %02X %02X %02X %02X <---- ", + bmf.streams[channel][pos].note, + bmf.streams[channel][pos].delay, + bmf.streams[channel][pos].volume, + bmf.streams[channel][pos].instrument, + bmf.streams[channel][pos].cmd, + bmf.streams[channel][pos].cmd_data + ); + for(int zz=0;zz<(stream-last);zz++) + AdPlug_LogWrite("%02X ",last[zz]); + AdPlug_LogWrite("\n"); + last=stream; +#endif + pos++; + } // while (true) + + return (stream - stream_start); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/bmf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/bmf.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,91 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] BMF player, by Riven the Mage + */ + +#include "xad.h" + +class CxadbmfPlayer: public CxadPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CxadbmfPlayer(Copl *newopl): CxadPlayer(newopl) + { }; + ~CxadbmfPlayer() + { }; + +protected: + enum { BMF0_9B, BMF1_1, BMF1_2 }; + // + struct bmf_event + { + unsigned char note; + unsigned char delay; + unsigned char volume; + unsigned char instrument; + unsigned char cmd; + unsigned char cmd_data; + }; + + struct + { + unsigned char version; + char title[36]; + char author[36]; + float timer; + unsigned char speed; + + struct + { + char name[11]; + unsigned char data[13]; + } instruments[32]; + + bmf_event streams[9][1024]; + + int active_streams; + + struct + { + unsigned short stream_position; + unsigned char delay; + unsigned short loop_position; + unsigned char loop_counter; + } channel[9]; + } bmf; + // + bool xadplayer_load(); + void xadplayer_rewind(int subsong); + void xadplayer_update(); + float xadplayer_getrefresh(); + std::string xadplayer_gettype(); + std::string xadplayer_gettitle(); + std::string xadplayer_getauthor(); + std::string xadplayer_getinstrument(unsigned int i); + unsigned int xadplayer_getinstruments(); + // +private: + static const unsigned char bmf_adlib_registers[117]; + static const unsigned short bmf_notes[12]; + static const unsigned short bmf_notes_2[12]; + static const unsigned char bmf_default_instrument[13]; + + int __bmf_convert_stream(unsigned char *stream, int channel); +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/cff.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/cff.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,487 @@ +/* + AdPlug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2002 Simon Peter , et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + cff.cpp - BoomTracker loader by Riven the Mage +*/ +/* + NOTE: Conversion of slides is not 100% accurate. Original volume slides + have effect on carrier volume only. Also, original arpeggio, frequency & volume + slides use previous effect data instead of current. +*/ + +#include + +#include "cff.h" + +/* -------- Public Methods -------------------------------- */ + +CPlayer *CcffLoader::factory(Copl *newopl) +{ + return new CcffLoader(newopl); +} + +bool CcffLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 }; + const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE }; + + int i,j,k,t=0; + + // '' - signed ? + f->readString(header.id, 16); + header.version = f->readInt(1); header.size = f->readInt(2); + header.packed = f->readInt(1); f->readString((char *)header.reserved, 12); + if (memcmp(header.id,"""\x1A\xDE\xE0",16)) + { fp.close(f); return false; } + + unsigned char *module = new unsigned char [0x10000]; + + // packed ? + if (header.packed) + { + cff_unpacker *unpacker = new cff_unpacker; + + unsigned char *packed_module = new unsigned char [header.size + 4]; + + memset(packed_module,0,header.size + 4); + + f->readString((char *)packed_module, header.size); + fp.close(f); + + if (!unpacker->unpack(packed_module,module)) + { + delete unpacker; + delete packed_module; + delete module; + return false; + } + + delete unpacker; + delete packed_module; + + if (memcmp(&module[0x5E1],"CUD-FM-File - SEND A POSTCARD -",31)) + { + delete module; + return false; + } + } + else + { + f->readString((char *)module, header.size); + fp.close(f); + } + + // init CmodPlayer + realloc_instruments(47); + realloc_order(64); + realloc_patterns(36,64,9); + init_notetable(conv_note); + init_trackord(); + + // load instruments + for (i=0;i<47;i++) + { + memcpy(&instruments[i],&module[i*32],sizeof(cff_instrument)); + + for (j=0;j<11;j++) + inst[i].data[conv_inst[j]] = instruments[i].data[j]; + + instruments[i].name[20] = 0; + } + + // number of patterns + nop = module[0x5E0]; + + // load title & author + memcpy(song_title,&module[0x614],20); + memcpy(song_author,&module[0x600],20); + + // load order + memcpy(order,&module[0x628],64); + + // load tracks + for (i=0;ibyte0 == 0x6D) + tracks[t][k].note = 127; + else + if (event->byte0) + tracks[t][k].note = event->byte0; + + if (event->byte2) + old_event_byte2[j] = event->byte2; + + // convert effect + switch (event->byte1) + { + case 'I': // set instrument + tracks[t][k].inst = event->byte2 + 1; + tracks[t][k].param1 = tracks[t][k].param2 = 0; + break; + + case 'H': // set tempo + tracks[t][k].command = 7; + if (event->byte2 < 16) + { + tracks[t][k].param1 = 0x07; + tracks[t][k].param2 = 0x0D; + } + break; + + case 'A': // set speed + tracks[t][k].command = 19; + tracks[t][k].param1 = event->byte2 >> 4; + tracks[t][k].param2 = event->byte2 & 15; + break; + + case 'L': // pattern break + tracks[t][k].command = 13; + tracks[t][k].param1 = event->byte2 >> 4; + tracks[t][k].param2 = event->byte2 & 15; + break; + + case 'K': // order jump + tracks[t][k].command = 11; + tracks[t][k].param1 = event->byte2 >> 4; + tracks[t][k].param2 = event->byte2 & 15; + break; + + case 'M': // set vibrato/tremolo + tracks[t][k].command = 27; + tracks[t][k].param1 = event->byte2 >> 4; + tracks[t][k].param2 = event->byte2 & 15; + break; + + case 'C': // set modulator volume + tracks[t][k].command = 21; + tracks[t][k].param1 = (0x3F - event->byte2) >> 4; + tracks[t][k].param2 = (0x3F - event->byte2) & 15; + break; + + case 'G': // set carrier volume + tracks[t][k].command = 22; + tracks[t][k].param1 = (0x3F - event->byte2) >> 4; + tracks[t][k].param2 = (0x3F - event->byte2) & 15; + break; + + case 'B': // set carrier waveform + tracks[t][k].command = 25; + tracks[t][k].param1 = event->byte2; + tracks[t][k].param2 = 0x0F; + break; + + case 'E': // fine frequency slide down + tracks[t][k].command = 24; + tracks[t][k].param1 = old_event_byte2[j] >> 4; + tracks[t][k].param2 = old_event_byte2[j] & 15; + break; + + case 'F': // fine frequency slide up + tracks[t][k].command = 23; + tracks[t][k].param1 = old_event_byte2[j] >> 4; + tracks[t][k].param2 = old_event_byte2[j] & 15; + break; + + case 'D': // fine volume slide + tracks[t][k].command = 14; + if (old_event_byte2[j] & 15) + { + // slide down + tracks[t][k].param1 = 5; + tracks[t][k].param2 = old_event_byte2[j] & 15; + } + else + { + // slide up + tracks[t][k].param1 = 4; + tracks[t][k].param2 = old_event_byte2[j] >> 4; + } + break; + + case 'J': // arpeggio + tracks[t][k].param1 = old_event_byte2[j] >> 4; + tracks[t][k].param2 = old_event_byte2[j] & 15; + break; + } + } + + t++; + } + } + + delete [] module; + + // order loop + restartpos = 0; + + // order length + for (i=0;i<64;i++) + { + if (order[i] >= 0x80) + { + length = i; + break; + } + } + + // default tempo + bpm = 0x7D; + + rewind(0); + + return true; +} + +void CcffLoader::rewind(int subsong) +{ + CmodPlayer::rewind(subsong); + + // default instruments + for (int i=0;i<9;i++) + { + channel[i].inst = i; + + channel[i].vol1 = 63 - (inst[i].data[10] & 63); + channel[i].vol2 = 63 - (inst[i].data[9] & 63); + } +} + +std::string CcffLoader::gettype() +{ + if (header.packed) + return std::string("BoomTracker 4, packed"); + else + return std::string("BoomTracker 4"); +} + +std::string CcffLoader::gettitle() +{ + return std::string(song_title,20); +} + +std::string CcffLoader::getauthor() +{ + return std::string(song_author,20); +} + +std::string CcffLoader::getinstrument(unsigned int n) +{ + return std::string(instruments[n].name); +} + +unsigned int CcffLoader::getinstruments() +{ + return 47; +} + +/* -------- Private Methods ------------------------------- */ + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4018) +#endif + +/* + Lempel-Ziv-Tyr ;-) +*/ +long CcffLoader::cff_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf) +{ + if (memcmp(ibuf,"YsComp""\x07""CUD1997""\x1A\x04",16)) + return 0; + + input = ibuf + 16; + output = obuf; + + output_length = 0; + + heap = (unsigned char *)malloc(0x10000); + dictionary = (unsigned char **)malloc(sizeof(unsigned char *)*0x8000); + + memset(heap,0,0x10000); + memset(dictionary,0,0x8000); + + cleanup(); + startup(); + + // LZW + while (1) + { + new_code = get_code(); + + // 0x00: end of data + if (new_code == 0) + break; + + // 0x01: end of block + if (new_code == 1) + { + cleanup(); + startup(); + + continue; + } + + // 0x02: expand code length + if (new_code == 2) + { + code_length++; + + continue; + } + + // 0x03: RLE + if (new_code == 3) + { + unsigned char old_code_length = code_length; + + code_length = 2; + + unsigned char repeat_length = get_code() + 1; + + code_length = 4 << get_code(); + + unsigned long repeat_counter = get_code(); + + for (unsigned int i=0;i= (0x104 + dictionary_length)) + { + // dictionary <- old.code.string + old.code.char + the_string[++the_string[0]] = the_string[1]; + } + else + { + // dictionary <- old.code.string + new.code.char + unsigned char temp_string[256]; + + translate_code(new_code,temp_string); + + the_string[++the_string[0]] = temp_string[1]; + } + + expand_dictionary(the_string); + + // output <- new.code.string + translate_code(new_code,the_string); + + for (int i=0;i>= code_length; + bits_left -= code_length; + + return code; +} + +void CcffLoader::cff_unpacker::translate_code(unsigned long code, unsigned char *string) +{ + unsigned char translated_string[256]; + + if (code >= 0x104) + { + memcpy(translated_string,dictionary[code - 0x104],(*(dictionary[code - 0x104])) + 1); + } + else + { + translated_string[0] = 1; + translated_string[1] = (code - 4) & 0xFF; + } + + memcpy(string,translated_string,256); +} + +void CcffLoader::cff_unpacker::cleanup() +{ + code_length = 9; + + bits_buffer = 0; + bits_left = 0; + + heap_length = 0; + dictionary_length = 0; +} + +void CcffLoader::cff_unpacker::startup() +{ + old_code = get_code(); + + translate_code(old_code,the_string); + + for (int i=0;i= 0xF0) + return; + + memcpy(&heap[heap_length],string,string[0] + 1); + + dictionary[dictionary_length] = &heap[heap_length]; + + dictionary_length++; + + heap_length += (string[0] + 1); +} + +#ifdef _WIN32 +#pragma warning(default:4244) +#pragma warning(default:4018) +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/cff.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/cff.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,103 @@ +/* + AdPlug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2003 Simon Peter , et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + cff.h - BoomTracker loader by Riven the Mage +*/ + +#include "protrack.h" + +class CcffLoader: public CmodPlayer +{ + public: + static CPlayer *factory(Copl *newopl); + + CcffLoader(Copl *newopl) : CmodPlayer(newopl) { }; + + bool load(const std::string &filename, const CFileProvider &fp); + void rewind(int subsong); + + std::string gettype(); + std::string gettitle(); + std::string getauthor(); + std::string getinstrument(unsigned int n); + unsigned int getinstruments(); + + private: + + class cff_unpacker + { + public: + + long unpack(unsigned char *ibuf, unsigned char *obuf); + + private: + + unsigned long get_code(); + void translate_code(unsigned long code, unsigned char *string); + + void cleanup(); + void startup(); + + void expand_dictionary(unsigned char *string); + + unsigned char *input; + unsigned char *output; + + long output_length; + + unsigned char code_length; + + unsigned long bits_buffer; + unsigned int bits_left; + + unsigned char *heap; + unsigned char **dictionary; + + unsigned int heap_length; + unsigned int dictionary_length; + + unsigned long old_code,new_code; + + unsigned char the_string[256]; + }; + + struct cff_header + { + char id[16]; + unsigned char version; + unsigned short size; + unsigned char packed; + unsigned char reserved[12]; + } header; + + struct cff_instrument + { + unsigned char data[12]; + char name[21]; + } instruments[47]; + + char song_title[20]; + char song_author[20]; + + struct cff_event + { + unsigned char byte0; + unsigned char byte1; + unsigned char byte2; + }; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/d00.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/d00.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,527 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * d00.c - D00 Player by Simon Peter + * + * NOTES: + * Sorry for the goto's, but the code looks so much nicer now. + * I tried it with while loops but it was just a mess. If you + * can come up with a nicer solution, just tell me. + * + * BUGS: + * Hard restart SR is sometimes wrong + */ + +#include +#include + +#include "debug.h" +#include "d00.h" + +#define HIBYTE(val) (val >> 8) +#define LOBYTE(val) (val & 0xff) + +static const unsigned short notetable[12] = // D00 note table + {340,363,385,408,432,458,485,514,544,577,611,647}; + +/*** public methods *************************************/ + +CPlayer *Cd00Player::factory(Copl *newopl) +{ + return new Cd00Player(newopl); +} + +bool Cd00Player::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + d00header *checkhead; + d00header1 *ch; + unsigned long filesize; + int i,ver1=0; + char *str; + + // file validation section + checkhead = new d00header; + f->readString((char *)checkhead, sizeof(d00header)); + + // Check for version 2-4 header + if(strncmp(checkhead->id,"JCH\x26\x02\x66",6) || checkhead->type || + !checkhead->subsongs || checkhead->soundcard) { + // Check for version 0 or 1 header (and .d00 file extension) + delete checkhead; + if(!fp.extension(filename, ".d00")) { fp.close(f); return false; } + ch = new d00header1; + f->seek(0); f->readString((char *)ch, sizeof(d00header1)); + if(ch->version > 1 || !ch->subsongs) + { delete ch; fp.close(f); return false; } + delete ch; + ver1 = 1; + } else + delete checkhead; + + AdPlug_LogWrite("Cd00Player::load(f,\"%s\"): %s format D00 file detected!\n", + filename.c_str(), ver1 ? "Old" : "New"); + + // load section + filesize = fp.filesize(f); f->seek(0); + filedata = new char [filesize + 1]; // 1 byte is needed for old-style DataInfo block + f->readString((char *)filedata, filesize); + fp.close(f); + if(!ver1) { // version 2 and above + header = (struct d00header *)filedata; + version = header->version; + datainfo = (char *)filedata + header->infoptr; + inst = (struct Sinsts *)((char *)filedata + header->instptr); + seqptr = (unsigned short *)((char *)filedata + header->seqptr); + for(i=31;i>=0;i--) // erase whitespace + if(header->songname[i] == ' ') + header->songname[i] = '\0'; + else + break; + for(i=31;i>=0;i--) + if(header->author[i] == ' ') + header->author[i] = '\0'; + else + break; + } else { // version 1 + header1 = (struct d00header1 *)filedata; + version = header1->version; + datainfo = (char *)filedata + header1->infoptr; + inst = (struct Sinsts *)((char *)filedata + header1->instptr); + seqptr = (unsigned short *)((char *)filedata + header1->seqptr); + } + switch(version) { + case 0: + levpuls = 0; + spfx = 0; + header1->speed = 70; // v0 files default to 70Hz + break; + case 1: + levpuls = (struct Slevpuls *)((char *)filedata + header1->lpulptr); + spfx = 0; + break; + case 2: + levpuls = (struct Slevpuls *)((char *)filedata + header->spfxptr); + spfx = 0; + break; + case 3: + spfx = 0; + levpuls = 0; + break; + case 4: + spfx = (struct Sspfx *)((char *)filedata + header->spfxptr); + levpuls = 0; + break; + } + if((str = strstr(datainfo,"\xff\xff"))) + while((*str == '\xff' || *str == ' ') && str >= datainfo) { + *str = '\0'; str--; + } + else // old-style block + memset((char *)filedata+filesize,0,1); + + rewind(0); + return true; +} + +bool Cd00Player::update() +{ + unsigned char c,cnt,trackend=0,fx,note; + unsigned short ord,*patt,buf,fxop; + + // effect handling (timer dependant) + for(c=0;c<9;c++) { + channel[c].slideval += channel[c].slide; setfreq(c); // sliding + vibrato(c); // vibrato + + if(channel[c].spfx != 0xffff) { // SpFX + if(channel[c].fxdel) + channel[c].fxdel--; + else { + channel[c].spfx = spfx[channel[c].spfx].ptr; + channel[c].fxdel = spfx[channel[c].spfx].duration; + channel[c].inst = spfx[channel[c].spfx].instnr & 0xfff; + if(spfx[channel[c].spfx].modlev != 0xff) + channel[c].modvol = spfx[channel[c].spfx].modlev; + setinst(c); + if(spfx[channel[c].spfx].instnr & 0x8000) // locked frequency + note = spfx[channel[c].spfx].halfnote; + else // unlocked frequency + note = spfx[channel[c].spfx].halfnote + channel[c].note; + channel[c].freq = notetable[note%12] + ((note/12) << 10); + setfreq(c); + } + channel[c].modvol += spfx[channel[c].spfx].modlevadd; channel[c].modvol &= 63; + setvolume(c); + } + + if(channel[c].levpuls != 0xff) // Levelpuls + if(channel[c].frameskip) + channel[c].frameskip--; + else { + channel[c].frameskip = inst[channel[c].inst].timer; + if(channel[c].fxdel) + channel[c].fxdel--; + else { + channel[c].levpuls = levpuls[channel[c].levpuls].ptr - 1; + channel[c].fxdel = levpuls[channel[c].levpuls].duration; + if(levpuls[channel[c].levpuls].level != 0xff) + channel[c].modvol = levpuls[channel[c].levpuls].level; + } + channel[c].modvol += levpuls[channel[c].levpuls].voladd; channel[c].modvol &= 63; + setvolume(c); + } + } + + // song handling + for(c=0;c<9;c++) + if(version < 3 ? channel[c].del : channel[c].del <= 0x7f) { + if(version == 4) // v4: hard restart SR + if(channel[c].del == inst[channel[c].inst].timer) + if(channel[c].nextnote) + opl->write(0x83 + op_table[c], inst[channel[c].inst].sr); + if(version < 3) + channel[c].del--; + else + if(channel[c].speed) + channel[c].del += channel[c].speed; + else { + channel[c].seqend = 1; + continue; + } + } else { + if(channel[c].speed) { + if(version < 3) + channel[c].del = channel[c].speed; + else { + channel[c].del &= 0x7f; + channel[c].del += channel[c].speed; + } + } else { + channel[c].seqend = 1; + continue; + } + if(channel[c].rhcnt) { // process pending REST/HOLD events + channel[c].rhcnt--; + continue; + } +readorder: // process arrangement (orderlist) + ord = channel[c].order[channel[c].ordpos]; + switch(ord) { + case 0xfffe: channel[c].seqend = 1; continue; // end of arrangement stream + case 0xffff: // jump to order + channel[c].ordpos = channel[c].order[channel[c].ordpos+1]; + channel[c].seqend = 1; + goto readorder; + default: + if(ord >= 0x9000) { // set speed + channel[c].speed = ord & 0xff; + ord = channel[c].order[channel[c].ordpos - 1]; + channel[c].ordpos++; + } else + if(ord >= 0x8000) { // transpose track + channel[c].transpose = ord & 0xff; + if(ord & 0x100) + channel[c].transpose = -channel[c].transpose; + ord = channel[c].order[++channel[c].ordpos]; + } + patt = (unsigned short *)((char *)filedata + seqptr[ord]); + break; + } +readseq: // process sequence (pattern) + if(!version) // v0: always initialize rhcnt + channel[c].rhcnt = channel[c].irhcnt; + if(patt[channel[c].pattpos] == 0xffff) { // pattern ended? + channel[c].pattpos = 0; + channel[c].ordpos++; + goto readorder; + } + cnt = HIBYTE(patt[channel[c].pattpos]); + note = LOBYTE(patt[channel[c].pattpos]); + fx = patt[channel[c].pattpos] >> 12; + fxop = patt[channel[c].pattpos] & 0x0fff; + channel[c].pattpos++; + channel[c].nextnote = LOBYTE(patt[channel[c].pattpos]) & 0x7f; + if(version ? cnt < 0x40 : !fx) { // note event + switch(note) { + case 0: // REST event + case 0x80: + if(!note || version) { + channel[c].key = 0; + setfreq(c); + } + // fall through... + case 0x7e: // HOLD event + if(version) + channel[c].rhcnt = cnt; + channel[c].nextnote = 0; + break; + default: // play note + channel[c].slideval = 0; channel[c].slide = 0; channel[c].vibdepth = 0; // restart fx + + if(version) { // note handling for v1 and above + if(note > 0x80) // locked note (no channel transpose) + note -= 0x80; + else // unlocked note + note += channel[c].transpose; + channel[c].note = note; // remember note for SpFX + + if(channel[c].ispfx != 0xffff && cnt < 0x20) { // reset SpFX + channel[c].spfx = channel[c].ispfx; + if(spfx[channel[c].spfx].instnr & 0x8000) // locked frequency + note = spfx[channel[c].spfx].halfnote; + else // unlocked frequency + note += spfx[channel[c].spfx].halfnote; + channel[c].inst = spfx[channel[c].spfx].instnr & 0xfff; + channel[c].fxdel = spfx[channel[c].spfx].duration; + if(spfx[channel[c].spfx].modlev != 0xff) + channel[c].modvol = spfx[channel[c].spfx].modlev; + else + channel[c].modvol = inst[channel[c].inst].data[7] & 63; + } + + if(channel[c].ilevpuls != 0xff && cnt < 0x20) { // reset LevelPuls + channel[c].levpuls = channel[c].ilevpuls; + channel[c].fxdel = levpuls[channel[c].levpuls].duration; + channel[c].frameskip = inst[channel[c].inst].timer; + if(levpuls[channel[c].levpuls].level != 0xff) + channel[c].modvol = levpuls[channel[c].levpuls].level; + else + channel[c].modvol = inst[channel[c].inst].data[7] & 63; + } + + channel[c].freq = notetable[note%12] + ((note/12) << 10); + if(cnt < 0x20) // normal note + playnote(c); + else { // tienote + setfreq(c); + cnt -= 0x20; // make count proper + } + channel[c].rhcnt = cnt; + } else { // note handling for v0 + if(cnt < 2) // unlocked note + note += channel[c].transpose; + channel[c].note = note; + + channel[c].freq = notetable[note%12] + ((note/12) << 10); + if(cnt == 1) // tienote + setfreq(c); + else // normal note + playnote(c); + } + break; + } + continue; // event is complete + } else { // effect event + switch(fx) { + case 6: // Cut/Stop Voice + buf = channel[c].inst; + channel[c].inst = 0; + playnote(c); + channel[c].inst = buf; + channel[c].rhcnt = fxop; + continue; // no note follows this event + case 7: // Vibrato + channel[c].vibspeed = fxop & 0xff; + channel[c].vibdepth = fxop >> 8; + channel[c].trigger = fxop >> 9; + break; + case 8: // v0: Duration + if(!version) + channel[c].irhcnt = fxop; + break; + case 9: // New Level + channel[c].vol = fxop & 63; + if(channel[c].vol + channel[c].cvol < 63) // apply channel volume + channel[c].vol += channel[c].cvol; + else + channel[c].vol = 63; + setvolume(c); + break; + case 0xb: // v4: Set SpFX + if(version == 4) + channel[c].ispfx = fxop; + break; + case 0xc: // Set Instrument + channel[c].ispfx = 0xffff; + channel[c].spfx = 0xffff; + channel[c].inst = fxop; + channel[c].modvol = inst[fxop].data[7] & 63; + if(version < 3 && version && inst[fxop].tunelev) // Set LevelPuls + channel[c].ilevpuls = inst[fxop].tunelev - 1; + else { + channel[c].ilevpuls = 0xff; + channel[c].levpuls = 0xff; + } + break; + case 0xd: // Slide up + channel[c].slide = fxop; + break; + case 0xe: // Slide down + channel[c].slide = -fxop; + break; + } + goto readseq; // event is incomplete, note follows + } + } + + for(c=0;c<9;c++) + if(channel[c].seqend) + trackend++; + if(trackend == 9) + songend = 1; + + return !songend; +} + +void Cd00Player::rewind(int subsong) +{ + struct Stpoin { + unsigned short ptr[9]; + unsigned char volume[9],dummy[5]; + } *tpoin; + int i; + + if(version > 1) { // do nothing if subsong > number of subsongs + if(subsong >= header->subsongs) + return; + } else + if(subsong >= header1->subsongs) + return; + + memset(channel,0,sizeof(channel)); + if(version > 1) + tpoin = (struct Stpoin *)((char *)filedata + header->tpoin); + else + tpoin = (struct Stpoin *)((char *)filedata + header1->tpoin); + for(i=0;i<9;i++) { + if(tpoin[subsong].ptr[i]) { // track enabled + channel[i].speed = *((unsigned short *)((char *)filedata + tpoin[subsong].ptr[i])); + channel[i].order = (unsigned short *)((char *)filedata + tpoin[subsong].ptr[i] + 2); + } else { // track disabled + channel[i].speed = 0; + channel[i].order = 0; + } + channel[i].ispfx = 0xffff; channel[i].spfx = 0xffff; // no SpFX + channel[i].ilevpuls = 0xff; channel[i].levpuls = 0xff; // no LevelPuls + channel[i].cvol = tpoin[subsong].volume[i] & 0x7f; // our player may savely ignore bit 7 + channel[i].vol = channel[i].cvol; // initialize volume + } + songend = 0; + opl->init(); opl->write(1,32); // reset OPL chip +} + +std::string Cd00Player::gettype() +{ + char tmpstr[40]; + + sprintf(tmpstr,"EdLib packed (version %d)",version > 1 ? header->version : header1->version); + return std::string(tmpstr); +} + +float Cd00Player::getrefresh() +{ + if(version > 1) + return header->speed; + else + return header1->speed; +} + +unsigned int Cd00Player::getsubsongs() +{ + if(version <= 1) // return number of subsongs + return header1->subsongs; + else + return header->subsongs; +} + +/*** private methods *************************************/ + +void Cd00Player::setvolume(unsigned char chan) +{ + unsigned char op = op_table[chan]; + unsigned short insnr = channel[chan].inst; + + opl->write(0x43 + op,(int)(63-((63-(inst[insnr].data[2] & 63))/63.0)*(63-channel[chan].vol)) + + (inst[insnr].data[2] & 192)); + if(inst[insnr].data[10] & 1) + opl->write(0x40 + op,(int)(63-((63-channel[chan].modvol)/63.0)*(63-channel[chan].vol)) + + (inst[insnr].data[7] & 192)); + else + opl->write(0x40 + op,channel[chan].modvol + (inst[insnr].data[7] & 192)); +} + +void Cd00Player::setfreq(unsigned char chan) +{ + unsigned short freq = channel[chan].freq; + + if(version == 4) // v4: apply instrument finetune + freq += inst[channel[chan].inst].tunelev; + + freq += channel[chan].slideval; + opl->write(0xa0 + chan, freq & 255); + if(channel[chan].key) + opl->write(0xb0 + chan, ((freq >> 8) & 31) | 32); + else + opl->write(0xb0 + chan, (freq >> 8) & 31); +} + +void Cd00Player::setinst(unsigned char chan) +{ + unsigned char op = op_table[chan]; + unsigned short insnr = channel[chan].inst; + + // set instrument data + opl->write(0x63 + op, inst[insnr].data[0]); + opl->write(0x83 + op, inst[insnr].data[1]); + opl->write(0x23 + op, inst[insnr].data[3]); + opl->write(0xe3 + op, inst[insnr].data[4]); + opl->write(0x60 + op, inst[insnr].data[5]); + opl->write(0x80 + op, inst[insnr].data[6]); + opl->write(0x20 + op, inst[insnr].data[8]); + opl->write(0xe0 + op, inst[insnr].data[9]); + if(version) + opl->write(0xc0 + chan, inst[insnr].data[10]); + else + opl->write(0xc0 + chan, (inst[insnr].data[10] << 1) + (inst[insnr].tunelev & 1)); +} + +void Cd00Player::playnote(unsigned char chan) +{ + // set misc vars & play + opl->write(0xb0 + chan, 0); // stop old note + setinst(chan); + channel[chan].key = 1; + setfreq(chan); + setvolume(chan); +} + +void Cd00Player::vibrato(unsigned char chan) +{ + if(!channel[chan].vibdepth) + return; + + if(channel[chan].trigger) + channel[chan].trigger--; + else { + channel[chan].trigger = channel[chan].vibdepth; + channel[chan].vibspeed = -channel[chan].vibspeed; + } + channel[chan].freq += channel[chan].vibspeed; + setfreq(chan); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/d00.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/d00.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,107 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * d00.h - D00 Player by Simon Peter + */ + +#ifndef H_D00 +#define H_D00 + +#include "player.h" + +class Cd00Player: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + Cd00Player(Copl *newopl) + : CPlayer(newopl), filedata(0) + { }; + ~Cd00Player() + { if(filedata) delete [] filedata; }; + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype(); + std::string gettitle() + { if(version > 1) return std::string(header->songname); else return std::string(); }; + std::string getauthor() + { if(version > 1) return std::string(header->author); else return std::string(); }; + std::string getdesc() + { if(*datainfo) return std::string(datainfo); else return std::string(); }; + unsigned int getsubsongs(); + +protected: +#pragma pack(1) + struct d00header { + char id[6]; + unsigned char type,version,speed,subsongs,soundcard; + char songname[32],author[32],dummy[32]; + unsigned short tpoin,seqptr,instptr,infoptr,spfxptr,endmark; + }; + + struct d00header1 { + unsigned char version,speed,subsongs; + unsigned short tpoin,seqptr,instptr,infoptr,lpulptr,endmark; + }; +#pragma pack() + + struct { + unsigned short *order,ordpos,pattpos,del,speed,rhcnt,key,freq,inst,spfx,ispfx,irhcnt; + signed short transpose,slide,slideval,vibspeed; + unsigned char seqend,vol,vibdepth,fxdel,modvol,cvol,levpuls,frameskip,nextnote,note,ilevpuls,trigger; + } channel[9]; + + struct Sinsts { + unsigned char data[11],tunelev,timer,sr,dummy[2]; + } *inst; + + struct Sspfx { + unsigned short instnr; + signed char halfnote; + unsigned char modlev; + signed char modlevadd; + unsigned char duration; + unsigned short ptr; + } *spfx; + + struct Slevpuls { + unsigned char level; + signed char voladd; + unsigned char duration,ptr; + } *levpuls; + + unsigned char songend,version; + char *datainfo; + unsigned short *seqptr; + d00header *header; + d00header1 *header1; + char *filedata; + +private: + void setvolume(unsigned char chan); + void setfreq(unsigned char chan); + void setinst(unsigned char chan); + void playnote(unsigned char chan); + void vibrato(unsigned char chan); +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/database.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/database.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,423 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (c) 1999 - 2003 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * database.cpp - AdPlug database class + * Copyright (c) 2002 Riven the Mage + * Copyright (c) 2002, 2003 Simon Peter + */ + +#include +#include +#include + +#include "database.h" + +#define DB_FILEID_V10 "AdPlug Module Information Database 1.0\x10" + +/***** CAdPlugDatabase *****/ + +const unsigned short CAdPlugDatabase::hash_radix = 0xfff1; // should be prime + +CAdPlugDatabase::CAdPlugDatabase() + : linear_index(0), linear_logic_length(0), linear_length(0) +{ + db_linear = new DB_Bucket * [hash_radix]; + db_hashed = new DB_Bucket * [hash_radix]; + memset(db_linear, 0, sizeof(DB_Bucket *) * hash_radix); + memset(db_hashed, 0, sizeof(DB_Bucket *) * hash_radix); +} + +CAdPlugDatabase::~CAdPlugDatabase() +{ + unsigned long i; + + for(i = 0; i < linear_length; i++) + delete db_linear[i]; + + delete [] db_linear; + delete [] db_hashed; +} + +bool CAdPlugDatabase::load(std::string db_name) +{ + binifstream f(db_name); + if(f.error()) return false; + return load(f); +} + +bool CAdPlugDatabase::load(binistream &f) +{ + unsigned int idlen = strlen(DB_FILEID_V10); + char *id = new char [idlen]; + unsigned long length; + + // Open database as little endian with IEEE floats + f.setFlag(binio::BigEndian, false); f.setFlag(binio::FloatIEEE); + + f.readString(id,idlen); + if(memcmp(id,DB_FILEID_V10,idlen)) { + delete [] id; + return false; + } + delete [] id; + length = f.readInt(4); + + // read records + for(unsigned long i = 0; i < length; i++) + insert(CRecord::factory(f)); + + return true; +} + +bool CAdPlugDatabase::save(std::string db_name) +{ + binofstream f(db_name); + if(f.error()) return false; + return save(f); +} + +bool CAdPlugDatabase::save(binostream &f) +{ + unsigned long i; + + f.writeString(DB_FILEID_V10); + f.writeInt(linear_logic_length, 4); + + // write records + for(i = 0; i < linear_length; i++) + if(!db_linear[i]->deleted) + db_linear[i]->record->write(f); + + return true; +} + +CAdPlugDatabase::CRecord *CAdPlugDatabase::search(CKey const &key) +{ + if(lookup(key)) return get_record(); else return 0; +} + +bool CAdPlugDatabase::lookup(CKey const &key) +{ + unsigned long index = make_hash(key); + if(!db_hashed[index]) return false; + + // immediate hit ? + DB_Bucket *bucket = db_hashed[index]; + + if(!bucket->deleted && bucket->record->key == key) { + linear_index = bucket->index; + return true; + } + + // in-chain hit ? + bucket = db_hashed[index]->chain; + + while(bucket) { + if(!bucket->deleted && bucket->record->key == key) { + linear_index = bucket->index; + return true; + } + + bucket = bucket->chain; + } + + return false; +} + +bool CAdPlugDatabase::insert(CRecord *record) +{ + long index; + + // sanity checks + if(!record) return false; // null-pointer given + if(linear_length == hash_radix) return false; // max. db size exceeded + if(lookup(record->key)) return false; // record already in db + + // make bucket + DB_Bucket *bucket = new DB_Bucket(linear_length, record); + if(!bucket) return false; + + // add to linear list + db_linear[linear_length] = bucket; + linear_logic_length++; linear_length++; + + // add to hashed list + index = make_hash(record->key); + + if(!db_hashed[index]) // First entry in hashtable + db_hashed[index] = bucket; + else { // Add entry in chained list + DB_Bucket *chain = db_hashed[index]; + + while(chain->chain) chain = chain->chain; + chain->chain = bucket; + } + + return true; +} + +void CAdPlugDatabase::wipe(CRecord *record) +{ + if(!lookup(record->key)) return; + wipe(); +} + +void CAdPlugDatabase::wipe() +{ + if(!linear_length) return; + + DB_Bucket *bucket = db_linear[linear_index]; + + if(!bucket->deleted) { + delete bucket->record; + linear_logic_length--; + bucket->deleted = true; + } +} + +CAdPlugDatabase::CRecord *CAdPlugDatabase::get_record() +{ + if(!linear_length) return 0; + return db_linear[linear_index]->record; +} + +bool CAdPlugDatabase::go_forward() +{ + if(linear_index + 1 < linear_length) { + linear_index++; + return true; + } else + return false; +} + +bool CAdPlugDatabase::go_backward() +{ + if(!linear_index) return false; + linear_index--; + return true; +} + +void CAdPlugDatabase::goto_begin() +{ + if(linear_length) linear_index = 0; +} + +void CAdPlugDatabase::goto_end() +{ + if(linear_length) linear_index = linear_length - 1; +} + +inline unsigned long CAdPlugDatabase::make_hash(CKey const &key) +{ + return (key.crc32 + key.crc16) % hash_radix; +} + +/***** CAdPlugDatabase::DB_Bucket *****/ + +CAdPlugDatabase::DB_Bucket::DB_Bucket(unsigned long nindex, CRecord *newrecord, DB_Bucket *newchain) + : index(nindex), deleted(false), chain(newchain), record(newrecord) +{ +} + +CAdPlugDatabase::DB_Bucket::~DB_Bucket() +{ + if(!deleted) delete record; +} + +/***** CAdPlugDatabase::CRecord *****/ + +CAdPlugDatabase::CRecord *CAdPlugDatabase::CRecord::factory(RecordType type) +{ + switch(type) { + case Plain: return new CPlainRecord; + case SongInfo: return new CInfoRecord; + case ClockSpeed: return new CClockRecord; + default: return 0; + } +} + +CAdPlugDatabase::CRecord *CAdPlugDatabase::CRecord::factory(binistream &in) +{ + RecordType type; + unsigned long size; + CRecord *rec; + + type = (RecordType)in.readInt(1); size = in.readInt(4); + rec = factory(type); + + if(rec) { + rec->key.crc16 = in.readInt(2); rec->key.crc32 = in.readInt(4); + rec->filetype = in.readString('\0'); rec->comment = in.readString('\0'); + rec->read_own(in); + return rec; + } else { + // skip this record, cause we don't know about it + in.seek(size, binio::Add); + return 0; + } +} + +void CAdPlugDatabase::CRecord::write(binostream &out) +{ + out.writeInt(type, 1); + out.writeInt(get_size() + filetype.length() + comment.length() + 8, 4); + out.writeInt(key.crc16, 2); out.writeInt(key.crc32, 4); + out.writeString(filetype); out.writeInt('\0', 1); + out.writeString(comment); out.writeInt('\0', 1); + + write_own(out); +} + +bool CAdPlugDatabase::CRecord::user_read(std::istream &in, std::ostream &out) +{ + return user_read_own(in, out); +} + +bool CAdPlugDatabase::CRecord::user_write(std::ostream &out) +{ + out << "Record type: "; + switch(type) { + case Plain: out << "Plain"; break; + case SongInfo: out << "SongInfo"; break; + case ClockSpeed: out << "ClockSpeed"; break; + default: out << "*** Unknown ***"; break; + } + out << std::endl; + out << "Key: " << std::hex << key.crc16 << ":" << key.crc32 << std::dec << std::endl; + out << "File type: " << filetype << std::endl; + out << "Comment: " << comment << std::endl; + + return user_write_own(out); +} + +/***** CAdPlugDatabase::CRecord::CKey *****/ + +CAdPlugDatabase::CKey::CKey(binistream &buf) +{ + make(buf); +} + +bool CAdPlugDatabase::CKey::operator==(const CKey &key) +{ + return ((crc16 == key.crc16) && (crc32 == key.crc32)); +} + +void CAdPlugDatabase::CKey::make(binistream &buf) +// Key is CRC16:CRC32 pair. CRC16 and CRC32 calculation routines (c) Zhengxi +{ + static const unsigned short magic16 = 0xa001; + static const unsigned long magic32 = 0xedb88320; + + crc16 = 0; crc32 = ~0; + + while(!buf.eof()) + { + unsigned char byte = buf.readInt(1); + + for (int j=0;j<8;j++) + { + if ((crc16 ^ byte) & 1) + crc16 = (crc16 >> 1) ^ magic16; + else + crc16 >>= 1; + + if ((crc32 ^ byte) & 1) + crc32 = (crc32 >> 1) ^ magic32; + else + crc32 >>= 1; + + byte >>= 1; + } + } + + crc16 &= 0xffff; + crc32 = ~crc32; +} + +/***** CInfoRecord *****/ + +CInfoRecord::CInfoRecord() +{ + type = SongInfo; +} + +void CInfoRecord::read_own(binistream &in) +{ + title = in.readString('\0'); + author = in.readString('\0'); +} + +void CInfoRecord::write_own(binostream &out) +{ + out.writeString(title); out.writeInt('\0', 1); + out.writeString(author); out.writeInt('\0', 1); +} + +unsigned long CInfoRecord::get_size() +{ + return title.length() + author.length() + 2; +} + +bool CInfoRecord::user_read_own(std::istream &in, std::ostream &out) +{ + out << "Title: "; in >> title; + out << "Author: "; in >> author; + return true; +} + +bool CInfoRecord::user_write_own(std::ostream &out) +{ + out << "Title: " << title << std::endl; + out << "Author: " << author << std::endl; + return true; +} + +/***** CClockRecord *****/ + +CClockRecord::CClockRecord() + : clock(0.0f) +{ + type = ClockSpeed; +} + +void CClockRecord::read_own(binistream &in) +{ + clock = in.readFloat(binio::Single); +} + +void CClockRecord::write_own(binostream &out) +{ + out.writeFloat(clock, binio::Single); +} + +unsigned long CClockRecord::get_size() +{ + return 4; +} + +bool CClockRecord::user_read_own(std::istream &in, std::ostream &out) +{ + out << "Clockspeed: "; in >> clock; + return true; +} + +bool CClockRecord::user_write_own(std::ostream &out) +{ + out << "Clock speed: " << clock << " Hz" << std::endl; + return true; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/database.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/database.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,169 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (c) 1999 - 2003 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * database.h - AdPlug database class + * Copyright (c) 2002 Riven the Mage + * Copyright (c) 2002, 2003 Simon Peter + */ + +#ifndef H_ADPLUG_DATABASE +#define H_ADPLUG_DATABASE + +#include +#include +#include + +class CAdPlugDatabase +{ +public: + class CKey + { + public: + unsigned short crc16; + unsigned long crc32; + + CKey() {}; + CKey(binistream &in); + + bool operator==(const CKey &key); + + private: + void make(binistream &in); + }; + + class CRecord + { + public: + typedef enum { Plain, SongInfo, ClockSpeed } RecordType; + + RecordType type; + CKey key; + std::string filetype, comment; + + static CRecord *factory(RecordType type); + static CRecord *factory(binistream &in); + + CRecord() {} + virtual ~CRecord() {} + + void write(binostream &out); + + bool user_read(std::istream &in, std::ostream &out); + bool user_write(std::ostream &out); + + protected: + virtual void read_own(binistream &in) = 0; + virtual void write_own(binostream &out) = 0; + virtual unsigned long get_size() = 0; + virtual bool user_read_own(std::istream &in, std::ostream &out) = 0; + virtual bool user_write_own(std::ostream &out) = 0; + }; + + CAdPlugDatabase(); + ~CAdPlugDatabase(); + + bool load(std::string db_name); + bool load(binistream &f); + bool save(std::string db_name); + bool save(binostream &f); + + bool insert(CRecord *record); + + void wipe(CRecord *record); + void wipe(); + + CRecord *search(CKey const &key); + bool lookup(CKey const &key); + + CRecord *get_record(); + + bool go_forward(); + bool go_backward(); + + void goto_begin(); + void goto_end(); + +private: + static const unsigned short hash_radix; + + class DB_Bucket + { + public: + unsigned long index; + bool deleted; + DB_Bucket *chain; + + CRecord *record; + + DB_Bucket(unsigned long nindex, CRecord *newrecord, DB_Bucket *newchain = 0); + ~DB_Bucket(); + }; + + DB_Bucket **db_linear; + DB_Bucket **db_hashed; + + unsigned long linear_index, linear_logic_length, linear_length; + + unsigned long make_hash(CKey const &key); +}; + +class CPlainRecord: public CAdPlugDatabase::CRecord +{ +public: + CPlainRecord() { type = Plain; } + +protected: + virtual void read_own(binistream &in) {} + virtual void write_own(binostream &out) {} + virtual unsigned long get_size() { return 0; } + virtual bool user_read_own(std::istream &in, std::ostream &out) { return true; } + virtual bool user_write_own(std::ostream &out) { return true; } +}; + +class CInfoRecord: public CAdPlugDatabase::CRecord +{ +public: + std::string title; + std::string author; + + CInfoRecord(); + +protected: + virtual void read_own(binistream &in); + virtual void write_own(binostream &out); + virtual unsigned long get_size(); + virtual bool user_read_own(std::istream &in, std::ostream &out); + virtual bool user_write_own(std::ostream &out); +}; + +class CClockRecord: public CAdPlugDatabase::CRecord +{ +public: + float clock; + + CClockRecord(); + +protected: + virtual void read_own(binistream &in); + virtual void write_own(binostream &out); + virtual unsigned long get_size(); + virtual bool user_read_own(std::istream &in, std::ostream &out); + virtual bool user_write_own(std::ostream &out); +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/debug.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/debug.c Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,57 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * debug.h - AdPlug Debug Logger + * Copyright (c) 2002 Riven the Mage + * Copyright (c) 2002 Simon Peter + */ + +#ifdef DEBUG + +#include +#include + +static FILE *log = NULL; + +void AdPlug_LogFile(const char *filename) +{ + if(log) fclose(log); + log = fopen(filename,"wt"); +} + +void AdPlug_LogWrite(const char *fmt, ...) +{ + va_list argptr; + + va_start(argptr, fmt); + + if(log) { + vfprintf(log, fmt, argptr); + fflush(log); + } else + vfprintf(stderr, fmt, argptr); + + va_end(argptr); +} + +#else + +void AdPlug_LogFile(char *filename) { } +void AdPlug_LogWrite(char *fmt, ...) { } + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/debug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/debug.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,41 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * debug.h - AdPlug Debug Logger + * Copyright (c) 2002 Riven the Mage + * Copyright (c) 2002 Simon Peter + * + * NOTES: + * This debug logger is used throughout AdPlug to log debug output to stderr + * (the default) or to a user-specified logfile. + * + * To use it, AdPlug has to be compiled with debug logging support enabled. + * This is done by defining the DEBUG macro with every source-file. The + * LogFile() function can be used to specify a logfile to write to. + */ + +#ifndef H_DEBUG +#define H_DEBUG + +extern "C" +{ + void AdPlug_LogFile(const char *filename); + void AdPlug_LogWrite(const char *fmt, ...); +} + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/dfm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/dfm.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,115 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * dfm.cpp - Digital-FM Loader by Simon Peter + */ + +#include +#include + +#include "dfm.h" +#include "debug.h" + +CPlayer *CdfmLoader::factory(Copl *newopl) +{ + return new CdfmLoader(newopl); +} + +bool CdfmLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + unsigned char npats,n,note,fx,c,r,param; + unsigned int i; + const unsigned char convfx[8] = {255,255,17,19,23,24,255,13}; + + // file validation + f->readString(header.id, 4); + header.hiver = f->readInt(1); header.lover = f->readInt(1); + if(strncmp(header.id,"DFM\x1a",4) || header.hiver > 1) + { fp.close(f); return false; } + + // load + restartpos = 0; flags = Standard; bpm = 0; + init_trackord(); + f->readString(songinfo, 33); + initspeed = f->readInt(1); + for(i = 0; i < 32; i++) + f->readString(instname[i], 12); + for(i = 0; i < 32; i++) { + inst[i].data[1] = f->readInt(1); + inst[i].data[2] = f->readInt(1); + inst[i].data[9] = f->readInt(1); + inst[i].data[10] = f->readInt(1); + inst[i].data[3] = f->readInt(1); + inst[i].data[4] = f->readInt(1); + inst[i].data[5] = f->readInt(1); + inst[i].data[6] = f->readInt(1); + inst[i].data[7] = f->readInt(1); + inst[i].data[8] = f->readInt(1); + inst[i].data[0] = f->readInt(1); + } + for(i = 0; i < 128; i++) order[i] = f->readInt(1); + for(i = 0; i < 128 && order[i] != 128; i++) ; length = i; + npats = f->readInt(1); + for(i = 0; i < npats; i++) { + n = f->readInt(1); + for(r = 0; r < 64; r++) + for(c = 0; c < 9; c++) { + note = f->readInt(1); + if((note & 15) == 15) + tracks[n*9+c][r].note = 127; // key off + else + tracks[n*9+c][r].note = ((note & 127) >> 4) * 12 + (note & 15); + if(note & 128) { // additional effect byte + fx = f->readInt(1); + if(fx >> 5 == 1) + tracks[n*9+c][r].inst = (fx & 31) + 1; + else { + tracks[n*9+c][r].command = convfx[fx >> 5]; + if(tracks[n*9+c][r].command == 17) { // set volume + param = fx & 31; + param = 63 - param * 2; + tracks[n*9+c][r].param1 = param >> 4; + tracks[n*9+c][r].param2 = param & 15; + } else { + tracks[n*9+c][r].param1 = (fx & 31) >> 4; + tracks[n*9+c][r].param2 = fx & 15; + } + } + } + + } + } + + fp.close(f); + rewind(0); + return true; +} + +std::string CdfmLoader::gettype() +{ + char tmpstr[20]; + + sprintf(tmpstr,"Digital-FM %d.%d",header.hiver,header.lover); + return std::string(tmpstr); +} + +float CdfmLoader::getrefresh() +{ + return 125.0f; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/dfm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/dfm.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,52 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * dfm.h - Digital-FM Loader by Simon Peter + */ + +#include "protrack.h" + +class CdfmLoader: public CmodPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CdfmLoader(Copl *newopl) + : CmodPlayer(newopl) + { }; + + bool load(const std::string &filename, const CFileProvider &fp); + float getrefresh(); + + std::string gettype(); + unsigned int getinstruments() + { return 32; }; + std::string getinstrument(unsigned int n) + { if(*instname[n]) return std::string(instname[n],1,*instname[n]); else return std::string(); }; + std::string getdesc() + { return std::string(songinfo,1,*songinfo); }; + +private: + struct { + char id[4]; + unsigned char hiver,lover; + } header; + + char songinfo[33]; + char instname[32][12]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/diskopl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/diskopl.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,78 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999, 2000, 2001 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * diskopl.cpp - Disk Writer OPL, by Simon Peter + */ + +#include "diskopl.h" + +static const unsigned short note_table[12] = {363,385,408,432,458,485,514,544,577,611,647,686}; +static const unsigned char op_table[9] = {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12}; + +CDiskopl::CDiskopl(std::string filename): old_freq(0.0f), del(1), nowrite(false) +{ + unsigned short clock = 0xffff; + f = fopen(filename.c_str(),"wb"); + fwrite("RAWADATA",8,1,f); + fwrite(&clock,sizeof(clock),1,f); +} + +CDiskopl::~CDiskopl() +{ + fclose(f); +} + +void CDiskopl::update(CPlayer *p) +{ + unsigned short clock; + unsigned int wait; + + if(p->getrefresh() != old_freq) { + old_freq = p->getrefresh(); + del = wait = (unsigned int)(18.2f / old_freq); + clock = (unsigned short)(1192737/(old_freq*(wait+1))); + fputc(0,f); fputc(2,f); + fwrite(&clock,2,1,f); + } + if(!nowrite) { + fputc(del+1,f); + fputc(0,f); + } +} + +void CDiskopl::write(int reg, int val) +{ + if(!nowrite) + diskwrite(reg,val); +} + +void CDiskopl::init() +{ + for (int i=0;i<9;i++) { // stop instruments + diskwrite(0xb0 + i,0); // key off + diskwrite(0x80 + op_table[i],0xff); // fastest release + } + diskwrite(0xbd,0); // clear misc. register +} + +void CDiskopl::diskwrite(int reg, int val) +{ + fputc(val,f); + fputc(reg,f); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/diskopl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/diskopl.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,49 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999, 2000, 2001 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * diskopl.h - Disk Writer OPL, by Simon Peter + */ + +#include +#include +#include "opl.h" +#include "player.h" + +class CDiskopl: public Copl +{ +public: + CDiskopl(std::string filename); + virtual ~CDiskopl(); + + void update(CPlayer *p); // write to file + void setnowrite(bool nw = true) // set file write status + { nowrite = nw; }; + + // template methods + void write(int reg, int val); + void init(); + +private: + void diskwrite(int reg, int val); + + FILE *f; + float old_freq; + unsigned char del; + bool nowrite; // don't write to file, if true +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/dmo.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/dmo.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,391 @@ +/* + Adplug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2004 Simon Peter, , et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + dmo.cpp - TwinTeam loader by Riven the Mage +*/ +/* + NOTES: + Panning is ignored. + + A WORD ist 16 bits, a DWORD is 32 bits and a BYTE is 8 bits in this context. +*/ + +#include +#include + +#include "dmo.h" +#include "debug.h" + +#define LOWORD(l) ((l) & 0xffff) +#define HIWORD(l) ((l) >> 16) +#define LOBYTE(w) ((w) & 0xff) +#define HIBYTE(w) ((w) >> 8) + +#define ARRAY_AS_DWORD(a, i) \ +((a[i + 3] << 24) + (a[i + 2] << 16) + (a[i + 1] << 8) + a[i]) +#define ARRAY_AS_WORD(a, i) ((a[i + 1] << 8) + a[i]) + +#define CHARP_AS_WORD(p) (((*(p + 1)) << 8) + (*p)) + +/* -------- Public Methods -------------------------------- */ + +CPlayer *CdmoLoader::factory(Copl *newopl) +{ + return new CdmoLoader(newopl); +} + +bool CdmoLoader::load(const std::string &filename, const CFileProvider &fp) +{ + int i,j; + binistream *f; + + // check header + dmo_unpacker *unpacker = new dmo_unpacker; + unsigned char chkhdr[16]; + + if(!fp.extension(filename, ".dmo")) return false; + f = fp.open(filename); if(!f) return false; + + f->readString((char *)chkhdr, 16); + + if (!unpacker->decrypt(chkhdr, 16)) + { + delete unpacker; + fp.close(f); + return false; + } + + // get file size + long packed_length = fp.filesize(f); + f->seek(0); + + unsigned char *packed_module = new unsigned char [packed_length]; + + // load file + f->readString((char *)packed_module, packed_length); + fp.close(f); + + // decrypt + unpacker->decrypt(packed_module,packed_length); + + long unpacked_length = 0x2000 * ARRAY_AS_WORD(packed_module, 12); + unsigned char *module = new unsigned char [unpacked_length]; + + // unpack + if (!unpacker->unpack(packed_module+12,module)) + { + delete unpacker; + delete [] packed_module; + delete [] module; + return false; + } + + delete unpacker; + delete [] packed_module; + + // "TwinTeam" - signed ? + if (memcmp(module,"TwinTeam Module File""\x0D\x0A",22)) + { + delete module; + return false; + } + + // load header + binisstream uf(module, unpacked_length); + uf.setFlag(binio::BigEndian, false); uf.setFlag(binio::FloatIEEE); + + memset(&header,0,sizeof(s3mheader)); + + uf.ignore(22); // ignore DMO header ID string + uf.readString(header.name, 28); + + uf.ignore(2); // _unk_1 + header.ordnum = uf.readInt(2); + header.insnum = uf.readInt(2); + header.patnum = uf.readInt(2); + uf.ignore(2); // _unk_2 + header.is = uf.readInt(2); + header.it = uf.readInt(2); + + memset(header.chanset,0xFF,32); + + for (i=0;i<9;i++) + header.chanset[i] = 0x10 + i; + + uf.ignore(32); // ignore panning settings for all 32 channels + + // load orders + for(i = 0; i < 256; i++) orders[i] = uf.readInt(1); + + orders[header.ordnum] = 0xFF; + + // load pattern lengths + unsigned short my_patlen[100]; + for(i = 0; i < 100; i++) my_patlen[i] = uf.readInt(2); + + // load instruments + for (i = 0; i < header.insnum; i++) + { + memset(&inst[i],0,sizeof(s3minst)); + + uf.readString(inst[i].name, 28); + + inst[i].volume = uf.readInt(1); + inst[i].dsk = uf.readInt(1); + inst[i].c2spd = uf.readInt(4); + inst[i].type = uf.readInt(1); + inst[i].d00 = uf.readInt(1); + inst[i].d01 = uf.readInt(1); + inst[i].d02 = uf.readInt(1); + inst[i].d03 = uf.readInt(1); + inst[i].d04 = uf.readInt(1); + inst[i].d05 = uf.readInt(1); + inst[i].d06 = uf.readInt(1); + inst[i].d07 = uf.readInt(1); + inst[i].d08 = uf.readInt(1); + inst[i].d09 = uf.readInt(1); + inst[i].d0a = uf.readInt(1); + /* + * Originally, riven sets d0b = d0a and ignores 1 byte in the + * stream, but i guess this was a typo, so i read it here. + */ + inst[i].d0b = uf.readInt(1); + } + + // load patterns + for (i = 0; i < header.patnum; i++) { + long cur_pos = uf.pos(); + + for (j = 0; j < 64; j++) { + while (1) { + unsigned char token = uf.readInt(1); + + if (!token) + break; + + unsigned char chan = token & 31; + + // note + instrument ? + if (token & 32) { + unsigned char bufbyte = uf.readInt(1); + + pattern[i][j][chan].note = bufbyte & 15; + pattern[i][j][chan].oct = bufbyte >> 4; + pattern[i][j][chan].instrument = uf.readInt(1); + } + + // volume ? + if (token & 64) + pattern[i][j][chan].volume = uf.readInt(1); + + // command ? + if (token & 128) { + pattern[i][j][chan].command = uf.readInt(1); + pattern[i][j][chan].info = uf.readInt(1); + } + } + } + + uf.seek(cur_pos + my_patlen[i]); + } + + delete [] module; + rewind(0); + return true; +} + +std::string CdmoLoader::gettype() +{ + return std::string("TwinTeam (packed S3M)"); +} + +std::string CdmoLoader::getauthor() +{ + /* + All available .DMO modules written by one composer. And because all .DMO + stuff was lost due to hd crash (TwinTeam guys said this), there are + never(?) be another. + */ + return std::string("Benjamin GERARDIN"); +} + +/* -------- Private Methods ------------------------------- */ + +unsigned short CdmoLoader::dmo_unpacker::brand(unsigned short range) +{ + unsigned short ax,bx,cx,dx; + + ax = LOWORD(bseed); + bx = HIWORD(bseed); + cx = ax; + ax = LOWORD(cx * 0x8405); + dx = HIWORD(cx * 0x8405); + cx <<= 3; + cx = (((HIBYTE(cx) + LOBYTE(cx)) & 0xFF) << 8) + LOBYTE(cx); + dx += cx; + dx += bx; + bx <<= 2; + dx += bx; + dx = (((HIBYTE(dx) + LOBYTE(bx)) & 0xFF) << 8) + LOBYTE(dx); + bx <<= 5; + dx = (((HIBYTE(dx) + LOBYTE(bx)) & 0xFF) << 8) + LOBYTE(dx); + ax += 1; + if (!ax) dx += 1; + + // leave it that way or amd64 might get it wrong + bseed = dx; + bseed <<= 16; + bseed += ax; + + return HIWORD(HIWORD(LOWORD(bseed) * range) + HIWORD(bseed) * range); +} + +bool CdmoLoader::dmo_unpacker::decrypt(unsigned char *buf, long len) +{ + unsigned long seed = 0; + int i; + + bseed = ARRAY_AS_DWORD(buf, 0); + + for (i=0; i < ARRAY_AS_WORD(buf, 4) + 1; i++) + seed += brand(0xffff); + + bseed = seed ^ ARRAY_AS_DWORD(buf, 6); + + if (ARRAY_AS_WORD(buf, 10) != brand(0xffff)) + return false; + + for (i=0;i<(len-12);i++) + buf[12+i] ^= brand(0x100); + + buf[len - 2] = buf[len - 1] = 0; + + return true; +} + +short CdmoLoader::dmo_unpacker::unpack_block(unsigned char *ibuf, long ilen, unsigned char *obuf) +{ + unsigned char code,par1,par2; + unsigned short ax,bx,cx; + + unsigned char *ipos = ibuf; + unsigned char *opos = obuf; + + // LZ77 child + while (ipos - ibuf < ilen) + { + code = *ipos++; + + // 00xxxxxx: copy (xxxxxx + 1) bytes + if ((code >> 6) == 0) + { + cx = (code & 0x3F) + 1; + + for (int i=0;i> 6) == 1) + { + par1 = *ipos++; + + ax = ((code & 0x3F) << 3) + ((par1 & 0xE0) >> 5) + 1; + cx = (par1 & 0x1F) + 3; + + for(int i=0;i> 6) == 2) + { + int i; + + par1 = *ipos++; + + ax = ((code & 0x3F) << 1) + (par1 >> 7) + 1; + cx = ((par1 & 0x70) >> 4) + 3; + bx = par1 & 0x0F; + + for(i=0;i> 6) == 3) + { + int i; + + par1 = *ipos++; + par2 = *ipos++; + + bx = ((code & 0x3F) << 7) + (par1 >> 1); + cx = ((par1 & 0x01) << 4) + (par2 >> 4) + 4; + ax = par2 & 0x0F; + + for(i=0;i, et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + dmo.cpp - TwinTeam loader by Riven the Mage +*/ + +#include "s3m.h" + +class CdmoLoader: public Cs3mPlayer +{ + public: + static CPlayer *factory(Copl *newopl); + + CdmoLoader(Copl *newopl) : Cs3mPlayer(newopl) { }; + + bool load(const std::string &filename, const CFileProvider &fp); + + std::string gettype(); + std::string getauthor(); + + private: + + class dmo_unpacker { + public: + bool decrypt(unsigned char *buf, long len); + long unpack(unsigned char *ibuf, unsigned char *obuf); + + private: + unsigned short brand(unsigned short range); + short unpack_block(unsigned char *ibuf, long ilen, unsigned char *obuf); + unsigned long bseed; + }; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/dro.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/dro.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,99 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * dro.c - DOSBox Raw OPL Player by Sjoerd van der Berg + * + * NOTES: + * OPL3 and second opl2 writes are ignored + */ + +#include "dro.h" + +/*** public methods *************************************/ + +CPlayer *CdroPlayer::factory(Copl *newopl) +{ + return new CdroPlayer(newopl); +} + +bool CdroPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[8];unsigned long i; + + // file validation section + f->readString(id, 8); + if(strncmp(id,"DBRAWOPL",8)) { fp.close (f); return false; } + + // load section + mstotal = f->readInt(4); // Total milliseconds in file + length = f->readInt(4); // Total data bytes in file + mode = (OplMode)f->readInt(1); // Type of opl data this can contain + data = new unsigned char [length]; + for (i=0;ireadInt(1); + fp.close(f); + rewind(0); + return true; +} + +bool CdroPlayer::update() +{ + if (delay>500) { + delay-=500; + return true; + } else delay=0; + while (pos < length) + { + unsigned char cmd = data[pos++]; + switch(cmd) { + case 0: + delay = 1 + data[pos++]; + return true; + case 1: + delay = 1 + data[pos] + (data[pos+1]<<8); + pos+=2; + return true; + case 2: + index = 0; + break; + case 3: + index = 0; + break; + default: + if(!index) + opl->write(cmd,data[pos++]); + break; + } + } + return posinit(); + opl->write(1,32); // go to OPL2 mode +} + +float CdroPlayer::getrefresh() +{ + if (delay > 500) return 1000 / 500; + else return 1000 / (double)delay; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/dro.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/dro.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,52 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * dro.h - DOSBox Raw OPL Player by Sjoerd van der Berg + */ + +#include "player.h" + +class CdroPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CdroPlayer(Copl *newopl) + : CPlayer(newopl), data(0) + { }; + ~CdroPlayer() + { if(data) delete [] data; }; + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype() + { return std::string("DOSBox Raw OPL"); }; + +protected: + unsigned char *data; + unsigned long pos,length; + unsigned long msdone,mstotal; + unsigned short delay; + unsigned char index; + enum OplMode { + ModeOPL2,ModeOPL3,ModeDUALOPL2 + } mode; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/dtm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/dtm.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,312 @@ +/* + Adplug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2003 Simon Peter, , et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + dtm.cpp - DTM loader by Riven the Mage +*/ +/* + NOTE: Panning (Ex) effect is ignored. +*/ + +#include "dtm.h" + +/* -------- Public Methods -------------------------------- */ + +CPlayer *CdtmLoader::factory(Copl *newopl) +{ + return new CdtmLoader(newopl); +} + +bool CdtmLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 }; + const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE }; + + int i,j,k,t=0; + + // read header + f->readString(header.id, 12); + header.version = f->readInt(1); + f->readString(header.title, 20); f->readString(header.author, 20); + header.numpat = f->readInt(1); header.numinst = f->readInt(1); + + // signature exists ? good version ? + if(memcmp(header.id,"DeFy DTM ",9) || header.version != 0x10) + { fp.close (f); return false; } + + header.numinst++; + + // load description + memset(desc,0,80*16); + + char bufstr[80]; + + for (i=0;i<16;i++) + { + // get line length + unsigned char bufstr_length = f->readInt(1); + + // read line + if (bufstr_length) + { + f->readString(bufstr,bufstr_length); + + for (j=0;jreadInt(1); + + if (name_length) + f->readString(instruments[i].name, name_length); + + instruments[i].name[name_length] = 0; + + for(j = 0; j < 12; j++) + instruments[i].data[j] = f->readInt(1); + + for (j=0;j<11;j++) + inst[i].data[conv_inst[j]] = instruments[i].data[j]; + } + + // load order + for(i = 0; i < 100; i++) order[i] = f->readInt(1); + + nop = header.numpat; + + unsigned char *pattern = new unsigned char [0x480]; + + // load tracks + for (i=0;ireadInt(2); + + unsigned char *packed_pattern = new unsigned char [packed_length]; + + for(j = 0; j < packed_length; j++) + packed_pattern[j] = f->readInt(1); + + long unpacked_length = unpack_pattern(packed_pattern,packed_length,pattern,0x480); + + delete [] packed_pattern; + + if (!unpacked_length) + { + delete pattern; + fp.close(f); + return false; + } + + // convert pattern + for (j=0;j<9;j++) + { + for (k=0;k<64;k++) + { + dtm_event *event = (dtm_event *)&pattern[(k*9+j)*2]; + + // instrument + if (event->byte0 == 0x80) + { + if (event->byte1 <= 0x80) + tracks[t][k].inst = event->byte1 + 1; + } + + // note + effect + else + { + tracks[t][k].note = event->byte0; + + if ((event->byte0 != 0) && (event->byte0 != 127)) + tracks[t][k].note++; + + // convert effects + switch (event->byte1 >> 4) + { + case 0x0: // pattern break + if ((event->byte1 & 15) == 1) + tracks[t][k].command = 13; + break; + + case 0x1: // freq. slide up + tracks[t][k].command = 28; + tracks[t][k].param1 = event->byte1 & 15; + break; + + case 0x2: // freq. slide down + tracks[t][k].command = 28; + tracks[t][k].param2 = event->byte1 & 15; + break; + + case 0xA: // set carrier volume + case 0xC: // set instrument volume + tracks[t][k].command = 22; + tracks[t][k].param1 = (0x3F - (event->byte1 & 15)) >> 4; + tracks[t][k].param2 = (0x3F - (event->byte1 & 15)) & 15; + break; + + case 0xB: // set modulator volume + tracks[t][k].command = 21; + tracks[t][k].param1 = (0x3F - (event->byte1 & 15)) >> 4; + tracks[t][k].param2 = (0x3F - (event->byte1 & 15)) & 15; + break; + + case 0xE: // set panning + break; + + case 0xF: // set speed + tracks[t][k].command = 13; + tracks[t][k].param2 = event->byte1 & 15; + break; + } + } + } + + t++; + } + } + + delete [] pattern; + fp.close(f); + + // order length + for (i=0;i<100;i++) + { + if (order[i] >= 0x80) + { + length = i; + + if (order[i] == 0xFF) + restartpos = 0; + else + restartpos = order[i] - 0x80; + + break; + } + } + + // initial speed + initspeed = 2; + + rewind(0); + + return true; +} + +void CdtmLoader::rewind(int subsong) +{ + CmodPlayer::rewind(subsong); + + // default instruments + for (int i=0;i<9;i++) + { + channel[i].inst = i; + + channel[i].vol1 = 63 - (inst[i].data[10] & 63); + channel[i].vol2 = 63 - (inst[i].data[9] & 63); + } +} + +float CdtmLoader::getrefresh() +{ + return 18.2f; +} + +std::string CdtmLoader::gettype() +{ + return std::string("DeFy Adlib Tracker"); +} + +std::string CdtmLoader::gettitle() +{ + return std::string(header.title); +} + +std::string CdtmLoader::getauthor() +{ + return std::string(header.author); +} + +std::string CdtmLoader::getdesc() +{ + return std::string(desc); +} + +std::string CdtmLoader::getinstrument(unsigned int n) +{ + return std::string(instruments[n].name); +} + +unsigned int CdtmLoader::getinstruments() +{ + return header.numinst; +} + +/* -------- Private Methods ------------------------------- */ + +long CdtmLoader::unpack_pattern(unsigned char *ibuf, long ilen, unsigned char *obuf, long olen) +{ + unsigned char *input = ibuf; + unsigned char *output = obuf; + + long input_length = 0; + long output_length = 0; + + unsigned char repeat_byte, repeat_counter; + + // RLE + while (input_length < ilen) + { + repeat_byte = input[input_length++]; + + if ((repeat_byte & 0xF0) == 0xD0) + { + repeat_counter = repeat_byte & 15; + repeat_byte = input[input_length++]; + } + else + repeat_counter = 1; + + for (int i=0;i, et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + dtm.h - DTM loader by Riven the Mage +*/ + +#include "protrack.h" + +class CdtmLoader: public CmodPlayer +{ + public: + static CPlayer *factory(Copl *newopl); + + CdtmLoader(Copl *newopl) : CmodPlayer(newopl) { }; + + bool load(const std::string &filename, const CFileProvider &fp); + void rewind(int subsong); + float getrefresh(); + + std::string gettype(); + std::string gettitle(); + std::string getauthor(); + std::string getdesc(); + std::string getinstrument(unsigned int n); + unsigned int getinstruments(); + + private: + + struct dtm_header + { + char id[12]; + unsigned char version; + char title[20]; + char author[20]; + unsigned char numpat; + unsigned char numinst; + } header; + + char desc[80*16]; + + struct dtm_instrument + { + char name[13]; + unsigned char data[12]; + } instruments[128]; + + struct dtm_event + { + unsigned char byte0; + unsigned char byte1; + }; + + long unpack_pattern(unsigned char *ibuf, long ilen, unsigned char *obuf, long olen); +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/emuopl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/emuopl.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,75 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * emuopl.cpp - Emulated OPL, by Simon Peter + */ + +#include "emuopl.h" + +CEmuopl::CEmuopl(int rate, bool bit16, bool usestereo) + : use16bit(bit16), stereo(usestereo) +{ + opl = OPLCreate(OPL_TYPE_YM3812, 3579545, rate); +} + +CEmuopl::~CEmuopl() +{ + OPLDestroy(opl); +} + +void CEmuopl::update(short *buf, int samples) +{ + int i; + + if(use16bit) { + YM3812UpdateOne(opl,buf,samples); + + if(stereo) + for(i=samples-1;i>=0;i--) { + buf[i*2] = buf[i]; + buf[i*2+1] = buf[i]; + } + } else { + short *tempbuf = new short[stereo ? samples*2 : samples]; + int i; + + YM3812UpdateOne(opl,tempbuf,samples); + + if(stereo) + for(i=samples-1;i>=0;i--) { + tempbuf[i*2] = tempbuf[i]; + tempbuf[i*2+1] = tempbuf[i]; + } + + for(i=0;i<(stereo ? samples*2 : samples);i++) + ((char *)buf)[i] = (tempbuf[i] >> 8) ^ 0x80; + + delete [] tempbuf; + } +} + +void CEmuopl::write(int reg, int val) +{ + OPLWrite(opl,0,reg); + OPLWrite(opl,1,val); +} + +void CEmuopl::init() +{ + OPLResetChip(opl); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/emuopl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/emuopl.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,47 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * emuopl.h - Emulated OPL, by Simon Peter + */ + +#ifndef H_ADPLUG_EMUOPL +#define H_ADPLUG_EMUOPL + +#include "opl.h" +extern "C" { +#include "fmopl.h" +} + +class CEmuopl: public Copl +{ +public: + CEmuopl(int rate, bool bit16, bool usestereo); // rate = sample rate + virtual ~CEmuopl(); + + void update(short *buf, int samples); // fill buffer + + // template methods + void write(int reg, int val); + void init(); + +private: + bool use16bit,stereo; + FM_OPL *opl; // holds emulator data +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/flash.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/flash.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,230 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] FLASH player, by Riven the Mage + */ + +/* + - discovery - + + file(s) : LA-INTRO.EXE + type : Lunatic Asylum BBStro + tune : by Rogue [Logic Design] + player : by Flash [Logic Design] +*/ + +#include "flash.h" +#include "debug.h" + +const unsigned char CxadflashPlayer::flash_adlib_registers[99] = +{ + 0x23, 0x20, 0x43, 0x40, 0x63, 0x60, 0x83, 0x80, 0xC0, 0xE3, 0xE0, + 0x24, 0x21, 0x44, 0x41, 0x64, 0x61, 0x84, 0x81, 0xC1, 0xE4, 0xE1, + 0x25, 0x22, 0x45, 0x42, 0x65, 0x62, 0x85, 0x82, 0xC2, 0xE5, 0xE2, + 0x2B, 0x28, 0x4B, 0x48, 0x6B, 0x68, 0x8B, 0x88, 0xC3, 0xEB, 0xE8, + 0x2C, 0x29, 0x4C, 0x49, 0x6C, 0x69, 0x8C, 0x89, 0xC4, 0xEC, 0xE9, + 0x2D, 0x2A, 0x4D, 0x4A, 0x6D, 0x6A, 0x8D, 0x8A, 0xC5, 0xED, 0xEA, + 0x33, 0x30, 0x53, 0x50, 0x73, 0x70, 0x93, 0x90, 0xC6, 0xF3, 0xF0, + 0x34, 0x31, 0x54, 0x51, 0x74, 0x71, 0x94, 0x91, 0xC7, 0xF4, 0xF1, + 0x35, 0x32, 0x55, 0x52, 0x75, 0x72, 0x95, 0x92, 0xC8, 0xF5, 0xF2 +}; + +const unsigned short CxadflashPlayer::flash_notes_encoded[268] = +{ + 0x000, + 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800, 0x900, 0xA00, 0xB00, 0xC00, + 0x101, 0x201, 0x301, 0x401, 0x501, 0x601, 0x701, 0x801, 0x901, 0xA01, 0xB01, 0xC01, + 0x102, 0x202, 0x302, 0x402, 0x502, 0x602, 0x702, 0x802, 0x902, 0xA02, 0xB02, 0xC02, + 0x103, 0x203, 0x303, 0x403, 0x503, 0x603, 0x703, 0x803, 0x903, 0xA03, 0xB03, 0xC03, + 0x104, 0x204, 0x304, 0x404, 0x504, 0x604, 0x704, 0x804, 0x904, 0xA04, 0xB04, 0xC04, + 0x105, 0x205, 0x305, 0x405, 0x505, 0x605, 0x705, 0x805, 0x905, 0xA05, 0xB05, 0xC05, + 0x106, 0x206, 0x306, 0x406, 0x506, 0x606, 0x706, 0x806, 0x906, 0xA06, 0xB06, 0xC06, + 0x107, 0x207, 0x307, 0x407, 0x507, 0x607, 0x707, 0x807, 0x907, 0xA07, 0xB07, 0xC07, + 0x108, 0x208, 0x308, 0x408, 0x508, 0x608, 0x708, 0x808, 0x908, 0xA08, 0xB08, 0xC08, + 0x109, 0x209, 0x309, 0x409, 0x509, 0x609, 0x709, 0x809, 0x909, 0xA09, 0xB09, 0xC09, + 0x10A, 0x20A, 0x30A, 0x40A, 0x50A, 0x60A, 0x70A, 0x80A, 0x90A, 0xA0A, 0xB0A, 0xC0A, + 0x10B, 0x20B, 0x30B, 0x40B, 0x50B, 0x60B, 0x70B, 0x80B, 0x90B, 0xA0B, 0xB0B, 0xC0B, + 0x10C, 0x20C, 0x30C, 0x40C, 0x50C, 0x60C, 0x70C, 0x80C, 0x90C, 0xA0C, 0xB0C, 0xC0C, + 0x10D, 0x20D, 0x30D, 0x40D, 0x50D, 0x60D, 0x70D, 0x80D, 0x90D, 0xA0D, 0xB0D, 0xC0D, + 0x10E, 0x20E, 0x30E, 0x40E, 0x50E, 0x60E, 0x70E, 0x80E, 0x90E, 0xA0E, 0xB0E, 0xC0E, + 0x10F, 0x20F, 0x30F, 0x40F, 0x50F, 0x60F, 0x70F, 0x80F, 0x90F, 0xA0F, 0xB0F, 0xC0F, + 0x110, 0x210, 0x310, 0x410, 0x510, 0x610, 0x710, 0x810, 0x910, 0xA10, 0xB10, 0xC10, + 0x111, 0x211, 0x311, 0x411, 0x511, 0x611, 0x711, 0x811, 0x911, 0xA11, 0xB11, 0xC11, + 0x112, 0x212, 0x312, 0x412, 0x512, 0x612, 0x712, 0x812, 0x912, 0xA12, 0xB12, 0xC12, + 0x113, 0x213, 0x313, 0x413, 0x513, 0x613, 0x713, 0x813, 0x913, 0xA13, 0xB13, 0xC13, + 0x114, 0x214, 0x314, 0x414, 0x514, 0x614, 0x714, 0x814, 0x914, 0xA14, 0xB14, 0xC14, + 0x115, 0x215, 0x315 +}; + +const unsigned short CxadflashPlayer::flash_notes[12] = +{ + 0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287 +}; + +const unsigned char CxadflashPlayer::flash_default_instrument[8] = +{ + 0x00, 0x00, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF +}; + +CPlayer *CxadflashPlayer::factory(Copl *newopl) +{ + return new CxadflashPlayer(newopl); +} + +void CxadflashPlayer::xadplayer_rewind(int subsong) +{ + int i; + + plr.speed = xad.speed; + + flash.order_pos = 0; + flash.pattern_pos = 0; + + opl_write(0x08, 0x00); + opl_write(0xBD, 0x00); + + // assign default instrument + for(i=0; i<9; i++) + { + opl_write(0xA0+i, 0x00); + opl_write(0xB0+i, 0x00); + } + + // assign instruments + for(i=0; i<9; i++) + for(int j=0; j<11; j++) + opl_write(flash_adlib_registers[i*11+j], tune[i*12+j]); +} + +void CxadflashPlayer::xadplayer_update() +{ + unsigned short event_pos = (tune[0x600+flash.order_pos]*1152) + \ + (flash.pattern_pos*18) + \ + 0x633; + + for (int i=0; i<9; i++) + { + unsigned short flash_channel_freq = (adlib[0xB0+i] << 8) + adlib[0xA0+i]; + + unsigned char event_b0 = tune[event_pos++]; + unsigned char event_b1 = tune[event_pos++]; +#ifdef DEBUG + AdPlug_LogWrite("channel %02X, event %02X %02X:\n",i+1,event_b0,event_b1); +#endif + + if (event_b0 == 0x80) // 0.0x80: Set Instrument + { + for(int j=0; j<11; j++) + opl_write(flash_adlib_registers[i*11+j], tune[event_b1*12+j]); + } + else + { + if (event_b1 == 0x01) + flash.pattern_pos = 0x3F; // 1.0x01: Pattern Break + + unsigned char fx = (event_b1 >> 4); + unsigned char fx_p = (event_b1 & 0x0F); + + switch(fx) + { + case 0x0A: // 1.0xAy: Set Carrier volume + opl_write(flash_adlib_registers[11*i+2], fx_p << 2); + break; + case 0x0B: // 1.0xBy: Set Modulator volume + opl_write(flash_adlib_registers[11*i+3], fx_p << 2); + break; + case 0x0C: // 1.0xCy: Set both operators volume + opl_write(flash_adlib_registers[11*i+2], fx_p << 2); + opl_write(flash_adlib_registers[11*i+3], fx_p << 2); + break; +// case 0x0E: // 1.0xEy: ? (increase some value) + case 0x0F: // 1.0xFy: Set Speed + plr.speed = (fx_p + 1); + break; + } + + if (event_b0) + { + // mute channel + opl_write(0xA0+i, adlib[0xA0+i]); + opl_write(0xB0+i, adlib[0xB0+i] & 0xDF); + + // is note ? + if (event_b0 != 0x7F) + { + unsigned short note_encoded = flash_notes_encoded[event_b0]; + unsigned short freq = flash_notes[(note_encoded >> 8) - 1]; + + flash_channel_freq = freq | ((note_encoded & 0xFF) << 10) | 0x2000; + + opl_write(0xA0+i, flash_channel_freq & 0xFF); + opl_write(0xB0+i, flash_channel_freq >> 8); + } + } + + if (fx == 0x01) // 1.0x1y: Fine Frequency Slide Up + { + flash_channel_freq += (fx_p << 1); + + opl_write(0xA0+i, flash_channel_freq & 0xFF); + opl_write(0xB0+i, flash_channel_freq >> 8); + } + else if (fx == 0x02) // 1.0x2y: Fine Frequency Slide Down + { + flash_channel_freq -= (fx_p << 1); + + opl_write(0xA0+i, flash_channel_freq & 0xFF); + opl_write(0xB0+i, flash_channel_freq >> 8); + } + } + } + + // next row + flash.pattern_pos++; + + // end of pattern ? + if (flash.pattern_pos >= 0x40) + { + flash.pattern_pos = 0; + + flash.order_pos++; + + // end of module ? + if (tune[0x600+flash.order_pos] == 0xFF) + { + flash.order_pos = 0; + + plr.looping = 1; + } + } +} + +float CxadflashPlayer::xadplayer_getrefresh() +{ + return 17.5f; +} + +std::string CxadflashPlayer::xadplayer_gettype() +{ + return std::string("xad: flash player"); +} + +unsigned int CxadflashPlayer::xadplayer_getinstruments() +{ + return 32; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/flash.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/flash.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,57 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] FLASH player, by Riven the Mage + */ + +#include "xad.h" + +class CxadflashPlayer: public CxadPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CxadflashPlayer(Copl *newopl): CxadPlayer(newopl) + { }; + +protected: + struct + { + unsigned char order_pos; + unsigned char pattern_pos; + } flash; + // + bool xadplayer_load() + { + if(xad.fmt == FLASH) + return true; + else + return false; + } + void xadplayer_rewind(int subsong); + void xadplayer_update(); + float xadplayer_getrefresh(); + std::string xadplayer_gettype(); + unsigned int xadplayer_getinstruments(); + +private: + static const unsigned char flash_adlib_registers[99]; + static const unsigned short flash_notes_encoded[268]; + static const unsigned short flash_notes[12]; + static const unsigned char flash_default_instrument[8]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/fmc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/fmc.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,223 @@ +/* + Adplug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2003 Simon Peter , et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + fmc.cpp - FMC Loader by Riven the Mage +*/ + +#include "fmc.h" + +/* -------- Public Methods -------------------------------- */ + +CPlayer *CfmcLoader::factory(Copl *newopl) +{ + return new CfmcLoader(newopl); +} + +bool CfmcLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + const unsigned char conv_fx[16] = {0,1,2,3,4,8,255,255,255,255,26,11,12,13,14,15}; + + int i,j,k,t=0; + + // read header + f->readString(header.id, 4); + f->readString(header.title, 21); + header.numchan = f->readInt(1); + + // 'FMC!' - signed ? + if (strncmp(header.id,"FMC!",4)) { fp.close(f); return false; } + + // init CmodPlayer + realloc_instruments(32); + realloc_order(256); + realloc_patterns(64,64,header.numchan); + init_trackord(); + + // load order + for(i = 0; i < 256; i++) order[i] = f->readInt(1); + + f->ignore(2); + + // load instruments + for(i = 0; i < 32; i++) { + instruments[i].synthesis = f->readInt(1); + instruments[i].feedback = f->readInt(1); + + instruments[i].mod_attack = f->readInt(1); + instruments[i].mod_decay = f->readInt(1); + instruments[i].mod_sustain = f->readInt(1); + instruments[i].mod_release = f->readInt(1); + instruments[i].mod_volume = f->readInt(1); + instruments[i].mod_ksl = f->readInt(1); + instruments[i].mod_freq_multi = f->readInt(1); + instruments[i].mod_waveform = f->readInt(1); + instruments[i].mod_sustain_sound = f->readInt(1); + instruments[i].mod_ksr = f->readInt(1); + instruments[i].mod_vibrato = f->readInt(1); + instruments[i].mod_tremolo = f->readInt(1); + + instruments[i].car_attack = f->readInt(1); + instruments[i].car_decay = f->readInt(1); + instruments[i].car_sustain = f->readInt(1); + instruments[i].car_release = f->readInt(1); + instruments[i].car_volume = f->readInt(1); + instruments[i].car_ksl = f->readInt(1); + instruments[i].car_freq_multi = f->readInt(1); + instruments[i].car_waveform = f->readInt(1); + instruments[i].car_sustain_sound = f->readInt(1); + instruments[i].car_ksr = f->readInt(1); + instruments[i].car_vibrato = f->readInt(1); + instruments[i].car_tremolo = f->readInt(1); + + instruments[i].pitch_shift = f->readInt(1); + + f->readString(instruments[i].name, 21); + } + + // load tracks + for (i=0;i<64;i++) + { + if(f->ateof()) break; + + for (j=0;jreadInt(1); + event.byte1 = f->readInt(1); + event.byte2 = f->readInt(1); + + // convert event + tracks[t][k].note = event.byte0 & 0x7F; + tracks[t][k].inst = ((event.byte0 & 0x80) >> 3) + (event.byte1 >> 4) + 1; + tracks[t][k].command = conv_fx[event.byte1 & 0x0F]; + tracks[t][k].param1 = event.byte2 >> 4; + tracks[t][k].param2 = event.byte2 & 0x0F; + + // fix effects + if (tracks[t][k].command == 0x0E) // 0x0E (14): Retrig + tracks[t][k].param1 = 3; + if (tracks[t][k].command == 0x1A) // 0x1A (26): Volume Slide + if (tracks[t][k].param1 > tracks[t][k].param2) + { + tracks[t][k].param1 -= tracks[t][k].param2; + tracks[t][k].param2 = 0; + } + else + { + tracks[t][k].param2 -= tracks[t][k].param1; + tracks[t][k].param1 = 0; + } + } + + t++; + } + } + fp.close(f); + + // convert instruments + for (i=0;i<31;i++) + buildinst(i); + + // order length + for (i=0;i<256;i++) + { + if (order[i] >= 0xFE) + { + length = i; + break; + } + } + + // data for Protracker + activechan = (0xffff >> (16 - header.numchan)) << (16 - header.numchan); + nop = t / header.numchan; + restartpos = 0; + + // flags + flags = Faust; + + rewind(0); + + return true; +} + +float CfmcLoader::getrefresh() +{ + return 50.0f; +} + +std::string CfmcLoader::gettype() +{ + return std::string("Faust Music Creator"); +} + +std::string CfmcLoader::gettitle() +{ + return std::string(header.title); +} + +std::string CfmcLoader::getinstrument(unsigned int n) +{ + return std::string(instruments[n].name); +} + +unsigned int CfmcLoader::getinstruments() +{ + return 32; +} + +/* -------- Private Methods ------------------------------- */ + +void CfmcLoader::buildinst(unsigned char i) +{ + inst[i].data[0] = ((instruments[i].synthesis & 1) ^ 1); + inst[i].data[0] |= ((instruments[i].feedback & 7) << 1); + + inst[i].data[3] = ((instruments[i].mod_attack & 15) << 4); + inst[i].data[3] |= (instruments[i].mod_decay & 15); + inst[i].data[5] = ((15 - (instruments[i].mod_sustain & 15)) << 4); + inst[i].data[5] |= (instruments[i].mod_release & 15); + inst[i].data[9] = (63 - (instruments[i].mod_volume & 63)); + inst[i].data[9] |= ((instruments[i].mod_ksl & 3) << 6); + inst[i].data[1] = (instruments[i].mod_freq_multi & 15); + inst[i].data[7] = (instruments[i].mod_waveform & 3); + inst[i].data[1] |= ((instruments[i].mod_sustain_sound & 1) << 5); + inst[i].data[1] |= ((instruments[i].mod_ksr & 1) << 4); + inst[i].data[1] |= ((instruments[i].mod_vibrato & 1) << 6); + inst[i].data[1] |= ((instruments[i].mod_tremolo & 1) << 7); + + inst[i].data[4] = ((instruments[i].car_attack & 15) << 4); + inst[i].data[4] |= (instruments[i].car_decay & 15); + inst[i].data[6] = ((15 - (instruments[i].car_sustain & 15)) << 4); + inst[i].data[6] |= (instruments[i].car_release & 15); + inst[i].data[10] = (63 - (instruments[i].car_volume & 63)); + inst[i].data[10] |= ((instruments[i].car_ksl & 3) << 6); + inst[i].data[2] = (instruments[i].car_freq_multi & 15); + inst[i].data[8] = (instruments[i].car_waveform & 3); + inst[i].data[2] |= ((instruments[i].car_sustain_sound & 1) << 5); + inst[i].data[2] |= ((instruments[i].car_ksr & 1) << 4); + inst[i].data[2] |= ((instruments[i].car_vibrato & 1) << 6); + inst[i].data[2] |= ((instruments[i].car_tremolo & 1) << 7); + + inst[i].slide = instruments[i].pitch_shift; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/fmc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/fmc.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,91 @@ +/* + Adplug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2003 Simon Peter, , et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + fmc.h - FMC loader by Riven the Mage +*/ + +#include "protrack.h" + +class CfmcLoader: public CmodPlayer +{ + public: + static CPlayer *factory(Copl *newopl); + + CfmcLoader(Copl *newopl) : CmodPlayer(newopl) { }; + + bool load(const std::string &filename, const CFileProvider &fp); + float getrefresh(); + + std::string gettype(); + std::string gettitle(); + std::string getinstrument(unsigned int n); + unsigned int getinstruments(); + + private: + + struct fmc_event + { + unsigned char byte0; + unsigned char byte1; + unsigned char byte2; + }; + + struct fmc_header + { + char id[4]; + char title[21]; + unsigned char numchan; + } header; + + struct fmc_instrument + { + unsigned char synthesis; + unsigned char feedback; + + unsigned char mod_attack; + unsigned char mod_decay; + unsigned char mod_sustain; + unsigned char mod_release; + unsigned char mod_volume; + unsigned char mod_ksl; + unsigned char mod_freq_multi; + unsigned char mod_waveform; + unsigned char mod_sustain_sound; + unsigned char mod_ksr; + unsigned char mod_vibrato; + unsigned char mod_tremolo; + unsigned char car_attack; + unsigned char car_decay; + unsigned char car_sustain; + unsigned char car_release; + unsigned char car_volume; + unsigned char car_ksl; + unsigned char car_freq_multi; + unsigned char car_waveform; + unsigned char car_sustain_sound; + unsigned char car_ksr; + unsigned char car_vibrato; + unsigned char car_tremolo; + + signed char pitch_shift; + + char name[21]; + } instruments[32]; + + void buildinst(unsigned char i); +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/fmopl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/fmopl.c Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,1390 @@ +/* +** +** File: fmopl.c -- software implementation of FM sound generator +** +** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development +** +** Version 0.37a +** +*/ + +/* + preliminary : + Problem : + note: +*/ + +/* This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define INLINE __inline +#define HAS_YM3812 1 + +#include +#include +#include +#include +#include +//#include "driver.h" /* use M.A.M.E. */ +#include "fmopl.h" + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +/* -------------------- for debug --------------------- */ +/* #define OPL_OUTPUT_LOG */ +#ifdef OPL_OUTPUT_LOG +static FILE *opl_dbg_fp = NULL; +static FM_OPL *opl_dbg_opl[16]; +static int opl_dbg_maxchip,opl_dbg_chip; +#endif + +/* -------------------- preliminary define section --------------------- */ +/* attack/decay rate time rate */ +#define OPL_ARRATE 141280 /* RATE 4 = 2826.24ms @ 3.6MHz */ +#define OPL_DRRATE 1956000 /* RATE 4 = 39280.64ms @ 3.6MHz */ + +#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */ + +#define FREQ_BITS 24 /* frequency turn */ + +/* counter bits = 20 , octerve 7 */ +#define FREQ_RATE (1<<(FREQ_BITS-20)) +#define TL_BITS (FREQ_BITS+2) + +/* final output shift , limit minimum and maximum */ +#define OPL_OUTSB (TL_BITS+3-16) /* OPL output final shift 16bit */ +#define OPL_MAXOUT (0x7fff<=LOG_LEVEL ) logerror x +#define LOG(n,x) + +/* --------------------- subroutines --------------------- */ + +INLINE int Limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + +/* status set and IRQ handling */ +INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) +{ + /* set status flag */ + OPL->status |= flag; + if(!(OPL->status & 0x80)) + { + if(OPL->status & OPL->statusmask) + { /* IRQ on */ + OPL->status |= 0x80; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); + } + } +} + +/* status reset and IRQ handling */ +INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) +{ + /* reset status flag */ + OPL->status &=~flag; + if((OPL->status & 0x80)) + { + if (!(OPL->status & OPL->statusmask) ) + { + OPL->status &= 0x7f; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); + } + } +} + +/* IRQ mask set */ +INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) +{ + OPL->statusmask = flag; + /* IRQ handling check */ + OPL_STATUS_SET(OPL,0); + OPL_STATUS_RESET(OPL,0); +} + +/* ----- key on ----- */ +INLINE void OPL_KEYON(OPL_SLOT *SLOT) +{ + /* sin wave restart */ + SLOT->Cnt = 0; + /* set attack */ + SLOT->evm = ENV_MOD_AR; + SLOT->evs = SLOT->evsa; + SLOT->evc = EG_AST; + SLOT->eve = EG_AED; +} +/* ----- key off ----- */ +INLINE void OPL_KEYOFF(OPL_SLOT *SLOT) +{ + if( SLOT->evm > ENV_MOD_RR) + { + /* set envelope counter from envleope output */ + SLOT->evm = ENV_MOD_RR; + if( !(SLOT->evc&EG_DST) ) + //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<evc = EG_DST; + SLOT->eve = EG_DED; + SLOT->evs = SLOT->evsr; + } +} + +/* ---------- calcrate Envelope Generator & Phase Generator ---------- */ +/* return : envelope output */ +INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT ) +{ + /* calcrate envelope generator */ + if( (SLOT->evc+=SLOT->evs) >= SLOT->eve ) + { + switch( SLOT->evm ){ + case ENV_MOD_AR: /* ATTACK -> DECAY1 */ + /* next DR */ + SLOT->evm = ENV_MOD_DR; + SLOT->evc = EG_DST; + SLOT->eve = SLOT->SL; + SLOT->evs = SLOT->evsd; + break; + case ENV_MOD_DR: /* DECAY -> SL or RR */ + SLOT->evc = SLOT->SL; + SLOT->eve = EG_DED; + if(SLOT->eg_typ) + { + SLOT->evs = 0; + } + else + { + SLOT->evm = ENV_MOD_RR; + SLOT->evs = SLOT->evsr; + } + break; + case ENV_MOD_RR: /* RR -> OFF */ + SLOT->evc = EG_OFF; + SLOT->eve = EG_OFF+1; + SLOT->evs = 0; + break; + } + } + /* calcrate envelope */ + return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0); +} + +/* set algorythm connection */ +static void set_algorythm( OPL_CH *CH) +{ + INT32 *carrier = &outd[0]; + CH->connect1 = CH->CON ? carrier : &feedback2; + CH->connect2 = carrier; +} + +/* ---------- frequency counter for operater update ---------- */ +INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) +{ + int ksr; + + /* frequency step counter */ + SLOT->Incr = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + /* attack , decay rate recalcration */ + SLOT->evsa = SLOT->AR[ksr]; + SLOT->evsd = SLOT->DR[ksr]; + SLOT->evsr = SLOT->RR[ksr]; + } + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +INLINE void set_mul(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = MUL_TABLE[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_typ = (v&0x20)>>5; + SLOT->vib = (v&0x40); + SLOT->ams = (v&0x80); + CALC_FCSLOT(CH,SLOT); +} + +/* set ksl & tl */ +INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */ + + SLOT->ksl = ksl ? 3-ksl : 31; + SLOT->TL = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */ + + if( !(OPL->mode&0x80) ) + { /* not CSM latch total level */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } +} + +/* set attack rate & decay rate */ +INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int ar = v>>4; + int dr = v&0x0f; + + SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0; + SLOT->evsa = SLOT->AR[SLOT->ksr]; + if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa; + + SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0; + SLOT->evsd = SLOT->DR[SLOT->ksr]; + if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd; +} + +/* set sustain level & release rate */ +INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int sl = v>>4; + int rr = v & 0x0f; + + SLOT->SL = SL_TABLE[sl]; + if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL; + SLOT->RR = &OPL->DR_TABLE[rr<<2]; + SLOT->evsr = SLOT->RR[SLOT->ksr]; + if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr; +} + +/* operator output calcrator */ +#define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env] +/* ---------- calcrate one of channel ---------- */ +INLINE void OPL_CALC_CH( OPL_CH *CH ) +{ + UINT32 env_out; + OPL_SLOT *SLOT; + + feedback2 = 0; + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + if(CH->FB) + { + int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; + CH->op1_out[1] = CH->op1_out[0]; + *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1); + } + else + { + *CH->connect1 += OP_OUT(SLOT,env_out,0); + } + }else + { + CH->op1_out[1] = CH->op1_out[0]; + CH->op1_out[0] = 0; + } + /* SLOT 2 */ + SLOT = &CH->SLOT[SLOT2]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + outd[0] += OP_OUT(SLOT,env_out, feedback2); + } +} + +/* ---------- calcrate rythm block ---------- */ +#define WHITE_NOISE_db 6.0 +INLINE void OPL_CALC_RH( OPL_CH *CH ) +{ + UINT32 env_tam,env_sd,env_top,env_hh; + int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP); + INT32 tone8; + + OPL_SLOT *SLOT; + int env_out; + + /* BD : same as FM serial mode and output level is large */ + feedback2 = 0; + /* SLOT 1 */ + SLOT = &CH[6].SLOT[SLOT1]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + if(CH[6].FB) + { + int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB; + CH[6].op1_out[1] = CH[6].op1_out[0]; + feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1); + } + else + { + feedback2 = OP_OUT(SLOT,env_out,0); + } + }else + { + feedback2 = 0; + CH[6].op1_out[1] = CH[6].op1_out[0]; + CH[6].op1_out[0] = 0; + } + /* SLOT 2 */ + SLOT = &CH[6].SLOT[SLOT2]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + outd[0] += OP_OUT(SLOT,env_out, feedback2)*2; + } + + // SD (17) = mul14[fnum7] + white noise + // TAM (15) = mul15[fnum8] + // TOP (18) = fnum6(mul18[fnum8]+whitenoise) + // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise + env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise; + env_tam=OPL_CALC_SLOT(SLOT8_1); + env_top=OPL_CALC_SLOT(SLOT8_2); + env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise; + + /* PG */ + if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE); + else SLOT7_1->Cnt += 2*SLOT7_1->Incr; + if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE); + else SLOT7_2->Cnt += (CH[7].fc*8); + if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE); + else SLOT8_1->Cnt += SLOT8_1->Incr; + if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE); + else SLOT8_2->Cnt += (CH[8].fc*48); + + tone8 = OP_OUT(SLOT8_2,whitenoise,0 ); + + /* SD */ + if( env_sd < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8; + /* TAM */ + if( env_tam < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2; + /* TOP-CY */ + if( env_top < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2; + /* HH */ + if( env_hh < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2; +} + +/* ----------- initialize time tabls ----------- */ +static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE ) +{ + int i; + double rate; + + /* make attack rate & decay rate tables */ + for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0; + for (i = 4;i <= 60;i++){ + rate = OPL->freqbase; /* frequency rate */ + if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ + rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */ + rate *= (double)(EG_ENT<AR_TABLE[i] = rate / ARRATE; + OPL->DR_TABLE[i] = rate / DRRATE; + } + for (i = 60;i < 76;i++) + { + OPL->AR_TABLE[i] = EG_AED-1; + OPL->DR_TABLE[i] = OPL->DR_TABLE[60]; + } +#if 0 + for (i = 0;i < 64 ;i++){ /* make for overflow area */ + LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i, + ((double)(EG_ENT<AR_TABLE[i]) * (1000.0 / OPL->rate), + ((double)(EG_ENT<DR_TABLE[i]) * (1000.0 / OPL->rate) )); + } +#endif +} + +/* ---------- generic table initialize ---------- */ +static int OPLOpenTable( void ) +{ + int s,t; + double rate; + int i,j; + double pom; + + /* allocate dynamic tables */ + if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL) + return 0; + if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL) + { + free(TL_TABLE); + return 0; + } + if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL) + { + free(TL_TABLE); + free(SIN_TABLE); + return 0; + } + if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL) + { + free(TL_TABLE); + free(SIN_TABLE); + free(AMS_TABLE); + return 0; + } + /* make total level table */ + for (t = 0;t < EG_ENT-1 ;t++){ + rate = ((1< voltage */ + TL_TABLE[ t] = (int)rate; + TL_TABLE[TL_MAX+t] = -TL_TABLE[t]; +/* LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/ + } + /* fill volume off area */ + for ( t = EG_ENT-1; t < TL_MAX ;t++){ + TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0; + } + + /* make sinwave table (total level offet) */ + /* degree 0 = degree 180 = off */ + SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1]; + for (s = 1;s <= SIN_ENT/4;s++){ + pom = sin(2*PI*s/SIN_ENT); /* sin */ + pom = 20*log10(1/pom); /* decibel */ + j = pom / EG_STEP; /* TL_TABLE steps */ + + /* degree 0 - 90 , degree 180 - 90 : plus section */ + SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j]; + /* degree 180 - 270 , degree 360 - 270 : minus section */ + SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j]; +/* LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/ + } + for (s = 0;s < SIN_ENT;s++) + { + SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT]; + SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)]; + SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s]; + } + + /* envelope counter -> envelope output table */ + for (i=0; i= EG_ENT ) pom = EG_ENT-1; */ + ENV_CURVE[i] = (int)pom; + /* DECAY ,RELEASE curve */ + ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i; + } + /* off */ + ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1; + /* make LFO ams table */ + for (i=0; iSLOT[SLOT1]; + OPL_SLOT *slot2 = &CH->SLOT[SLOT2]; + /* all key off */ + OPL_KEYOFF(slot1); + OPL_KEYOFF(slot2); + /* total level latch */ + slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); + slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); + /* key on */ + CH->op1_out[0] = CH->op1_out[1] = 0; + OPL_KEYON(slot1); + OPL_KEYON(slot2); +} + +/* ---------- opl initialize ---------- */ +static void OPL_initalize(FM_OPL *OPL) +{ + int fn; + + /* frequency base */ + OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0; + /* Timer base time */ + OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 ); + /* make time tables */ + init_timetables( OPL , OPL_ARRATE , OPL_DRRATE ); + /* make fnumber -> increment counter table */ + for( fn=0 ; fn < 1024 ; fn++ ) + { + OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2; + } + /* LFO freq.table */ + OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<rate * 3.7 * ((double)OPL->clock/3600000) : 0; + OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<rate * 6.4 * ((double)OPL->clock/3600000) : 0; +} + +/* ---------- write a OPL registers ---------- */ +static void OPLWriteReg(FM_OPL *OPL, int r, int v) +{ + OPL_CH *CH; + int slot; + int block_fnum; + + switch(r&0xe0) + { + case 0x00: /* 00-1f:controll */ + switch(r&0x1f) + { + case 0x01: + /* wave selector enable */ + if(OPL->type&OPL_TYPE_WAVESEL) + { + OPL->wavesel = v&0x20; + if(!OPL->wavesel) + { + /* preset compatible mode */ + int c; + for(c=0;cmax_ch;c++) + { + OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0]; + OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0]; + } + } + } + return; + case 0x02: /* Timer 1 */ + OPL->T[0] = (256-v)*4; + break; + case 0x03: /* Timer 2 */ + OPL->T[1] = (256-v)*16; + return; + case 0x04: /* IRQ clear / mask and Timer enable */ + if(v&0x80) + { /* IRQ flag clear */ + OPL_STATUS_RESET(OPL,0x7f); + } + else + { /* set IRQ mask ,timer enable*/ + UINT8 st1 = v&1; + UINT8 st2 = (v>>1)&1; + /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ + OPL_STATUS_RESET(OPL,v&0x78); + OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01); + /* timer 2 */ + if(OPL->st[1] != st2) + { + double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0; + OPL->st[1] = st2; + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); + } + /* timer 1 */ + if(OPL->st[0] != st1) + { + double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0; + OPL->st[0] = st1; + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); + } + } + return; +#if BUILD_Y8950 + case 0x06: /* Key Board OUT */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_w) + OPL->keyboardhandler_w(OPL->keyboard_param,v); + else + LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n")); + } + return; + case 0x07: /* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + return; + case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ + OPL->mode = v; + v&=0x1f; /* for DELTA-T unit */ + case 0x09: /* START ADD */ + case 0x0a: + case 0x0b: /* STOP ADD */ + case 0x0c: + case 0x0d: /* PRESCALE */ + case 0x0e: + case 0x0f: /* ADPCM data */ + case 0x10: /* DELTA-N */ + case 0x11: /* DELTA-N */ + case 0x12: /* EG-CTRL */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + return; +#if 0 + case 0x15: /* DAC data */ + case 0x16: + case 0x17: /* SHIFT */ + return; + case 0x18: /* I/O CTRL (Direction) */ + if(OPL->type&OPL_TYPE_IO) + OPL->portDirection = v&0x0f; + return; + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + OPL->portLatch = v; + if(OPL->porthandler_w) + OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); + } + return; + case 0x1a: /* PCM data */ + return; +#endif +#endif + } + break; + case 0x20: /* am,vib,ksr,eg type,mul */ + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_mul(OPL,slot,v); + return; + case 0x40: + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_ksl_tl(OPL,slot,v); + return; + case 0x60: + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_ar_dr(OPL,slot,v); + return; + case 0x80: + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_sl_rr(OPL,slot,v); + return; + case 0xa0: + switch(r) + { + case 0xbd: + /* amsep,vibdep,r,bd,sd,tom,tc,hh */ + { + UINT8 rkey = OPL->rythm^v; + OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0]; + OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0]; + OPL->rythm = v&0x3f; + if(OPL->rythm&0x20) + { +#if 0 + usrintf_showmessage("OPL Rythm mode select"); +#endif + /* BD key on/off */ + if(rkey&0x10) + { + if(v&0x10) + { + OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0; + OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]); + OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]); + } + else + { + OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]); + OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]); + } + } + /* SD key on/off */ + if(rkey&0x08) + { + if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]); + else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]); + }/* TAM key on/off */ + if(rkey&0x04) + { + if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]); + else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]); + } + /* TOP-CY key on/off */ + if(rkey&0x02) + { + if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]); + else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]); + } + /* HH key on/off */ + if(rkey&0x01) + { + if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]); + else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]); + } + } + } + return; + } + /* keyon,block,fnum */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + if(!(r&0x10)) + { /* a0-a8 */ + block_fnum = (CH->block_fnum&0x1f00) | v; + } + else + { /* b0-b8 */ + int keyon = (v>>5)&1; + block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); + if(CH->keyon != keyon) + { + if( (CH->keyon=keyon) ) + { + CH->op1_out[0] = CH->op1_out[1] = 0; + OPL_KEYON(&CH->SLOT[SLOT1]); + OPL_KEYON(&CH->SLOT[SLOT2]); + } + else + { + OPL_KEYOFF(&CH->SLOT[SLOT1]); + OPL_KEYOFF(&CH->SLOT[SLOT2]); + } + } + } + /* update */ + if(CH->block_fnum != block_fnum) + { + int blockRv = 7-(block_fnum>>10); + int fnum = block_fnum&0x3ff; + CH->block_fnum = block_fnum; + + CH->ksl_base = KSL_TABLE[block_fnum>>6]; + CH->fc = OPL->FN_TABLE[fnum]>>blockRv; + CH->kcode = CH->block_fnum>>9; + if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1; + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + return; + case 0xc0: + /* FB,C */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + { + int feedback = (v>>1)&7; + CH->FB = feedback ? (8+1) - feedback : 0; + CH->CON = v&1; + set_algorythm(CH); + } + return; + case 0xe0: /* wave type */ + slot = slot_array[r&0x1f]; + if(slot == -1) return; + CH = &OPL->P_CH[slot/2]; + if(OPL->wavesel) + { + /* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */ + CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT]; + } + return; + } +} + +/* lock/unlock for common table */ +static int OPL_LockTable(void) +{ + num_lock++; + if(num_lock>1) return 0; + /* first time */ + cur_chip = NULL; + /* allocate total level table (128kb space) */ + if( !OPLOpenTable() ) + { + num_lock--; + return -1; + } + return 0; +} + +static void OPL_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + /* last time */ + cur_chip = NULL; + OPLCloseTable(); +} + +#if (BUILD_YM3812 || BUILD_YM3526) +/*******************************************************************************/ +/* YM3812 local section */ +/*******************************************************************************/ + +/* ---------- update one of chip ----------- */ +void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) +{ + int i; + int data; + OPLSAMPLE *buf = buffer; + UINT32 amsCnt = OPL->amsCnt; + UINT32 vibCnt = OPL->vibCnt; + UINT8 rythm = OPL->rythm&0x20; + OPL_CH *CH,*R_CH; + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* channel pointers */ + S_CH = OPL->P_CH; + E_CH = &S_CH[9]; + /* rythm slot */ + SLOT7_1 = &S_CH[7].SLOT[SLOT1]; + SLOT7_2 = &S_CH[7].SLOT[SLOT2]; + SLOT8_1 = &S_CH[8].SLOT[SLOT1]; + SLOT8_2 = &S_CH[8].SLOT[SLOT2]; + /* LFO state */ + amsIncr = OPL->amsIncr; + vibIncr = OPL->vibIncr; + ams_table = OPL->ams_table; + vib_table = OPL->vib_table; + } + R_CH = rythm ? &S_CH[6] : E_CH; + for( i=0; i < length ; i++ ) + { + /* channel A channel B channel C */ + /* LFO */ + ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; + vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; + outd[0] = 0; + /* FM part */ + for(CH=S_CH ; CH < R_CH ; CH++) + OPL_CALC_CH(CH); + /* Rythn part */ + if(rythm) + OPL_CALC_RH(S_CH); + /* limit check */ + data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); + /* store to sound buffer */ + buf[i] = data >> OPL_OUTSB; + } + + OPL->amsCnt = amsCnt; + OPL->vibCnt = vibCnt; +#ifdef OPL_OUTPUT_LOG + if(opl_dbg_fp) + { + for(opl_dbg_chip=0;opl_dbg_chipamsCnt; + UINT32 vibCnt = OPL->vibCnt; + UINT8 rythm = OPL->rythm&0x20; + OPL_CH *CH,*R_CH; + YM_DELTAT *DELTAT = OPL->deltat; + + /* setup DELTA-T unit */ + YM_DELTAT_DECODE_PRESET(DELTAT); + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* channel pointers */ + S_CH = OPL->P_CH; + E_CH = &S_CH[9]; + /* rythm slot */ + SLOT7_1 = &S_CH[7].SLOT[SLOT1]; + SLOT7_2 = &S_CH[7].SLOT[SLOT2]; + SLOT8_1 = &S_CH[8].SLOT[SLOT1]; + SLOT8_2 = &S_CH[8].SLOT[SLOT2]; + /* LFO state */ + amsIncr = OPL->amsIncr; + vibIncr = OPL->vibIncr; + ams_table = OPL->ams_table; + vib_table = OPL->vib_table; + } + R_CH = rythm ? &S_CH[6] : E_CH; + for( i=0; i < length ; i++ ) + { + /* channel A channel B channel C */ + /* LFO */ + ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; + vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; + outd[0] = 0; + /* deltaT ADPCM */ + if( DELTAT->portstate ) + YM_DELTAT_ADPCM_CALC(DELTAT); + /* FM part */ + for(CH=S_CH ; CH < R_CH ; CH++) + OPL_CALC_CH(CH); + /* Rythn part */ + if(rythm) + OPL_CALC_RH(S_CH); + /* limit check */ + data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); + /* store to sound buffer */ + buf[i] = data >> OPL_OUTSB; + } + OPL->amsCnt = amsCnt; + OPL->vibCnt = vibCnt; + /* deltaT START flag */ + if( !DELTAT->portstate ) + OPL->status &= 0xfe; +} +#endif + +/* ---------- reset one of chip ---------- */ +void OPLResetChip(FM_OPL *OPL) +{ + int c,s; + int i; + + /* reset chip */ + OPL->mode = 0; /* normal mode */ + OPL_STATUS_RESET(OPL,0x7f); + /* reset with register write */ + OPLWriteReg(OPL,0x01,0); /* wabesel disable */ + OPLWriteReg(OPL,0x02,0); /* Timer1 */ + OPLWriteReg(OPL,0x03,0); /* Timer2 */ + OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ + for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); + /* reset OPerator paramater */ + for( c = 0 ; c < OPL->max_ch ; c++ ) + { + OPL_CH *CH = &OPL->P_CH[c]; + /* OPL->P_CH[c].PAN = OPN_CENTER; */ + for(s = 0 ; s < 2 ; s++ ) + { + /* wave table */ + CH->SLOT[s].wavetable = &SIN_TABLE[0]; + /* CH->SLOT[s].evm = ENV_MOD_RR; */ + CH->SLOT[s].evc = EG_OFF; + CH->SLOT[s].eve = EG_OFF+1; + CH->SLOT[s].evs = 0; + } + } +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + { + YM_DELTAT *DELTAT = OPL->deltat; + + DELTAT->freqbase = OPL->freqbase; + DELTAT->output_pointer = outd; + DELTAT->portshift = 5; + DELTAT->output_range = DELTAT_MIXING_LEVEL<P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch; +#if BUILD_Y8950 + if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT); +#endif + /* set channel state pointer */ + OPL->type = type; + OPL->clock = clock; + OPL->rate = rate; + OPL->max_ch = max_ch; + /* init grobal tables */ + OPL_initalize(OPL); + /* reset chip */ + OPLResetChip(OPL); +#ifdef OPL_OUTPUT_LOG + if(!opl_dbg_fp) + { + opl_dbg_fp = fopen("opllog.opl","wb"); + opl_dbg_maxchip = 0; + } + if(opl_dbg_fp) + { + opl_dbg_opl[opl_dbg_maxchip] = OPL; + fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip, + type, + clock&0xff, + (clock/0x100)&0xff, + (clock/0x10000)&0xff, + (clock/0x1000000)&0xff); + opl_dbg_maxchip++; + } +#endif + return OPL; +} + +/* ---------- Destroy one of vietual YM3812 ---------- */ +void OPLDestroy(FM_OPL *OPL) +{ +#ifdef OPL_OUTPUT_LOG + if(opl_dbg_fp) + { + fclose(opl_dbg_fp); + opl_dbg_fp = NULL; + } +#endif + OPL_UnLockTable(); + free(OPL); +} + +/* ---------- Option handlers ---------- */ + +void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) +{ + OPL->TimerHandler = TimerHandler; + OPL->TimerParam = channelOffset; +} +void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) +{ + OPL->IRQHandler = IRQHandler; + OPL->IRQParam = param; +} +void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPL->UpdateHandler = UpdateHandler; + OPL->UpdateParam = param; +} +#if BUILD_Y8950 +void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) +{ + OPL->porthandler_w = PortHandler_w; + OPL->porthandler_r = PortHandler_r; + OPL->port_param = param; +} + +void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) +{ + OPL->keyboardhandler_w = KeyboardHandler_w; + OPL->keyboardhandler_r = KeyboardHandler_r; + OPL->keyboard_param = param; +} +#endif +/* ---------- YM3812 I/O interface ---------- */ +int OPLWrite(FM_OPL *OPL,int a,int v) +{ + if( !(a&1) ) + { /* address port */ + OPL->address = v & 0xff; + } + else + { /* data port */ + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); +#ifdef OPL_OUTPUT_LOG + if(opl_dbg_fp) + { + for(opl_dbg_chip=0;opl_dbg_chipaddress,v); + } +#endif + OPLWriteReg(OPL,OPL->address,v); + } + return OPL->status>>7; +} + +unsigned char OPLRead(FM_OPL *OPL,int a) +{ + if( !(a&1) ) + { /* status port */ + return OPL->status & (OPL->statusmask|0x80); + } + /* data port */ + switch(OPL->address) + { + case 0x05: /* KeyBoard IN */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_r) + return OPL->keyboardhandler_r(OPL->keyboard_param); + else + LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n")); + } + return 0; +#if 0 + case 0x0f: /* ADPCM-DATA */ + return 0; +#endif + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + if(OPL->porthandler_r) + return OPL->porthandler_r(OPL->port_param); + else + LOG(LOG_WAR,("OPL:read unmapped I/O port\n")); + } + return 0; + case 0x1a: /* PCM-DATA */ + return 0; + } + return 0; +} + +int OPLTimerOver(FM_OPL *OPL,int c) +{ + if( c ) + { /* Timer B */ + OPL_STATUS_SET(OPL,0x20); + } + else + { /* Timer A */ + OPL_STATUS_SET(OPL,0x40); + /* CSM mode key,TL controll */ + if( OPL->mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + int ch; + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + for(ch=0;ch<9;ch++) + CSMKeyControll( &OPL->P_CH[ch] ); + } + } + /* reload timer */ + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); + return OPL->status>>7; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/fmopl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/fmopl.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,174 @@ +#ifndef __FMOPL_H_ +#define __FMOPL_H_ + +/* --- select emulation chips --- */ +#define BUILD_YM3812 (HAS_YM3812) +//#define BUILD_YM3526 (HAS_YM3526) +//#define BUILD_Y8950 (HAS_Y8950) + +/* --- system optimize --- */ +/* select bit size of output : 8 or 16 */ +#define OPL_OUTPUT_BIT 16 + +/* compiler dependence */ +#ifndef OSD_CPU_H +#define OSD_CPU_H +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif + +#if (OPL_OUTPUT_BIT==16) +typedef INT16 OPLSAMPLE; +#endif +#if (OPL_OUTPUT_BIT==8) +typedef unsigned char OPLSAMPLE; +#endif + + +#if BUILD_Y8950 +#include "ymdeltat.h" +#endif + +typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); +typedef void (*OPL_IRQHANDLER)(int param,int irq); +typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); +typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); +typedef unsigned char (*OPL_PORTHANDLER_R)(int param); + +/* !!!!! here is private section , do not access there member direct !!!!! */ + +#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ +#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ +#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ +#define OPL_TYPE_IO 0x08 /* I/O port */ + +/* Saving is necessary for member of the 'R' mark for suspend/resume */ +/* ---------- OPL one of slot ---------- */ +typedef struct fm_opl_slot { + INT32 TL; /* total level :TL << 8 */ + INT32 TLL; /* adjusted now TL */ + UINT8 KSR; /* key scale rate :(shift down bit) */ + INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */ + INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */ + INT32 SL; /* sustin level :SL_TALBE[SL] */ + INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */ + UINT8 ksl; /* keyscale level :(shift down bits) */ + UINT8 ksr; /* key scale rate :kcode>>KSR */ + UINT32 mul; /* multiple :ML_TABLE[ML] */ + UINT32 Cnt; /* frequency count : */ + UINT32 Incr; /* frequency step : */ + /* envelope generator state */ + UINT8 eg_typ; /* envelope type flag */ + UINT8 evm; /* envelope phase */ + INT32 evc; /* envelope counter */ + INT32 eve; /* envelope counter end point */ + INT32 evs; /* envelope counter step */ + INT32 evsa; /* envelope step for AR :AR[ksr] */ + INT32 evsd; /* envelope step for DR :DR[ksr] */ + INT32 evsr; /* envelope step for RR :RR[ksr] */ + /* LFO */ + UINT8 ams; /* ams flag */ + UINT8 vib; /* vibrate flag */ + /* wave selector */ + INT32 **wavetable; +}OPL_SLOT; + +/* ---------- OPL one of channel ---------- */ +typedef struct fm_opl_channel { + OPL_SLOT SLOT[2]; + UINT8 CON; /* connection type */ + UINT8 FB; /* feed back :(shift down bit) */ + INT32 *connect1; /* slot1 output pointer */ + INT32 *connect2; /* slot2 output pointer */ + INT32 op1_out[2]; /* slot1 output for selfeedback */ + /* phase generator state */ + UINT32 block_fnum; /* block+fnum : */ + UINT8 kcode; /* key code : KeyScaleCode */ + UINT32 fc; /* Freq. Increment base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 keyon; /* key on/off flag */ +} OPL_CH; + +/* OPL state */ +typedef struct fm_opl_f { + UINT8 type; /* chip type */ + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + double TimerBase; /* Timer base time (==sampling time) */ + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + UINT32 mode; /* Reg.08 : CSM , notesel,etc. */ + /* Timer */ + int T[2]; /* timer counter */ + UINT8 st[2]; /* timer enable */ + /* FM channel slots */ + OPL_CH *P_CH; /* pointer of CH */ + int max_ch; /* maximum channel */ + /* Rythm sention */ + UINT8 rythm; /* Rythm mode , key flag */ +#if BUILD_Y8950 + /* Delta-T ADPCM unit (Y8950) */ + YM_DELTAT *deltat; /* DELTA-T ADPCM */ +#endif + /* Keyboard / I/O interface unit (Y8950) */ + UINT8 portDirection; + UINT8 portLatch; + OPL_PORTHANDLER_R porthandler_r; + OPL_PORTHANDLER_W porthandler_w; + int port_param; + OPL_PORTHANDLER_R keyboardhandler_r; + OPL_PORTHANDLER_W keyboardhandler_w; + int keyboard_param; + /* time tables */ + INT32 AR_TABLE[75]; /* atttack rate tables */ + INT32 DR_TABLE[75]; /* decay rate tables */ + UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */ + /* LFO */ + INT32 *ams_table; + INT32 *vib_table; + INT32 amsCnt; + INT32 amsIncr; + INT32 vibCnt; + INT32 vibIncr; + /* wave selector enable flag */ + UINT8 wavesel; + /* external event callback handler */ + OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ + int TimerParam; /* TIMER parameter */ + OPL_IRQHANDLER IRQHandler; /* IRQ handler */ + int IRQParam; /* IRQ parameter */ + OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */ + int UpdateParam; /* stream update parameter */ +} FM_OPL; + +/* ---------- Generic interface section ---------- */ +#define OPL_TYPE_YM3526 (0) +#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) +#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) + +FM_OPL *OPLCreate(int type, int clock, int rate); +void OPLDestroy(FM_OPL *OPL); +void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset); +void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param); +void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param); +/* Y8950 port handlers */ +void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param); +void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param); + +void OPLResetChip(FM_OPL *OPL); +int OPLWrite(FM_OPL *OPL,int a,int v); +unsigned char OPLRead(FM_OPL *OPL,int a); +int OPLTimerOver(FM_OPL *OPL,int c); + +/* YM3626/YM3812 local section */ +void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); + +void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/fprovide.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/fprovide.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,76 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * fprovide.cpp - File provider class framework, by Simon Peter + */ + +#include +#include +#include + +#include "fprovide.h" + +/***** CFileProvider *****/ + +bool CFileProvider::extension(const std::string &filename, + const std::string &extension) +{ + const char *fname = filename.c_str(), *ext = extension.c_str(); + + if(strlen(fname) < strlen(ext) || + stricmp(fname + strlen(fname) - strlen(ext), ext)) + return false; + else + return true; +} + +unsigned long CFileProvider::filesize(binistream *f) +{ + unsigned long oldpos = f->pos(), size; + + f->seek(0, binio::End); + size = f->pos(); + f->seek(oldpos, binio::Set); + + return size; +} + +/***** CProvider_Filesystem *****/ + +binistream *CProvider_Filesystem::open(std::string filename) const +{ + binifstream *f = new binifstream(filename); + + if(!f) return 0; + if(f->error()) { delete f; return 0; } + + // Open all files as little endian with IEEE floats by default + f->setFlag(binio::BigEndian, false); f->setFlag(binio::FloatIEEE); + + return f; +} + +void CProvider_Filesystem::close(binistream *f) const +{ + binifstream *ff = (binifstream *)f; + + if(f) { + ff->close(); + delete ff; + } +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/fprovide.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/fprovide.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,46 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * fprovide.h - File provider class framework, by Simon Peter + */ + +#ifndef H_ADPLUG_FILEPROVIDER +#define H_ADPLUG_FILEPROVIDER + +#include +#include + +class CFileProvider +{ +public: + virtual binistream *open(std::string) const = 0; + virtual void close(binistream *) const = 0; + + static bool extension(const std::string &filename, + const std::string &extension); + static unsigned long filesize(binistream *f); +}; + +class CProvider_Filesystem: public CFileProvider +{ +public: + virtual binistream *open(std::string filename) const; + virtual void close(binistream *f) const; +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/hsc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hsc.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,317 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * hsc.cpp - HSC Player by Simon Peter + */ + +#include + +#include "hsc.h" +#include "debug.h" + +/*** public methods **************************************/ + +CPlayer *ChscPlayer::factory(Copl *newopl) +{ + return new ChscPlayer(newopl); +} + +bool ChscPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); + int i; + + // file validation section + if(!f || !fp.extension(filename, ".hsc") || fp.filesize(f) > 59187) { + AdPlug_LogWrite("ChscPlayer::load(\"%s\"): Not a HSC file!\n", filename.c_str()); + fp.close(f); + return false; + } + + // load section + for(i=0;i<128*12;i++) // load instruments + *((unsigned char *)instr + i) = f->readInt(1); + for (i=0;i<128;i++) { // correct instruments + instr[i][2] ^= (instr[i][2] & 0x40) << 1; + instr[i][3] ^= (instr[i][3] & 0x40) << 1; + instr[i][11] >>= 4; // slide + } + for(i=0;i<51;i++) song[i] = f->readInt(1); // load tracklist + for(i=0;i<50*64*9;i++) // load patterns + *((char *)patterns + i) = f->readInt(1); + + fp.close(f); + rewind(0); // rewind module + return true; +} + +bool ChscPlayer::update() +{ + // general vars + unsigned char chan,pattnr,note,effect,eff_op,inst,vol,Okt,db; + unsigned short Fnr; + unsigned long pattoff; + + del--; // player speed handling + if(del) + return !songend; // nothing done + + if(fadein) // fade-in handling + fadein--; + + pattnr = song[songpos]; + if(pattnr == 0xff) { // arrangement handling + songend = 1; // set end-flag + songpos = 0; + pattnr = song[songpos]; + } else + if ((pattnr & 128) && (pattnr <= 0xb1)) { // goto pattern "nr" + songpos = song[songpos] & 127; + pattpos = 0; + pattnr = song[songpos]; + songend = 1; + } + + pattoff = pattpos*9; + for (chan=0;chan<9;chan++) { // handle all channels + note = patterns[pattnr][pattoff].note; + effect = patterns[pattnr][pattoff].effect; + pattoff++; + + if(note & 128) { // set instrument + setinstr(chan,effect); + continue; + } + eff_op = effect & 0x0f; + inst = channel[chan].inst; + if(note) + channel[chan].slide = 0; + + switch (effect & 0xf0) { // effect handling + case 0: // global effect + /* The following fx are unimplemented on purpose: + * 02 - Slide Mainvolume up + * 03 - Slide Mainvolume down (here: fade in) + * 04 - Set Mainvolume to 0 + * + * This is because i've never seen any HSC modules using the fx this way. + * All modules use the fx the way, i've implemented it. + */ + switch(eff_op) { + case 1: pattbreak++; break; // jump to next pattern + case 3: fadein = 31; break; // fade in (divided by 2) + case 5: mode6 = 1; break; // 6 voice mode on + case 6: mode6 = 0; break; // 6 voice mode off + } + break; + case 0x20: + case 0x10: // manual slides + if (effect & 0x10) { + channel[chan].freq += eff_op; + channel[chan].slide += eff_op; + } else { + channel[chan].freq -= eff_op; + channel[chan].slide -= eff_op; + } + if(!note) + setfreq(chan,channel[chan].freq); + break; + case 0x50: // set percussion instrument (unimplemented) + break; + case 0x60: // set feedback + opl->write(0xc0 + chan, (instr[channel[chan].inst][8] & 1) + (eff_op << 1)); + break; + case 0xa0: // set carrier volume + vol = eff_op << 2; + opl->write(0x43 + op_table[chan], vol | (instr[channel[chan].inst][2] & ~63)); + break; + case 0xb0: // set modulator volume + vol = eff_op << 2; + if (instr[inst][8] & 1) + opl->write(0x40 + op_table[chan], vol | (instr[channel[chan].inst][3] & ~63)); + else + opl->write(0x40 + op_table[chan],vol | (instr[inst][3] & ~63)); + break; + case 0xc0: // set instrument volume + db = eff_op << 2; + opl->write(0x43 + op_table[chan], db | (instr[channel[chan].inst][2] & ~63)); + if (instr[inst][8] & 1) + opl->write(0x40 + op_table[chan], db | (instr[channel[chan].inst][3] & ~63)); + break; + case 0xd0: pattbreak++; songpos = eff_op; songend = 1; break; // position jump + case 0xf0: // set speed + speed = eff_op; + del = ++speed; + break; + } + + if(fadein) // fade-in volume setting + setvolume(chan,fadein*2,fadein*2); + + if(!note) // note handling + continue; + note--; + + if ((note == 0x7f-1) || ((note/12) & ~7)) { // pause (7fh) + adl_freq[chan] &= ~32; + opl->write(0xb0 + chan,adl_freq[chan]); + continue; + } + + // play the note + if(mtkmode) // imitate MPU-401 Trakker bug + note--; + Okt = ((note/12) & 7) << 2; + Fnr = note_table[(note % 12)] + instr[inst][11] + channel[chan].slide; + channel[chan].freq = Fnr; + if(!mode6 || chan < 6) + adl_freq[chan] = Okt | 32; + else + adl_freq[chan] = Okt; // never set key for drums + opl->write(0xb0 + chan, 0); + setfreq(chan,Fnr); + if(mode6) { + switch(chan) { // play drums + case 6: opl->write(0xbd,bd & ~16); bd |= 48; break; // bass drum + case 7: opl->write(0xbd,bd & ~1); bd |= 33; break; // hihat + case 8: opl->write(0xbd,bd & ~2); bd |= 34; break; // cymbal + } + opl->write(0xbd,bd); + } + } + + del = speed; // player speed-timing + if(pattbreak) { // do post-effect handling + pattpos=0; // pattern break! + pattbreak=0; + songpos++; + songpos %= 50; + if(!songpos) + songend = 1; + } else { + pattpos++; + pattpos &= 63; // advance in pattern data + if (!pattpos) { + songpos++; + songpos %= 50; + if(!songpos) + songend = 1; + } + } + return !songend; // still playing +} + +void ChscPlayer::rewind(int subsong) +{ + int i; // counter + + // rewind HSC player + pattpos = 0; songpos = 0; pattbreak = 0; speed = 2; + del = 1; songend = 0; mode6 = 0; bd = 0; fadein = 0; + + opl->init(); // reset OPL chip + opl->write(1,32); opl->write(8,128); opl->write(0xbd,0); + + for(i=0;i<9;i++) + setinstr((char) i,(char) i); // init channels +} + +unsigned int ChscPlayer::getpatterns() +{ + unsigned char poscnt,pattcnt=0; + + // count patterns + for(poscnt=0;poscnt<51 && song[poscnt] != 0xff;poscnt++) + if(song[poscnt] > pattcnt) + pattcnt = song[poscnt]; + + return (pattcnt+1); +} + +unsigned int ChscPlayer::getorders() +{ + unsigned char poscnt; + + // count positions + for(poscnt=0;poscnt<51;poscnt++) + if(song[poscnt] == 0xff) + break; + + return poscnt; +} + +unsigned int ChscPlayer::getinstruments() +{ + unsigned char instcnt,instnum=0,i; + bool isinst; + + // count instruments + for(instcnt=0;instcnt<128;instcnt++) { + isinst = false; + for(i=0;i<12;i++) + if(instr[instcnt][i]) + isinst = true; + if(isinst) + instnum++; + } + + return instnum; +} + +/*** private methods *************************************/ + +void ChscPlayer::setfreq(unsigned char chan, unsigned short freq) +{ + adl_freq[chan] = (adl_freq[chan] & ~3) | (freq >> 8); + + opl->write(0xa0 + chan, freq & 0xff); + opl->write(0xb0 + chan, adl_freq[chan]); +} + +void ChscPlayer::setvolume(unsigned char chan, int volc, int volm) +{ + unsigned char *ins = instr[channel[chan].inst]; + char op = op_table[chan]; + + opl->write(0x43 + op,volc | (ins[2] & ~63)); + if (ins[8] & 1) // carrier + opl->write(0x40 + op,volm | (ins[3] & ~63)); + else + opl->write(0x40 + op, ins[3]); // modulator +} + +void ChscPlayer::setinstr(unsigned char chan, unsigned char insnr) +{ + unsigned char *ins = instr[insnr]; + char op = op_table[chan]; + + channel[chan].inst = insnr; // set internal instrument + opl->write(0xb0 + chan,0); // stop old note + + // set instrument + opl->write(0xc0 + chan, ins[8]); + opl->write(0x23 + op, ins[0]); // carrier + opl->write(0x20 + op, ins[1]); // modulator + opl->write(0x63 + op, ins[4]); // bits 0..3 = decay; 4..7 = attack + opl->write(0x60 + op, ins[5]); + opl->write(0x83 + op, ins[6]); // 0..3 = release; 4..7 = sustain + opl->write(0x80 + op, ins[7]); + opl->write(0xe3 + op, ins[9]); // bits 0..1 = Wellenform + opl->write(0xe0 + op, ins[10]); + setvolume(chan, ins[2] & 63, ins[3] & 63); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/hsc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hsc.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,75 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * hsc.h - HSC Player by Simon Peter + */ + +#ifndef H_ADPLUG_HSCPLAYER +#define H_ADPLUG_HSCPLAYER + +#include "player.h" + +class ChscPlayer: public CPlayer +{ + public: + static CPlayer *factory(Copl *newopl); + + ChscPlayer(Copl *newopl): CPlayer(newopl), mtkmode(0) {} + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh() { return 18.2f; }; // refresh rate is fixed at 18.2Hz + + std::string gettype() { return std::string("HSC Adlib Composer / HSC-Tracker"); } + unsigned int getpatterns(); + unsigned int getpattern() { return song[songpos]; } + unsigned int getorders(); + unsigned int getorder() { return songpos; } + unsigned int getrow() { return pattpos; } + unsigned int getspeed() { return speed; } + unsigned int getinstruments(); + + protected: + struct hscnote { + unsigned char note, effect; + }; // note type in HSC pattern + + struct hscchan { + unsigned char inst; // current instrument + signed char slide; // used for manual slide-effects + unsigned short freq; // actual replaying frequency + }; // HSC channel data + + hscchan channel[9]; // player channel-info + unsigned char instr[128][12]; // instrument data + unsigned char song[0x80]; // song-arrangement (MPU-401 Trakker enhanced) + hscnote patterns[50][64*9]; // pattern data + unsigned char pattpos,songpos, // various bytes & flags + pattbreak,songend,mode6,bd,fadein; + unsigned int speed,del; + unsigned char adl_freq[9]; // adlib frequency registers + int mtkmode; // flag: MPU-401 Trakker mode on/off + + private: + void setfreq(unsigned char chan, unsigned short freq); + void setvolume(unsigned char chan, int volc, int volm); + void setinstr(unsigned char chan, unsigned char insnr); +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/hsp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hsp.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,68 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * hsp.cpp - HSP Loader by Simon Peter + */ + +#include + +#include "hsp.h" + +CPlayer *ChspLoader::factory(Copl *newopl) +{ + return new ChspLoader(newopl); +} + +bool ChspLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + unsigned long i, j, orgsize, filesize; + unsigned char *cmp, *org; + + // file validation section + if(!fp.extension(filename, ".hsp")) { fp.close(f); return false; } + + filesize = fp.filesize(f); + orgsize = f->readInt(2); + if(orgsize > 59187) { fp.close(f); return false; } + + // load section + cmp = new unsigned char[filesize]; + for(i = 0; i < filesize; i++) cmp[i] = f->readInt(1); + fp.close(f); + + org = new unsigned char[orgsize]; + for(i = 0, j = 0; i < filesize; j += cmp[i], i += 2) { // RLE decompress + if(j >= orgsize) break; // memory boundary check + memset(org + j, cmp[i + 1], j + cmp[i] < orgsize ? cmp[i] : orgsize - j - 1); + } + delete [] cmp; + + memcpy(instr, org, 128 * 12); // instruments + for(i = 0; i < 128; i++) { // correct instruments + instr[i][2] ^= (instr[i][2] & 0x40) << 1; + instr[i][3] ^= (instr[i][3] & 0x40) << 1; + instr[i][11] >>= 4; // slide + } + memcpy(song, org + 128 * 12, 51); // tracklist + memcpy(patterns, org + 128 * 12 + 51, orgsize - 128 * 12 - 51); // patterns + delete [] org; + + rewind(0); + return true; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/hsp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hsp.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,39 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * hsp.h: HSC Packed Loader by Simon Peter + */ + +#ifndef H_ADPLUG_HSPLOADER +#define H_ADPLUG_HSPLOADER + +#include "hsc.h" + +class ChspLoader: public ChscPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + ChspLoader(Copl *newopl) + : ChscPlayer(newopl) + {}; + + bool load(const std::string &filename, const CFileProvider &fp); +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/hybrid.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hybrid.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,247 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] HYBRID player, by Riven the Mage + */ + +/* + - discovery - + + file(s) : HYBRID.EXE + type : Hybrid cracktro for Apache Longbow CD-RIP + tune : from 'Mig-29 Super Fulcrum' game by Domark + player : from 'Mig-29 Super Fulcrum' game by Domark +*/ + +#include "hybrid.h" +#include "debug.h" + +const unsigned char CxadhybridPlayer::hyb_adlib_registers[99] = +{ + 0xE0, 0x60, 0x80, 0x20, 0x40, 0xE3, 0x63, 0x83, 0x23, 0x43, 0xC0, + 0xE1, 0x61, 0x81, 0x21, 0x41, 0xE4, 0x64, 0x84, 0x24, 0x44, 0xC1, + 0xE2, 0x62, 0x82, 0x22, 0x42, 0xE5, 0x65, 0x85, 0x25, 0x45, 0xC2, + 0xE8, 0x68, 0x88, 0x28, 0x48, 0xEB, 0x6B, 0x8B, 0x2B, 0x4B, 0xC3, + 0xE9, 0x69, 0x89, 0x29, 0x49, 0xEC, 0x6C, 0x8C, 0x2C, 0x4C, 0xC4, + 0xEA, 0x6A, 0x8A, 0x2A, 0x4A, 0xED, 0x6D, 0x8D, 0x2D, 0x4D, 0xC5, + 0xF0, 0x70, 0x90, 0x30, 0x50, 0xF3, 0x73, 0x93, 0x33, 0x53, 0xC6, + 0xF1, 0x71, 0x91, 0x31, 0x51, 0xF4, 0x74, 0x94, 0x34, 0x54, 0xC7, + 0xF2, 0x72, 0x92, 0x32, 0x52, 0xF5, 0x75, 0x95, 0x35, 0x55, 0xC8 +}; + +const unsigned short CxadhybridPlayer::hyb_notes[98] = +{ + 0x0000, 0x0000, + 0x016B, 0x0181, 0x0198, 0x01B0, 0x01CA, 0x01E5, 0x0202, 0x0220, 0x0241, 0x0263, 0x0287, 0x02AE, + 0x056B, 0x0581, 0x0598, 0x05B0, 0x05CA, 0x05E5, 0x0602, 0x0620, 0x0641, 0x0663, 0x0687, 0x06AE, + 0x096B, 0x0981, 0x0998, 0x09B0, 0x09CA, 0x09E5, 0x0A02, 0x0A20, 0x0A41, 0x0A63, 0x0A87, 0x0AAE, + 0x0D6B, 0x0D81, 0x0D98, 0x0DB0, 0x0DCA, 0x0DE5, 0x0E02, 0x0E20, 0x0E41, 0x0E63, 0x0E87, 0x0EAE, + 0x116B, 0x1181, 0x1198, 0x11B0, 0x11CA, 0x11E5, 0x1202, 0x1220, 0x1241, 0x1263, 0x1287, 0x12AE, + 0x156B, 0x1581, 0x1598, 0x15B0, 0x15CA, 0x15E5, 0x1602, 0x1620, 0x1641, 0x1663, 0x1687, 0x16AE, + 0x196B, 0x1981, 0x1998, 0x19B0, 0x19CA, 0x19E5, 0x1A02, 0x1A20, 0x1A41, 0x1A63, 0x1A87, 0x1AAE, + 0x1D6B, 0x1D81, 0x1D98, 0x1DB0, 0x1DCA, 0x1DE5, 0x1E02, 0x1E20, 0x1E41, 0x1E63, 0x1E87, 0x1EAE +}; + +const unsigned char CxadhybridPlayer::hyb_default_instrument[11] = +{ + 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00 +}; + +CPlayer *CxadhybridPlayer::factory(Copl *newopl) +{ + return new CxadhybridPlayer(newopl); +} + +bool CxadhybridPlayer::xadplayer_load() +{ + if(xad.fmt != HYBRID) + return false; + + // load instruments + hyb.inst = (hyb_instrument *)&tune[0]; + + // load order + hyb.order = &tune[0x1D4]; + + return true; +} + +void CxadhybridPlayer::xadplayer_rewind(int subsong) +{ + int i; + + hyb.order_pos = 0; + hyb.pattern_pos = 0; + + hyb.speed = 6; + hyb.speed_counter = 1; + + plr.speed = 1; + + // init channel data + for(i=0;i<9;i++) + { + hyb.channel[i].freq = 0x2000; + hyb.channel[i].freq_slide = 0x0000; + } + + // basic OPL init + opl_write(0x01, 0x20); + opl_write(0xBD, 0x40); + opl_write(0x08, 0x00); + + // init OPL channels + for(i=0;i<9;i++) + { + for(int j=0;j<11;j++) + opl_write(hyb_adlib_registers[i*11+j], 0x00 /* hyb_default_instrument[j] */ ); + + opl_write(0xA0+i, 0x00); + opl_write(0xB0+i, 0x20); + } +} + +void CxadhybridPlayer::xadplayer_update() +{ + int i,j; + unsigned char patpos,ordpos; + + if (--hyb.speed_counter) + goto update_slides; + + hyb.speed_counter = hyb.speed; + + patpos = hyb.pattern_pos; + ordpos = hyb.order_pos; + + // process channels + for(i=0;i<9;i++) + { + // read event + unsigned short event = *(unsigned short *)&tune[0xADE + (hyb.order[hyb.order_pos*9 + i] * 64 * 2) + (patpos * 2)]; + +#ifdef DEBUG + AdPlug_LogWrite("track %02X, channel %02X, event %04X:\n", hyb.order[hyb.order_pos*9 + i], i, event ); +#endif + + // calculate variables + unsigned char note = event >> 9; + unsigned char ins = ((event & 0x01F0) >> 4); + unsigned char slide = event & 0x000F; + + // play event + switch(note) + { + case 0x7D: // 0x7D: Set Speed + hyb.speed = event & 0xFF; + break; + case 0x7E: // 0x7E: Jump Position + hyb.order_pos = event & 0xFF; + hyb.pattern_pos = 0x3F; + + // jumpback ? + if (hyb.order_pos <= ordpos) + plr.looping = 1; + + break; + case 0x7F: // 0x7F: Pattern Break + hyb.pattern_pos = 0x3F; + break; + default: + + // is instrument ? + if (ins) + for(j=0;j<11;j++) + opl_write(hyb_adlib_registers[i*11+j], *((unsigned char *)&hyb.inst[ins-1] + 7 + j)); // +7 = skip name... + + // is note ? + if (note) + { + hyb.channel[i].freq = hyb_notes[note]; + hyb.channel[i].freq_slide = 0; + } + + // is slide ? + if (slide) + { + hyb.channel[i].freq_slide = (((slide >> 3) * -1) * (slide & 7)) << 1; + + if (slide & 0x80) + slide = -(slide & 7); + } + + // set frequency + if (!(hyb.channel[i].freq & 0x2000)) + { + opl_write(0xA0+i, hyb.channel[i].freq & 0xFF); + opl_write(0xB0+i, hyb.channel[i].freq >> 8); + + hyb.channel[i].freq |= 0x2000; + + opl_write(0xA0+i, hyb.channel[i].freq & 0xFF); + opl_write(0xB0+i, hyb.channel[i].freq >> 8); + } + + break; + } + } + + hyb.pattern_pos++; + + // end of pattern ? + if (hyb.pattern_pos >= 0x40) + { + hyb.pattern_pos = 0; + + hyb.order_pos++; + } + +update_slides: +#ifdef DEBUG + AdPlug_LogWrite("slides:\n"); +#endif + // update fine frequency slides + for(i=0;i<9;i++) + if (hyb.channel[i].freq_slide) + { + hyb.channel[i].freq = (((hyb.channel[i].freq & 0x1FFF) + hyb.channel[i].freq_slide) & 0x1FFF) | 0x2000; + + opl_write(0xA0+i, hyb.channel[i].freq & 0xFF); + opl_write(0xB0+i, hyb.channel[i].freq >> 8); + } +} + +float CxadhybridPlayer::xadplayer_getrefresh() +{ + return 50.0f; +} + +std::string CxadhybridPlayer::xadplayer_gettype() +{ + return (std::string("xad: hybrid player")); +} + +std::string CxadhybridPlayer::xadplayer_getinstrument(unsigned int i) +{ + return (std::string(hyb.inst[i].name,7)); +} + +unsigned int CxadhybridPlayer::xadplayer_getinstruments() +{ + return 26; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/hybrid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hybrid.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,80 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] HYBRID player, by Riven the Mage + */ + +#include "xad.h" + +class CxadhybridPlayer: public CxadPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CxadhybridPlayer(Copl *newopl): CxadPlayer(newopl) + { } + +protected: + struct hyb_instrument + { + char name[7]; + unsigned char mod_wave; + unsigned char mod_AD; + unsigned char mod_SR; + unsigned char mod_crtl; + unsigned char mod_volume; + unsigned char car_wave; + unsigned char car_AD; + unsigned char car_SR; + unsigned char car_crtl; + unsigned char car_volume; + unsigned char connect; + }; + + struct + { + unsigned char order_pos; + unsigned char pattern_pos; + + unsigned char *order; + + hyb_instrument *inst; + + struct + { + unsigned short freq; + unsigned short freq_slide; + } channel[9]; + + unsigned char speed; + unsigned char speed_counter; + } hyb; + // + bool xadplayer_load(); + void xadplayer_rewind(int subsong); + void xadplayer_update(); + float xadplayer_getrefresh(); + std::string xadplayer_gettype(); + std::string xadplayer_getinstrument(unsigned int i); + unsigned int xadplayer_getinstruments(); + +private: + static const unsigned char hyb_adlib_registers[99]; + static const unsigned short hyb_notes[98]; + static const unsigned char hyb_default_instrument[11]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/hyp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hyp.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,125 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] HYP player, by Riven the Mage + */ + +/* + - discovery - + + file(s) : HT-EF2.COM, HT-EF3.COM + type : Eiserne Front BBStro + tune : by Shadowdancer [Hypnosis] + player : by (?)Hetero [LKCC/SAC] +*/ + +#include "hyp.h" +#include "debug.h" + +const unsigned char CxadhypPlayer::hyp_adlib_registers[99] = +{ + 0x20, 0x23, 0x40, 0x43, 0x60, 0x63, 0x80, 0x83, 0xA0, 0xB0, 0xC0, + 0x21, 0x24, 0x41, 0x44, 0x61, 0x64, 0x81, 0x84, 0xA1, 0xB1, 0xC1, + 0x22, 0x25, 0x42, 0x45, 0x62, 0x65, 0x82, 0x85, 0xA2, 0xB2, 0xC2, + 0x28, 0x2B, 0x48, 0x4B, 0x68, 0x6B, 0x88, 0x8B, 0xA3, 0xB3, 0xC3, + 0x29, 0x2C, 0x49, 0x4C, 0x69, 0x6C, 0x89, 0x8C, 0xA4, 0xB4, 0xC4, + 0x2A, 0x2D, 0x4A, 0x4D, 0x6A, 0x6D, 0x8A, 0x8D, 0xA5, 0xB5, 0xC5, + 0x30, 0x33, 0x50, 0x53, 0x70, 0x73, 0x90, 0x93, 0xA6, 0xB6, 0xC6, + 0x31, 0x34, 0x51, 0x54, 0x71, 0x74, 0x91, 0x94, 0xA7, 0xB7, 0xC7, + 0x32, 0x35, 0x52, 0x55, 0x72, 0x75, 0x92, 0x95, 0xA8, 0xB8, 0xC8 +}; + +const unsigned short CxadhypPlayer::hyp_notes[73] = +{ + 0x0000, // by riven + 0x0956, 0x096B, 0x0980, 0x0998, 0x09B1, 0x09C9, 0x09E5, 0x0A03, 0x0A21, + 0x0A41, 0x0A63, 0x0A86, 0x0D56, 0x0D6B, 0x0D80, 0x0D98, 0x0DB1, 0x0DC9, + 0x0DE5, 0x0E03, 0x0E21, 0x0E41, 0x0E63, 0x0E86, 0x1156, 0x116B, 0x1180, + 0x1198, 0x11B1, 0x11C9, 0x11E5, 0x1203, 0x1221, 0x1241, 0x1263, 0x1286, + 0x1556, 0x156B, 0x1580, 0x1598, 0x15B1, 0x15C9, 0x15E5, 0x1603, 0x1621, + 0x1641, 0x1663, 0x1686, 0x1956, 0x196B, 0x1980, 0x1998, 0x19B1, 0x19C9, + 0x19E5, 0x1A03, 0x1A21, 0x1A41, 0x1A63, 0x1A86, 0x1D56, 0x1D6B, 0x1D80, + 0x1D98, 0x1DB1, 0x1DC9, 0x1DE5, 0x1E03, 0x1E21, 0x1E41, 0x1E63, 0x1E86 +}; + +CPlayer *CxadhypPlayer::factory(Copl *newopl) +{ + return new CxadhypPlayer(newopl); +} + +void CxadhypPlayer::xadplayer_rewind(int subsong) +{ + int i; + + plr.speed = tune[5]; + + opl_write(0xBD,0xC0); + + for(i=0; i<9; i++) + adlib[0xB0+i] = 0; + + // define instruments + for(i=0; i<99; i++) + opl_write(hyp_adlib_registers[i], tune[6+i]); + + hyp.pointer = 0x69; +} + +void CxadhypPlayer::xadplayer_update() +{ + for(int i=0; i<9; i++) + { + unsigned char event = tune[hyp.pointer++]; + + if (event) + { + unsigned short freq = hyp_notes[event & 0x3F]; + + unsigned char lofreq = (freq & 0xFF); + unsigned char hifreq = (freq >> 8); + + opl_write(0xB0+i, adlib[0xB0+i]); + + if (!(event & 0x40)) + { + opl_write(0xA0+i, lofreq); + opl_write(0xB0+i, hifreq | 0x20); + } + + adlib[0xB0+i] &= 0xDF; + } + } + + hyp.pointer += 3; + + if (hyp.pointer >= tune_size) + { + hyp.pointer = 0x69; + plr.looping = 1; + } +} + +float CxadhypPlayer::xadplayer_getrefresh() +{ + return 60.0f; +} + +std::string CxadhypPlayer::xadplayer_gettype() +{ + return std::string("xad: hypnosis player"); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/hyp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hyp.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,53 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] HYP player, by Riven the Mage + */ + +#include "xad.h" + +class CxadhypPlayer: public CxadPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CxadhypPlayer(Copl *newopl): CxadPlayer(newopl) + { } + +protected: + struct + { + unsigned short pointer; + } hyp; + // + bool xadplayer_load() + { + if(xad.fmt == HYP) + return true; + else + return false; + } + void xadplayer_rewind(int subsong); + void xadplayer_update(); + float xadplayer_getrefresh(); + std::string xadplayer_gettype(); + +private: + static const unsigned char hyp_adlib_registers[99]; + static const unsigned short hyp_notes[73]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/imf.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/imf.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,169 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * imf.cpp - IMF Player by Simon Peter + * + * FILE FORMAT: + * There seem to be 2 different flavors of IMF formats out there. One version + * contains just the raw IMF music data. In this case, the first word of the + * file is always 0 (because the music data starts this way). This is already + * the music data! So read in the entire file and play it. + * + * If this word is greater than 0, it specifies the size of the following + * song data in bytes. In this case, the file has a footer that contains + * arbitrary infos about it. Mostly, this is plain ASCII text with some words + * of the author. Read and play the specified amount of song data and display + * the remaining data as ASCII text. + * + * NOTES: + * This player handles the two above mentioned formats, as well as a third + * type, invented by Martin Fernandez , that's got a + * proper header to add title/game name information. After the header starts + * the normal IMF file in one of the two above mentioned formats. + */ + +#include + +#include "imf.h" +#include "database.h" + +/*** public methods *************************************/ + +CPlayer *CimfPlayer::factory(Copl *newopl) +{ + return new CimfPlayer(newopl); +} + +bool CimfPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + unsigned long fsize, flsize, mfsize = 0; + unsigned int i; + + // file validation section + { + char header[5]; + int version; + + f->readString(header, 5); + version = f->readInt(1); + + if(strncmp(header, "ADLIB", 5) || version != 1) { + if(!fp.extension(filename, ".imf") && !fp.extension(filename, ".wlf")) { + // It's no IMF file at all + fp.close(f); + return false; + } else + f->seek(0); // It's a normal IMF file + } else { + // It's a IMF file with header + track_name = f->readString('\0'); + game_name = f->readString('\0'); + f->ignore(1); + mfsize = f->pos() + 2; + } + } + + // load section + if(mfsize) + fsize = f->readInt(4); + else + fsize = f->readInt(2); + flsize = fp.filesize(f); + if(!fsize) { // footerless file (raw music data) + if(mfsize) + f->seek(-4, binio::Add); + else + f->seek(-2, binio::Add); + size = flsize / 4; + } else // file has got a footer + size = fsize / 4; + + data = new Sdata[size]; + for(i = 0; i < size; i++) { + data[i].reg = f->readInt(1); data[i].val = f->readInt(1); + data[i].time = f->readInt(2); + } + + // read footer, if any + if(fsize && (fsize < flsize - 2 - mfsize)) { + unsigned long footerlen = flsize - fsize - 2 - mfsize; + + footer = new char[footerlen + 1]; + f->readString(footer, footerlen); + footer[footerlen] = '\0'; // Make ASCIIZ string + } + + rate = getrate(f); + fp.close(f); + rewind(0); + return true; +} + +bool CimfPlayer::update() +{ + do { + opl->write(data[pos].reg,data[pos].val); + del = data[pos].time; + pos++; + } while(!del && pos < size); + + if(pos >= size) { + pos = 0; + songend = true; + } + else timer = rate / (float)del; + + return !songend; +} + +void CimfPlayer::rewind(int subsong) +{ + pos = 0; del = 0; timer = rate; songend = false; + opl->init(); opl->write(1,32); // go to OPL2 mode +} + +std::string CimfPlayer::gettitle() +{ + std::string title; + + title = track_name; + + if(!track_name.empty() && !game_name.empty()) + title += " - "; + + title += game_name; + + return title; +} + +/*** private methods *************************************/ + +float CimfPlayer::getrate(binistream *f) +{ + if(!db) return 700.0f; // Database offline + + f->seek(0, binio::Set); + + CClockRecord *record = (CClockRecord *)db->search(CAdPlugDatabase::CKey(*f)); + + if(!record || record->type != CAdPlugDatabase::CRecord::ClockSpeed) + return 700.0f; + else + return record->clock; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/imf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/imf.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,67 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * imf.h - IMF Player by Simon Peter + */ + +#ifndef H_ADPLUG_IMFPLAYER +#define H_ADPLUG_IMFPLAYER + +#include "player.h" + +class CimfPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CimfPlayer(Copl *newopl) + : CPlayer(newopl), footer(0), data(0) + { } + ~CimfPlayer() + { if(data) delete [] data; if(footer) delete [] footer; }; + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh() + { return timer; }; + + std::string gettype() + { return std::string("IMF File Format"); } + std::string gettitle(); + std::string getdesc() + { if(footer) return std::string(footer); else return std::string(); } + +protected: + unsigned long pos,size; + unsigned short del; + bool songend; + float rate,timer; + char *footer; + std::string track_name, game_name; + + struct Sdata { + unsigned char reg, val; + unsigned short time; + } *data; + +private: + float getrate(binistream *f); +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/kemuopl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/kemuopl.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,59 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * kemuopl.h - Emulated OPL using Ken Silverman's emulator, by Simon Peter + * + */ + +#ifndef H_ADPLUG_KEMUOPL +#define H_ADPLUG_KEMUOPL + +#include "opl.h" +extern "C" { +#include "adlibemu.h" +} + +class CKemuopl: public Copl +{ +public: + CKemuopl(int rate, bool bit16, bool usestereo) + : use16bit(bit16), stereo(usestereo) + { + adlibinit(rate, usestereo ? 2 : 1, bit16 ? 2 : 1); + }; + + void update(short *buf, int samples) + { + if(use16bit) samples *= 2; + if(stereo) samples *= 2; + adlibgetsample(buf, samples); + } + + // template methods + void write(int reg, int val) + { + adlib0(reg, val); + }; + + void init() {}; + +private: + bool use16bit,stereo; +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/ksm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/ksm.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,333 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ksm.cpp - KSM Player for AdPlug by Simon Peter + */ + +#include + +#include "ksm.h" +#include "debug.h" + +const unsigned int CksmPlayer::adlibfreq[63] = { + 0, + 2390,2411,2434,2456,2480,2506,2533,2562,2592,2625,2659,2695, + 3414,3435,3458,3480,3504,3530,3557,3586,3616,3649,3683,3719, + 4438,4459,4482,4504,4528,4554,4581,4610,4640,4673,4707,4743, + 5462,5483,5506,5528,5552,5578,5605,5634,5664,5697,5731,5767, + 6486,6507,6530,6552,6576,6602,6629,6658,6688,6721,6755,6791, + 7510}; + +/*** public methods **************************************/ + +CPlayer *CksmPlayer::factory(Copl *newopl) +{ + return new CksmPlayer(newopl); +} + +bool CksmPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f; + int i; + char *fn = new char[filename.length() + 9]; + + // file validation section + if(!fp.extension(filename, ".ksm")) { + AdPlug_LogWrite("CksmPlayer::load(,\"%s\"): File doesn't have '.ksm' " + "extension! Rejected!\n", filename.c_str()); + return false; + } + AdPlug_LogWrite("*** CksmPlayer::load(,\"%s\") ***\n", filename.c_str()); + + // Load instruments from 'insts.dat' + strcpy(fn, filename.c_str()); + for(i = strlen(fn) - 1; i >= 0; i--) + if(fn[i] == '/' || fn[i] == '\\') + break; + strcpy(fn + i + 1, "insts.dat"); + AdPlug_LogWrite("Instruments file: \"%s\"\n", fn); + f = fp.open(fn); + delete [] fn; + if(!f) { + AdPlug_LogWrite("Couldn't open instruments file! Aborting!\n"); + AdPlug_LogWrite("--- CksmPlayer::load ---\n"); + return false; + } + loadinsts(f); + fp.close(f); + + f = fp.open(filename); if(!f) return false; + for(i = 0; i < 16; i++) trinst[i] = f->readInt(1); + for(i = 0; i < 16; i++) trquant[i] = f->readInt(1); + for(i = 0; i < 16; i++) trchan[i] = f->readInt(1); + f->ignore(16); + for(i = 0; i < 16; i++) trvol[i] = f->readInt(1); + numnotes = f->readInt(2); + note = new unsigned long [numnotes]; + for(i = 0; i < numnotes; i++) note[i] = f->readInt(4); + fp.close(f); + + if(!trchan[11]) { + drumstat = 0; + numchans = 9; + } else { + drumstat = 32; + numchans = 6; + } + + rewind(0); + AdPlug_LogWrite("--- CksmPlayer::load ---\n"); + return true; +} + +bool CksmPlayer::update() +{ + int quanter,chan,drumnum,freq,track,volevel,volval; + unsigned int i,j,bufnum; + unsigned long temp,templong; + + count++; + if (count >= countstop) + { + bufnum = 0; + while (count >= countstop) + { + templong = note[nownote]; + track = (int)((templong>>8)&15); + if ((templong&192) == 0) + { + i = 0; + while (((chanfreq[i] != (templong&63)) || (chantrack[i] != ((templong>>8)&15))) && (i < numchans)) + i++; + if (i < numchans) + { + databuf[bufnum] = (char)0; bufnum++; + databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++; + databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)&223); bufnum++; + chanfreq[i] = 0; + chanage[i] = 0; + } + } + else + { + volevel = trvol[track]; + if ((templong&192) == 128) + { + volevel -= 4; + if (volevel < 0) + volevel = 0; + } + if ((templong&192) == 192) + { + volevel += 4; + if (volevel > 63) + volevel = 63; + } + if (track < 11) + { + temp = 0; + i = numchans; + for(j=0;j= temp) && (chantrack[j] == track)) + { + temp = countstop - chanage[j]; + i = j; + } + if (i < numchans) + { + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++; + databuf[bufnum] = (unsigned char)0; bufnum++; + volval = (inst[trinst[track]][1]&192)+(volevel^63); + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0x40+op_table[i]+3); bufnum++; + databuf[bufnum] = (unsigned char)volval; bufnum++; + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xa0+i); bufnum++; + databuf[bufnum] = (unsigned char)(adlibfreq[templong&63]&255); bufnum++; + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++; + databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)|32); bufnum++; + chanfreq[i] = templong&63; + chanage[i] = countstop; + } + } + else if ((drumstat&32) > 0) + { + freq = adlibfreq[templong&63]; + switch(track) + { + case 11: drumnum = 16; chan = 6; freq -= 2048; break; + case 12: drumnum = 8; chan = 7; freq -= 2048; break; + case 13: drumnum = 4; chan = 8; break; + case 14: drumnum = 2; chan = 8; break; + case 15: drumnum = 1; chan = 7; freq -= 2048; break; + } + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xa0+chan); bufnum++; + databuf[bufnum] = (unsigned char)(freq&255); bufnum++; + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xb0+chan); bufnum++; + databuf[bufnum] = (unsigned char)((freq>>8)&223); bufnum++; + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xbd); bufnum++; + databuf[bufnum] = (unsigned char)(drumstat&(255-drumnum)); bufnum++; + drumstat |= drumnum; + if ((track == 11) || (track == 12) || (track == 14)) + { + volval = (inst[trinst[track]][1]&192)+(volevel^63); + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0x40+op_table[chan]+3); bufnum++; + databuf[bufnum] = (unsigned char)(volval); bufnum++; + } + else + { + volval = (inst[trinst[track]][6]&192)+(volevel^63); + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0x40+op_table[chan]); bufnum++; + databuf[bufnum] = (unsigned char)(volval); bufnum++; + } + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xbd); bufnum++; + databuf[bufnum] = (unsigned char)(drumstat); bufnum++; + } + } + nownote++; + if (nownote >= numnotes) { + nownote = 0; + songend = true; + } + templong = note[nownote]; + if (nownote == 0) + count = (templong>>12)-1; + quanter = (240/trquant[(templong>>8)&15]); + countstop = (((templong>>12)+(quanter>>1)) / quanter) * quanter; + } + for(i=0;iwrite(databuf[i+1],databuf[i+2]); + } + return !songend; +} + +void CksmPlayer::rewind(int subsong) +{ + unsigned int i,j,k; + unsigned char instbuf[11]; + unsigned long templong; + + songend = false; + opl->init(); opl->write(1,32); opl->write(4,0); opl->write(8,0); opl->write(0xbd,drumstat); + + if (trchan[11] == 1) { + for(i=0;i<11;i++) + instbuf[i] = inst[trinst[11]][i]; + instbuf[1] = ((instbuf[1]&192)|(trvol[11])^63); + setinst(6,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); + for(i=0;i<5;i++) + instbuf[i] = inst[trinst[12]][i]; + for(i=5;i<11;i++) + instbuf[i] = inst[trinst[15]][i]; + instbuf[1] = ((instbuf[1]&192)|(trvol[12])^63); + instbuf[6] = ((instbuf[6]&192)|(trvol[15])^63); + setinst(7,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); + for(i=0;i<5;i++) + instbuf[i] = inst[trinst[14]][i]; + for(i=5;i<11;i++) + instbuf[i] = inst[trinst[13]][i]; + instbuf[1] = ((instbuf[1]&192)|(trvol[14])^63); + instbuf[6] = ((instbuf[6]&192)|(trvol[13])^63); + setinst(8,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); + } + + for(i=0;i 0) && (j < numchans)) + { + k = trchan[i]; + while ((j < numchans) && (k > 0)) + { + chantrack[j] = i; + k--; + j++; + } + } + for(i=0;i>12)-1; + countstop = (templong>>12)-1; + nownote = 0; +} + +std::string CksmPlayer::getinstrument(unsigned int n) +{ + if(trchan[n]) + return std::string(instname[trinst[n]]); + else + return std::string(); +} + +/*** private methods *************************************/ + +void CksmPlayer::loadinsts(binistream *f) +{ + int i, j; + + for(i = 0; i < 256; i++) { + f->readString(instname[i], 20); + for(j = 0; j < 11; j++) inst[i][j] = f->readInt(1); + f->ignore(2); + } +} + +void CksmPlayer::setinst(int chan, + unsigned char v0,unsigned char v1,unsigned char v2, + unsigned char v3,unsigned char v4,unsigned char v5, + unsigned char v6,unsigned char v7,unsigned char v8, + unsigned char v9,unsigned char v10) +{ + int offs; + + opl->write(0xa0+chan,0); + opl->write(0xb0+chan,0); + opl->write(0xc0+chan,v10); + offs = op_table[chan]; + opl->write(0x20+offs,v5); + opl->write(0x40+offs,v6); + opl->write(0x60+offs,v7); + opl->write(0x80+offs,v8); + opl->write(0xe0+offs,v9); + offs+=3; + opl->write(0x20+offs,v0); + opl->write(0x40+offs,v1); + opl->write(0x60+offs,v2); + opl->write(0x80+offs,v3); + opl->write(0xe0+offs,v4); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/ksm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/ksm.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,62 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ksm.h - KSM Player for AdPlug by Simon Peter + */ + +#include "player.h" + +class CksmPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CksmPlayer(Copl *newopl) + : CPlayer(newopl), note(0) + { }; + ~CksmPlayer() + { if(note) delete [] note; }; + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh() + { return 240.0f; }; + + std::string gettype() + { return std::string("Ken Silverman's Music Format"); }; + unsigned int getinstruments() + { return 16; }; + std::string getinstrument(unsigned int n); + +private: + static const unsigned int adlibfreq[63]; + + unsigned long count,countstop,chanage[18],*note; + unsigned short numnotes; + unsigned int nownote,numchans,drumstat; + unsigned char trinst[16],trquant[16],trchan[16],trvol[16],inst[256][11],databuf[2048],chanfreq[18],chantrack[18]; + char instname[256][20]; + + bool songend; + + void loadinsts(binistream *f); + void setinst(int chan,unsigned char v0,unsigned char v1,unsigned char v2,unsigned char v3, + unsigned char v4,unsigned char v5,unsigned char v6,unsigned char v7, + unsigned char v8,unsigned char v9,unsigned char v10); +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/lds.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/lds.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,676 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * lds.cpp - LOUDNESS Player by Simon Peter + */ + +#include + +#include "lds.h" +#include "debug.h" + +// Note frequency table (16 notes / octave) +const unsigned short CldsPlayer::frequency[] = { + 343, 344, 345, 347, 348, 349, 350, 352, 353, 354, 356, 357, 358, + 359, 361, 362, 363, 365, 366, 367, 369, 370, 371, 373, 374, 375, + 377, 378, 379, 381, 382, 384, 385, 386, 388, 389, 391, 392, 393, + 395, 396, 398, 399, 401, 402, 403, 405, 406, 408, 409, 411, 412, + 414, 415, 417, 418, 420, 421, 423, 424, 426, 427, 429, 430, 432, + 434, 435, 437, 438, 440, 442, 443, 445, 446, 448, 450, 451, 453, + 454, 456, 458, 459, 461, 463, 464, 466, 468, 469, 471, 473, 475, + 476, 478, 480, 481, 483, 485, 487, 488, 490, 492, 494, 496, 497, + 499, 501, 503, 505, 506, 508, 510, 512, 514, 516, 518, 519, 521, + 523, 525, 527, 529, 531, 533, 535, 537, 538, 540, 542, 544, 546, + 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 568, 571, 573, + 575, 577, 579, 581, 583, 585, 587, 589, 591, 594, 596, 598, 600, + 602, 604, 607, 609, 611, 613, 615, 618, 620, 622, 624, 627, 629, + 631, 633, 636, 638, 640, 643, 645, 647, 650, 652, 654, 657, 659, + 662, 664, 666, 669, 671, 674, 676, 678, 681, 683 +}; + +// Vibrato (sine) table +const unsigned char CldsPlayer::vibtab[] = { + 0, 13, 25, 37, 50, 62, 74, 86, 98, 109, 120, 131, 142, 152, 162, + 171, 180, 189, 197, 205, 212, 219, 225, 231, 236, 240, 244, 247, + 250, 252, 254, 255, 255, 255, 254, 252, 250, 247, 244, 240, 236, + 231, 225, 219, 212, 205, 197, 189, 180, 171, 162, 152, 142, 131, + 120, 109, 98, 86, 74, 62, 50, 37, 25, 13 +}; + +// Tremolo (sine * sine) table +const unsigned char CldsPlayer::tremtab[] = { + 0, 0, 1, 1, 2, 4, 5, 7, 10, 12, 15, 18, 21, 25, 29, 33, 37, 42, 47, + 52, 57, 62, 67, 73, 79, 85, 90, 97, 103, 109, 115, 121, 128, 134, + 140, 146, 152, 158, 165, 170, 176, 182, 188, 193, 198, 203, 208, + 213, 218, 222, 226, 230, 234, 237, 240, 243, 245, 248, 250, 251, + 253, 254, 254, 255, 255, 255, 254, 254, 253, 251, 250, 248, 245, + 243, 240, 237, 234, 230, 226, 222, 218, 213, 208, 203, 198, 193, + 188, 182, 176, 170, 165, 158, 152, 146, 140, 134, 127, 121, 115, + 109, 103, 97, 90, 85, 79, 73, 67, 62, 57, 52, 47, 42, 37, 33, 29, + 25, 21, 18, 15, 12, 10, 7, 5, 4, 2, 1, 1, 0 +}; + +// 'maxsound' is maximum number of patches (instruments) +// 'maxpos' is maximum number of entries in position list (orderlist) +const unsigned short CldsPlayer::maxsound = 0x3f, CldsPlayer::maxpos = 0xff; + +/*** public methods *************************************/ + +CldsPlayer::CldsPlayer(Copl *newopl) + : CPlayer(newopl), soundbank(0), positions(0), patterns(0) +{ +} + +CldsPlayer::~CldsPlayer() +{ + if(soundbank) delete [] soundbank; + if(positions) delete [] positions; + if(patterns) delete [] patterns; +} + +bool CldsPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f; + unsigned int i, j; + SoundBank *sb; + + // file validation section (actually just an extension check) + if(!fp.extension(filename, ".lds")) return false; + f = fp.open(filename); if(!f) return false; + + // file load section (header) + mode = f->readInt(1); + if(mode > 2) { fp.close(f); return false; } + speed = f->readInt(2); + tempo = f->readInt(1); + pattlen = f->readInt(1); + for(i = 0; i < 9; i++) chandelay[i] = f->readInt(1); + regbd = f->readInt(1); + + // load patches + numpatch = f->readInt(2); + soundbank = new SoundBank[numpatch]; + for(i = 0; i < numpatch; i++) { + sb = &soundbank[i]; + sb->mod_misc = f->readInt(1); sb->mod_vol = f->readInt(1); + sb->mod_ad = f->readInt(1); sb->mod_sr = f->readInt(1); + sb->mod_wave = f->readInt(1); sb->car_misc = f->readInt(1); + sb->car_vol = f->readInt(1); sb->car_ad = f->readInt(1); + sb->car_sr = f->readInt(1); sb->car_wave = f->readInt(1); + sb->feedback = f->readInt(1); sb->keyoff = f->readInt(1); + sb->portamento = f->readInt(1); sb->glide = f->readInt(1); + sb->finetune = f->readInt(1); sb->vibrato = f->readInt(1); + sb->vibdelay = f->readInt(1); sb->mod_trem = f->readInt(1); + sb->car_trem = f->readInt(1); sb->tremwait = f->readInt(1); + sb->arpeggio = f->readInt(1); + for(j = 0; j < 12; j++) sb->arp_tab[j] = f->readInt(1); + sb->start = f->readInt(2); sb->size = f->readInt(2); + sb->fms = f->readInt(1); sb->transp = f->readInt(2); + sb->midinst = f->readInt(1); sb->midvelo = f->readInt(1); + sb->midkey = f->readInt(1); sb->midtrans = f->readInt(1); + sb->middum1 = f->readInt(1); sb->middum2 = f->readInt(1); + } + + // load positions + numposi = f->readInt(2); + positions = new Position[9 * numposi]; + for(i = 0; i < numposi; i++) + for(j = 0; j < 9; j++) { + /* + * patnum is a pointer inside the pattern space, but patterns are 16bit + * word fields anyway, so it ought to be an even number (hopefully) and + * we can just divide it by 2 to get our array index of 16bit words. + */ + positions[i * 9 + j].patnum = f->readInt(2) / 2; + positions[i * 9 + j].transpose = f->readInt(1); + } + + AdPlug_LogWrite("CldsPlayer::load(\"%s\",fp): loading LOUDNESS file: mode = " + "%d, pattlen = %d, numpatch = %d, numposi = %d\n", + filename.c_str(), mode, pattlen, numpatch, numposi); + + // load patterns + f->ignore(2); // ignore # of digital sounds (not played by this player) + patterns = new unsigned short[(fp.filesize(f) - f->pos()) / 2 + 1]; + for(i = 0; !f->eof(); i++) + patterns[i] = f->readInt(2); + + fp.close(f); + rewind(0); + return true; +} + +bool CldsPlayer::update() +{ + unsigned short comword, freq, octave, chan, tune, wibc, tremc, arpreg; + bool vbreak; + unsigned char level, regnum, comhi, comlo; + int i; + Channel *c; + + if(!playing) return false; + + // handle fading + if(fadeonoff) + if(fadeonoff <= 128) { + if(allvolume > fadeonoff || allvolume == 0) + allvolume -= fadeonoff; + else { + allvolume = 1; + fadeonoff = 0; + if(hardfade != 0) { + playing = false; + hardfade = 0; + for(i = 0; i < 9; i++) + channel[i].keycount = 1; + } + } + } else + if(((allvolume + (0x100 - fadeonoff)) & 0xff) <= mainvolume) + allvolume += 0x100 - fadeonoff; + else { + allvolume = mainvolume; + fadeonoff = 0; + } + + // handle channel delay + for(chan = 0; chan < 9; chan++) { + c = &channel[chan]; + if(c->chancheat.chandelay) + if(!(--c->chancheat.chandelay)) + playsound(c->chancheat.sound, chan, c->chancheat.high); + } + + // handle notes + if(!tempo_now) { + vbreak = false; + for(chan = 0; chan < 9; chan++) { + c = &channel[chan]; + if(!c->packwait) { + unsigned short patnum = positions[posplay * 9 + chan].patnum; + unsigned char transpose = positions[posplay * 9 + chan].transpose; + + comword = patterns[patnum + c->packpos]; + comhi = comword >> 8; comlo = comword & 0xff; + if(comword) + if(comhi == 0x80) + c->packwait = comlo; + else + if(comhi >= 0x80) { + switch(comhi) { + case 0xff: + c->volcar = (((c->volcar & 0x3f) * comlo) >> 6) & 0x3f; + if(fmchip[0xc0 + chan] & 1) + c->volmod = (((c->volmod & 0x3f) * comlo) >> 6) & 0x3f; + break; + case 0xfe: + tempo = comword & 0x3f; + break; + case 0xfd: + c->nextvol = comlo; + break; + case 0xfc: + playing = false; + // in real player there's also full keyoff here, but we don't need it + break; + case 0xfb: + c->keycount = 1; + break; + case 0xfa: + vbreak = true; + jumppos = (posplay + 1) & maxpos; + break; + case 0xf9: + vbreak = true; + jumppos = comlo & maxpos; + jumping = 1; + if(jumppos < posplay) songlooped = true; + break; + case 0xf8: + c->lasttune = 0; + break; + case 0xf7: + c->vibwait = 0; + // PASCAL: c->vibspeed = ((comlo >> 4) & 15) + 2; + c->vibspeed = (comlo >> 4) + 2; + c->vibrate = (comlo & 15) + 1; + break; + case 0xf6: + c->glideto = comlo; + break; + case 0xf5: + c->finetune = comlo; + break; + case 0xf4: + if(!hardfade) { + allvolume = mainvolume = comlo; + fadeonoff = 0; + } + break; + case 0xf3: + if(!hardfade) fadeonoff = comlo; + break; + case 0xf2: + c->trmstay = comlo; + break; + case 0xf1: // panorama + case 0xf0: // progch + // MIDI commands (unhandled) + AdPlug_LogWrite("CldsPlayer(): not handling MIDI command 0x%x, " + "value = 0x%x\n", comhi); + break; + default: + if(comhi < 0xa0) + c->glideto = comhi & 0x1f; + else + AdPlug_LogWrite("CldsPlayer(): unknown command 0x%x encountered!" + " value = 0x%x\n", comhi, comlo); + break; + } + } else { + unsigned char sound; + unsigned short high; + signed char transp = transpose & 127; + + /* + * Originally, in assembler code, the player first shifted + * logically left the transpose byte by 1 and then shifted + * arithmetically right the same byte to achieve the final, + * signed transpose value. Since we can't do arithmetic shifts + * in C, we just duplicate the 7th bit into the 8th one and + * discard the 8th one completely. + */ + + if(transpose & 64) transp |= 128; + + if(transpose & 128) { + sound = (comlo + transp) & maxsound; + high = comhi << 4; + } else { + sound = comlo & maxsound; + high = (comhi + transp) << 4; + } + + /* + PASCAL: + sound = comlo & maxsound; + high = (comhi + (((transpose + 0x24) & 0xff) - 0x24)) << 4; + */ + + if(!chandelay[chan]) + playsound(sound, chan, high); + else { + c->chancheat.chandelay = chandelay[chan]; + c->chancheat.sound = sound; + c->chancheat.high = high; + } + } + + c->packpos++; + } else + c->packwait--; + } + + tempo_now = tempo; + /* + The continue table is updated here, but this is only used in the + original player, which can be paused in the middle of a song and then + unpaused. Since AdPlug does all this for us automatically, we don't + have a continue table here. The continue table update code is noted + here for reference only. + + if(!pattplay) { + conttab[speed & maxcont].position = posplay & 0xff; + conttab[speed & maxcont].tempo = tempo; + } + */ + pattplay++; + if(vbreak) { + pattplay = 0; + for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; + posplay = jumppos; + } else + if(pattplay >= pattlen) { + pattplay = 0; + for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; + posplay = (posplay + 1) & maxpos; + } + } else + tempo_now--; + + // make effects + for(chan = 0; chan < 9; chan++) { + c = &channel[chan]; + regnum = op_table[chan]; + if(c->keycount > 0) { + if(c->keycount == 1) + setregs_adv(0xb0 + chan, 0xdf, 0); + c->keycount--; + } + + // arpeggio + if(c->arp_size == 0) + arpreg = 0; + else { + arpreg = c->arp_tab[c->arp_pos] << 4; + if(arpreg == 0x800) { + if(c->arp_pos > 0) c->arp_tab[0] = c->arp_tab[c->arp_pos - 1]; + c->arp_size = 1; c->arp_pos = 0; + arpreg = c->arp_tab[0] << 4; + } + + if(c->arp_count == c->arp_speed) { + c->arp_pos++; + if(c->arp_pos >= c->arp_size) c->arp_pos = 0; + c->arp_count = 0; + } else + c->arp_count++; + } + + // glide & portamento + if(c->lasttune && (c->lasttune != c->gototune)) { + if(c->lasttune > c->gototune) { + if(c->lasttune - c->gototune < c->portspeed) + c->lasttune = c->gototune; + else + c->lasttune -= c->portspeed; + } else { + if(c->gototune - c->lasttune < c->portspeed) + c->lasttune = c->gototune; + else + c->lasttune += c->portspeed; + } + + if(arpreg >= 0x800) + arpreg = c->lasttune - (arpreg ^ 0xff0) - 16; + else + arpreg += c->lasttune; + + freq = frequency[arpreg % (12 * 16)]; + octave = arpreg / (12 * 16) - 1; + setregs(0xa0 + chan, freq & 0xff); + setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + } else { + // vibrato + if(!c->vibwait) { + if(c->vibrate) { + wibc = vibtab[c->vibcount & 0x3f] * c->vibrate; + + if((c->vibcount & 0x40) == 0) + tune = c->lasttune + (wibc >> 8); + else + tune = c->lasttune - (wibc >> 8); + + if(arpreg >= 0x800) + tune = tune - (arpreg ^ 0xff0) - 16; + else + tune += arpreg; + + freq = frequency[tune % (12 * 16)]; + octave = tune / (12 * 16) - 1; + setregs(0xa0 + chan, freq & 0xff); + setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + c->vibcount += c->vibspeed; + } else + if(c->arp_size != 0) { // no vibrato, just arpeggio + if(arpreg >= 0x800) + tune = c->lasttune - (arpreg ^ 0xff0) - 16; + else + tune = c->lasttune + arpreg; + + freq = frequency[tune % (12 * 16)]; + octave = tune / (12 * 16) - 1; + setregs(0xa0 + chan, freq & 0xff); + setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + } + } else { // no vibrato, just arpeggio + c->vibwait--; + + if(c->arp_size != 0) { + if(arpreg >= 0x800) + tune = c->lasttune - (arpreg ^ 0xff0) - 16; + else + tune = c->lasttune + arpreg; + + freq = frequency[tune % (12 * 16)]; + octave = tune / (12 * 16) - 1; + setregs(0xa0 + chan, freq & 0xff); + setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + } + } + } + + // tremolo (modulator) + if(!c->trmwait) { + if(c->trmrate) { + tremc = tremtab[c->trmcount & 0x7f] * c->trmrate; + if((tremc >> 8) <= (c->volmod & 0x3f)) + level = (c->volmod & 0x3f) - (tremc >> 8); + else + level = 0; + + if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) + setregs_adv(0x40 + regnum, 0xc0, ((level * allvolume) >> 8) ^ 0x3f); + else + setregs_adv(0x40 + regnum, 0xc0, level ^ 0x3f); + + c->trmcount += c->trmspeed; + } else + if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) + setregs_adv(0x40 + regnum, 0xc0, ((((c->volmod & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + else + setregs_adv(0x40 + regnum, 0xc0, (c->volmod ^ 0x3f) & 0x3f); + } else { + c->trmwait--; + if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) + setregs_adv(0x40 + regnum, 0xc0, ((((c->volmod & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + } + + // tremolo (carrier) + if(!c->trcwait) { + if(c->trcrate) { + tremc = tremtab[c->trccount & 0x7f] * c->trcrate; + if((tremc >> 8) <= (c->volcar & 0x3f)) + level = (c->volcar & 0x3f) - (tremc >> 8); + else + level = 0; + + if(allvolume != 0) + setregs_adv(0x43 + regnum, 0xc0, ((level * allvolume) >> 8) ^ 0x3f); + else + setregs_adv(0x43 + regnum, 0xc0, level ^ 0x3f); + c->trccount += c->trcspeed; + } else + if(allvolume != 0) + setregs_adv(0x43 + regnum, 0xc0, ((((c->volcar & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + else + setregs_adv(0x43 + regnum, 0xc0, (c->volcar ^ 0x3f) & 0x3f); + } else { + c->trcwait--; + if(allvolume != 0) + setregs_adv(0x43 + regnum, 0xc0, ((((c->volcar & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + } + } + + return (!playing || songlooped) ? false : true; +} + +void CldsPlayer::rewind(int subsong) +{ + int i; + + // init all with 0 + tempo_now = 3; playing = true; songlooped = false; + jumping = fadeonoff = allvolume = hardfade = pattplay = posplay = jumppos = + mainvolume = 0; + memset(channel, 0, sizeof(channel)); + memset(fmchip, 0, sizeof(fmchip)); + + // OPL2 init + opl->init(); // Reset OPL chip + opl->write(1, 0x20); + opl->write(8, 0); + opl->write(0xbd, regbd); + + for(i = 0; i < 9; i++) { + opl->write(0x20 + op_table[i], 0); + opl->write(0x23 + op_table[i], 0); + opl->write(0x40 + op_table[i], 0x3f); + opl->write(0x43 + op_table[i], 0x3f); + opl->write(0x60 + op_table[i], 0xff); + opl->write(0x63 + op_table[i], 0xff); + opl->write(0x80 + op_table[i], 0xff); + opl->write(0x83 + op_table[i], 0xff); + opl->write(0xe0 + op_table[i], 0); + opl->write(0xe3 + op_table[i], 0); + opl->write(0xa0 + i, 0); + opl->write(0xb0 + i, 0); + opl->write(0xc0 + i, 0); + } +} + +/*** private methods *************************************/ + +void CldsPlayer::playsound(int inst_number, int channel_number, int tunehigh) +{ + Channel *c = &channel[channel_number]; // current channel + SoundBank *i = &soundbank[inst_number]; // current instrument + unsigned int regnum = op_table[channel_number]; // channel's OPL2 register + unsigned char volcalc, octave; + unsigned short freq; + + // set fine tune + tunehigh += ((i->finetune + c->finetune + 0x80) & 0xff) - 0x80; + + // arpeggio handling + if(!i->arpeggio) { + unsigned short arpcalc = i->arp_tab[0] << 4; + + if(arpcalc > 0x800) + tunehigh = tunehigh - (arpcalc ^ 0xff0) - 16; + else + tunehigh += arpcalc; + } + + // glide handling + if(c->glideto != 0) { + c->gototune = tunehigh; + c->portspeed = c->glideto; + c->glideto = c->finetune = 0; + return; + } + + // set modulator registers + setregs(0x20 + regnum, i->mod_misc); + volcalc = i->mod_vol; + if(!c->nextvol || !(i->feedback & 1)) + c->volmod = volcalc; + else + c->volmod = (volcalc & 0xc0) | ((((volcalc & 0x3f) * c->nextvol) >> 6)); + + if((i->feedback & 1) == 1 && allvolume != 0) + setregs(0x40 + regnum, ((c->volmod & 0xc0) | (((c->volmod & 0x3f) * allvolume) >> 8)) ^ 0x3f); + else + setregs(0x40 + regnum, c->volmod ^ 0x3f); + setregs(0x60 + regnum, i->mod_ad); + setregs(0x80 + regnum, i->mod_sr); + setregs(0xe0 + regnum, i->mod_wave); + + // Set carrier registers + setregs(0x23 + regnum, i->car_misc); + volcalc = i->car_vol; + if(!c->nextvol) + c->volcar = volcalc; + else + c->volcar = (volcalc & 0xc0) | ((((volcalc & 0x3f) * c->nextvol) >> 6)); + + if(allvolume) + setregs(0x43 + regnum, ((c->volcar & 0xc0) | (((c->volcar & 0x3f) * allvolume) >> 8)) ^ 0x3f); + else + setregs(0x43 + regnum, c->volcar ^ 0x3f); + setregs(0x63 + regnum, i->car_ad); + setregs(0x83 + regnum, i->car_sr); + setregs(0xe3 + regnum, i->car_wave); + setregs(0xc0 + channel_number, i->feedback); + setregs_adv(0xb0 + channel_number, 0xdf, 0); // key off + + freq = frequency[tunehigh % (12 * 16)]; + octave = tunehigh / (12 * 16) - 1; + if(!i->glide) { + if(!i->portamento || !c->lasttune) { + setregs(0xa0 + channel_number, freq & 0xff); + setregs(0xb0 + channel_number, (octave << 2) + 0x20 + (freq >> 8)); + c->lasttune = c->gototune = tunehigh; + } else { + c->gototune = tunehigh; + c->portspeed = i->portamento; + setregs_adv(0xb0 + channel_number, 0xdf, 0x20); // key on + } + } else { + setregs(0xa0 + channel_number, freq & 0xff); + setregs(0xb0 + channel_number, (octave << 2) + 0x20 + (freq >> 8)); + c->lasttune = tunehigh; + c->gototune = tunehigh + ((i->glide + 0x80) & 0xff) - 0x80; // set destination + c->portspeed = i->portamento; + } + + if(!i->vibrato) + c->vibwait = c->vibspeed = c->vibrate = 0; + else { + c->vibwait = i->vibdelay; + // PASCAL: c->vibspeed = ((i->vibrato >> 4) & 15) + 1; + c->vibspeed = (i->vibrato >> 4) + 2; + c->vibrate = (i->vibrato & 15) + 1; + } + + if(!(c->trmstay & 0xf0)) { + c->trmwait = (i->tremwait & 0xf0) >> 3; + // PASCAL: c->trmspeed = (i->mod_trem >> 4) & 15; + c->trmspeed = i->mod_trem >> 4; + c->trmrate = i->mod_trem & 15; + c->trmcount = 0; + } + + if(!(c->trmstay & 0x0f)) { + c->trcwait = (i->tremwait & 15) << 1; + // PASCAL: c->trcspeed = (i->car_trem >> 4) & 15; + c->trcspeed = i->car_trem >> 4; + c->trcrate = i->car_trem & 15; + c->trccount = 0; + } + + c->arp_size = i->arpeggio & 15; + c->arp_speed = i->arpeggio >> 4; + memcpy(c->arp_tab, i->arp_tab, 12); + c->keycount = i->keyoff; + c->nextvol = c->glideto = c->finetune = c->vibcount = c->arp_pos = c->arp_count = 0; +} + +inline void CldsPlayer::setregs(unsigned char reg, unsigned char val) +{ + if(fmchip[reg] == val) return; + + fmchip[reg] = val; + opl->write(reg, val); +} + +inline void CldsPlayer::setregs_adv(unsigned char reg, unsigned char mask, + unsigned char val) +{ + setregs(reg, (fmchip[reg] & mask) | val); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/lds.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/lds.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,91 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * lds.h - LOUDNESS Player by Simon Peter + */ + +#include "player.h" + +class CldsPlayer: public CPlayer +{ + public: + static CPlayer *factory(Copl *newopl) { return new CldsPlayer(newopl); } + + CldsPlayer(Copl *newopl); + virtual ~CldsPlayer(); + + bool load(const std::string &filename, const CFileProvider &fp); + virtual bool update(); + virtual void rewind(int subsong = -1); + float getrefresh() { return 70.0f; } + + std::string gettype() { return std::string("LOUDNESS Sound System"); } + unsigned int getorders() { return numposi; } + unsigned int getorder() { return posplay; } + unsigned int getrow() { return pattplay; } + unsigned int getspeed() { return speed; } + unsigned int getinstruments() { return numpatch; } + + private: + typedef struct { + unsigned char mod_misc, mod_vol, mod_ad, mod_sr, mod_wave, + car_misc, car_vol, car_ad, car_sr, car_wave, feedback, keyoff, + portamento, glide, finetune, vibrato, vibdelay, mod_trem, car_trem, + tremwait, arpeggio, arp_tab[12]; + unsigned short start, size; + unsigned char fms; + unsigned short transp; + unsigned char midinst, midvelo, midkey, midtrans, middum1, middum2; + } SoundBank; + + typedef struct { + unsigned short gototune, lasttune, packpos; + unsigned char finetune, glideto, portspeed, nextvol, volmod, volcar, + vibwait, vibspeed, vibrate, trmstay, trmwait, trmspeed, trmrate, trmcount, + trcwait, trcspeed, trcrate, trccount, arp_size, arp_speed, keycount, + vibcount, arp_pos, arp_count, packwait, arp_tab[12]; + + struct { + unsigned char chandelay, sound; + unsigned short high; + } chancheat; + } Channel; + + typedef struct { + unsigned short patnum; + unsigned char transpose; + } Position; + + static const unsigned short frequency[]; + static const unsigned char vibtab[], tremtab[]; + static const unsigned short maxsound, maxpos; + + SoundBank *soundbank; + Channel channel[9]; + Position *positions; + unsigned char fmchip[0xff], jumping, fadeonoff, allvolume, hardfade, + tempo_now, pattplay, tempo, regbd, chandelay[9], mode, pattlen; + unsigned short posplay, jumppos, *patterns, speed; + bool playing, songlooped; + unsigned int numpatch, numposi, patterns_size, mainvolume; + + void playsound(int inst_number, int channel_number, int tunehigh); + inline void setregs(unsigned char reg, unsigned char val); + inline void setregs_adv(unsigned char reg, unsigned char mask, + unsigned char val); +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/mad.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mad.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,126 @@ +/* + Adplug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2003 Simon Peter, , et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + mad.cpp - MAD loader by Riven the Mage +*/ + +#include "mad.h" + +/* -------- Public Methods -------------------------------- */ + +CPlayer *CmadLoader::factory(Copl *newopl) +{ + return new CmadLoader(newopl); +} + +bool CmadLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + const unsigned char conv_inst[10] = { 2,1,10,9,4,3,6,5,8,7 }; + unsigned int i, j, k, t = 0; + + // 'MAD+' - signed ? + char id[4]; f->readString(id, 4); + if (strncmp(id,"MAD+",4)) { fp.close(f); return false; } + + // load instruments + for(i = 0; i < 9; i++) { + f->readString(instruments[i].name, 8); + for(j = 0; j < 12; j++) instruments[i].data[j] = f->readInt(1); + } + + f->ignore(1); + + // data for Protracker + length = f->readInt(1); nop = f->readInt(1); timer = f->readInt(1); + + // init CmodPlayer + realloc_instruments(9); + realloc_order(length); + realloc_patterns(nop,32,9); + init_trackord(); + + // load tracks + for(i = 0; i < nop; i++) + for(k = 0; k < 32; k++) + for(j = 0; j < 9; j++) { + t = i * 9 + j; + + // read event + unsigned char event = f->readInt(1); + + // convert event + if (event < 0x61) + tracks[t][k].note = event; + if (event == 0xFF) // 0xFF: Release note + tracks[t][k].command = 8; + if (event == 0xFE) // 0xFE: Pattern Break + tracks[t][k].command = 13; + } + + // load order + for(i = 0; i < length; i++) order[i] = f->readInt(1) - 1; + + fp.close(f); + + // convert instruments + for(i = 0; i < 9; i++) + for(j = 0; j < 10; j++) + inst[i].data[conv_inst[j]] = instruments[i].data[j]; + + // data for Protracker + restartpos = 0; + initspeed = 1; + + rewind(0); + return true; +} + +void CmadLoader::rewind(int subsong) +{ + CmodPlayer::rewind(subsong); + + // default instruments + for (int i=0;i<9;i++) + { + channel[i].inst = i; + + channel[i].vol1 = 63 - (inst[i].data[10] & 63); + channel[i].vol2 = 63 - (inst[i].data[9] & 63); + } +} + +float CmadLoader::getrefresh() +{ + return (float)timer; +} + +std::string CmadLoader::gettype() +{ + return std::string("Mlat Adlib Tracker"); +} + +std::string CmadLoader::getinstrument(unsigned int n) +{ + return std::string(instruments[n].name,8); +} + +unsigned int CmadLoader::getinstruments() +{ + return 9; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/mad.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mad.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,48 @@ +/* + Adplug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2003 Simon Peter, , et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + mad.h - MAD loader by Riven the Mage +*/ + +#include "protrack.h" + +class CmadLoader: public CmodPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CmadLoader(Copl *newopl) : CmodPlayer(newopl) { }; + + bool load(const std::string &filename, const CFileProvider &fp); + void rewind(int subsong); + float getrefresh(); + + std::string gettype(); + std::string getinstrument(unsigned int n); + unsigned int getinstruments(); + +private: + + struct mad_instrument + { + char name[8]; + unsigned char data[12]; // last two unused + } instruments[9]; + + unsigned char timer; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/mid.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mid.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,1050 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * MIDI & MIDI-like file player - Last Update: 8/16/2000 + * by Phil Hassey - www.imitationpickles.org + * philhassey@hotmail.com + * + * Can play the following + * .LAA - a raw save of a Lucas Arts Adlib music + * or + * a raw save of a LucasFilm Adlib music + * .MID - a "midi" save of a Lucas Arts Adlib music + * - or general MIDI files + * .CMF - Creative Music Format + * .SCI - the sierra "midi" format. + * Files must be in the form + * xxxNAME.sci + * So that the loader can load the right patch file: + * xxxPATCH.003 (patch.003 must be saved from the + * sierra resource from each game.) + * + * 6/2/2000: v1.0 relased by phil hassey + * Status: LAA is almost perfect + * - some volumes are a bit off (intrument too quiet) + * MID is fine (who wants to listen to MIDI vid adlib anyway) + * CMF is okay (still needs the adlib rythm mode implemented + * for real) + * 6/6/2000: + * Status: SCI: there are two SCI formats, orginal and advanced. + * original: (Found in SCI/EGA Sierra Adventures) + * played almost perfectly, I believe + * there is one mistake in the instrument + * loader that causes some sounds to + * not be quite right. Most sounds are fine. + * advanced: (Found in SCI/VGA Sierra Adventures) + * These are multi-track files. (Thus the + * player had to be modified to work with + * them.) This works fine. + * There are also multiple tunes in each file. + * I think some of them are supposed to be + * played at the same time, but I'm not sure + * when. + * 8/16/200: + * Status: LAA: now EGA and VGA lucas games work pretty well + * + * Other acknowledgements: + * Allegro - for the midi instruments and the midi volume table + * SCUMM Revisited - for getting the .LAA / .MIDs out of those + * LucasArts files. + * FreeSCI - for some information on the sci music files + * SD - the SCI Decoder (to get all .sci out of the Sierra files) + */ + +#include +#include +#include +#include +#include "mid.h" +#include "mididata.h" + +/*#define TESTING*/ +#ifdef TESTING +#define midiprintf printf +#else +void CmidPlayer::midiprintf(char *format, ...) + { + } +#endif + +CPlayer *CmidPlayer::factory(Copl *newopl) +{ + return new CmidPlayer(newopl); +} + +unsigned char CmidPlayer::datalook(long pos) +{ + if (pos<0 || pos >= flen) return(0); + return(data[pos]); +} + +unsigned long CmidPlayer::getnexti(unsigned long num) +{ + unsigned long v=0; + unsigned long i; + + for (i=0; i= 0; i--) + if(pfilename[i] == '/' || pfilename[i] == '\\') { + j = i+1; + break; + } + sprintf(pfilename+j+3,"patch.003"); + + f = fp.open(pfilename); + free(pfilename); + if(!f) return false; + + f->ignore(2); + stins = 0; + for (i=0; i<2; i++) + { + for (k=0; k<48; k++) + { + l=i*48+k; + midiprintf ("\n%2d: ",l); + for (j=0; j<28; j++) + ins[j] = f->readInt(1); + + myinsbank[l][0]= + (ins[9]*0x80) + (ins[10]*0x40) + + (ins[5]*0x20) + (ins[11]*0x10) + + ins[1]; //1=ins5 + myinsbank[l][1]= + (ins[22]*0x80) + (ins[23]*0x40) + + (ins[18]*0x20) + (ins[24]*0x10) + + ins[14]; //1=ins18 + + myinsbank[l][2]=(ins[0]<<6)+ins[8]; + myinsbank[l][3]=(ins[13]<<6)+ins[21]; + + myinsbank[l][4]=(ins[3]<<4)+ins[6]; + myinsbank[l][5]=(ins[16]<<4)+ins[19]; + myinsbank[l][6]=(ins[4]<<4)+ins[7]; + myinsbank[l][7]=(ins[17]<<4)+ins[20]; + + myinsbank[l][8]=ins[26]; + myinsbank[l][9]=ins[27]; + + myinsbank[l][10]=((ins[2]<<1))+(1-(ins[12]&1)); + //(ins[12] ? 0:1)+((ins[2]<<1)); + + for (j=0; j<11; j++) + midiprintf ("%02X ",myinsbank[l][j]); + stins++; + } + f->ignore(2); + } + + fp.close(f); + memcpy(smyinsbank, myinsbank, 128 * 16); + return true; +} + +void CmidPlayer::sierra_next_section() +{ + int i,j; + + for (i=0; i<16; i++) + track[i].on=0; + + midiprintf("\n\nnext adv sierra section:\n"); + + pos=sierra_pos; + i=0;j=0; + while (i!=0xff) + { + getnext(1); + curtrack=j; j++; + track[curtrack].on=1; + track[curtrack].spos = getnext(1); + track[curtrack].spos += (getnext(1) << 8) + 4; //4 best usually +3? not 0,1,2 or 5 +// track[curtrack].spos=getnext(1)+(getnext(1)<<8)+4; // dynamite!: doesn't optimize correctly!! + track[curtrack].tend=flen; //0xFC will kill it + track[curtrack].iwait=0; + track[curtrack].pv=0; + midiprintf ("track %d starts at %lx\n",curtrack,track[curtrack].spos); + + getnext(2); + i=getnext(1); + } + getnext(2); + deltas=0x20; + sierra_pos=pos; + //getch(); + + fwait=0; + doing=1; +} + +#define FILE_LUCAS 1 +#define FILE_MIDI 2 +#define FILE_CMF 3 +#define FILE_SIERRA 4 +#define FILE_ADVSIERRA 5 +#define FILE_OLDLUCAS 6 + +bool CmidPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + int good; + unsigned char s[6]; + + f->readString((char *)s, 6); + good=0; + subsongs=0; + switch(s[0]) + { + case 'A': + if (s[1]=='D' && s[2]=='L') good=FILE_LUCAS; + break; + case 'M': + if (s[1]=='T' && s[2]=='h' && s[3]=='d') good=FILE_MIDI; + break; + case 'C': + if (s[1]=='T' && s[2]=='M' && s[3]=='F') good=FILE_CMF; + break; + case 0x84: + if (s[1]==0x00 && load_sierra_ins(filename, fp)) + if (s[2]==0xf0) + good=FILE_ADVSIERRA; + else + good=FILE_SIERRA; + break; + default: + if (s[4]=='A' && s[5]=='D') good=FILE_OLDLUCAS; + break; + } + + if (good!=0) + subsongs=1; + else { + fp.close(f); + return false; + } + + type=good; + f->seek(0); + flen = fp.filesize(f); + data = new unsigned char [flen]; + f->readString((char *)data, flen); + + fp.close(f); + rewind(0); + return true; +} + +void CmidPlayer::midi_write_adlib(unsigned int r, unsigned char v) +{ + opl->write(r,v); + adlib_data[r]=v; +} + +unsigned char adlib_opadd[] = {0x00 ,0x01 ,0x02 ,0x08 ,0x09 ,0x0A ,0x10 ,0x11 ,0x12}; +int ops[] = {0x20,0x20,0x40,0x40,0x60,0x60,0x80,0x80,0xe0,0xe0,0xc0}; + +void CmidPlayer::midi_fm_instrument(int voice, unsigned char *inst) +{ + if ((adlib_style&SIERRA_STYLE)!=0) + midi_write_adlib(0xbd,0); //just gotta make sure this happens.. + //'cause who knows when it'll be + //reset otherwise. + + + midi_write_adlib(0x20+adlib_opadd[voice],inst[0]); + midi_write_adlib(0x23+adlib_opadd[voice],inst[1]); + + if ((adlib_style&LUCAS_STYLE)!=0) + { + midi_write_adlib(0x43+adlib_opadd[voice],0x3f); + if ((inst[10] & 1)==0) + midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); + else + midi_write_adlib(0x40+adlib_opadd[voice],0x3f); + } + else + { + if ((adlib_style&SIERRA_STYLE)!=0) + { + midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); + midi_write_adlib(0x43+adlib_opadd[voice],inst[3]); + } + else + { + midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); + if ((inst[10] & 1)==0) + midi_write_adlib(0x43+adlib_opadd[voice],inst[3]); + else + midi_write_adlib(0x43+adlib_opadd[voice],0); + } + } + + midi_write_adlib(0x60+adlib_opadd[voice],inst[4]); + midi_write_adlib(0x63+adlib_opadd[voice],inst[5]); + midi_write_adlib(0x80+adlib_opadd[voice],inst[6]); + midi_write_adlib(0x83+adlib_opadd[voice],inst[7]); + midi_write_adlib(0xe0+adlib_opadd[voice],inst[8]); + midi_write_adlib(0xe3+adlib_opadd[voice],inst[9]); + + midi_write_adlib(0xc0+voice,inst[10]); +} + +void CmidPlayer::midi_fm_volume(int voice, int volume) +{ + int vol; + + if ((adlib_style&SIERRA_STYLE)==0) //sierra likes it loud! + { + vol=volume>>2; + + if ((adlib_style&LUCAS_STYLE)!=0) + { + if ((adlib_data[0xc0+voice]&1)==1) + midi_write_adlib(0x40+adlib_opadd[voice], (unsigned +char)((63-vol) | + (adlib_data[0x40+adlib_opadd[voice]]&0xc0))); + midi_write_adlib(0x43+adlib_opadd[voice], (unsigned char)((63-vol) | + (adlib_data[0x43+adlib_opadd[voice]]&0xc0))); + } + else + { + if ((adlib_data[0xc0+voice]&1)==1) + midi_write_adlib(0x40+adlib_opadd[voice], (unsigned +char)((63-vol) | + (adlib_data[0x40+adlib_opadd[voice]]&0xc0))); + midi_write_adlib(0x43+adlib_opadd[voice], (unsigned char)((63-vol) | + (adlib_data[0x43+adlib_opadd[voice]]&0xc0))); + } + } +} + + +int fnums[] = { +0x16b,0x181,0x198,0x1b0,0x1ca,0x1e5,0x202,0x220,0x241,0x263,0x287,0x2ae + }; + +void CmidPlayer::midi_fm_playnote(int voice, int note, int volume) +{ + int freq=fnums[note%12]; + int oct=note/12; + int c; + + midi_fm_volume(voice,volume); + midi_write_adlib(0xa0+voice,(unsigned char)(freq&0xff)); + + c=((freq&0x300) >> 8)+(oct<<2) + (1<<5); + midi_write_adlib(0xb0+voice,(unsigned char)c); +} + +void CmidPlayer::midi_fm_endnote(int voice) +{ + //midi_fm_volume(voice,0); + //midi_write_adlib(0xb0+voice,0); + + midi_write_adlib(0xb0+voice,(unsigned char)(adlib_data[0xb0+voice]&(255-32))); +} + +void CmidPlayer::midi_fm_reset() +{ + int i; + for (i=0; i<256; i++) + midi_write_adlib(i,0); + + midi_write_adlib(0x01, 0x20); + midi_write_adlib(0xBD,0xc0); +} + +bool CmidPlayer::update() +{ + long w,v,note,vel,ctrl,nv,x,l,lnum; + int i=0,j,c; + int on,onl; + unsigned char ins[11]; + int ret; + + if (doing == 1) + { + // just get the first wait and ignore it :> + for (curtrack=0; curtrack<16; curtrack++) + if (track[curtrack].on) + { + pos=track[curtrack].pos; + if (type != FILE_SIERRA && type !=FILE_ADVSIERRA) + track[curtrack].iwait+=getval(); + else + track[curtrack].iwait+=getnext(1); + track[curtrack].pos=pos; + } + doing=0; + } + + iwait=0; + ret=1; + + while (iwait==0 && ret==1) + { + for (curtrack=0; curtrack<16; curtrack++) + if (track[curtrack].on && track[curtrack].iwait==0 && + track[curtrack].pos < track[curtrack].tend) + { + pos=track[curtrack].pos; + + v=getnext(1); + + // This is to do implied MIDI events. + if (v<0x80) {v=track[curtrack].pv; pos--;} + track[curtrack].pv=(unsigned char)v; + + c=v&0x0f; + midiprintf ("[%2X]",v); + switch(v&0xf0) + { + case 0x80: /*note off*/ + note=getnext(1); vel=getnext(1); + for (i=0; i<9; i++) + if (chp[i][0]==c && chp[i][1]==note) + { + midi_fm_endnote(i); + chp[i][0]=-1; + } + break; + case 0x90: /*note on*/ + // doing=0; + note=getnext(1); vel=getnext(1); + + if (ch[c].on!=0) + { + for (i=0; i<9; i++) + chp[i][2]++; + + j=0; + on=-1;onl=0; + for (i=0; i<9; i++) + if (chp[i][0]==-1 && chp[i][2]>onl) + { onl=chp[i][2]; on=i; j=1; } + + if (on==-1) + { + onl=0; + for (i=0; i<9; i++) + if (chp[i][2]>onl) + { onl=chp[i][2]; on=i; } + } + + if (j==0) + midi_fm_endnote(on); + + if (vel!=0 && ch[c].inum>=0 && ch[c].inum<128) + { + if (adlib_mode == ADLIB_MELODIC || c < 12) + midi_fm_instrument(on,ch[c].ins); + else + { + //the following fails to be effective + //at doing rythm sounds .. (cmf blah) + ins[0]=ins[1]=ch[c].ins[0]; + ins[2]=ins[3]=ch[c].ins[2]; + ins[4]=ins[5]=ch[c].ins[4]; + ins[6]=ins[7]=ch[c].ins[6]; + ins[8]=ins[9]=ch[c].ins[8]; + ins[10]=ch[c].ins[10]|1; + midi_fm_instrument(on,ins); + } + + if ((adlib_style&MIDI_STYLE)!=0) + { + nv=((ch[c].vol*vel)/128); + if ((adlib_style&LUCAS_STYLE)!=0) + nv*=2; + if (nv>127) nv=127; + nv=my_midi_fm_vol_table[nv]; + if ((adlib_style&LUCAS_STYLE)!=0) + nv=(int)((float)sqrt((float)nv)*11); + } + else + { + nv=vel; + } + + midi_fm_playnote(on,note+ch[c].nshift,nv*2); + chp[on][0]=c; + chp[on][1]=note; + chp[on][2]=0; + } + else + { + if (vel==0) //same code as end note + { + for (i=0; i<9; i++) + if (chp[i][0]==c && chp[i][1]==note) + { + // midi_fm_volume(i,0); // really end the note + midi_fm_endnote(i); + chp[i][0]=-1; + } + } + else + { // i forget what this is for. + chp[on][0]=-1; + chp[on][2]=0; + } + } + midiprintf(" [%d:%d:%d:%d]\n",c,ch[c].inum,note,vel); + } + else + midiprintf ("off"); + break; + case 0xa0: /*key after touch */ + note=getnext(1); vel=getnext(1); + /* //this might all be good + for (i=0; i<9; i++) + if (chp[i][0]==c & chp[i][1]==note) + +midi_fm_playnote(i,note+cnote[c],my_midi_fm_vol_table[(cvols[c]*vel)/128]*2); + */ + break; + case 0xb0: /*control change .. pitch bend? */ + ctrl=getnext(1); vel=getnext(1); + + switch(ctrl) + { + case 0x07: + midiprintf ("(pb:%d: %d %d)",c,ctrl,vel); + ch[c].vol=vel; + midiprintf("vol"); + break; + case 0x67: + midiprintf ("\n\nhere:%d\n\n",vel); + if ((adlib_style&CMF_STYLE)!=0) + adlib_mode=vel; // this gets faked - no mode change + break; + } + break; + case 0xc0: /*patch change*/ + x=getnext(1); + ch[c].inum=x; + for (j=0; j<11; j++) + ch[c].ins[j]=myinsbank[ch[c].inum][j]; + break; + case 0xd0: /*chanel touch*/ + x=getnext(1); + break; + case 0xe0: /*pitch wheel*/ + x=getnext(1); + x=getnext(1); + break; + case 0xf0: + switch(v) + { + case 0xf0: + case 0xf7: /*sysex*/ + l=getval(); + if (datalook(pos+l)==0xf7) + i=1; + midiprintf("{%d}",l); + midiprintf("\n"); + + if (datalook(pos)==0x7d && + datalook(pos+1)==0x10 && + datalook(pos+2)<16) + { + adlib_style=LUCAS_STYLE|MIDI_STYLE; + for (i=0; i",w); + f = +((float)w/(float)deltas)*((float)msqtr/(float)1000000); + if (doing==1) f=0; //not playing yet. don't wait yet + } + */ + } + else + track[curtrack].iwait=0; + + track[curtrack].pos=pos; + } + + + ret=0; //end of song. + iwait=0; + for (curtrack=0; curtrack<16; curtrack++) + if (track[curtrack].on == 1 && + track[curtrack].pos < track[curtrack].tend) + ret=1; //not yet.. + + if (ret==1) + { + iwait=0xffffff; // bigger than any wait can be! + for (curtrack=0; curtrack<16; curtrack++) + if (track[curtrack].on == 1 && + track[curtrack].pos < track[curtrack].tend && + track[curtrack].iwait < iwait) + iwait=track[curtrack].iwait; + } + } + + + if (iwait !=0 && ret==1) + { + for (curtrack=0; curtrack<16; curtrack++) + if (track[curtrack].on) + track[curtrack].iwait-=iwait; + + +fwait=1.0f/(((float)iwait/(float)deltas)*((float)msqtr/(float)1000000)); + } + else + fwait=50; // 1/50th of a second + + midiprintf ("\n"); + for (i=0; i<16; i++) + if (track[i].on) + if (track[i].pos < track[i].tend) + midiprintf ("<%d>",track[i].iwait); + else + midiprintf("stop"); + + /* + if (ret==0 && type==FILE_ADVSIERRA) + if (datalook(sierra_pos-2)!=0xff) + { + midiprintf ("next sectoin!"); + sierra_next_section(p); + fwait=50; + ret=1; + } + */ + + if(ret) + return true; + else + return false; +} + +float CmidPlayer::getrefresh() +{ + return (fwait > 0.01f ? fwait : 0.01f); +} + +void CmidPlayer::rewind(int subsong) +{ + long i,j,n,m,l; + long o_sierra_pos; + unsigned char ins[16]; + + pos=0; tins=0; + adlib_style=MIDI_STYLE|CMF_STYLE; + adlib_mode=ADLIB_MELODIC; + for (i=0; i<128; i++) + for (j=0; j<16; j++) + myinsbank[i][j]=midi_fm_instruments[i][j]; + for (i=0; i<16; i++) + { + ch[i].inum=0; + for (j=0; j<11; j++) + ch[i].ins[j]=myinsbank[ch[i].inum][j]; + ch[i].vol=127; + ch[i].nshift=-25; + ch[i].on=1; + } + + /* General init */ + for (i=0; i<9; i++) + { + chp[i][0]=-1; + chp[i][2]=0; + } + + deltas=250; // just a number, not a standard + msqtr=500000; + fwait=123; // gotta be a small thing.. sorta like nothing + iwait=0; + + subsongs=1; + + for (i=0; i<16; i++) + { + track[i].tend=0; + track[i].spos=0; + track[i].pos=0; + track[i].iwait=0; + track[i].on=0; + track[i].pv=0; + } + curtrack=0; + + /* specific to file-type init */ + + pos=0; + i=getnext(1); + switch(type) + { + case FILE_LUCAS: + getnext(24); //skip junk and get to the midi. + adlib_style=LUCAS_STYLE|MIDI_STYLE; + //note: no break, we go right into midi headers... + case FILE_MIDI: + if (type != FILE_LUCAS) + tins=128; + getnext(11); /*skip header*/ + deltas=getnext(2); + midiprintf ("deltas:%ld\n",deltas); + getnext(4); + + curtrack=0; + track[curtrack].on=1; + track[curtrack].tend=getnext(4); + track[curtrack].spos=pos; + midiprintf ("tracklen:%ld\n",track[curtrack].tend); + break; + case FILE_CMF: + getnext(3); // ctmf + getnexti(2); //version + n=getnexti(2); // instrument offset + m=getnexti(2); // music offset + deltas=getnexti(2); //ticks/qtr note + msqtr=1000000/getnexti(2)*deltas; + //the stuff in the cmf is click ticks per second.. + + i=getnexti(2); + if(i) title = (char *)data+i; + i=getnexti(2); + if(i) author = (char *)data+i; + i=getnexti(2); + if(i) remarks = (char *)data+i; + + getnext(16); // channel in use table .. + i=getnexti(2); // num instr + if (i>128) i=128; // to ward of bad numbers... + getnexti(2); //basic tempo + + midiprintf("\nioff:%d\nmoff%d\ndeltas:%ld\nmsqtr:%ld\nnumi:%d\n", + n,m,deltas,msqtr,i); + pos=n; // jump to instruments + tins=i; + for (j=0; j= subsongs) subsong=0; + + sierra_pos=o_sierra_pos; + sierra_next_section(); + i=0; + while (i != subsong) + { + sierra_next_section(); + i++; + } + + adlib_style=SIERRA_STYLE|MIDI_STYLE; //advanced sierra tunes use volume + break; + case FILE_SIERRA: + memcpy(myinsbank, smyinsbank, 128 * 16); + tins = stins; + getnext(2); + deltas=0x20; + + curtrack=0; + track[curtrack].on=1; + track[curtrack].tend=flen; // music until the end of the file + + for (i=0; i<16; i++) + { + ch[i].nshift=-13; + ch[i].on=getnext(1); + ch[i].inum=getnext(1); + for (j=0; j<11; j++) + ch[i].ins[j]=myinsbank[ch[i].inum][j]; + } + + track[curtrack].spos=pos; + adlib_style=SIERRA_STYLE|MIDI_STYLE; + break; + } + + +/* sprintf(info,"%s\r\nTicks/Quarter Note: %ld\r\n",info,deltas); + sprintf(info,"%sms/Quarter Note: %ld",info,msqtr); */ + + for (i=0; i<16; i++) + if (track[i].on) + { + track[i].pos=track[i].spos; + track[i].pv=0; + track[i].iwait=0; + } + + doing=1; + opl->init(); +} + +std::string CmidPlayer::gettype() +{ + switch(type) { + case FILE_LUCAS: + return std::string("LucasArts AdLib MIDI"); + case FILE_MIDI: + return std::string("General MIDI"); + case FILE_CMF: + return std::string("Creative Music Format (CMF MIDI)"); + case FILE_OLDLUCAS: + return std::string("Lucasfilm Adlib MIDI"); + case FILE_ADVSIERRA: + return std::string("Sierra On-Line VGA MIDI"); + case FILE_SIERRA: + return std::string("Sierra On-Line EGA MIDI"); + default: + return std::string("MIDI unknown"); + } +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/mid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mid.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,111 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * mid.h - LAA, SCI, MID & CMF Player by Philip Hassey + */ + +#include "player.h" + +class CmidPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CmidPlayer(Copl *newopl) + : CPlayer(newopl), author(&emptystr), title(&emptystr), + remarks(&emptystr), emptystr('\0'), flen(0), data(0) + { }; + ~CmidPlayer() + { if(data) delete [] data; }; + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype(); + std::string gettitle() + { return std::string(title); }; + std::string getauthor() + { return std::string(author); }; + std::string getdesc() + { return std::string(remarks); }; + unsigned int getinstruments() + { return tins; }; + unsigned int getsubsongs() + { return subsongs; }; + +protected: + struct midi_channel { + int inum; + unsigned char ins[11]; + int vol; + int nshift; + int on; + }; + + struct midi_track { + unsigned long tend; + unsigned long spos; + unsigned long pos; + unsigned long iwait; + int on; + unsigned char pv; + }; + + char *author,*title,*remarks,emptystr; + long flen; + unsigned long pos; + unsigned long sierra_pos; //sierras gotta be special.. :> + int subsongs; + unsigned char *data; + + unsigned char adlib_data[256]; + int adlib_style; + int adlib_mode; + unsigned char myinsbank[128][16], smyinsbank[128][16]; + midi_channel ch[16]; + int chp[9][3]; + + long deltas; + long msqtr; + + midi_track track[16]; + unsigned int curtrack; + + float fwait; + unsigned long iwait; + int doing; + + int type,tins,stins; + +private: + bool load_sierra_ins(const std::string &fname, const CFileProvider &fp); + void midiprintf(char *format, ...); + unsigned char datalook(long pos); + unsigned long getnexti(unsigned long num); + unsigned long getnext(unsigned long num); + unsigned long getval(); + void sierra_next_section(); + void midi_write_adlib(unsigned int r, unsigned char v); + void midi_fm_instrument(int voice, unsigned char *inst); + void midi_fm_volume(int voice, int volume); + void midi_fm_playnote(int voice, int note, int volume); + void midi_fm_endnote(int voice); + void midi_fm_reset(); +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/mididata.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mididata.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,174 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999, 2000, 2001 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * FM instrument definitions below borrowed from the Allegro library by + * Phil Hassey, - see "adplug/players/mid.cpp" + * for further acknowledgements. + */ + +unsigned char midi_fm_instruments[128][14] = +{ + + /* This set of GM instrument patches was provided by Jorrit Rouwe... + */ + + { 0x21, 0x21, 0x8f, 0x0c, 0xf2, 0xf2, 0x45, 0x76, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Acoustic Grand */ + { 0x31, 0x21, 0x4b, 0x09, 0xf2, 0xf2, 0x54, 0x56, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Bright Acoustic */ + { 0x31, 0x21, 0x49, 0x09, 0xf2, 0xf2, 0x55, 0x76, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Electric Grand */ + { 0xb1, 0x61, 0x0e, 0x09, 0xf2, 0xf3, 0x3b, 0x0b, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Honky-Tonk */ + { 0x01, 0x21, 0x57, 0x09, 0xf1, 0xf1, 0x38, 0x28, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Piano 1 */ + { 0x01, 0x21, 0x93, 0x09, 0xf1, 0xf1, 0x38, 0x28, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Piano 2 */ + { 0x21, 0x36, 0x80, 0x17, 0xa2, 0xf1, 0x01, 0xd5, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Harpsichord */ + { 0x01, 0x01, 0x92, 0x09, 0xc2, 0xc2, 0xa8, 0x58, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Clav */ + { 0x0c, 0x81, 0x5c, 0x09, 0xf6, 0xf3, 0x54, 0xb5, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Celesta */ + { 0x07, 0x11, 0x97, 0x89, 0xf6, 0xf5, 0x32, 0x11, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Glockenspiel */ + { 0x17, 0x01, 0x21, 0x09, 0x56, 0xf6, 0x04, 0x04, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Music Box */ + { 0x18, 0x81, 0x62, 0x09, 0xf3, 0xf2, 0xe6, 0xf6, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Vibraphone */ + { 0x18, 0x21, 0x23, 0x09, 0xf7, 0xe5, 0x55, 0xd8, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Marimba */ + { 0x15, 0x01, 0x91, 0x09, 0xf6, 0xf6, 0xa6, 0xe6, 0x00, 0x00, 0x04, 0, 0, 0 }, /* Xylophone */ + { 0x45, 0x81, 0x59, 0x89, 0xd3, 0xa3, 0x82, 0xe3, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Tubular Bells */ + { 0x03, 0x81, 0x49, 0x89, 0x74, 0xb3, 0x55, 0x05, 0x01, 0x00, 0x04, 0, 0, 0 }, /* Dulcimer */ + { 0x71, 0x31, 0x92, 0x09, 0xf6, 0xf1, 0x14, 0x07, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Drawbar Organ */ + { 0x72, 0x30, 0x14, 0x09, 0xc7, 0xc7, 0x58, 0x08, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Percussive Organ */ + { 0x70, 0xb1, 0x44, 0x09, 0xaa, 0x8a, 0x18, 0x08, 0x00, 0x00, 0x04, 0, 0, 0 }, /* Rock Organ */ + { 0x23, 0xb1, 0x93, 0x09, 0x97, 0x55, 0x23, 0x14, 0x01, 0x00, 0x04, 0, 0, 0 }, /* Church Organ */ + { 0x61, 0xb1, 0x13, 0x89, 0x97, 0x55, 0x04, 0x04, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Reed Organ */ + { 0x24, 0xb1, 0x48, 0x09, 0x98, 0x46, 0x2a, 0x1a, 0x01, 0x00, 0x0c, 0, 0, 0 }, /* Accoridan */ + { 0x61, 0x21, 0x13, 0x09, 0x91, 0x61, 0x06, 0x07, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Harmonica */ + { 0x21, 0xa1, 0x13, 0x92, 0x71, 0x61, 0x06, 0x07, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Tango Accordian */ + { 0x02, 0x41, 0x9c, 0x89, 0xf3, 0xf3, 0x94, 0xc8, 0x01, 0x00, 0x0c, 0, 0, 0 }, /* Acoustic Guitar(nylon) */ + { 0x03, 0x11, 0x54, 0x09, 0xf3, 0xf1, 0x9a, 0xe7, 0x01, 0x00, 0x0c, 0, 0, 0 }, /* Acoustic Guitar(steel) */ + { 0x23, 0x21, 0x5f, 0x09, 0xf1, 0xf2, 0x3a, 0xf8, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Guitar(jazz) */ + { 0x03, 0x21, 0x87, 0x89, 0xf6, 0xf3, 0x22, 0xf8, 0x01, 0x00, 0x06, 0, 0, 0 }, /* Electric Guitar(clean) */ + { 0x03, 0x21, 0x47, 0x09, 0xf9, 0xf6, 0x54, 0x3a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Guitar(muted) */ + { 0x23, 0x21, 0x4a, 0x0e, 0x91, 0x84, 0x41, 0x19, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Overdriven Guitar */ + { 0x23, 0x21, 0x4a, 0x09, 0x95, 0x94, 0x19, 0x19, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Distortion Guitar */ + { 0x09, 0x84, 0xa1, 0x89, 0x20, 0xd1, 0x4f, 0xf8, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Guitar Harmonics */ + { 0x21, 0xa2, 0x1e, 0x09, 0x94, 0xc3, 0x06, 0xa6, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Acoustic Bass */ + { 0x31, 0x31, 0x12, 0x09, 0xf1, 0xf1, 0x28, 0x18, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Electric Bass(finger) */ + { 0x31, 0x31, 0x8d, 0x09, 0xf1, 0xf1, 0xe8, 0x78, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Electric Bass(pick) */ + { 0x31, 0x32, 0x5b, 0x09, 0x51, 0x71, 0x28, 0x48, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Fretless Bass */ + { 0x01, 0x21, 0x8b, 0x49, 0xa1, 0xf2, 0x9a, 0xdf, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Slap Bass 1 */ + { 0x21, 0x21, 0x8b, 0x11, 0xa2, 0xa1, 0x16, 0xdf, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Slap Bass 2 */ + { 0x31, 0x31, 0x8b, 0x09, 0xf4, 0xf1, 0xe8, 0x78, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Synth Bass 1 */ + { 0x31, 0x31, 0x12, 0x09, 0xf1, 0xf1, 0x28, 0x18, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Synth Bass 2 */ + { 0x31, 0x21, 0x15, 0x09, 0xdd, 0x56, 0x13, 0x26, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Violin */ + { 0x31, 0x21, 0x16, 0x09, 0xdd, 0x66, 0x13, 0x06, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Viola */ + { 0x71, 0x31, 0x49, 0x09, 0xd1, 0x61, 0x1c, 0x0c, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Cello */ + { 0x21, 0x23, 0x4d, 0x89, 0x71, 0x72, 0x12, 0x06, 0x01, 0x00, 0x02, 0, 0, 0 }, /* Contrabass */ + { 0xf1, 0xe1, 0x40, 0x09, 0xf1, 0x6f, 0x21, 0x16, 0x01, 0x00, 0x02, 0, 0, 0 }, /* Tremolo Strings */ + { 0x02, 0x01, 0x1a, 0x89, 0xf5, 0x85, 0x75, 0x35, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Pizzicato Strings */ + { 0x02, 0x01, 0x1d, 0x89, 0xf5, 0xf3, 0x75, 0xf4, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Orchestral Strings */ + { 0x10, 0x11, 0x41, 0x09, 0xf5, 0xf2, 0x05, 0xc3, 0x01, 0x00, 0x02, 0, 0, 0 }, /* Timpani */ + { 0x21, 0xa2, 0x9b, 0x0a, 0xb1, 0x72, 0x25, 0x08, 0x01, 0x00, 0x0e, 0, 0, 0 }, /* String Ensemble 1 */ + { 0xa1, 0x21, 0x98, 0x09, 0x7f, 0x3f, 0x03, 0x07, 0x01, 0x01, 0x00, 0, 0, 0 }, /* String Ensemble 2 */ + { 0xa1, 0x61, 0x93, 0x09, 0xc1, 0x4f, 0x12, 0x05, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* SynthStrings 1 */ + { 0x21, 0x61, 0x18, 0x09, 0xc1, 0x4f, 0x22, 0x05, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* SynthStrings 2 */ + { 0x31, 0x72, 0x5b, 0x8c, 0xf4, 0x8a, 0x15, 0x05, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Choir Aahs */ + { 0xa1, 0x61, 0x90, 0x09, 0x74, 0x71, 0x39, 0x67, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Voice Oohs */ + { 0x71, 0x72, 0x57, 0x09, 0x54, 0x7a, 0x05, 0x05, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Synth Voice */ + { 0x90, 0x41, 0x00, 0x09, 0x54, 0xa5, 0x63, 0x45, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Orchestra Hit */ + { 0x21, 0x21, 0x92, 0x0a, 0x85, 0x8f, 0x17, 0x09, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Trumpet */ + { 0x21, 0x21, 0x94, 0x0e, 0x75, 0x8f, 0x17, 0x09, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Trombone */ + { 0x21, 0x61, 0x94, 0x09, 0x76, 0x82, 0x15, 0x37, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Tuba */ + { 0x31, 0x21, 0x43, 0x09, 0x9e, 0x62, 0x17, 0x2c, 0x01, 0x01, 0x02, 0, 0, 0 }, /* Muted Trumpet */ + { 0x21, 0x21, 0x9b, 0x09, 0x61, 0x7f, 0x6a, 0x0a, 0x00, 0x00, 0x02, 0, 0, 0 }, /* French Horn */ + { 0x61, 0x22, 0x8a, 0x0f, 0x75, 0x74, 0x1f, 0x0f, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Brass Section */ + { 0xa1, 0x21, 0x86, 0x8c, 0x72, 0x71, 0x55, 0x18, 0x01, 0x00, 0x00, 0, 0, 0 }, /* SynthBrass 1 */ + { 0x21, 0x21, 0x4d, 0x09, 0x54, 0xa6, 0x3c, 0x1c, 0x00, 0x00, 0x08, 0, 0, 0 }, /* SynthBrass 2 */ + { 0x31, 0x61, 0x8f, 0x09, 0x93, 0x72, 0x02, 0x0b, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Soprano Sax */ + { 0x31, 0x61, 0x8e, 0x09, 0x93, 0x72, 0x03, 0x09, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Alto Sax */ + { 0x31, 0x61, 0x91, 0x09, 0x93, 0x82, 0x03, 0x09, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Tenor Sax */ + { 0x31, 0x61, 0x8e, 0x09, 0x93, 0x72, 0x0f, 0x0f, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Baritone Sax */ + { 0x21, 0x21, 0x4b, 0x09, 0xaa, 0x8f, 0x16, 0x0a, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Oboe */ + { 0x31, 0x21, 0x90, 0x09, 0x7e, 0x8b, 0x17, 0x0c, 0x01, 0x01, 0x06, 0, 0, 0 }, /* English Horn */ + { 0x31, 0x32, 0x81, 0x09, 0x75, 0x61, 0x19, 0x19, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Bassoon */ + { 0x32, 0x21, 0x90, 0x09, 0x9b, 0x72, 0x21, 0x17, 0x00, 0x00, 0x04, 0, 0, 0 }, /* Clarinet */ + { 0xe1, 0xe1, 0x1f, 0x09, 0x85, 0x65, 0x5f, 0x1a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Piccolo */ + { 0xe1, 0xe1, 0x46, 0x09, 0x88, 0x65, 0x5f, 0x1a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Flute */ + { 0xa1, 0x21, 0x9c, 0x09, 0x75, 0x75, 0x1f, 0x0a, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Recorder */ + { 0x31, 0x21, 0x8b, 0x09, 0x84, 0x65, 0x58, 0x1a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Pan Flute */ + { 0xe1, 0xa1, 0x4c, 0x09, 0x66, 0x65, 0x56, 0x26, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Blown Bottle */ + { 0x62, 0xa1, 0xcb, 0x09, 0x76, 0x55, 0x46, 0x36, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Skakuhachi */ + { 0x62, 0xa1, 0xa2, 0x09, 0x57, 0x56, 0x07, 0x07, 0x00, 0x00, 0x0b, 0, 0, 0 }, /* Whistle */ + { 0x62, 0xa1, 0x9c, 0x09, 0x77, 0x76, 0x07, 0x07, 0x00, 0x00, 0x0b, 0, 0, 0 }, /* Ocarina */ + { 0x22, 0x21, 0x59, 0x09, 0xff, 0xff, 0x03, 0x0f, 0x02, 0x00, 0x00, 0, 0, 0 }, /* Lead 1 (square) */ + { 0x21, 0x21, 0x0e, 0x09, 0xff, 0xff, 0x0f, 0x0f, 0x01, 0x01, 0x00, 0, 0, 0 }, /* Lead 2 (sawtooth) */ + { 0x22, 0x21, 0x46, 0x89, 0x86, 0x64, 0x55, 0x18, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Lead 3 (calliope) */ + { 0x21, 0xa1, 0x45, 0x09, 0x66, 0x96, 0x12, 0x0a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Lead 4 (chiff) */ + { 0x21, 0x22, 0x8b, 0x09, 0x92, 0x91, 0x2a, 0x2a, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Lead 5 (charang) */ + { 0xa2, 0x61, 0x9e, 0x49, 0xdf, 0x6f, 0x05, 0x07, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Lead 6 (voice) */ + { 0x20, 0x60, 0x1a, 0x09, 0xef, 0x8f, 0x01, 0x06, 0x00, 0x02, 0x00, 0, 0, 0 }, /* Lead 7 (fifths) */ + { 0x21, 0x21, 0x8f, 0x86, 0xf1, 0xf4, 0x29, 0x09, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Lead 8 (bass+lead) */ + { 0x77, 0xa1, 0xa5, 0x09, 0x53, 0xa0, 0x94, 0x05, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Pad 1 (new age) */ + { 0x61, 0xb1, 0x1f, 0x89, 0xa8, 0x25, 0x11, 0x03, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Pad 2 (warm) */ + { 0x61, 0x61, 0x17, 0x09, 0x91, 0x55, 0x34, 0x16, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Pad 3 (polysynth) */ + { 0x71, 0x72, 0x5d, 0x09, 0x54, 0x6a, 0x01, 0x03, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Pad 4 (choir) */ + { 0x21, 0xa2, 0x97, 0x09, 0x21, 0x42, 0x43, 0x35, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Pad 5 (bowed) */ + { 0xa1, 0x21, 0x1c, 0x09, 0xa1, 0x31, 0x77, 0x47, 0x01, 0x01, 0x00, 0, 0, 0 }, /* Pad 6 (metallic) */ + { 0x21, 0x61, 0x89, 0x0c, 0x11, 0x42, 0x33, 0x25, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Pad 7 (halo) */ + { 0xa1, 0x21, 0x15, 0x09, 0x11, 0xcf, 0x47, 0x07, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Pad 8 (sweep) */ + { 0x3a, 0x51, 0xce, 0x09, 0xf8, 0x86, 0xf6, 0x02, 0x00, 0x00, 0x02, 0, 0, 0 }, /* FX 1 (rain) */ + { 0x21, 0x21, 0x15, 0x09, 0x21, 0x41, 0x23, 0x13, 0x01, 0x00, 0x00, 0, 0, 0 }, /* FX 2 (soundtrack) */ + { 0x06, 0x01, 0x5b, 0x09, 0x74, 0xa5, 0x95, 0x72, 0x00, 0x00, 0x00, 0, 0, 0 }, /* FX 3 (crystal) */ + { 0x22, 0x61, 0x92, 0x8c, 0xb1, 0xf2, 0x81, 0x26, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* FX 4 (atmosphere) */ + { 0x41, 0x42, 0x4d, 0x09, 0xf1, 0xf2, 0x51, 0xf5, 0x01, 0x00, 0x00, 0, 0, 0 }, /* FX 5 (brightness) */ + { 0x61, 0xa3, 0x94, 0x89, 0x11, 0x11, 0x51, 0x13, 0x01, 0x00, 0x06, 0, 0, 0 }, /* FX 6 (goblins) */ + { 0x61, 0xa1, 0x8c, 0x89, 0x11, 0x1d, 0x31, 0x03, 0x00, 0x00, 0x06, 0, 0, 0 }, /* FX 7 (echoes) */ + { 0xa4, 0x61, 0x4c, 0x09, 0xf3, 0x81, 0x73, 0x23, 0x01, 0x00, 0x04, 0, 0, 0 }, /* FX 8 (sci-fi) */ + { 0x02, 0x07, 0x85, 0x0c, 0xd2, 0xf2, 0x53, 0xf6, 0x00, 0x01, 0x00, 0, 0, 0 }, /* Sitar */ + { 0x11, 0x13, 0x0c, 0x89, 0xa3, 0xa2, 0x11, 0xe5, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Banjo */ + { 0x11, 0x11, 0x06, 0x09, 0xf6, 0xf2, 0x41, 0xe6, 0x01, 0x02, 0x04, 0, 0, 0 }, /* Shamisen */ + { 0x93, 0x91, 0x91, 0x09, 0xd4, 0xeb, 0x32, 0x11, 0x00, 0x01, 0x08, 0, 0, 0 }, /* Koto */ + { 0x04, 0x01, 0x4f, 0x09, 0xfa, 0xc2, 0x56, 0x05, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Kalimba */ + { 0x21, 0x22, 0x49, 0x09, 0x7c, 0x6f, 0x20, 0x0c, 0x00, 0x01, 0x06, 0, 0, 0 }, /* Bagpipe */ + { 0x31, 0x21, 0x85, 0x09, 0xdd, 0x56, 0x33, 0x16, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Fiddle */ + { 0x20, 0x21, 0x04, 0x8a, 0xda, 0x8f, 0x05, 0x0b, 0x02, 0x00, 0x06, 0, 0, 0 }, /* Shanai */ + { 0x05, 0x03, 0x6a, 0x89, 0xf1, 0xc3, 0xe5, 0xe5, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Tinkle Bell */ + { 0x07, 0x02, 0x15, 0x09, 0xec, 0xf8, 0x26, 0x16, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Agogo */ + { 0x05, 0x01, 0x9d, 0x09, 0x67, 0xdf, 0x35, 0x05, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Steel Drums */ + { 0x18, 0x12, 0x96, 0x09, 0xfa, 0xf8, 0x28, 0xe5, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Woodblock */ + { 0x10, 0x00, 0x86, 0x0c, 0xa8, 0xfa, 0x07, 0x03, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Taiko Drum */ + { 0x11, 0x10, 0x41, 0x0c, 0xf8, 0xf3, 0x47, 0x03, 0x02, 0x00, 0x04, 0, 0, 0 }, /* Melodic Tom */ + { 0x01, 0x10, 0x8e, 0x09, 0xf1, 0xf3, 0x06, 0x02, 0x02, 0x00, 0x0e, 0, 0, 0 }, /* Synth Drum */ + { 0x0e, 0xc0, 0x00, 0x09, 0x1f, 0x1f, 0x00, 0xff, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Reverse Cymbal */ + { 0x06, 0x03, 0x80, 0x91, 0xf8, 0x56, 0x24, 0x84, 0x00, 0x02, 0x0e, 0, 0, 0 }, /* Guitar Fret Noise */ + { 0x0e, 0xd0, 0x00, 0x0e, 0xf8, 0x34, 0x00, 0x04, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Breath Noise */ + { 0x0e, 0xc0, 0x00, 0x09, 0xf6, 0x1f, 0x00, 0x02, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Seashore */ + { 0xd5, 0xda, 0x95, 0x49, 0x37, 0x56, 0xa3, 0x37, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Bird Tweet */ + { 0x35, 0x14, 0x5c, 0x11, 0xb2, 0xf4, 0x61, 0x15, 0x02, 0x00, 0x0a, 0, 0, 0 }, /* Telephone ring */ + { 0x0e, 0xd0, 0x00, 0x09, 0xf6, 0x4f, 0x00, 0xf5, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Helicopter */ + { 0x26, 0xe4, 0x00, 0x09, 0xff, 0x12, 0x01, 0x16, 0x00, 0x01, 0x0e, 0, 0, 0 }, /* Applause */ + { 0x00, 0x00, 0x00, 0x09, 0xf3, 0xf6, 0xf0, 0xc9, 0x00, 0x02, 0x0e, 0, 0, 0 } /* Gunshot */ + +}; + +/* logarithmic relationship between midi and FM volumes */ +static int my_midi_fm_vol_table[128] = { + 0, 11, 16, 19, 22, 25, 27, 29, 32, 33, 35, 37, 39, 40, 42, 43, + 45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 64, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77, + 78, 79, 80, 80, 81, 82, 83, 83, 84, 85, 86, 86, 87, 88, 89, 89, + 90, 91, 91, 92, 93, 93, 94, 95, 96, 96, 97, 97, 98, 99, 99, 100, + 101, 101, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108, + 109, 109, 110, 110, 111, 112, 112, 113, 113, 114, 114, 115, 115, + 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, + 123, 123, 124, 124, 125, 125, 126, 126, 127 +}; + diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/mkj.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mkj.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,163 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * mkj.cpp - MKJamz Player, by Simon Peter + */ + +#include + +#include "mkj.h" +#include "debug.h" + +CPlayer *CmkjPlayer::factory(Copl *newopl) +{ + return new CmkjPlayer(newopl); +} + +bool CmkjPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[6]; + float ver; + int i, j; + short inst[8]; + + // file validation + f->readString(id, 6); + if(strncmp(id,"MKJamz",6)) { fp.close(f); return false; } + ver = f->readFloat(binio::Single); + if(ver > 1.12) { fp.close(f); return false; } + + // load + maxchannel = f->readInt(2); + opl->init(); opl->write(1, 32); + for(i = 0; i < maxchannel; i++) { + for(j = 0; j < 8; j++) inst[j] = f->readInt(2); + opl->write(0x20+op_table[i],inst[4]); + opl->write(0x23+op_table[i],inst[0]); + opl->write(0x40+op_table[i],inst[5]); + opl->write(0x43+op_table[i],inst[1]); + opl->write(0x60+op_table[i],inst[6]); + opl->write(0x63+op_table[i],inst[2]); + opl->write(0x80+op_table[i],inst[7]); + opl->write(0x83+op_table[i],inst[3]); + } + maxnotes = f->readInt(2); + songbuf = new short [(maxchannel+1)*maxnotes]; + for(i = 0; i < maxchannel; i++) channel[i].defined = f->readInt(2); + for(i = 0; i < (maxchannel + 1) * maxnotes; i++) + songbuf[i] = f->readInt(2); + + AdPlug_LogWrite("CmkjPlayer::load(\"%s\"): loaded file ver %.2f, %d channels," + " %d notes/channel.\n", filename.c_str(), ver, maxchannel, + maxnotes); + fp.close(f); + rewind(0); + return true; +} + +bool CmkjPlayer::update() +{ + int c, i; + short note; + + for(c = 0; c < maxchannel; c++) { + if(!channel[c].defined) // skip if channel is disabled + continue; + + if(channel[c].pstat) { + channel[c].pstat--; + continue; + } + + opl->write(0xb0 + c, 0); // key off + do { + assert(channel[c].songptr < (maxchannel + 1) * maxnotes); + note = songbuf[channel[c].songptr]; + if(channel[c].songptr - c > maxchannel) + if(note && note < 250) + channel[c].pstat = channel[c].speed; + switch(note) { + // normal notes + case 68: opl->write(0xa0 + c,0x81); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 69: opl->write(0xa0 + c,0xb0); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 70: opl->write(0xa0 + c,0xca); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 71: opl->write(0xa0 + c,0x2); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 65: opl->write(0xa0 + c,0x41); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 66: opl->write(0xa0 + c,0x87); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 67: opl->write(0xa0 + c,0xae); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 17: opl->write(0xa0 + c,0x6b); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 18: opl->write(0xa0 + c,0x98); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 20: opl->write(0xa0 + c,0xe5); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 21: opl->write(0xa0 + c,0x20); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 15: opl->write(0xa0 + c,0x63); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 255: // delay + channel[c].songptr += maxchannel; + channel[c].pstat = songbuf[channel[c].songptr]; + break; + case 254: // set octave + channel[c].songptr += maxchannel; + channel[c].octave = songbuf[channel[c].songptr]; + break; + case 253: // set speed + channel[c].songptr += maxchannel; + channel[c].speed = songbuf[channel[c].songptr]; + break; + case 252: // set waveform + channel[c].songptr += maxchannel; + channel[c].waveform = songbuf[channel[c].songptr] - 300; + if(c > 2) + opl->write(0xe0 + c + (c+6),channel[c].waveform); + else + opl->write(0xe0 + c,channel[c].waveform); + break; + case 251: // song end + for(i = 0; i < maxchannel; i++) channel[i].songptr = i; + songend = true; + return false; + } + + if(channel[c].songptr - c < maxnotes) + channel[c].songptr += maxchannel; + else + channel[c].songptr = c; + } while(!channel[c].pstat); + } + + return !songend; +} + +void CmkjPlayer::rewind(int subsong) +{ + int i; + + for(i = 0; i < maxchannel; i++) { + channel[i].pstat = 0; + channel[i].speed = 0; + channel[i].waveform = 0; + channel[i].songptr = i; + channel[i].octave = 4; + } + + songend = false; +} + +float CmkjPlayer::getrefresh() +{ + return 100.0f; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/mkj.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mkj.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,50 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * mkj.h - MKJamz Player, by Simon Peter + */ + +#include "player.h" + +class CmkjPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CmkjPlayer(Copl *newopl) + : CPlayer(newopl), songbuf(0) + { } + ~CmkjPlayer() + { if(songbuf) delete [] songbuf; } + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype() + { return std::string("MKJamz Audio File"); } + +private: + short maxchannel,maxnotes,*songbuf; + bool songend; + + struct { + short defined,songptr,octave,waveform,pstat,speed,delay; + } channel[9]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/mtk.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mtk.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,109 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * mtk.cpp - MPU-401 Trakker Loader by Simon Peter (dn.tlp@gmx.net) + */ + +#include "mtk.h" + +/*** public methods **************************************/ + +CPlayer *CmtkLoader::factory(Copl *newopl) +{ + return new CmtkLoader(newopl); +} + +bool CmtkLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + struct { + char id[18]; + unsigned short crc,size; + } header; + struct mtkdata { + char songname[34],composername[34],instname[0x80][34]; + unsigned char insts[0x80][12],order[0x80],dummy,patterns[0x32][0x40][9]; + } *data; + unsigned char *cmp,*org; + unsigned int i; + unsigned long cmpsize,cmpptr=0,orgptr=0; + unsigned short ctrlbits=0,ctrlmask=0,cmd,cnt,offs; + + // read header + f->readString(header.id, 18); + header.crc = f->readInt(2); + header.size = f->readInt(2); + + // file validation section + if(strncmp(header.id,"mpu401tr\x92kk\xeer@data",18)) + { fp.close(f); return false; } + + // load section + cmpsize = fp.filesize(f) - 22; + cmp = new unsigned char[cmpsize]; + org = new unsigned char[header.size]; + for(i = 0; i < cmpsize; i++) cmp[i] = f->readInt(1); + fp.close(f); + + while(cmpptr < cmpsize) { // decompress + ctrlmask >>= 1; + if(!ctrlmask) { + ctrlbits = cmp[cmpptr] + (cmp[cmpptr + 1] << 8); + cmpptr += 2; + ctrlmask = 0x8000; + } + if(!(ctrlbits & ctrlmask)) { // uncompressed data + org[orgptr] = cmp[cmpptr]; + orgptr++; cmpptr++; + continue; + } + + // compressed data + cmd = (cmp[cmpptr] >> 4) & 0x0f; + cnt = cmp[cmpptr] & 0x0f; + cmpptr++; + switch(cmd) { + case 0: cnt += 3; memset(&org[orgptr],cmp[cmpptr],cnt); cmpptr++; orgptr += cnt; break; + case 1: cnt += (cmp[cmpptr] << 4) + 19; memset(&org[orgptr],cmp[++cmpptr],cnt); cmpptr++; orgptr += cnt; break; + case 2: offs = (cnt+3) + (cmp[cmpptr] << 4); cnt = cmp[++cmpptr] + 16; cmpptr++; + memcpy(&org[orgptr],&org[orgptr - offs],cnt); orgptr += cnt; break; + default: offs = (cnt+3) + (cmp[cmpptr++] << 4); memcpy(&org[orgptr],&org[orgptr-offs],cmd); orgptr += cmd; break; + } + } + delete [] cmp; + data = (struct mtkdata *) org; + + // convert to HSC replay data + memset(title,0,34); strncpy(title,data->songname+1,33); + memset(composer,0,34); strncpy(composer,data->composername+1,33); + memset(instname,0,0x80*34); + for(i=0;i<0x80;i++) + strncpy(instname[i],data->instname[i]+1,33); + memcpy(instr,data->insts,0x80 * 12); + memcpy(song,data->order,0x80); + memcpy(patterns,data->patterns,header.size-6084); + for (i=0;i<128;i++) { // correct instruments + instr[i][2] ^= (instr[i][2] & 0x40) << 1; + instr[i][3] ^= (instr[i][3] & 0x40) << 1; + instr[i][11] >>= 4; // make unsigned + } + + delete [] org; + rewind(0); + return true; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/mtk.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mtk.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,50 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * mtk.h - MPU-401 Trakker Loader by Simon Peter + */ + +#include "hsc.h" + +class CmtkLoader: public ChscPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CmtkLoader(Copl *newopl) + : ChscPlayer(newopl) + { + mtkmode = 1; + }; + + bool load(const std::string &filename, const CFileProvider &fp); + + std::string gettype() + { return std::string("MPU-401 Trakker"); }; + std::string gettitle() + { return std::string(title); }; + std::string getauthor() + { return std::string(composer); }; + unsigned int getinstruments() + { return 128; }; + std::string getinstrument(unsigned int n) + { return std::string(instname[n]); }; + +private: + char title[34],composer[34],instname[0x80][34]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/opl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/opl.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,34 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * opl.h - OPL base class declaration, by Simon Peter + */ + +#ifndef H_ADPLUG_OPL +#define H_ADPLUG_OPL + +class Copl +{ +public: + virtual void write(int reg, int val) = 0; // combined register select + data write + virtual void init(void) = 0; // reinitialize OPL chip + + virtual void update(short *buf, int samples) {}; // Emulation only: fill buffer +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/player.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/player.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,70 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * player.cpp - Replayer base class, by Simon Peter + */ + +#include "player.h" +#include "adplug.h" +#include "silentopl.h" + +/***** CPlayer *****/ + +const unsigned short CPlayer::note_table[12] = + {363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647, 686}; + +const unsigned char CPlayer::op_table[9] = + {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12}; + +CPlayer::CPlayer(Copl *newopl) + : opl(newopl), db(CAdPlug::database) +{ +} + +CPlayer::~CPlayer() +{ +} + +unsigned long CPlayer::songlength(int subsong) +{ + CSilentopl tempopl; + Copl *saveopl = opl; + float slength = 0.0f; + + // save original OPL from being overwritten + opl = &tempopl; + + // get song length + rewind(subsong); + while(update() && slength < 600000) // song length limit: 10 minutes + slength += 1000.0f / getrefresh(); + rewind(subsong); + + // restore original OPL and return + opl = saveopl; + return (unsigned long)slength; +} + +void CPlayer::seek(unsigned long ms) +{ + float pos = 0.0f; + + rewind(); + while(pos < ms && update()) // seek to new position + pos += 1000/getrefresh(); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/player.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/player.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,83 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * player.h - Replayer base class, by Simon Peter + */ + +#ifndef H_ADPLUG_PLAYER +#define H_ADPLUG_PLAYER + +#include + +#include "fprovide.h" +#include "opl.h" +#include "database.h" + +class CPlayer +{ +public: + CPlayer(Copl *newopl); + virtual ~CPlayer(); + +/***** Operational methods *****/ + void seek(unsigned long ms); + + virtual bool load(const std::string &filename, // loads file + const CFileProvider &fp = CProvider_Filesystem()) = 0; + virtual bool update() = 0; // executes replay code for 1 tick + virtual void rewind(int subsong = -1) = 0; // rewinds to specified subsong + virtual float getrefresh() = 0; // returns needed timer refresh rate + +/***** Informational methods *****/ + unsigned long songlength(int subsong = -1); + + virtual std::string gettype() = 0; // returns file type + virtual std::string gettitle() // returns song title + { return std::string(); } + virtual std::string getauthor() // returns song author name + { return std::string(); } + virtual std::string getdesc() // returns song description + { return std::string(); } + virtual unsigned int getpatterns() // returns number of patterns + { return 0; } + virtual unsigned int getpattern() // returns currently playing pattern + { return 0; } + virtual unsigned int getorders() // returns size of orderlist + { return 0; } + virtual unsigned int getorder() // returns currently playing song position + { return 0; } + virtual unsigned int getrow() // returns currently playing row + { return 0; } + virtual unsigned int getspeed() // returns current song speed + { return 0; } + virtual unsigned int getsubsongs() // returns number of subsongs + { return 1; } + virtual unsigned int getinstruments() // returns number of instruments + { return 0; } + virtual std::string getinstrument(unsigned int n) // returns n-th instrument name + { return std::string(); } + +protected: + Copl *opl; // our OPL chip + CAdPlugDatabase *db; // AdPlug Database + + static const unsigned short note_table[12]; // standard adlib note table + static const unsigned char op_table[9]; // the 9 operators as expected by the OPL2 +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/players.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/players.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,105 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * players.h - Players enumeration, by Simon Peter + */ + +#include +#include + +#include "players.h" + +/***** CPlayerDesc *****/ + +CPlayerDesc::CPlayerDesc() + : factory(0), extensions(0), extlength(0) +{ +} + +CPlayerDesc::CPlayerDesc(const CPlayerDesc &pd) + : factory(pd.factory), filetype(pd.filetype), extlength(pd.extlength) +{ + if(pd.extensions) { + extensions = (char *)malloc(extlength); + memcpy(extensions, pd.extensions, extlength); + } else + extensions = 0; +} + +CPlayerDesc::CPlayerDesc(Factory f, const std::string &type, const char *ext) + : factory(f), filetype(type), extensions(0) +{ + const char *i = ext; + + // Determine length of passed extensions list + while(*i) i += strlen(i) + 1; + extlength = i - ext + 1; // length = difference between last and first char + 1 + + extensions = (char *)malloc(extlength); + memcpy(extensions, ext, extlength); +} + +CPlayerDesc::~CPlayerDesc() +{ + if(extensions) free(extensions); +} + +void CPlayerDesc::add_extension(const char *ext) +{ + unsigned long newlength = extlength + strlen(ext) + 1; + + extensions = (char *)realloc(extensions, newlength); + strcpy(extensions + extlength - 1, ext); + extensions[newlength - 1] = '\0'; + extlength = newlength; +} + +const char *CPlayerDesc::get_extension(unsigned int n) const +{ + const char *i = extensions; + unsigned int j; + + for(j = 0; j < n && (*i); j++, i += strlen(i) + 1) ; + return (*i != '\0' ? i : 0); +} + +/***** CPlayers *****/ + +const CPlayerDesc *CPlayers::lookup_filetype(const std::string &ftype) const +{ + const_iterator i; + + for(i = begin(); i != end(); i++) + if((*i)->filetype == ftype) + return *i; + + return 0; +} + +const CPlayerDesc *CPlayers::lookup_extension(const std::string &extension) const +{ + const_iterator i; + unsigned int j; + + for(i = begin(); i != end(); i++) + for(j = 0; (*i)->get_extension(j); j++) + if(!stricmp(extension.c_str(), (*i)->get_extension(j))) + return *i; + + return 0; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/players.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/players.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,60 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * players.h - Players enumeration, by Simon Peter + */ + +#ifndef H_ADPLUG_PLAYERS +#define H_ADPLUG_PLAYERS + +#include +#include + +#include "opl.h" +#include "player.h" + +class CPlayerDesc +{ +public: + typedef CPlayer *(*Factory)(Copl *); + + Factory factory; + std::string filetype; + + CPlayerDesc(); + CPlayerDesc(const CPlayerDesc &pd); + CPlayerDesc(Factory f, const std::string &type, const char *ext); + + ~CPlayerDesc(); + + void add_extension(const char *ext); + const char *get_extension(unsigned int n) const; + +private: + char *extensions; + unsigned long extlength; +}; + +class CPlayers: public std::list +{ +public: + const CPlayerDesc *lookup_filetype(const std::string &ftype) const; + const CPlayerDesc *lookup_extension(const std::string &extension) const; +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/protrack.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/protrack.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,722 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * protrack.cpp - Generic Protracker Player + * Copyright (C) 2000 - 2002 Simon Peter + * + * NOTES: + * This is a generic Protracker-based formats player. It offers all Protracker + * features, plus a good set of extensions to be compatible to other Protracker + * derivatives. It is derived from the original SA2 player by me. If you got a + * Protracker-like format, this is most certainly the player you want to use. + * + * USAGE: + * Read the file 'Protracker.txt' in the 'doc' subdirectory. + */ + +#include "protrack.h" +#include "debug.h" + +#define SPECIALARPLEN 256 // Standard length of special arpeggio lists +#define JUMPMARKER 0x80 // Orderlist jump marker + +// SA2 compatible adlib note table +const unsigned short CmodPlayer::sa2_notetable[12] = +{340,363,385,408,432,458,485,514,544,577,611,647}; + +// SA2 compatible vibrato rate table +const unsigned char CmodPlayer::vibratotab[32] = +{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}; + +/*** public methods *************************************/ + +CmodPlayer::CmodPlayer(Copl *newopl) + : CPlayer(newopl), inst(0), order(0), arplist(0), arpcmd(0), initspeed(6), + activechan(0xffff), flags(Standard), nop(0), nrows(0), npats(0), nchans(0) +{ + realloc_order(128); + realloc_patterns(64, 64, 9); + realloc_instruments(250); + init_notetable(sa2_notetable); +} + +CmodPlayer::~CmodPlayer() +{ + dealloc(); +} + +bool CmodPlayer::update() +{ + unsigned char pattbreak=0,donote; // remember vars + unsigned char pattnr,chan,info1,info2,info; // cache vars + unsigned short track; + unsigned long row; + + if(!speed) // song full stop + return !songend; + + // effect handling (timer dependant) + for(chan=0;chan 63) // ????? + channel[chan].vol1 = 63; + channel[chan].vol2 = channel[chan].vol1; + setvolume(chan); + break; + case 253: channel[chan].key = 0; setfreq(chan); break; // release sustaining note + case 254: channel[chan].arppos = arplist[channel[chan].arppos]; break; // arpeggio loop + default: if(arpcmd[channel[chan].arppos]) { + if(arpcmd[channel[chan].arppos] / 10) + opl->write(0xe3 + op_table[chan], arpcmd[channel[chan].arppos] / 10 - 1); + if(arpcmd[channel[chan].arppos] % 10) + opl->write(0xe0 + op_table[chan], (arpcmd[channel[chan].arppos] % 10) - 1); + if(arpcmd[channel[chan].arppos] < 10) // ????? + opl->write(0xe0 + op_table[chan], arpcmd[channel[chan].arppos] - 1); + } + } + if(arpcmd[channel[chan].arppos] != 252) { + if(arplist[channel[chan].arppos] <= 96) + setnote(chan,channel[chan].note + arplist[channel[chan].arppos]); + if(arplist[channel[chan].arppos] >= 100) + setnote(chan,arplist[channel[chan].arppos] - 100); + } else + setnote(chan,channel[chan].note); + setfreq(chan); + if(arpcmd[channel[chan].arppos] != 255) + channel[chan].arppos++; + channel[chan].arpspdcnt = inst[channel[chan].inst].arpspeed - 1; + } + + info1 = channel[chan].info1; + info2 = channel[chan].info2; + if(flags & Decimal) + info = channel[chan].info1 * 10 + channel[chan].info2; + else + info = (channel[chan].info1 << 4) + channel[chan].info2; + switch(channel[chan].fx) { + case 0: if(info) { // arpeggio + if(channel[chan].trigger < 2) + channel[chan].trigger++; + else + channel[chan].trigger = 0; + switch(channel[chan].trigger) { + case 0: setnote(chan,channel[chan].note); break; + case 1: setnote(chan,channel[chan].note + info1); break; + case 2: setnote(chan,channel[chan].note + info2); + } + setfreq(chan); + } + break; + case 1: slide_up(chan,info); setfreq(chan); break; // slide up + case 2: slide_down(chan,info); setfreq(chan); break; // slide down + case 3: tone_portamento(chan,channel[chan].portainfo); break; // tone portamento + case 4: vibrato(chan,channel[chan].vibinfo1,channel[chan].vibinfo2); break; // vibrato + case 5: // tone portamento & volume slide + case 6: if(channel[chan].fx == 5) // vibrato & volume slide + tone_portamento(chan,channel[chan].portainfo); + else + vibrato(chan,channel[chan].vibinfo1,channel[chan].vibinfo2); + case 10: if(del % 4) // SA2 volume slide + break; + if(info1) + vol_up(chan,info1); + else + vol_down(chan,info2); + setvolume(chan); + break; + case 14: if(info1 == 3) // retrig note + if(!(del % (info2+1))) + playnote(chan); + break; + case 16: if(del % 4) // AMD volume slide + break; + if(info1) + vol_up_alt(chan,info1); + else + vol_down_alt(chan,info2); + setvolume(chan); + break; + case 20: // RAD volume slide + if(info < 50) + vol_down_alt(chan,info); + else + vol_up_alt(chan,info - 50); + setvolume(chan); + break; + case 26: // volume slide + if(info1) + vol_up(chan,info1); + else + vol_down(chan,info2); + setvolume(chan); + break; + case 28: + if (info1) { + slide_up(chan,1); channel[chan].info1--; + } + if (info2) { + slide_down(chan,1); channel[chan].info2--; + } + setfreq(chan); + break; + } + } + + if(del) { // speed compensation + del--; + return !songend; + } + + // arrangement handling + if(ord >= length) { + songend = 1; // set end-flag + ord = restartpos; + } + pattnr = order[ord]; + + if(!rw) AdPlug_LogWrite("\nCmodPlayer::update(): Pattern: %d, Order: %d\n", pattnr, ord); + AdPlug_LogWrite("CmodPlayer::update():%3d|", rw); + + // play row + row = rw; + for(chan=0;chan> (15 - chan)) & 1) { // channel active? + AdPlug_LogWrite("N/A|"); + continue; + } + if(!(track = trackord[pattnr][chan])) { // resolve track + AdPlug_LogWrite("------------|"); + continue; + } else + track--; + + AdPlug_LogWrite("%3d%3d%2X%2X%2X|", tracks[track][row].note, + tracks[track][row].inst, tracks[track][row].command, + tracks[track][row].param1, tracks[track][row].param2); + + donote = 0; + if(tracks[track][row].inst) { + channel[chan].inst = tracks[track][row].inst - 1; + if (!(flags & Faust)) { + channel[chan].vol1 = 63 - (inst[channel[chan].inst].data[10] & 63); + channel[chan].vol2 = 63 - (inst[channel[chan].inst].data[9] & 63); + setvolume(chan); + } + } + + if(tracks[track][row].note && tracks[track][row].command != 3) { // no tone portamento + channel[chan].note = tracks[track][row].note; + setnote(chan,tracks[track][row].note); + channel[chan].nextfreq = channel[chan].freq; + channel[chan].nextoct = channel[chan].oct; + channel[chan].arppos = inst[channel[chan].inst].arpstart; + channel[chan].arpspdcnt = 0; + if(tracks[track][row].note != 127) // handle key off + donote = 1; + } + channel[chan].fx = tracks[track][row].command; + channel[chan].info1 = tracks[track][row].param1; + channel[chan].info2 = tracks[track][row].param2; + + if(donote) + playnote(chan); + + // command handling (row dependant) + info1 = channel[chan].info1; + info2 = channel[chan].info2; + if(flags & Decimal) + info = channel[chan].info1 * 10 + channel[chan].info2; + else + info = (channel[chan].info1 << 4) + channel[chan].info2; + switch(channel[chan].fx) { + case 3: if(tracks[track][row].note) { // tone portamento + if(tracks[track][row].note < 13) + channel[chan].nextfreq = notetable[tracks[track][row].note - 1]; + else + if(tracks[track][row].note % 12 > 0) + channel[chan].nextfreq = notetable[(tracks[track][row].note % 12) - 1]; + else + channel[chan].nextfreq = notetable[11]; + channel[chan].nextoct = (tracks[track][row].note - 1) / 12; + if(tracks[track][row].note == 127) { // handle key off + channel[chan].nextfreq = channel[chan].freq; + channel[chan].nextoct = channel[chan].oct; + } + } + if(info) // remember vars + channel[chan].portainfo = info; + break; + case 4: if(info) { // vibrato (remember vars) + channel[chan].vibinfo1 = info1; + channel[chan].vibinfo2 = info2; + } + break; + case 7: tempo = info; break; // set tempo + case 8: channel[chan].key = 0; setfreq(chan); break; // release sustaining note + case 9: // set carrier/modulator volume + if(info1) + channel[chan].vol1 = info1 * 7; + else + channel[chan].vol2 = info2 * 7; + setvolume(chan); + break; + case 11: pattbreak = 1; rw = 0; if(info < ord) songend = 1; ord = info; break; // position jump + case 12: // set volume + channel[chan].vol1 = info; + channel[chan].vol2 = info; + if(channel[chan].vol1 > 63) + channel[chan].vol1 = 63; + if(channel[chan].vol2 > 63) + channel[chan].vol2 = 63; + setvolume(chan); + break; + case 13: if(!pattbreak) { pattbreak = 1; rw = info; ord++; } break; // pattern break + case 14: // extended command + switch(info1) { + case 0: if(info2) // define cell-tremolo + regbd |= 128; + else + regbd &= 127; + opl->write(0xbd,regbd); + break; + case 1: if(info2) // define cell-vibrato + regbd |= 64; + else + regbd &= 191; + opl->write(0xbd,regbd); + break; + case 4: vol_up_alt(chan,info2); // increase volume fine + setvolume(chan); + break; + case 5: vol_down_alt(chan,info2); // decrease volume fine + setvolume(chan); + break; + case 6: slide_up(chan,info2); // manual slide up + setfreq(chan); + break; + case 7: slide_down(chan,info2); // manual slide down + setfreq(chan); + break; + } + break; + case 15: // SA2 set speed + if(info <= 0x1f) + speed = info; + if(info >= 0x32) + tempo = info; + if(!info) + songend = 1; + break; + case 17: // alternate set volume + channel[chan].vol1 = info; + if(channel[chan].vol1 > 63) + channel[chan].vol1 = 63; + if(inst[channel[chan].inst].data[0] & 1) { + channel[chan].vol2 = info; + if(channel[chan].vol2 > 63) + channel[chan].vol2 = 63; + } + setvolume(chan); + break; + case 18: // AMD set speed + if(info <= 31 && info > 0) + speed = info; + if(info > 31 || !info) + tempo = info; + break; + case 19: // RAD/A2M set speed + speed = (info ? info : info + 1); + break; + case 21: // set modulator volume + if(info <= 63) + channel[chan].vol2 = info; + else + channel[chan].vol2 = 63; + setvolume(chan); + break; + case 22: // set carrier volume + if(info <= 63) + channel[chan].vol1 = info; + else + channel[chan].vol1 = 63; + setvolume(chan); + break; + case 23: // fine frequency slide up + slide_up(chan,info); + setfreq(chan); + break; + case 24: // fine frequency slide down + slide_down(chan,info); + setfreq(chan); + break; + case 25: // set carrier/modulator waveform + if(info1 != 0x0f) + opl->write(0xe3 + op_table[chan],info1); + if(info2 != 0x0f) + opl->write(0xe0 + op_table[chan],info2); + break; + case 27: // set chip tremolo/vibrato + if (info1) + regbd |= 128; + else + regbd &= 127; + if (info2) + regbd |= 64; + else + regbd &= 191; + opl->write(0xbd,regbd); + break; + } + } + + del = speed - 1; // speed compensation + if(!pattbreak) { // next row (only if no manual advance) + rw++; + if(rw >= nrows) { + rw = 0; + ord++; + } + } + if(ord < length) { + if(order[ord] >= JUMPMARKER) { // jump to order + ord = order[ord] - JUMPMARKER; + songend = 1; + } + } else + songend = 1; + + AdPlug_LogWrite("\n"); + return !songend; +} + +void CmodPlayer::rewind(int subsong) +{ + unsigned long i; + + // Reset playing variables + songend = del = ord = rw = regbd = 0; + tempo = bpm; speed = initspeed; + + // Reset channel data + memset(channel,0,sizeof(Channel)*nchans); + + // Compute number of patterns, if needed + if(!nop) + for(i=0;i nop ? order[i] : nop); + + opl->init(); // Reset OPL chip + opl->write(1,32); // Go to ym3812 mode +} + +float CmodPlayer::getrefresh() +{ + return (float) (tempo / 2.5); +} + +void CmodPlayer::init_trackord() +{ + unsigned long i; + + for(i=0;iwrite(0x40 + op_table[chan], 63-channel[chan].vol2 + (inst[channel[chan].inst].data[9] & 192)); + opl->write(0x43 + op_table[chan], 63-channel[chan].vol1 + (inst[channel[chan].inst].data[10] & 192)); + } +} + +void CmodPlayer::setvolume_alt(unsigned char chan) +{ + unsigned char ivol2 = inst[channel[chan].inst].data[9] & 63; + unsigned char ivol1 = inst[channel[chan].inst].data[10] & 63; + + opl->write(0x40 + op_table[chan], (((63 - channel[chan].vol2 & 63) + ivol2) >> 1) + (inst[channel[chan].inst].data[9] & 192)); + opl->write(0x43 + op_table[chan], (((63 - channel[chan].vol1 & 63) + ivol1) >> 1) + (inst[channel[chan].inst].data[10] & 192)); +} + +void CmodPlayer::setfreq(unsigned char chan) +{ + opl->write(0xa0 + chan, channel[chan].freq & 255); + if(channel[chan].key) + opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2) | 32); + else + opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2)); +} + +void CmodPlayer::playnote(unsigned char chan) +{ + unsigned char op = op_table[chan], insnr = channel[chan].inst; + + if(!(flags & NoKeyOn)) + opl->write(0xb0 + chan, 0); // stop old note + + // set instrument data + opl->write(0x20 + op, inst[insnr].data[1]); + opl->write(0x23 + op, inst[insnr].data[2]); + opl->write(0x60 + op, inst[insnr].data[3]); + opl->write(0x63 + op, inst[insnr].data[4]); + opl->write(0x80 + op, inst[insnr].data[5]); + opl->write(0x83 + op, inst[insnr].data[6]); + opl->write(0xe0 + op, inst[insnr].data[7]); + opl->write(0xe3 + op, inst[insnr].data[8]); + opl->write(0xc0 + chan, inst[insnr].data[0]); + opl->write(0xbd, inst[insnr].misc); // set misc. register + + // set frequency, volume & play + channel[chan].key = 1; + setfreq(chan); + + if (flags & Faust) { + channel[chan].vol2 = 63; + channel[chan].vol1 = 63; + } + setvolume(chan); +} + +void CmodPlayer::setnote(unsigned char chan, int note) +{ + if(note > 96) + if(note == 127) { // key off + channel[chan].key = 0; + setfreq(chan); + return; + } else + note = 96; + + if(note < 13) + channel[chan].freq = notetable[note - 1]; + else + if(note % 12 > 0) + channel[chan].freq = notetable[(note % 12) - 1]; + else + channel[chan].freq = notetable[11]; + channel[chan].oct = (note - 1) / 12; + channel[chan].freq += inst[channel[chan].inst].slide; // apply pre-slide +} + +void CmodPlayer::slide_down(unsigned char chan, int amount) +{ + channel[chan].freq -= amount; + if(channel[chan].freq <= 342) + if(channel[chan].oct) { + channel[chan].oct--; + channel[chan].freq <<= 1; + } else + channel[chan].freq = 342; +} + +void CmodPlayer::slide_up(unsigned char chan, int amount) +{ + channel[chan].freq += amount; + if(channel[chan].freq >= 686) + if(channel[chan].oct < 7) { + channel[chan].oct++; + channel[chan].freq >>= 1; + } else + channel[chan].freq = 686; +} + +void CmodPlayer::tone_portamento(unsigned char chan, unsigned char info) +{ + if(channel[chan].freq + (channel[chan].oct << 10) < channel[chan].nextfreq + + (channel[chan].nextoct << 10)) { + slide_up(chan,info); + if(channel[chan].freq + (channel[chan].oct << 10) > channel[chan].nextfreq + + (channel[chan].nextoct << 10)) { + channel[chan].freq = channel[chan].nextfreq; + channel[chan].oct = channel[chan].nextoct; + } + } + if(channel[chan].freq + (channel[chan].oct << 10) > channel[chan].nextfreq + + (channel[chan].nextoct << 10)) { + slide_down(chan,info); + if(channel[chan].freq + (channel[chan].oct << 10) < channel[chan].nextfreq + + (channel[chan].nextoct << 10)) { + channel[chan].freq = channel[chan].nextfreq; + channel[chan].oct = channel[chan].nextoct; + } + } + setfreq(chan); +} + +void CmodPlayer::vibrato(unsigned char chan, unsigned char speed, unsigned char depth) +{ + int i; + + if(!speed || !depth) + return; + + if(depth > 14) + depth = 14; + + for(i=0;i= 64) + channel[chan].trigger -= 64; + if(channel[chan].trigger >= 16 && channel[chan].trigger < 48) + slide_down(chan,vibratotab[channel[chan].trigger - 16] / (16-depth)); + if(channel[chan].trigger < 16) + slide_up(chan,vibratotab[channel[chan].trigger + 16] / (16-depth)); + if(channel[chan].trigger >= 48) + slide_up(chan,vibratotab[channel[chan].trigger - 48] / (16-depth)); + } + setfreq(chan); +} + +void CmodPlayer::vol_up(unsigned char chan, int amount) +{ + if(channel[chan].vol1 + amount < 63) + channel[chan].vol1 += amount; + else + channel[chan].vol1 = 63; + + if(channel[chan].vol2 + amount < 63) + channel[chan].vol2 += amount; + else + channel[chan].vol2 = 63; +} + +void CmodPlayer::vol_down(unsigned char chan, int amount) +{ + if(channel[chan].vol1 - amount > 0) + channel[chan].vol1 -= amount; + else + channel[chan].vol1 = 0; + + if(channel[chan].vol2 - amount > 0) + channel[chan].vol2 -= amount; + else + channel[chan].vol2 = 0; +} + +void CmodPlayer::vol_up_alt(unsigned char chan, int amount) +{ + if(channel[chan].vol1 + amount < 63) + channel[chan].vol1 += amount; + else + channel[chan].vol1 = 63; + if(inst[channel[chan].inst].data[0] & 1) + if(channel[chan].vol2 + amount < 63) + channel[chan].vol2 += amount; + else + channel[chan].vol2 = 63; +} + +void CmodPlayer::vol_down_alt(unsigned char chan, int amount) +{ + if(channel[chan].vol1 - amount > 0) + channel[chan].vol1 -= amount; + else + channel[chan].vol1 = 0; + if(inst[channel[chan].inst].data[0] & 1) + if(channel[chan].vol2 - amount > 0) + channel[chan].vol2 -= amount; + else + channel[chan].vol2 = 0; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/protrack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/protrack.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,107 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * protrack.h - Generic Protracker Player by Simon Peter + */ + +#ifndef H_PROTRACK +#define H_PROTRACK + +#include "player.h" + +class CmodPlayer: public CPlayer +{ +public: + CmodPlayer(Copl *newopl); + virtual ~CmodPlayer(); + + bool update(); + void rewind(int subsong); + float getrefresh(); + + unsigned int getpatterns() + { return nop; }; + unsigned int getpattern() + { return order[ord]; }; + unsigned int getorders() + { return length; }; + unsigned int getorder() + { return ord; }; + unsigned int getrow() + { return rw; }; + unsigned int getspeed() + { return speed; }; + +protected: + enum Flags {Standard = 0, Decimal = 1, Faust = 2, NoKeyOn = 4}; + + struct Instrument { + unsigned char data[11],arpstart,arpspeed,arppos,arpspdcnt,misc; + signed char slide; + } *inst; + + struct Tracks { + unsigned char note,command,inst,param2,param1; + } **tracks; + + unsigned char *order, *arplist, *arpcmd, initspeed; + unsigned short tempo, activechan, **trackord, bpm, flags, nop; + unsigned long length, restartpos; + + struct Channel { + unsigned short freq,nextfreq; + unsigned char oct,vol1,vol2,inst,fx,info1,info2,key,nextoct, + note,portainfo,vibinfo1,vibinfo2,arppos,arpspdcnt; + signed char trigger; + } *channel; + + void init_trackord(); + bool init_specialarp(); + void init_notetable(const unsigned short *newnotetable); + bool realloc_order(unsigned long len); + bool realloc_patterns(unsigned long pats, unsigned long rows, unsigned long chans); + bool realloc_instruments(unsigned long len); + + void dealloc(); + +private: + static const unsigned short sa2_notetable[12]; + static const unsigned char vibratotab[32]; + + unsigned char speed, del, songend, regbd; + unsigned short rows, notetable[12]; + unsigned long rw, ord, nrows, npats, nchans; + + void setvolume(unsigned char chan); + void setvolume_alt(unsigned char chan); + void setfreq(unsigned char chan); + void playnote(unsigned char chan); + void setnote(unsigned char chan, int note); + void slide_down(unsigned char chan, int amount); + void slide_up(unsigned char chan, int amount); + void tone_portamento(unsigned char chan, unsigned char info); + void vibrato(unsigned char chan, unsigned char speed, unsigned char depth); + void vol_up(unsigned char chan, int amount); + void vol_down(unsigned char chan, int amount); + void vol_up_alt(unsigned char chan, int amount); + void vol_down_alt(unsigned char chan, int amount); + + void dealloc_patterns(); +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/psi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/psi.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,169 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] PSI player, by Riven the Mage + */ + +/* + - discovery - + + file(s) : 4BIDDEN.COM, PGRID.EXE + type : Forbidden Dreams BBStro + Power Grid BBStro + tune : by Friar Tuck [Shadow Faction/ICE] + player : by Psi [Future Crew] + comment : seems to me what 4bidden tune & player was ripped from pgrid + + file(s) : MYSTRUNE.COM + type : Mystical Runes BBStro + tune : by ? + player : by Psi [Future Crew] +*/ + +#include "psi.h" +#include "debug.h" + +const unsigned char CxadpsiPlayer::psi_adlib_registers[99] = +{ + 0x20, 0x23, 0x40, 0x43, 0x60, 0x63, 0x80, 0x83, 0xE0, 0xE3, 0xC0, + 0x21, 0x24, 0x41, 0x44, 0x61, 0x64, 0x81, 0x84, 0xE1, 0xE4, 0xC1, + 0x22, 0x25, 0x42, 0x45, 0x62, 0x65, 0x82, 0x85, 0xE2, 0xE5, 0xC2, + 0x28, 0x2B, 0x48, 0x4B, 0x68, 0x6B, 0x88, 0x8B, 0xE8, 0xEB, 0xC3, + 0x29, 0x2C, 0x49, 0x4C, 0x69, 0x6C, 0x89, 0x8C, 0xE9, 0xEC, 0xC4, + 0x2A, 0x2D, 0x4A, 0x4D, 0x6A, 0x6D, 0x8A, 0x8D, 0xEA, 0xED, 0xC5, + 0x30, 0x33, 0x50, 0x53, 0x70, 0x73, 0x90, 0x93, 0xF0, 0xF3, 0xC6, + 0x31, 0x34, 0x51, 0x54, 0x71, 0x74, 0x91, 0x94, 0xF1, 0xF4, 0xC7, + 0x32, 0x35, 0x52, 0x55, 0x72, 0x75, 0x92, 0x95, 0xF2, 0xF5, 0xC8 +}; + +const unsigned short CxadpsiPlayer::psi_notes[16] = +{ + 0x216B, 0x2181, 0x2198, 0x21B0, 0x21CA, 0x21E5, 0x2202, 0x2220, + 0x2241, 0x2263, 0x2287, 0x2364, + 0x0000, 0x0000, 0x0000, 0x0000 // by riven +}; + +CPlayer *CxadpsiPlayer::factory(Copl *newopl) +{ + return new CxadpsiPlayer(newopl); +} + +void CxadpsiPlayer::xadplayer_rewind(int subsong) +{ + opl_write(0x01, 0x20); + opl_write(0x08, 0x00); + opl_write(0xBD, 0x00); + + // define instruments + psi.instr_table = (unsigned short *)&tune[((psi_header *)&tune[0])->instr_ptr]; + + for(int i=0; i<8; i++) + { + for(int j=0; j<11; j++) + opl_write(psi_adlib_registers[i*11 + j],tune[psi.instr_table[i] + j]); + + opl_write(0xA0+i, 0x00); + opl_write(0xB0+i, 0x00); + + psi.note_delay[i] = 1; + psi.note_curdelay[i] = 1; + psi.looping[i] = 0; + } + + // calculate sequence pointer + psi.seq_table = (unsigned short *)&tune[((psi_header *)&tune[0])->seq_ptr]; +} + +void CxadpsiPlayer::xadplayer_update() +{ + unsigned short ptr; + + for(int i=0; i<8; i++) + { + ptr = psi.seq_table[i<<1]; + + psi.note_curdelay[i]--; + + if (!psi.note_curdelay[i]) + { + opl_write(0xA0+i, 0x00); + opl_write(0xB0+i, 0x00); + + unsigned char event = tune[ptr++]; +#ifdef DEBUG + AdPlug_LogWrite("channel %02X, event %02X:\n",i+1,event); +#endif + + // end of sequence ? + if (!event) + { + ptr = psi.seq_table[(i<<1) + 1]; + + event = tune[ptr++]; +#ifdef DEBUG + AdPlug_LogWrite(" channel %02X, event %02X:\n",i+1,event); +#endif + + // set sequence loop flag + psi.looping[i] = 1; + + // module loop ? + plr.looping = 1; + for(int j=0; j<8; j++) + plr.looping &= psi.looping[j]; + } + + // new note delay ? + if (event & 0x80) + { + psi.note_delay[i] = (event & 0x7F); + + event = tune[ptr++]; +#ifdef DEBUG + AdPlug_LogWrite(" channel %02X, event %02X:\n",i+1,event); +#endif + } + + psi.note_curdelay[i] = psi.note_delay[i]; + + // play note + unsigned short note = psi_notes[event & 0x0F]; + + opl_write(0xA0+i, note & 0xFF); + opl_write(0xB0+i, (note >> 8) + ((event >> 2) & 0xFC)); + + // save position + psi.seq_table[i<<1] = ptr; + } + } +} + +float CxadpsiPlayer::xadplayer_getrefresh() +{ + return 70.0f; +} + +std::string CxadpsiPlayer::xadplayer_gettype() +{ + return std::string("xad: psi player"); +} + +unsigned int CxadpsiPlayer::xadplayer_getinstruments() +{ + return 8; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/psi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/psi.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,64 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] PSI player, by Riven the Mage + */ + +#include "xad.h" + +class CxadpsiPlayer: public CxadPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CxadpsiPlayer(Copl *newopl): CxadPlayer(newopl) + { } + +protected: + struct psi_header + { + unsigned short instr_ptr; + unsigned short seq_ptr; + }; + + struct + { + unsigned short *instr_table; + unsigned short *seq_table; + unsigned char note_delay[9]; + unsigned char note_curdelay[9]; + unsigned char looping[9]; + } psi; + // + bool xadplayer_load() + { + if(xad.fmt == PSI) + return true; + else + return false; + } + void xadplayer_rewind(int subsong); + void xadplayer_update(); + float xadplayer_getrefresh(); + std::string xadplayer_gettype(); + unsigned int xadplayer_getinstruments(); + +private: + static const unsigned char psi_adlib_registers[99]; + static const unsigned short psi_notes[16]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/rad.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/rad.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,124 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * rad.cpp - RAD Loader by Simon Peter + * + * BUGS: + * some volumes are dropped out + */ + +#include "rad.h" + +CPlayer *CradLoader::factory(Copl *newopl) +{ + return new CradLoader(newopl); +} + +bool CradLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[16]; + unsigned char buf,ch,c,b,inp; + char bufstr[2] = "\0"; + unsigned int i,j; + unsigned short patofs[32]; + const unsigned char convfx[16] = {255,1,2,3,255,5,255,255,255,255,20,255,17,0xd,255,19}; + + // file validation section + f->readString(id, 16); version = f->readInt(1); + if(strncmp(id,"RAD by REALiTY!!",16) || version != 0x10) + { fp.close(f); return false; } + + // load section + radflags = f->readInt(1); + if(radflags & 128) { // description + memset(desc,0,80*22); + while((buf = f->readInt(1))) + if(buf == 1) + strcat(desc,"\n"); + else + if(buf >= 2 && buf <= 0x1f) + for(i=0;ireadInt(1))) { // instruments + buf--; + inst[buf].data[2] = f->readInt(1); inst[buf].data[1] = f->readInt(1); + inst[buf].data[10] = f->readInt(1); inst[buf].data[9] = f->readInt(1); + inst[buf].data[4] = f->readInt(1); inst[buf].data[3] = f->readInt(1); + inst[buf].data[6] = f->readInt(1); inst[buf].data[5] = f->readInt(1); + inst[buf].data[0] = f->readInt(1); + inst[buf].data[8] = f->readInt(1); inst[buf].data[7] = f->readInt(1); + } + length = f->readInt(1); + for(i = 0; i < length; i++) order[i] = f->readInt(1); // orderlist + for(i = 0; i < 32; i++) patofs[i] = f->readInt(2); // pattern offset table + init_trackord(); // patterns + for(i=0;i<32;i++) + if(patofs[i]) { + f->seek(patofs[i]); + do { + buf = f->readInt(1); b = buf & 127; + do { + ch = f->readInt(1); c = ch & 127; + inp = f->readInt(1); + tracks[i*9+c][b].note = inp & 127; + tracks[i*9+c][b].inst = (inp & 128) >> 3; + inp = f->readInt(1); + tracks[i*9+c][b].inst += inp >> 4; + tracks[i*9+c][b].command = inp & 15; + if(inp & 15) { + inp = f->readInt(1); + tracks[i*9+c][b].param1 = inp / 10; + tracks[i*9+c][b].param2 = inp % 10; + } + } while(!(ch & 128)); + } while(!(buf & 128)); + } else + memset(trackord[i],0,9*2); + fp.close(f); + + // convert replay data + for(i=0;i<32*9;i++) // convert patterns + for(j=0;j<64;j++) { + if(tracks[i][j].note == 15) + tracks[i][j].note = 127; + if(tracks[i][j].note > 16 && tracks[i][j].note < 127) + tracks[i][j].note -= 4 * (tracks[i][j].note >> 4); + if(tracks[i][j].note && tracks[i][j].note < 126) + tracks[i][j].note++; + tracks[i][j].command = convfx[tracks[i][j].command]; + } + restartpos = 0; activechan = 0xffff; initspeed = radflags & 31; + bpm = radflags & 64 ? 0 : 50; flags = Decimal; + + rewind(0); + return true; +} + +float CradLoader::getrefresh() +{ + if(tempo) + return (float) (tempo); + else + return 18.2f; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/rad.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/rad.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,44 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * rad.h - RAD Loader by Simon Peter + */ + +#include "protrack.h" + +class CradLoader: public CmodPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CradLoader(Copl *newopl) + : CmodPlayer(newopl) + { *desc = '\0'; }; + + bool load(const std::string &filename, const CFileProvider &fp); + float getrefresh(); + + std::string gettype() + { return std::string("Reality ADlib Tracker"); }; + std::string getdesc() + { return std::string(desc); }; + +private: + unsigned char version,radflags; + char desc[80*22]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/rat.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/rat.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,290 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] RAT player, by Riven the Mage + */ + +/* + - discovery - + + file(s) : PINA.EXE + type : Experimental Connection BBStro tune + tune : by (?)Ratt/GRIF + player : by (?)Ratt/GRIF + comment : there are bug in original replayer's adlib_init(): wrong frequency registers. +*/ + +#include "rat.h" +#include "debug.h" + +const unsigned char CxadratPlayer::rat_adlib_bases[18] = +{ + 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12, + 0x03, 0x04, 0x05, 0x0B, 0x0C, 0x0D, 0x13, 0x14, 0x15 +}; + +const unsigned short CxadratPlayer::rat_notes[16] = +{ + 0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, + 0x000, 0x000, 0x000, 0x000 // by riven +}; + +CPlayer *CxadratPlayer::factory(Copl *newopl) +{ + return new CxadratPlayer(newopl); +} + +bool CxadratPlayer::xadplayer_load() +{ + if(xad.fmt != RAT) + return false; + + // load header + memcpy(&rat.hdr, &tune[0], sizeof(rat_header)); + + // is 'RAT'-signed ? + if (strncmp(rat.hdr.id,"RAT",3)) + return false; + + // is version 1.0 ? + if (rat.hdr.version != 0x10) + return false; + + // load order + rat.order = &tune[0x40]; + + // load instruments + rat.inst = (rat_instrument *)&tune[0x140]; + + // load pattern data + unsigned char *event_ptr = &tune[rat.hdr.patseg << 4]; + + for(int i=0;i> 8) | ((event.note & 0xF0) >> 2) | 0x20); + } + } + + // is effect ? + if (event.fx != 0xFF) + { + rat.channel[i].fx = event.fx; + rat.channel[i].fxp = event.fxp; + } + } + + // next row + rat.pattern_pos++; + + // process effects + for(i=0;i= 0x40) + { + rat.pattern_pos = 0; + + rat.order_pos++; + + // end of module ? + if (rat.order_pos == rat.hdr.order_end) + { + rat.order_pos = rat.hdr.order_loop; + + plr.looping = 1; + } + } +} + +float CxadratPlayer::xadplayer_getrefresh() +{ + return 60.0f; +} + +std::string CxadratPlayer::xadplayer_gettype() +{ + return (std::string("xad: rat player")); +} + +std::string CxadratPlayer::xadplayer_gettitle() +{ + return (std::string(rat.hdr.title,32)); +} + +unsigned int CxadratPlayer::xadplayer_getinstruments() +{ + return rat.hdr.numinst; +} + +/* -------- Internal Functions ---------------------------- */ + +unsigned char CxadratPlayer::__rat_calc_volume(unsigned char ivol, unsigned char cvol, unsigned char gvol) +{ +#ifdef DEBUG + AdPlug_LogWrite("volumes: instrument %02X, channel %02X, global %02X:\n", ivol, cvol, gvol); +#endif + unsigned short vol; + + vol = ivol; + vol &= 0x3F; + vol ^= 0x3F; + vol *= cvol; + vol >>= 6; + vol *= gvol; + vol >>= 6; + vol ^= 0x3F; + + vol |= ivol & 0xC0; + + return vol; +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/rat.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/rat.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,121 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * [xad] RAT player, by Riven the Mage + */ + +#include "xad.h" + +class CxadratPlayer: public CxadPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CxadratPlayer(Copl *newopl): CxadPlayer(newopl) + { } + +protected: + struct rat_header + { + char id[3]; + unsigned char version; + char title[32]; + unsigned char numchan; + unsigned char reserved_25; + unsigned char order_end; + unsigned char reserved_27; + unsigned char numinst; // ?: Number of Instruments + unsigned char reserved_29; + unsigned char numpat; // ?: Number of Patterns + unsigned char reserved_2B; + unsigned char order_start; + unsigned char reserved_2D; + unsigned char order_loop; + unsigned char reserved_2F; + unsigned char volume; + unsigned char speed; + unsigned char reserved_32[12]; + unsigned short patseg; + }; + + struct rat_event + { + unsigned char note; + unsigned char instrument; + unsigned char volume; + unsigned char fx; + unsigned char fxp; + }; + + struct rat_instrument + { + unsigned short freq; + unsigned char reserved_2[2]; + unsigned char mod_ctrl; + unsigned char car_ctrl; + unsigned char mod_volume; + unsigned char car_volume; + unsigned char mod_AD; + unsigned char car_AD; + unsigned char mod_SR; + unsigned char car_SR; + unsigned char mod_wave; + unsigned char car_wave; + unsigned char connect; + unsigned char reserved_F; + unsigned char volume; + unsigned char reserved_11[3]; + }; + + struct + { + rat_header hdr; + + unsigned char volume; + unsigned char order_pos; + unsigned char pattern_pos; + + unsigned char *order; + + rat_instrument *inst; + + rat_event tracks[256][64][9]; + + struct + { + unsigned char instrument; + unsigned char volume; + unsigned char fx; + unsigned char fxp; + } channel[9]; + } rat; + // + bool xadplayer_load(); + void xadplayer_rewind(int subsong); + void xadplayer_update(); + float xadplayer_getrefresh(); + std::string xadplayer_gettype(); + std::string xadplayer_gettitle(); + unsigned int xadplayer_getinstruments(); + // +private: + static const unsigned char rat_adlib_bases[18]; + static const unsigned short rat_notes[16]; + + unsigned char __rat_calc_volume(unsigned char ivol, unsigned char cvol, unsigned char gvol); +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/raw.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/raw.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,107 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * raw.c - RAW Player by Simon Peter + * + * NOTES: + * OPL3 register writes are ignored (not possible with AdLib). + */ + +#include "raw.h" + +/*** public methods *************************************/ + +CPlayer *CrawPlayer::factory(Copl *newopl) +{ + return new CrawPlayer(newopl); +} + +bool CrawPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[8]; + unsigned long i; + + // file validation section + f->readString(id, 8); + if(strncmp(id,"RAWADATA",8)) { fp.close (f); return false; } + + // load section + clock = f->readInt(2); // clock speed + length = (fp.filesize(f) - 10) / 2; + data = new Tdata [length]; + for(i = 0; i < length; i++) { + data[i].param = f->readInt(1); + data[i].command = f->readInt(1); + } + + fp.close(f); + rewind(0); + return true; +} + +bool CrawPlayer::update() +{ + bool setspeed; + + if(pos >= length) return false; + + if(del) { + del--; + return !songend; + } + + do { + setspeed = false; + switch(data[pos].command) { + case 0: del = data[pos].param - 1; break; + case 2: + if(!data[pos].param) { + pos++; + speed = data[pos].param + (data[pos].command << 8); + setspeed = true; + } else + opl3 = data[pos].param - 1; + break; + case 0xff: + if(data[pos].param == 0xff) { + rewind(0); // auto-rewind song + songend = true; + return !songend; + } + break; + default: + if(!opl3) + opl->write(data[pos].command,data[pos].param); + break; + } + } while(data[pos++].command || setspeed); + + return !songend; +} + +void CrawPlayer::rewind(int subsong) +{ + pos = del = opl3 = 0; speed = clock; songend = false; + opl->init(); opl->write(1,32); // go to OPL2 mode +} + +float CrawPlayer::getrefresh() +{ + return 1193180.0 / (speed ? speed : 0xffff); // timer oscillator speed / wait register = clock frequency +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/raw.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/raw.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,52 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * raw.h - RAW Player by Simon Peter + */ + +#include "player.h" + +class CrawPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CrawPlayer(Copl *newopl) + : CPlayer(newopl), data(0) + { }; + ~CrawPlayer() + { if(data) delete [] data; }; + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype() + { return std::string("RdosPlay RAW"); }; + +protected: + struct Tdata { + unsigned char param,command; + } *data; + + unsigned long pos,length; + unsigned short clock,speed; + unsigned char del,opl3; + bool songend; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/realopl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/realopl.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,158 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999, 2000, 2001 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * realopl.cpp - Real hardware OPL, by Simon Peter (dn.tlp@gmx.net) + */ + +#include +#include "realopl.h" + +#ifdef _MSC_VER + #define INP _inp + #define OUTP _outp +#elif defined(__WATCOMC__) + #define INP inp + #define OUTP outp +#endif + +/* + * chris: TODO: This isn't quite right. According to Jeff Lee's doc: + * + * "After writing to the register port, you must wait twelve cycles before + * sending the data; after writing the data, eighty-four cycles must elapse + * before any other sound card operation may be performed. + * + * | The AdLib manual gives the wait times in microseconds: three point three + * | (3.3) microseconds for the address, and twenty-three (23) microseconds + * | for the data. + * | + * | The most accurate method of producing the delay is to read the register + * | port six times after writing to the register port, and read the register + * | port thirty-five times after writing to the data port." + * + * + * In other words, the delay constants represented by {SHORT|LONG}DELAY below + * aren't given in microseconds, but rather direct reads (INB) from the Adlib + * I/O ports. + * + * Translation: SHORTDELAY should be 6, and LONGDELAY is just fine. :-) + */ + +#define SHORTDELAY 6 // short delay in I/O port-reads after OPL hardware output +#define LONGDELAY 35 // long delay in I/O port-reads after OPL hardware output + +// the 9 operators as expected by the OPL2 +static const unsigned char op_table[9] = {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12}; + +CRealopl::CRealopl(unsigned short initport): adlport(initport), hardvol(0), bequiet(false), nowrite(false) +{ + for(int i=0;i<22;i++) { + hardvols[i][0] = 0; + hardvols[i][1] = 0; + } +} + +bool CRealopl::detect() +{ + unsigned char stat1,stat2,i; + + hardwrite(4,0x60); hardwrite(4,0x80); + stat1 = INP(adlport); + hardwrite(2,0xff); hardwrite(4,0x21); + for(i=0;i<80;i++) // wait for adlib + INP(adlport); + stat2 = INP(adlport); + hardwrite(4,0x60); hardwrite(4,0x80); + + if(((stat1 & 0xe0) == 0) && ((stat2 & 0xe0) == 0xc0)) + return true; + else + return false; +} + +void CRealopl::setvolume(int volume) +{ + int i; + + hardvol = volume; + for(i=0;i<9;i++) { + hardwrite(0x43+op_table[i],((hardvols[op_table[i]+3][0] & 63) + volume) > 63 ? 63 : hardvols[op_table[i]+3][0] + volume); + if(hardvols[i][1] & 1) // modulator too? + hardwrite(0x40+op_table[i],((hardvols[op_table[i]][0] & 63) + volume) > 63 ? 63 : hardvols[op_table[i]][0] + volume); + } +} + +void CRealopl::setquiet(bool quiet) +{ + bequiet = quiet; + + if(quiet) { + oldvol = hardvol; + setvolume(63); + } else + setvolume(oldvol); +} + +void CRealopl::hardwrite(int reg, int val) +{ + int i; + + OUTP(adlport,reg); // set register + for(i=0;i= 0xb0 && reg <= 0xb8)) // filter all key-on commands + val &= ~32; + if(reg >= 0x40 && reg <= 0x55) // cache volumes + hardvols[reg-0x40][0] = val; + if(reg >= 0xc0 && reg <= 0xc8) + hardvols[reg-0xc0][1] = val; + if(hardvol) // reduce volume + for(i=0;i<9;i++) { + if(reg == 0x43 + op_table[i]) + val = ((val & 63) + hardvol) > 63 ? 63 : val + hardvol; + else + if((reg == 0x40 + op_table[i]) && (hardvols[i][1] & 1)) + val = ((val & 63) + hardvol) > 63 ? 63 : val + hardvol; + } + + hardwrite(reg,val); +} + +void CRealopl::init() +{ + int i; + + for (i=0;i<9;i++) { // stop instruments + hardwrite(0xb0 + i,0); // key off + hardwrite(0x80 + op_table[i],0xff); // fastest release + } + hardwrite(0xbd,0); // clear misc. register +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/realopl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/realopl.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,54 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * realopl.h - Real hardware OPL, by Simon Peter + */ + +#include "opl.h" + +#define DFL_ADLIBPORT 0x388 // default adlib baseport + +class CRealopl: public Copl +{ +public: + CRealopl(unsigned short initport = DFL_ADLIBPORT); // initport = OPL2 hardware baseport + + bool detect(); // returns true if adlib compatible board is found, else false + void setvolume(int volume); // set adlib master volume (0 - 63) 0 = loudest, 63 = softest + void setquiet(bool quiet = true); // sets the OPL2 quiet, while still writing to the registers + void setport(unsigned short port) // set new OPL2 hardware baseport + { adlport = port; }; + void setnowrite(bool nw = true) // set hardware write status + { nowrite = nw; }; + + int getvolume() // get adlib master volume + { return hardvol; }; + + // template methods + void write(int reg, int val); + void init(); + +private: + void hardwrite(int reg, int val); // write to OPL2 hardware registers + + unsigned short adlport; // adlib hardware baseport + int hardvol,oldvol; // hardware master volume + bool bequiet; // quiet status cache + char hardvols[22][2]; // volume cache + bool nowrite; // don't write to hardware, if true +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/rol.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/rol.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,723 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * rol.h - ROL Player by OPLx + * + * Visit: http://tenacity.hispeed.com/aomit/oplx/ + */ +#include + +#include "rol.h" +#include "debug.h" + +int const CrolPlayer::kSizeofDataRecord = 30; +int const CrolPlayer::kMaxTickBeat = 60; +int const CrolPlayer::kSilenceNote = -12; +int const CrolPlayer::kNumMelodicVoices = 9; +int const CrolPlayer::kNumPercussiveVoices = 11; +int const CrolPlayer::kBassDrumChannel = 6; +int const CrolPlayer::kSnareDrumChannel = 7; +int const CrolPlayer::kTomtomChannel = 8; +int const CrolPlayer::kTomtomFreq = 2;//4; +int const CrolPlayer::kSnareDrumFreq = 2;//kTomtomFreq + 7; +float const CrolPlayer::kDefaultUpdateTme = 18.2f; +float const CrolPlayer::kPitchFactor = 400.0f; + +static const unsigned char drum_table[4] = {0x14, 0x12, 0x15, 0x11}; + +CrolPlayer::uint16 const CrolPlayer::kNoteTable[12] = +{ + 340, // C + 363, // C# + 385, // D + 408, // D# + 432, // E + 458, // F + 485, // F# + 514, // G + 544, // G# + 577, // A + 611, // A# + 647 // B +}; + +/*** public methods **************************************/ + +CPlayer *CrolPlayer::factory(Copl *newopl) +{ + return new CrolPlayer(newopl); +} +//--------------------------------------------------------- +CrolPlayer::CrolPlayer(Copl *newopl) +: CPlayer ( newopl ) + ,rol_header ( NULL ) + ,mNextTempoEvent ( 0 ) + ,mCurrTick ( 0 ) + ,mTimeOfLastNote ( 0 ) + ,mRefresh ( kDefaultUpdateTme ) + ,bdRegister ( 0 ) +{ + int n; + + memset(bxRegister, 0, sizeof(bxRegister) ); + memset(volumeCache, 0, sizeof(volumeCache) ); + memset(freqCache, 0, sizeof(freqCache) ); + + for(n=0; n<11; n++) + pitchCache[n]=1.0f; +} +//--------------------------------------------------------- +CrolPlayer::~CrolPlayer() +{ + if( rol_header != NULL ) + { + delete rol_header; + rol_header=NULL; + } +} +//--------------------------------------------------------- +bool CrolPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + + char *fn = new char[filename.length()+9]; + int i; + std::string bnk_filename; + + AdPlug_LogWrite("*** CrolPlayer::load(f, \"%s\") ***\n", filename.c_str()); + strcpy(fn,filename.data()); + for (i=strlen(fn)-1; i>=0; i--) + if (fn[i] == '/' || fn[i] == '\\') + break; + strcpy(fn+i+1,"standard.bnk"); + bnk_filename = fn; + delete [] fn; + AdPlug_LogWrite("bnk_filename = \"%s\"\n",bnk_filename.c_str()); + + rol_header = new SRolHeader; + memset( rol_header, 0, sizeof(SRolHeader) ); + + rol_header->version_major = f->readInt( 2 ); + rol_header->version_minor = f->readInt( 2 ); + + // Version check + if(rol_header->version_major != 0 || rol_header->version_minor != 4) { + AdPlug_LogWrite("Unsupported file version %d.%d or not a ROL file!\n", + rol_header->version_major, rol_header->version_minor); + AdPlug_LogWrite("--- CrolPlayer::load ---\n"); + fp.close(f); + return false; + } + + f->seek( 40, binio::Add ); + + rol_header->ticks_per_beat = f->readInt( 2 ); + rol_header->beats_per_measure = f->readInt( 2 ); + rol_header->edit_scale_y = f->readInt( 2 ); + rol_header->edit_scale_x = f->readInt( 2 ); + + f->seek( 1, binio::Add ); + + rol_header->mode = f->readInt(1); + + f->seek( 90+38+15, binio::Add ); + + rol_header->basic_tempo = f->readFloat( binio::Single ); + + load_tempo_events( f ); + + mTimeOfLastNote = 0; + + if( load_voice_data( f, bnk_filename, fp ) != true ) + { + AdPlug_LogWrite("CrolPlayer::load_voice_data(f) failed!\n"); + AdPlug_LogWrite("--- CrolPlayer::load ---\n"); + + fp.close( f ); + return false; + } + + fp.close( f ); + + rewind( 0 ); + AdPlug_LogWrite("--- CrolPlayer::load ---\n"); + return true; +} +//--------------------------------------------------------- +bool CrolPlayer::update() +{ + if( mNextTempoEvent < mTempoEvents.size() && + mTempoEvents[mNextTempoEvent].time == mCurrTick ) + { + SetRefresh( mTempoEvents[mNextTempoEvent].multiplier ); + ++mNextTempoEvent; + } + + TVoiceData::iterator curr = voice_data.begin(); + TVoiceData::iterator end = voice_data.end(); + int voice = 0; + + while( curr != end ) + { + UpdateVoice( voice, *curr ); + ++curr; + ++voice; + } + + ++mCurrTick; + + if( mCurrTick > mTimeOfLastNote ) + { + return false; + } + + return true; + //return ( mCurrTick > mTimeOfLastNote ) ? false : true; +} +//--------------------------------------------------------- +void CrolPlayer::rewind( int subsong ) +{ + TVoiceData::iterator curr = voice_data.begin(); + TVoiceData::iterator end = voice_data.end(); + + while( curr != end ) + { + CVoiceData &voice = *curr; + + voice.Reset(); + ++curr; + } + + memset(bxRegister, 0, sizeof(bxRegister) ); + memset(volumeCache, 0, sizeof(volumeCache) ); + + bdRegister = 0; + + opl->init(); // initialize to melodic by default + opl->write(1,0x20); // Enable waveform select (bit 5) + + if( rol_header->mode == 0 ) + { + opl->write( 0xbd, 0x20 ); // select rhythm mode (bit 5) + bdRegister = 0x20; + + SetFreq( kTomtomChannel, 24 ); + SetFreq( kSnareDrumChannel, 31 ); + } + + mNextTempoEvent = 0; + mCurrTick = 0; + + SetRefresh(1.0f); +} +//--------------------------------------------------------- +inline float fmin( int const a, int const b ) +{ + return static_cast( a < b ? a : b ); +} +//--------------------------------------------------------- +void CrolPlayer::SetRefresh( float const multiplier ) +{ + float const tickBeat = fmin(kMaxTickBeat, rol_header->ticks_per_beat); + + mRefresh = (tickBeat*rol_header->basic_tempo*multiplier) / 60.0f; +} +//--------------------------------------------------------- +float CrolPlayer::getrefresh() +{ + return mRefresh; +} +//--------------------------------------------------------- +void CrolPlayer::UpdateVoice( int const voice, CVoiceData &voiceData ) +{ + TNoteEvents const &nEvents = voiceData.note_events; + + if( nEvents.empty() || voiceData.mEventStatus & CVoiceData::kES_NoteEnd ) + { + return; // no note data to process, don't bother doing anything. + } + + TInstrumentEvents &iEvents = voiceData.instrument_events; + TVolumeEvents &vEvents = voiceData.volume_events; + TPitchEvents &pEvents = voiceData.pitch_events; + + if( !(voiceData.mEventStatus & CVoiceData::kES_InstrEnd ) && + iEvents[voiceData.next_instrument_event].time == mCurrTick ) + { + if( voiceData.next_instrument_event < iEvents.size() ) + { + send_ins_data_to_chip( voice, iEvents[voiceData.next_instrument_event].ins_index ); + ++voiceData.next_instrument_event; + } + else + { + voiceData.mEventStatus |= CVoiceData::kES_InstrEnd; + } + } + + if( !(voiceData.mEventStatus & CVoiceData::kES_VolumeEnd ) && + vEvents[voiceData.next_volume_event].time == mCurrTick ) + { + SVolumeEvent const &volumeEvent = vEvents[voiceData.next_volume_event]; + + if( voiceData.next_volume_event < vEvents.size() ) + { + int const volume = (int)(63.0f*(1.0f - volumeEvent.multiplier)); + + SetVolume( voice, volume ); + + ++voiceData.next_volume_event; // move to next volume event + } + else + { + voiceData.mEventStatus |= CVoiceData::kES_VolumeEnd; + } + } + + if( voiceData.mForceNote || voiceData.current_note_duration > voiceData.mNoteDuration-1 ) + { + if( mCurrTick != 0 ) + { + ++voiceData.current_note; + } + + if( voiceData.current_note < nEvents.size() ) + { + SNoteEvent const ¬eEvent = nEvents[voiceData.current_note]; + + SetNote( voice, noteEvent.number ); + voiceData.current_note_duration = 0; + voiceData.mNoteDuration = noteEvent.duration; + voiceData.mForceNote = false; + } + else + { + SetNote( voice, kSilenceNote ); + voiceData.mEventStatus |= CVoiceData::kES_NoteEnd; + return; + } + } + + if( !(voiceData.mEventStatus & CVoiceData::kES_PitchEnd ) && + pEvents[voiceData.next_pitch_event].time == mCurrTick ) + { + if( voiceData.next_pitch_event < pEvents.size() ) + { + SetPitch(voice,pEvents[voiceData.next_pitch_event].variation); + ++voiceData.next_pitch_event; + } + else + { + voiceData.mEventStatus |= CVoiceData::kES_PitchEnd; + } + } + + ++voiceData.current_note_duration; +} +//--------------------------------------------------------- +void CrolPlayer::SetNote( int const voice, int const note ) +{ + if( voice < kBassDrumChannel || rol_header->mode ) + { + SetNoteMelodic( voice, note ); + } + else + { + SetNotePercussive( voice, note ); + } +} +//--------------------------------------------------------- +void CrolPlayer::SetNotePercussive( int const voice, int const note ) +{ + int const bit_pos = 4-voice+kBassDrumChannel; + + bdRegister &= ~( 1<write( 0xbd, bdRegister ); + + if( note != kSilenceNote ) + { + switch( voice ) + { + case kTomtomChannel: + SetFreq( kSnareDrumChannel, note+7 ); + case kBassDrumChannel: + SetFreq( voice, note ); + break; + } + + bdRegister |= 1<write( 0xbd, bdRegister ); + } +} +//--------------------------------------------------------- +void CrolPlayer::SetNoteMelodic( int const voice, int const note ) +{ + opl->write( 0xb0+voice, bxRegister[voice] & ~0x20 ); + + if( note != kSilenceNote ) + { + SetFreq( voice, note, true ); + } +} +//--------------------------------------------------------- +void CrolPlayer::SetPitch(int const voice, real32 const variation) +{ + pitchCache[voice] = variation; + freqCache[voice] += (uint16)((((float)freqCache[voice])*(variation-1.0f)) / kPitchFactor); + + opl->write(0xa0+voice,freqCache[voice] & 0xff); +} +//--------------------------------------------------------- +void CrolPlayer::SetFreq( int const voice, int const note, bool const keyOn ) +{ + uint16 freq = kNoteTable[note%12] + ((note/12) << 10); + freq += (uint16)((((float)freq)*(pitchCache[voice]-1.0f))/kPitchFactor); + + freqCache[voice] = freq; + bxRegister[voice] = ((freq >> 8) & 0x1f); + + opl->write( 0xa0+voice, freq & 0xff ); + opl->write( 0xb0+voice, bxRegister[voice] | (keyOn ? 0x20 : 0x0) ); +} +//--------------------------------------------------------- +void CrolPlayer::SetVolume( int const voice, int const volume ) +{ + volumeCache[voice] = (volumeCache[voice] &0xc0) | volume; + + int const op_offset = ( voice < kSnareDrumChannel || rol_header->mode ) ? + op_table[voice]+3 : drum_table[voice-kSnareDrumChannel]; + + opl->write( 0x40+op_offset, volumeCache[voice] ); +} +//--------------------------------------------------------- +void CrolPlayer::send_ins_data_to_chip( int const voice, int const ins_index ) +{ + SRolInstrument &instrument = ins_list[ins_index].instrument; + + send_operator( voice, instrument.modulator, instrument.carrier ); +} +//--------------------------------------------------------- +void CrolPlayer::send_operator( int const voice, SOPL2Op const &modulator, SOPL2Op const &carrier ) +{ + if( voice < kSnareDrumChannel || rol_header->mode ) + { + int const op_offset = op_table[voice]; + + opl->write( 0x20+op_offset, modulator.ammulti ); + opl->write( 0x40+op_offset, modulator.ksltl ); + opl->write( 0x60+op_offset, modulator.ardr ); + opl->write( 0x80+op_offset, modulator.slrr ); + opl->write( 0xc0+voice , modulator.fbc ); + opl->write( 0xe0+op_offset, modulator.waveform ); + + volumeCache[voice] = (carrier.ksltl & 0xc0) | volumeCache[voice] & 0x3f; + + opl->write( 0x23+op_offset, carrier.ammulti ); + opl->write( 0x43+op_offset, volumeCache[voice] ); + opl->write( 0x63+op_offset, carrier.ardr ); + opl->write( 0x83+op_offset, carrier.slrr ); +// opl->write( 0xc3+voice , carrier.fbc ); <- don't bother writing this. + opl->write( 0xe3+op_offset, carrier.waveform ); + } + else + { + int const op_offset = drum_table[voice-kSnareDrumChannel]; + + volumeCache[voice] = (modulator.ksltl & 0xc0) | volumeCache[voice] & 0x3f; + + opl->write( 0x20+op_offset, modulator.ammulti ); + opl->write( 0x40+op_offset, volumeCache[voice] ); + opl->write( 0x60+op_offset, modulator.ardr ); + opl->write( 0x80+op_offset, modulator.slrr ); + opl->write( 0xc0+voice , modulator.fbc ); + opl->write( 0xe0+op_offset, modulator.waveform ); + } +} +//--------------------------------------------------------- +void CrolPlayer::load_tempo_events( binistream *f ) +{ + int16 const num_tempo_events = f->readInt( 2 ); + + mTempoEvents.reserve( num_tempo_events ); + + for(int i=0; ireadInt( 2 ); + event.multiplier = f->readFloat( binio::Single ); + mTempoEvents.push_back( event ); + } +} +//--------------------------------------------------------- +bool CrolPlayer::load_voice_data( binistream *f, std::string const &bnk_filename, const CFileProvider &fp ) +{ + SBnkHeader bnk_header; + binistream *bnk_file = fp.open( bnk_filename.c_str() ); + + if( bnk_file ) + { + load_bnk_info( bnk_file, bnk_header ); + + int const numVoices = rol_header->mode ? kNumMelodicVoices : kNumPercussiveVoices; + + voice_data.reserve( numVoices ); + for(int i=0; iseek( 15, binio::Add ); + + int16 const time_of_last_note = f->readInt( 2 ); + + if( time_of_last_note != 0 ) + { + TNoteEvents ¬e_events = voice.note_events; + int16 total_duration = 0; + + do + { + SNoteEvent event; + + event.number = f->readInt( 2 ); + event.duration = f->readInt( 2 ); + + event.number += kSilenceNote; // adding -12 + + note_events.push_back( event ); + + total_duration += event.duration; + } while( total_duration < time_of_last_note ); + + if( time_of_last_note > mTimeOfLastNote ) + { + mTimeOfLastNote = time_of_last_note; + } + } + + f->seek( 15, binio::Add ); +} +//--------------------------------------------------------- +void CrolPlayer::load_instrument_events( binistream *f, CVoiceData &voice, + binistream *bnk_file, SBnkHeader const &bnk_header ) +{ + int16 const number_of_instrument_events = f->readInt( 2 ); + + TInstrumentEvents &instrument_events = voice.instrument_events; + + instrument_events.reserve( number_of_instrument_events ); + + for(int i=0; ireadInt( 2 ); + f->readString( event.name, 9 ); + + std::string event_name = event.name; + event.ins_index = load_rol_instrument( bnk_file, bnk_header, event_name ); + + instrument_events.push_back( event ); + + f->seek( 1+2, binio::Add ); + } + + f->seek( 15, binio::Add ); +} +//--------------------------------------------------------- +void CrolPlayer::load_volume_events( binistream *f, CVoiceData &voice ) +{ + int16 const number_of_volume_events = f->readInt( 2 ); + + TVolumeEvents &volume_events = voice.volume_events; + + volume_events.reserve( number_of_volume_events ); + + for(int i=0; ireadInt( 2 ); + event.multiplier = f->readFloat( binio::Single ); + + volume_events.push_back( event ); + } + + f->seek( 15, binio::Add ); +} +//--------------------------------------------------------- +void CrolPlayer::load_pitch_events( binistream *f, CVoiceData &voice ) +{ + int16 const number_of_pitch_events = f->readInt( 2 ); + + TPitchEvents &pitch_events = voice.pitch_events; + + pitch_events.reserve( number_of_pitch_events ); + + for(int i=0; ireadInt( 2 ); + event.variation = f->readFloat( binio::Single ); + + pitch_events.push_back( event ); + } +} +//--------------------------------------------------------- +bool CrolPlayer::load_bnk_info( binistream *f, SBnkHeader &header ) +{ + header.version_major = f->readInt(1); + header.version_minor = f->readInt(1); + f->readString( header.signature, 6 ); + + header.number_of_list_entries_used = f->readInt( 2 ); + header.total_number_of_list_entries = f->readInt( 2 ); + + header.abs_offset_of_name_list = f->readInt( 4 ); + header.abs_offset_of_data = f->readInt( 4 ); + + f->seek( header.abs_offset_of_name_list, binio::Set ); + + TInstrumentNames &ins_name_list = header.ins_name_list; + ins_name_list.reserve( header.number_of_list_entries_used ); + + for(int i=0; ireadInt( 2 ); + instrument.record_used = f->readInt(1); + f->readString( instrument.name, 9 ); + + // printf("%s = #%d\n", instrument.name, i ); + + ins_name_list.push_back( instrument ); + } + + //std::sort( ins_name_list.begin(), ins_name_list.end(), StringCompare() ); + + return true; +} +//--------------------------------------------------------- +int CrolPlayer::load_rol_instrument( binistream *f, SBnkHeader const &header, std::string &name ) +{ + TInstrumentNames const &ins_name_list = header.ins_name_list; + + int const ins_index = get_ins_index( name ); + + if( ins_index != -1 ) + { + return ins_index; + } + + typedef TInstrumentNames::const_iterator TInsIter; + typedef std::pair TInsIterPair; + + TInsIterPair range = std::equal_range( ins_name_list.begin(), + ins_name_list.end(), + name, + StringCompare() ); + + if( range.first != range.second ) + { + int const seekOffs = header.abs_offset_of_data + (range.first->index*kSizeofDataRecord); + f->seek( seekOffs, binio::Set ); + } + + SUsedList usedIns; + usedIns.name = name; + + if( range.first != range.second ) + { + read_rol_instrument( f, usedIns.instrument ); + } + else + { + // set up default instrument data here + memset( &usedIns.instrument, 0, kSizeofDataRecord ); + } + ins_list.push_back( usedIns ); + + return ins_list.size()-1; +} +//--------------------------------------------------------- +int CrolPlayer::get_ins_index( std::string const &name ) const +{ + for(unsigned int i=0; ireadInt(1); + ins.voice_number = f->readInt(1); + + read_fm_operator( f, ins.modulator ); + read_fm_operator( f, ins.carrier ); + + ins.modulator.waveform = f->readInt(1); + ins.carrier.waveform = f->readInt(1); +} +//--------------------------------------------------------- +void CrolPlayer::read_fm_operator( binistream *f, SOPL2Op &opl2_op ) +{ + SFMOperator fm_op; + + fm_op.key_scale_level = f->readInt(1); + fm_op.freq_multiplier = f->readInt(1); + fm_op.feed_back = f->readInt(1); + fm_op.attack_rate = f->readInt(1); + fm_op.sustain_level = f->readInt(1); + fm_op.sustaining_sound = f->readInt(1); + fm_op.decay_rate = f->readInt(1); + fm_op.release_rate = f->readInt(1); + fm_op.output_level = f->readInt(1); + fm_op.amplitude_vibrato = f->readInt(1); + fm_op.frequency_vibrato = f->readInt(1); + fm_op.envelope_scaling = f->readInt(1); + fm_op.fm_type = f->readInt(1); + + opl2_op.ammulti = fm_op.amplitude_vibrato << 7 | fm_op.frequency_vibrato << 6 | fm_op.sustaining_sound << 5 | fm_op.envelope_scaling << 4 | fm_op.freq_multiplier; + opl2_op.ksltl = fm_op.key_scale_level << 6 | fm_op.output_level; + opl2_op.ardr = fm_op.attack_rate << 4 | fm_op.decay_rate; + opl2_op.slrr = fm_op.sustain_level << 4 | fm_op.release_rate; + opl2_op.fbc = fm_op.feed_back << 1 | (fm_op.fm_type ^ 1); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/rol.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/rol.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,308 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * rol.h - ROL Player by OPLx + * + * Visit: http://tenacity.hispeed.com/aomit/oplx/ + */ +#ifndef H_ROLPLAYER +#define H_ROLPLAYER + +#include +#include + +#include "player.h" + +class CrolPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CrolPlayer(Copl *newopl); + + ~CrolPlayer(); + + bool load (const std::string &filename, const CFileProvider &fp); + bool update (); + void rewind (int subsong); // rewinds to specified subsong + float getrefresh(); // returns needed timer refresh rate + + std::string gettype() { return std::string("Adlib Visual Composer"); } + +private: + typedef unsigned short uint16; + typedef signed short int16; +#ifdef __x86_64__ + typedef signed int int32; +#else + typedef signed long int int32; +#endif + typedef float real32; + + typedef struct + { + uint16 version_major; + uint16 version_minor; + char unused0[40]; + uint16 ticks_per_beat; + uint16 beats_per_measure; + uint16 edit_scale_y; + uint16 edit_scale_x; + char unused1; + char mode; + char unused2[90]; + char filler0[38]; + char filler1[15]; + real32 basic_tempo; + } SRolHeader; + + typedef struct + { + int16 time; + real32 multiplier; + } STempoEvent; + + typedef struct + { + int16 number; + int16 duration; + } SNoteEvent; + + typedef struct + { + int16 time; + char name[9]; + int16 ins_index; + } SInstrumentEvent; + + typedef struct + { + int16 time; + real32 multiplier; + } SVolumeEvent; + + typedef struct + { + int16 time; + real32 variation; + } SPitchEvent; + + typedef std::vector TNoteEvents; + typedef std::vector TInstrumentEvents; + typedef std::vector TVolumeEvents; + typedef std::vector TPitchEvents; + +#define bit_pos( pos ) (1< TInstrumentNames; + + typedef struct + { + char version_major; + char version_minor; + char signature[6]; + uint16 number_of_list_entries_used; + uint16 total_number_of_list_entries; + int32 abs_offset_of_name_list; + int32 abs_offset_of_data; + + TInstrumentNames ins_name_list; + } SBnkHeader; + + typedef struct + { + unsigned char key_scale_level; + unsigned char freq_multiplier; + unsigned char feed_back; + unsigned char attack_rate; + unsigned char sustain_level; + unsigned char sustaining_sound; + unsigned char decay_rate; + unsigned char release_rate; + unsigned char output_level; + unsigned char amplitude_vibrato; + unsigned char frequency_vibrato; + unsigned char envelope_scaling; + unsigned char fm_type; + } SFMOperator; + + typedef struct + { + unsigned char ammulti; + unsigned char ksltl; + unsigned char ardr; + unsigned char slrr; + unsigned char fbc; + unsigned char waveform; + } SOPL2Op; + + typedef struct + { + char mode; + char voice_number; + SOPL2Op modulator; + SOPL2Op carrier; + } SRolInstrument; + + typedef struct + { + std::string name; + SRolInstrument instrument; + } SUsedList; + + void load_tempo_events ( binistream *f ); + bool load_voice_data ( binistream *f, std::string const &bnk_filename, const CFileProvider &fp ); + void load_note_events ( binistream *f, CVoiceData &voice ); + void load_instrument_events( binistream *f, CVoiceData &voice, + binistream *bnk_file, SBnkHeader const &bnk_header ); + void load_volume_events ( binistream *f, CVoiceData &voice ); + void load_pitch_events ( binistream *f, CVoiceData &voice ); + + bool load_bnk_info ( binistream *f, SBnkHeader &header ); + int load_rol_instrument ( binistream *f, SBnkHeader const &header, std::string &name ); + void read_rol_instrument ( binistream *f, SRolInstrument &ins ); + void read_fm_operator ( binistream *f, SOPL2Op &opl2_op ); + int get_ins_index( std::string const &name ) const; + + void UpdateVoice( int const voice, CVoiceData &voiceData ); + void SetNote( int const voice, int const note ); + void SetNoteMelodic( int const voice, int const note ); + void SetNotePercussive( int const voice, int const note ); + void SetFreq ( int const voice, int const note, bool const keyOn=false ); + void SetPitch ( int const voice, real32 const variation ); + void SetVolume ( int const voice, int const volume ); + void SetRefresh( float const multiplier ); + void send_ins_data_to_chip( int const voice, int const ins_index ); + void send_operator( int const voice, SOPL2Op const &modulator, SOPL2Op const &carrier ); + + class StringCompare + { + public: + bool operator()( SInstrumentName const &lhs, SInstrumentName const &rhs ) const + { + return keyLess(lhs.name, rhs.name); + } + + bool operator()( SInstrumentName const &lhs, std::string const &rhs ) const + { + return keyLess(lhs.name, rhs.c_str()); + } + + bool operator()( std::string const &lhs, SInstrumentName const &rhs ) const + { + return keyLess(lhs.c_str(), rhs.name); + } + private: + bool keyLess( const char *const lhs, const char *const rhs ) const + { + return stricmp(lhs, rhs) < 0; + } + }; + + typedef std::vector TVoiceData; + + SRolHeader *rol_header; + std::vector mTempoEvents; + TVoiceData voice_data; + std::vector ins_list; + + unsigned int mNextTempoEvent; + int mCurrTick; + int mTimeOfLastNote; + float mRefresh; + unsigned char bdRegister; + unsigned char bxRegister[9]; + unsigned char volumeCache[11]; + uint16 freqCache[11]; + real32 pitchCache[11]; + + static int const kSizeofDataRecord; + static int const kMaxTickBeat; + static int const kSilenceNote; + static int const kNumMelodicVoices; + static int const kNumPercussiveVoices; + static int const kBassDrumChannel; + static int const kSnareDrumChannel; + static int const kTomtomChannel; + static int const kTomtomFreq; + static int const kSnareDrumFreq; + static float const kDefaultUpdateTme; + static float const kPitchFactor; + static uint16 const kNoteTable[12]; +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/s3m.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/s3m.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,517 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * s3m.c - S3M Player by Simon Peter + * + * BUGS: + * Extra Fine Slides (EEx, FEx) & Fine Vibrato (Uxy) are inaccurate + */ + +#include "s3m.h" + +const char Cs3mPlayer::chnresolv[] = // S3M -> adlib channel conversion + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,-1,-1,-1,-1,-1,-1,-1}; + +const unsigned short Cs3mPlayer::notetable[12] = // S3M adlib note table + {340,363,385,408,432,458,485,514,544,577,611,647}; + +const unsigned char Cs3mPlayer::vibratotab[32] = // vibrato rate table + {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}; + +/*** public methods *************************************/ + +CPlayer *Cs3mPlayer::factory(Copl *newopl) +{ + return new Cs3mPlayer(newopl); +} + +Cs3mPlayer::Cs3mPlayer(Copl *newopl): CPlayer(newopl) +{ + int i,j,k; + + memset(pattern,255,sizeof(pattern)); + memset(orders,255,sizeof(orders)); + + for(i=0;i<99;i++) // setup pattern + for(j=0;j<64;j++) + for(k=0;k<32;k++) { + pattern[i][j][k].instrument = 0; + pattern[i][j][k].info = 0; + } +} + +bool Cs3mPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + unsigned short insptr[99],pattptr[99]; + int i,row; + unsigned char bufval,bufval2; + unsigned short ppatlen; + s3mheader *checkhead; + bool adlibins=false; + + // file validation section + checkhead = new s3mheader; + load_header(f, checkhead); + if((checkhead->kennung != 0x1a) || (checkhead->typ != 16)) { + delete checkhead; fp.close(f); return false; + } else + if(strncmp(checkhead->scrm,"SCRM",4)) { + delete checkhead; fp.close(f); return false; + } else { // is an adlib module? + f->seek(checkhead->ordnum, binio::Add); + for(i = 0; i < checkhead->insnum; i++) + insptr[i] = f->readInt(2); + for(i=0;iinsnum;i++) { + f->seek(insptr[i]*16); + if(f->readInt(1) >= 2) { + adlibins = true; + break; + } + } + delete checkhead; + if(!adlibins) { fp.close(f); return false; } + } + + // load section + f->seek(0); // rewind for load + load_header(f, &header); // read header + for(i = 0; i < header.ordnum; i++) orders[i] = f->readInt(1); // read orders + for(i = 0; i < header.insnum; i++) insptr[i] = f->readInt(2); // instrument parapointers + for(i = 0; i < header.patnum; i++) pattptr[i] = f->readInt(2); // pattern parapointers + + for(i=0;iseek(insptr[i]*16); + inst[i].type = f->readInt(1); + f->readString(inst[i].filename, 15); + inst[i].d00 = f->readInt(1); inst[i].d01 = f->readInt(1); + inst[i].d02 = f->readInt(1); inst[i].d03 = f->readInt(1); + inst[i].d04 = f->readInt(1); inst[i].d05 = f->readInt(1); + inst[i].d06 = f->readInt(1); inst[i].d07 = f->readInt(1); + inst[i].d08 = f->readInt(1); inst[i].d09 = f->readInt(1); + inst[i].d0a = f->readInt(1); inst[i].d0b = f->readInt(1); + inst[i].volume = f->readInt(1); inst[i].dsk = f->readInt(1); + f->ignore(2); + inst[i].c2spd = f->readInt(4); + f->ignore(12); + f->readString(inst[i].name, 28); + f->readString(inst[i].scri, 4); + } + + for(i=0;iseek(pattptr[i]*16); + ppatlen = f->readInt(2); + unsigned long pattpos = f->pos(); + for(row=0;(row<64) && (pattpos-pattptr[i]*16<=ppatlen);row++) + do { + bufval = f->readInt(1); + if(bufval & 32) { + bufval2 = f->readInt(1); + pattern[i][row][bufval & 31].note = bufval2 & 15; + pattern[i][row][bufval & 31].oct = (bufval2 & 240) >> 4; + pattern[i][row][bufval & 31].instrument = f->readInt(1); + } + if(bufval & 64) + pattern[i][row][bufval & 31].volume = f->readInt(1); + if(bufval & 128) { + pattern[i][row][bufval & 31].command = f->readInt(1); + pattern[i][row][bufval & 31].info = f->readInt(1); + } + } while(bufval); + } + + fp.close(f); + rewind(0); + return true; // done +} + +bool Cs3mPlayer::update() +{ + unsigned char pattbreak=0,donote; // remember vars + unsigned char pattnr,chan,row,info; // cache vars + signed char realchan; + + // effect handling (timer dependant) + for(realchan=0; realchan<9; realchan++) { + info = channel[realchan].info; // fill infobyte cache + switch(channel[realchan].fx) { + case 11: + case 12: if(channel[realchan].fx == 11) // dual command: H00 and Dxy + vibrato(realchan,channel[realchan].dualinfo); + else // dual command: G00 and Dxy + tone_portamento(realchan,channel[realchan].dualinfo); + case 4: if(info <= 0x0f) // volume slide down + if(channel[realchan].vol - info >= 0) + channel[realchan].vol -= info; + else + channel[realchan].vol = 0; + if((info & 0x0f) == 0) // volume slide up + if(channel[realchan].vol + (info >> 4) <= 63) + channel[realchan].vol += info >> 4; + else + channel[realchan].vol = 63; + setvolume(realchan); + break; + case 5: if(info == 0xf0 || info <= 0xe0) { // slide down + slide_down(realchan,info); + setfreq(realchan); + } + break; + case 6: if(info == 0xf0 || info <= 0xe0) { // slide up + slide_up(realchan,info); + setfreq(realchan); + } + break; + case 7: tone_portamento(realchan,channel[realchan].dualinfo); break; // tone portamento + case 8: vibrato(realchan,channel[realchan].dualinfo); break; // vibrato + case 10: channel[realchan].nextfreq = channel[realchan].freq; // arpeggio + channel[realchan].nextoct = channel[realchan].oct; + switch(channel[realchan].trigger) { + case 0: channel[realchan].freq = notetable[channel[realchan].note]; break; + case 1: if(channel[realchan].note + ((info & 0xf0) >> 4) < 12) + channel[realchan].freq = notetable[channel[realchan].note + ((info & 0xf0) >> 4)]; + else { + channel[realchan].freq = notetable[channel[realchan].note + ((info & 0xf0) >> 4) - 12]; + channel[realchan].oct++; + } + break; + case 2: if(channel[realchan].note + (info & 0x0f) < 12) + channel[realchan].freq = notetable[channel[realchan].note + (info & 0x0f)]; + else { + channel[realchan].freq = notetable[channel[realchan].note + (info & 0x0f) - 12]; + channel[realchan].oct++; + } + break; + } + if(channel[realchan].trigger < 2) + channel[realchan].trigger++; + else + channel[realchan].trigger = 0; + setfreq(realchan); + channel[realchan].freq = channel[realchan].nextfreq; + channel[realchan].oct = channel[realchan].nextoct; + break; + case 21: vibrato(realchan,(unsigned char) (info / 4)); break; // fine vibrato + } + } + + if(del) { // speed compensation + del--; + return !songend; + } + + // arrangement handling + pattnr = orders[ord]; + if(pattnr == 0xff || ord > header.ordnum) { // "--" end of song + songend = 1; // set end-flag + ord = 0; + pattnr = orders[ord]; + if(pattnr == 0xff) + return !songend; + } + if(pattnr == 0xfe) { // "++" skip marker + ord++; pattnr = orders[ord]; + } + + // play row + row = crow; // fill row cache + for(chan=0;chan<32;chan++) { + if(!(header.chanset[chan] & 128)) // resolve S3M -> AdLib channels + realchan = chnresolv[header.chanset[chan] & 127]; + else + realchan = -1; // channel disabled + if(realchan != -1) { // channel playable? + // set channel values + donote = 0; + if(pattern[pattnr][row][chan].note < 14) + // tone portamento + if(pattern[pattnr][row][chan].command == 7 || pattern[pattnr][row][chan].command == 12) { + channel[realchan].nextfreq = notetable[pattern[pattnr][row][chan].note]; + channel[realchan].nextoct = pattern[pattnr][row][chan].oct; + } else { // normal note + channel[realchan].note = pattern[pattnr][row][chan].note; + channel[realchan].freq = notetable[pattern[pattnr][row][chan].note]; + channel[realchan].oct = pattern[pattnr][row][chan].oct; + channel[realchan].key = 1; + donote = 1; + } + if(pattern[pattnr][row][chan].note == 14) { // key off (is 14 here, cause note is only first 4 bits) + channel[realchan].key = 0; + setfreq(realchan); + } + if((channel[realchan].fx != 8 && channel[realchan].fx != 11) && // vibrato begins + (pattern[pattnr][row][chan].command == 8 || pattern[pattnr][row][chan].command == 11)) { + channel[realchan].nextfreq = channel[realchan].freq; + channel[realchan].nextoct = channel[realchan].oct; + } + if(pattern[pattnr][row][chan].note >= 14) + if((channel[realchan].fx == 8 || channel[realchan].fx == 11) && // vibrato ends + (pattern[pattnr][row][chan].command != 8 && pattern[pattnr][row][chan].command != 11)) { + channel[realchan].freq = channel[realchan].nextfreq; + channel[realchan].oct = channel[realchan].nextoct; + setfreq(realchan); + } + if(pattern[pattnr][row][chan].instrument) { // set instrument + channel[realchan].inst = pattern[pattnr][row][chan].instrument - 1; + if(inst[channel[realchan].inst].volume < 64) + channel[realchan].vol = inst[channel[realchan].inst].volume; + else + channel[realchan].vol = 63; + if(pattern[pattnr][row][chan].command != 7) + donote = 1; + } + if(pattern[pattnr][row][chan].volume != 255) + if(pattern[pattnr][row][chan].volume < 64) // set volume + channel[realchan].vol = pattern[pattnr][row][chan].volume; + else + channel[realchan].vol = 63; + channel[realchan].fx = pattern[pattnr][row][chan].command; // set command + if(pattern[pattnr][row][chan].info) // set infobyte + channel[realchan].info = pattern[pattnr][row][chan].info; + + // play note + if(donote) + playnote(realchan); + if(pattern[pattnr][row][chan].volume != 255) // set volume + setvolume(realchan); + + // command handling (row dependant) + info = channel[realchan].info; // fill infobyte cache + switch(channel[realchan].fx) { + case 1: speed = info; break; // set speed + case 2: if(info <= ord) songend = 1; ord = info; crow = 0; pattbreak = 1; break; // jump to order + case 3: if(!pattbreak) { crow = info; ord++; pattbreak = 1; } break; // pattern break + case 4: if(info > 0xf0) // fine volume down + if(channel[realchan].vol - (info & 0x0f) >= 0) + channel[realchan].vol -= info & 0x0f; + else + channel[realchan].vol = 0; + if((info & 0x0f) == 0x0f && info >= 0x1f) // fine volume up + if(channel[realchan].vol + ((info & 0xf0) >> 4) <= 63) + channel[realchan].vol += (info & 0xf0) >> 4; + else + channel[realchan].vol = 63; + setvolume(realchan); + break; + case 5: if(info > 0xf0) { // fine slide down + slide_down(realchan,(unsigned char) (info & 0x0f)); + setfreq(realchan); + } + if(info > 0xe0 && info < 0xf0) { // extra fine slide down + slide_down(realchan,(unsigned char) ((info & 0x0f) / 4)); + setfreq(realchan); + } + break; + case 6: if(info > 0xf0) { // fine slide up + slide_up(realchan,(unsigned char) (info & 0x0f)); + setfreq(realchan); + } + if(info > 0xe0 && info < 0xf0) { // extra fine slide up + slide_up(realchan,(unsigned char) ((info & 0x0f) / 4)); + setfreq(realchan); + } + break; + case 7: // tone portamento + case 8: if((channel[realchan].fx == 7 || // vibrato (remember info for dual commands) + channel[realchan].fx == 8) && pattern[pattnr][row][chan].info) + channel[realchan].dualinfo = info; + break; + case 10: channel[realchan].trigger = 0; break; // arpeggio (set trigger) + case 19: if(info == 0xb0) // set loop start + loopstart = row; + if(info > 0xb0 && info <= 0xbf) // pattern loop + if(!loopcnt) { + loopcnt = info & 0x0f; + crow = loopstart; + pattbreak = 1; + } else + if(--loopcnt > 0) { + crow = loopstart; + pattbreak = 1; + } + if((info & 0xf0) == 0xe0) // patterndelay + del = speed * (info & 0x0f) - 1; + break; + case 20: tempo = info; break; // set tempo + } + } + } + + if(!del) + del = speed - 1;// speed compensation + if(!pattbreak) { // next row (only if no manual advance) + crow++; + if(crow > 63) { + crow = 0; + ord++; + loopstart = 0; + } + } + + return !songend; // still playing +} + +void Cs3mPlayer::rewind(int subsong) +{ + // set basic variables + songend = 0; ord = 0; crow = 0; tempo = header.it; + speed = header.is; del = 0; loopstart = 0; loopcnt = 0; + + memset(channel,0,sizeof(channel)); + + opl->init(); // reset OPL chip + opl->write(1,32); // Go to ym3812 mode +} + +std::string Cs3mPlayer::gettype() +{ + char filever[5]; + + switch(header.cwtv) { // determine version number + case 0x1300: strcpy(filever,"3.00"); break; + case 0x1301: strcpy(filever,"3.01"); break; + case 0x1303: strcpy(filever,"3.03"); break; + case 0x1320: strcpy(filever,"3.20"); break; + default: strcpy(filever,"3.??"); + } + + return (std::string("Scream Tracker ") + filever); +} + +float Cs3mPlayer::getrefresh() +{ + return (float) (tempo / 2.5); +} + +/*** private methods *************************************/ + +void Cs3mPlayer::load_header(binistream *f, s3mheader *h) +{ + int i; + + f->readString(h->name, 28); + h->kennung = f->readInt(1); h->typ = f->readInt(1); + f->ignore(2); + h->ordnum = f->readInt(2); h->insnum = f->readInt(2); + h->patnum = f->readInt(2); h->flags = f->readInt(2); + h->cwtv = f->readInt(2); h->ffi = f->readInt(2); + f->readString(h->scrm, 4); + h->gv = f->readInt(1); h->is = f->readInt(1); h->it = f->readInt(1); + h->mv = f->readInt(1); h->uc = f->readInt(1); h->dp = f->readInt(1); + f->ignore(8); + h->special = f->readInt(2); + for(i = 0; i < 32; i++) h->chanset[i] = f->readInt(1); +} + +void Cs3mPlayer::setvolume(unsigned char chan) +{ + unsigned char op = op_table[chan], insnr = channel[chan].inst; + + opl->write(0x43 + op,(int)(63-((63-(inst[insnr].d03 & 63))/63.0)*channel[chan].vol) + (inst[insnr].d03 & 192)); + if(inst[insnr].d0a & 1) + opl->write(0x40 + op,(int)(63-((63-(inst[insnr].d02 & 63))/63.0)*channel[chan].vol) + (inst[insnr].d02 & 192)); +} + +void Cs3mPlayer::setfreq(unsigned char chan) +{ + opl->write(0xa0 + chan, channel[chan].freq & 255); + if(channel[chan].key) + opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2) | 32); + else + opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2)); +} + +void Cs3mPlayer::playnote(unsigned char chan) +{ + unsigned char op = op_table[chan], insnr = channel[chan].inst; + + opl->write(0xb0 + chan, 0); // stop old note + + // set instrument data + opl->write(0x20 + op, inst[insnr].d00); + opl->write(0x23 + op, inst[insnr].d01); + opl->write(0x40 + op, inst[insnr].d02); + opl->write(0x43 + op, inst[insnr].d03); + opl->write(0x60 + op, inst[insnr].d04); + opl->write(0x63 + op, inst[insnr].d05); + opl->write(0x80 + op, inst[insnr].d06); + opl->write(0x83 + op, inst[insnr].d07); + opl->write(0xe0 + op, inst[insnr].d08); + opl->write(0xe3 + op, inst[insnr].d09); + opl->write(0xc0 + chan, inst[insnr].d0a); + + // set frequency & play + channel[chan].key = 1; + setfreq(chan); +} + +void Cs3mPlayer::slide_down(unsigned char chan, unsigned char amount) +{ + if(channel[chan].freq - amount > 340) + channel[chan].freq -= amount; + else + if(channel[chan].oct > 0) { + channel[chan].oct--; + channel[chan].freq = 684; + } else + channel[chan].freq = 340; +} + +void Cs3mPlayer::slide_up(unsigned char chan, unsigned char amount) +{ + if(channel[chan].freq + amount < 686) + channel[chan].freq += amount; + else + if(channel[chan].oct < 7) { + channel[chan].oct++; + channel[chan].freq = 341; + } else + channel[chan].freq = 686; +} + +void Cs3mPlayer::vibrato(unsigned char chan, unsigned char info) +{ + unsigned char i,speed,depth; + + speed = info >> 4; + depth = (info & 0x0f) / 2; + + for(i=0;i= 64) + channel[chan].trigger -= 64; + if(channel[chan].trigger >= 16 && channel[chan].trigger < 48) + slide_down(chan,(unsigned char) (vibratotab[channel[chan].trigger - 16] / (16-depth))); + if(channel[chan].trigger < 16) + slide_up(chan,(unsigned char) (vibratotab[channel[chan].trigger + 16] / (16-depth))); + if(channel[chan].trigger >= 48) + slide_up(chan,(unsigned char) (vibratotab[channel[chan].trigger - 48] / (16-depth))); + } + setfreq(chan); +} + +void Cs3mPlayer::tone_portamento(unsigned char chan, unsigned char info) +{ + if(channel[chan].freq + (channel[chan].oct << 10) < channel[chan].nextfreq + + (channel[chan].nextoct << 10)) + slide_up(chan,info); + if(channel[chan].freq + (channel[chan].oct << 10) > channel[chan].nextfreq + + (channel[chan].nextoct << 10)) + slide_down(chan,info); + setfreq(chan); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/s3m.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/s3m.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,107 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * s3m.h - AdLib S3M Player by Simon Peter + */ + +#ifndef H_ADPLUG_S3M +#define H_ADPLUG_S3M + +#include "player.h" + +class Cs3mPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + Cs3mPlayer(Copl *newopl); + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype(); + std::string gettitle() + { return std::string(header.name); }; + + unsigned int getpatterns() + { return header.patnum; }; + unsigned int getpattern() + { return orders[ord]; }; + unsigned int getorders() + { return (header.ordnum-1); }; + unsigned int getorder() + { return ord; }; + unsigned int getrow() + { return crow; }; + unsigned int getspeed() + { return speed; }; + unsigned int getinstruments() + { return header.insnum; }; + std::string getinstrument(unsigned int n) + { return std::string(inst[n].name); }; + +protected: + struct s3mheader { + char name[28]; // song name + unsigned char kennung,typ,dummy[2]; + unsigned short ordnum,insnum,patnum,flags,cwtv,ffi; + char scrm[4]; + unsigned char gv,is,it,mv,uc,dp,dummy2[8]; + unsigned short special; + unsigned char chanset[32]; + }; + + struct s3minst { + unsigned char type; + char filename[15]; + unsigned char d00,d01,d02,d03,d04,d05,d06,d07,d08,d09,d0a,d0b,volume,dsk,dummy[2]; + unsigned long c2spd; + char dummy2[12], name[28],scri[4]; + } inst[99]; + + struct { + unsigned char note,oct,instrument,volume,command,info; + } pattern[99][64][32]; + + struct { + unsigned short freq,nextfreq; + unsigned char oct,vol,inst,fx,info,dualinfo,key,nextoct,trigger,note; + } channel[9]; + + s3mheader header; + unsigned char orders[256]; + unsigned char crow,ord,speed,tempo,del,songend,loopstart,loopcnt; + +private: + static const char chnresolv[]; + static const unsigned short notetable[12]; + static const unsigned char vibratotab[32]; + + void load_header(binistream *f, s3mheader *h); + void setvolume(unsigned char chan); + void setfreq(unsigned char chan); + void playnote(unsigned char chan); + void slide_down(unsigned char chan, unsigned char amount); + void slide_up(unsigned char chan, unsigned char amount); + void vibrato(unsigned char chan, unsigned char info); + void tone_portamento(unsigned char chan, unsigned char info); +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/sa2.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/sa2.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,263 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * sa2.cpp - SAdT2 Loader by Simon Peter + * SAdT Loader by Mamiya + */ + +#include + +#include "sa2.h" +#include "debug.h" + +CPlayer *Csa2Loader::factory(Copl *newopl) +{ + return new Csa2Loader(newopl); +} + +bool Csa2Loader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + struct { + unsigned char data[11],arpstart,arpspeed,arppos,arpspdcnt; + } insts; + unsigned char buf; + int i,j, k, notedis = 0; + const unsigned char convfx[16] = {0,1,2,3,4,5,6,255,8,255,10,11,12,13,255,15}; + unsigned char sat_type; + enum SAT_TYPE { + HAS_ARPEGIOLIST = (1 << 7), + HAS_V7PATTERNS = (1 << 6), + HAS_ACTIVECHANNELS = (1 << 5), + HAS_TRACKORDER = (1 << 4), + HAS_ARPEGIO = (1 << 3), + HAS_OLDBPM = (1 << 2), + HAS_OLDPATTERNS = (1 << 1), + HAS_UNKNOWN127 = (1 << 0) + }; + + // read header + f->readString(header.sadt, 4); + header.version = f->readInt(1); + + // file validation section + if(strncmp(header.sadt,"SAdT",4)) { fp.close(f); return false; } + switch(header.version) { + case 1: + notedis = +0x18; + sat_type = HAS_UNKNOWN127 | HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 2: + notedis = +0x18; + sat_type = HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 3: + notedis = +0x0c; + sat_type = HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 4: + notedis = +0x0c; + sat_type = HAS_ARPEGIO | HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 5: + notedis = +0x0c; + sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 6: + sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 7: + sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_V7PATTERNS; + break; + case 8: + sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_TRACKORDER; + break; + case 9: + sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_TRACKORDER | HAS_ACTIVECHANNELS; + break; + default: /* unknown */ + fp.close(f); + return false; + } + + // load section + // instruments + for(i = 0; i < 31; i++) { + if(sat_type & HAS_ARPEGIO) { + for(j = 0; j < 11; j++) insts.data[j] = f->readInt(1); + insts.arpstart = f->readInt(1); + insts.arpspeed = f->readInt(1); + insts.arppos = f->readInt(1); + insts.arpspdcnt = f->readInt(1); + inst[i].arpstart = insts.arpstart; + inst[i].arpspeed = insts.arpspeed; + inst[i].arppos = insts.arppos; + inst[i].arpspdcnt = insts.arpspdcnt; + } else { + for(j = 0; j < 11; j++) insts.data[j] = f->readInt(1); + inst[i].arpstart = 0; + inst[i].arpspeed = 0; + inst[i].arppos = 0; + inst[i].arpspdcnt = 0; + } + for(j=0;j<11;j++) + inst[i].data[j] = insts.data[j]; + inst[i].misc = 0; + inst[i].slide = 0; + } + + // instrument names + for(i = 0; i < 29; i++) f->readString(instname[i], 17); + + f->ignore(3); // dummy bytes + for(i = 0; i < 128; i++) order[i] = f->readInt(1); // pattern orders + if(sat_type & HAS_UNKNOWN127) f->ignore(127); + + // infos + nop = f->readInt(2); length = f->readInt(1); restartpos = f->readInt(1); + + // bpm + bpm = f->readInt(2); + if(sat_type & HAS_OLDBPM) { + bpm = bpm * 125 / 50; // cps -> bpm + } + + if(sat_type & HAS_ARPEGIOLIST) { + init_specialarp(); + for(i = 0; i < 256; i++) arplist[i] = f->readInt(1); // arpeggio list + for(i = 0; i < 256; i++) arpcmd[i] = f->readInt(1); // arpeggio commands + } + + for(i=0;i<64;i++) { // track orders + for(j=0;j<9;j++) { + if(sat_type & HAS_TRACKORDER) + trackord[i][j] = f->readInt(1); + else + { + trackord[i][j] = i * 9 + j; + } + } + } + + if(sat_type & HAS_ACTIVECHANNELS) + activechan = f->readInt(2); // active channels + else + activechan = 0xffff; + + AdPlug_LogWrite("Csa2Loader::load(\"%s\"): sat_type = %x, nop = %d, " + "length = %d, restartpos = %d, activechan = %x, bpm = %d\n", + filename.c_str(), sat_type, nop, length, restartpos, activechan, bpm); + + // track data + if(sat_type & HAS_OLDPATTERNS) { + i = 0; + while(!f->ateof()) { + for(j=0;j<64;j++) { + for(k=0;k<9;k++) { + buf = f->readInt(1); + tracks[i+k][j].note = buf ? (buf + notedis) : 0; + tracks[i+k][j].inst = f->readInt(1); + tracks[i+k][j].command = convfx[f->readInt(1) & 0xf]; + tracks[i+k][j].param1 = f->readInt(1); + tracks[i+k][j].param2 = f->readInt(1); + } + } + i+=9; + } + } else + if(sat_type & HAS_V7PATTERNS) { + i = 0; + while(!f->ateof()) { + for(j=0;j<64;j++) { + for(k=0;k<9;k++) { + buf = f->readInt(1); + tracks[i+k][j].note = buf >> 1; + tracks[i+k][j].inst = (buf & 1) << 4; + buf = f->readInt(1); + tracks[i+k][j].inst += buf >> 4; + tracks[i+k][j].command = convfx[buf & 0x0f]; + buf = f->readInt(1); + tracks[i+k][j].param1 = buf >> 4; + tracks[i+k][j].param2 = buf & 0x0f; + } + } + i+=9; + } + } else { + i = 0; + while(!f->ateof()) { + for(j=0;j<64;j++) { + buf = f->readInt(1); + tracks[i][j].note = buf >> 1; + tracks[i][j].inst = (buf & 1) << 4; + buf = f->readInt(1); + tracks[i][j].inst += buf >> 4; + tracks[i][j].command = convfx[buf & 0x0f]; + buf = f->readInt(1); + tracks[i][j].param1 = buf >> 4; + tracks[i][j].param2 = buf & 0x0f; + } + i++; + } + } + fp.close(f); + + // fix instrument names + for(i=0;i<29;i++) + for(j=0;j<17;j++) + if(!instname[i][j]) + instname[i][j] = ' '; + + rewind(0); // rewind module + return true; +} + +std::string Csa2Loader::gettype() +{ + char tmpstr[40]; + + sprintf(tmpstr,"Surprise! Adlib Tracker 2 (version %d)",header.version); + return std::string(tmpstr); +} + +std::string Csa2Loader::gettitle() +{ + char bufinst[29*17],buf[18]; + int i,ptr; + + // parse instrument names for song name + memset(bufinst,'\0',29*17); + for(i=0;i<29;i++) { + buf[16] = ' '; buf[17] = '\0'; + memcpy(buf,instname[i]+1,16); + for(ptr=16;ptr>0;ptr--) + if(buf[ptr] == ' ') + buf[ptr] = '\0'; + else { + if(ptr<16) + buf[ptr+1] = ' '; + break; + } + strcat(bufinst,buf); + } + + if(strchr(bufinst,'"')) + return std::string(bufinst,strchr(bufinst,'"')-bufinst+1,strrchr(bufinst,'"')-strchr(bufinst,'"')-1); + else + return std::string(); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/sa2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/sa2.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,55 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * sa2.h - SAdT2 Loader by Simon Peter + * SAdT Loader by Mamiya + */ + +#include "protrack.h" + +class Csa2Loader: public CmodPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + Csa2Loader(Copl *newopl) + : CmodPlayer(newopl) + { } + + bool load(const std::string &filename, const CFileProvider &fp); + + std::string gettype(); + std::string gettitle(); + unsigned int getinstruments() + { return 31; } + std::string getinstrument(unsigned int n) + { + if(n < 29) + return std::string(instname[n],1,16); + else + return std::string("-broken-"); + } + +private: + struct sa2header { + char sadt[4]; + unsigned char version; + } header; + + char instname[29][17]; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/silentopl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/silentopl.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,30 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999, 2000, 2001 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * silentopl.h - Silent OPL device, by Simon Peter (dn.tlp@gmx.net) + */ + +#include "opl.h" + +class CSilentopl: public Copl +{ +public: + void write(int reg, int val) { }; + void init() { }; +}; diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/sng.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/sng.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,84 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * sng.cpp - SNG Player by Simon Peter + */ + +#include "sng.h" + +CPlayer *CsngPlayer::factory(Copl *newopl) +{ + return new CsngPlayer(newopl); +} + +bool CsngPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + int i; + + // load header + f->readString(header.id, 4); + header.length = f->readInt(2); header.start = f->readInt(2); + header.loop = f->readInt(2); header.delay = f->readInt(1); + header.compressed = f->readInt(1) ? true : false; + + // file validation section + if(strncmp(header.id,"ObsM",4)) { fp.close(f); return false; } + + // load section + header.length /= 2; header.start /= 2; header.loop /= 2; + data = new Sdata [header.length]; + for(i = 0; i < header.length; i++) { + data[i].val = f->readInt(1); + data[i].reg = f->readInt(1); + } + + rewind(0); + fp.close(f); + return true; +} + +bool CsngPlayer::update() +{ + if(header.compressed && del) { + del--; + return !songend; + } + + while(data[pos].reg) { + opl->write(data[pos].reg, data[pos].val); + pos++; + if(pos >= header.length) { + songend = true; + pos = header.loop; + } + } + + if(!header.compressed) + opl->write(data[pos].reg, data[pos].val); + + if(data[pos].val) del = data[pos].val - 1; pos++; + if(pos >= header.length) { songend = true; pos = header.loop; } + return !songend; +} + +void CsngPlayer::rewind(int subsong) +{ + pos = header.start; del = header.delay; songend = false; + opl->init(); opl->write(1,32); // go to OPL2 mode +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/sng.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/sng.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,64 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * sng.h - SNG Player by Simon Peter + */ + +#ifndef H_ADPLUG_SNGPLAYER +#define H_ADPLUG_SNGPLAYER + +#include "player.h" + +class CsngPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CsngPlayer(Copl *newopl) + : CPlayer(newopl), data(0) + { }; + ~CsngPlayer() + { if(data) delete [] data; }; + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh() + { return 70.0f; }; + + std::string gettype() + { return std::string("SNG File Format"); }; + +protected: + struct { + char id[4]; + unsigned short length,start,loop; + unsigned char delay; + bool compressed; + } header; + + struct Sdata { + unsigned char val,reg; + } *data; + + unsigned char del; + unsigned short pos; + bool songend; +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/u6m.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/u6m.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,923 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * u6m.cpp - Ultima 6 Music Player by Marc Winterrowd. + * This code extends the Adlib Winamp plug-in by Simon Peter + */ + +#include "u6m.h" + +CPlayer *Cu6mPlayer::factory(Copl *newopl) +{ + return new Cu6mPlayer(newopl); +} + +bool Cu6mPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + // file validation section + // this section only checks a few *necessary* conditions + unsigned long filesize, decompressed_filesize; + binistream *f; + + f = fp.open(filename); if(!f) return false; + filesize = fp.filesize(f); + + if (filesize >= 6) + { + // check if the file has a valid pseudo-header + unsigned char pseudo_header[6]; + f->readString((char *)pseudo_header, 6); + decompressed_filesize = pseudo_header[0] + (pseudo_header[1] << 8); + + if (!( (pseudo_header[2]==0) && (pseudo_header[3]==0) && + (pseudo_header[4] + ((pseudo_header[5] & 0x1)<<8) == 0x100) && + (decompressed_filesize > (filesize-4)) )) + { + fp.close(f); + return(false); + } + } + else + { + fp.close(f); + return(false); + } + + // load section + song_data = new unsigned char[decompressed_filesize]; + unsigned char* compressed_song_data = new unsigned char[filesize-4]; + + f->seek(4); + f->readString((char *)compressed_song_data, filesize - 4); + fp.close(f); + + // attempt to decompress the song data + // if unsuccessful, deallocate song_data[] on the spot, and return(false) + data_block source, destination; + source.size = filesize-4; + source.data = compressed_song_data; + destination.size = decompressed_filesize; + destination.data = song_data; + + if (!lzw_decompress(source,destination)) + { + delete[] compressed_song_data; + delete[] song_data; + return(false); + } + + // deallocation section + delete[] compressed_song_data; + + rewind(0); + return (true); +} + + +bool Cu6mPlayer::update() +{ + if (!driver_active) + { + driver_active = true; + dec_clip(read_delay); + if (read_delay == 0) + { + command_loop(); + } + + // on all Adlib channels: freq slide/vibrato, mute factor slide + for (int i = 0; i < 9; i++) + { + if (channel_freq_signed_delta[i]!=0) + // frequency slide + mute factor slide + { + // freq slide + freq_slide(i); + + // mute factor slide + if (carrier_mf_signed_delta[i]!=0) + { + mf_slide(i); + } + } + else + // vibrato + mute factor slide + { + // vibrato + if ((vb_multiplier[i]!=0) && ((channel_freq[i].hi & 0x20)==0x20)) + { + vibrato(i); + } + + // mute factor slide + if (carrier_mf_signed_delta[i]!=0) + { + mf_slide(i); + } + } + } + + driver_active = false; + } + + return !songend; +} + + +void Cu6mPlayer::rewind(int subsong) +{ + played_ticks = 0; + songend = false; + + // set the driver's internal variables + byte_pair freq_word = {0,0}; + + driver_active = false; + song_pos = 0; + loop_position = 0; // position of the loop point + read_delay = 0; // delay (in timer ticks) before further song data is read + + for (int i = 0; i < 9; i++) + { + // frequency + channel_freq_signed_delta[i] = 0; + channel_freq[i] = freq_word; // Adlib freq settings for each channel + + // vibrato ("vb") + vb_current_value[i] = 0; + vb_double_amplitude[i] = 0; + vb_multiplier[i] = 0; + vb_direction_flag[i] = 0; + + // mute factor ("mf") == ~(volume) + carrier_mf[i] = 0; + carrier_mf_signed_delta[i] = 0; + carrier_mf_mod_delay_backup[i] = 0; + carrier_mf_mod_delay[i] = 0; + } + + while (!subsong_stack.empty()) // empty subsong stack + subsong_stack.pop(); + + opl->init(); + out_adlib(1,32); // go to OPL2 mode +} + + +float Cu6mPlayer::getrefresh() +{ + return ((float)60); // the Ultima 6 music driver expects to be called at 60 Hz +} + + +// ============================================================================================ +// +// +// Functions called by load() +// +// +// ============================================================================================ + + +// decompress from memory to memory +bool Cu6mPlayer::lzw_decompress(Cu6mPlayer::data_block source, Cu6mPlayer::data_block dest) +{ + bool end_marker_reached = false; + int codeword_size = 9; + long bits_read = 0; + int next_free_codeword = 0x102; + int dictionary_size = 0x200; + MyDict dictionary = MyDict(); + std::stack root_stack; + + long bytes_written = 0; + + int cW; + int pW; + unsigned char C; + + while (!end_marker_reached) + { + cW = get_next_codeword(bits_read, source.data, codeword_size); + switch (cW) + { + // re-init the dictionary + case 0x100: + codeword_size = 9; + next_free_codeword = 0x102; + dictionary_size = 0x200; + dictionary.reset(); + cW = get_next_codeword(bits_read, source.data, codeword_size); + output_root((unsigned char)cW, dest.data, bytes_written); + break; + // end of compressed file has been reached + case 0x101: + end_marker_reached = true; + break; + // (cW <> 0x100) && (cW <> 0x101) + default: + if (cW < next_free_codeword) // codeword is already in the dictionary + { + // create the string associated with cW (on the stack) + get_string(cW,dictionary,root_stack); + C = root_stack.top(); + // output the string represented by cW + while (!root_stack.empty()) + { + output_root(root_stack.top(), dest.data, bytes_written); + root_stack.pop(); + } + // add pW+C to the dictionary + dictionary.add(C,pW); + + next_free_codeword++; + if (next_free_codeword >= dictionary_size) + { + if (codeword_size < max_codeword_length) + { + codeword_size += 1; + dictionary_size *= 2; + } + } + } + else // codeword is not yet defined + { + // create the string associated with pW (on the stack) + get_string(pW,dictionary,root_stack); + C = root_stack.top(); + // output the string represented by pW + while (!root_stack.empty()) + { + output_root(root_stack.top(), dest.data, bytes_written); + root_stack.pop(); + } + // output the char C + output_root(C, dest.data, bytes_written); + + // the new dictionary entry must correspond to cW + // if it doesn't, something is wrong with the lzw-compressed data. + if (cW != next_free_codeword) + { +/* printf("cW != next_free_codeword!\n"); + exit(-1); */ + return false; + } + // add pW+C to the dictionary + dictionary.add(C,pW); + + next_free_codeword++; + if (next_free_codeword >= dictionary_size) + { + if (codeword_size < max_codeword_length) + { + codeword_size += 1; + dictionary_size *= 2; + } + } + }; + break; + } + // shift roles - the current cW becomes the new pW + pW = cW; + } + + return(true); // indicate successful decompression +} + + +// -------------------- +// Additional functions +// -------------------- + + +// Read the next code word from the source buffer +int Cu6mPlayer::get_next_codeword (long& bits_read, unsigned char *source, int codeword_size) +{ + unsigned char b0,b1,b2; + int codeword; + + b0 = source[bits_read/8]; + b1 = source[bits_read/8+1]; + b2 = source[bits_read/8+2]; + + codeword = ((b2 << 16) + (b1 << 8) + b0); + codeword = codeword >> (bits_read % 8); + switch (codeword_size) + { + case 0x9: + codeword = codeword & 0x1ff; + break; + case 0xa: + codeword = codeword & 0x3ff; + break; + case 0xb: + codeword = codeword & 0x7ff; + break; + case 0xc: + codeword = codeword & 0xfff; + break; + default: + codeword = -1; // indicates that an error has occurred + break; + } + + bits_read += codeword_size; + return (codeword); +} + + +// output a root to memory +void Cu6mPlayer::output_root(unsigned char root, unsigned char *destination, long& position) +{ + destination[position] = root; + position++; +} + + +// output the string represented by a codeword +void Cu6mPlayer::get_string(int codeword, Cu6mPlayer::MyDict& dictionary, std::stack& root_stack) +{ + unsigned char root; + int current_codeword; + + current_codeword = codeword; + + while (current_codeword > 0xff) + { + root = dictionary.get_root(current_codeword); + current_codeword = dictionary.get_codeword(current_codeword); + root_stack.push(root); + } + + // push the root at the leaf + root_stack.push((unsigned char)current_codeword); +} + + +// ============================================================================================ +// +// +// Functions called by update() +// +// +// ============================================================================================ + + +// This function reads the song data and executes the embedded commands. +void Cu6mPlayer::command_loop() +{ + unsigned char command_byte; // current command byte + int command_nibble_hi; // command byte, bits 4-7 + int command_nibble_lo; // command byte, bite 0-3 + bool repeat_loop = true; // + + do + { + // extract low and high command nibbles + command_byte = read_song_byte(); // implicitly increments song_pos + command_nibble_hi = command_byte >> 4; + command_nibble_lo = command_byte & 0xf; + + switch (command_nibble_hi) + { + case 0x0: command_0(command_nibble_lo); break; + case 0x1: command_1(command_nibble_lo); break; + case 0x2: command_2(command_nibble_lo); break; + case 0x3: command_3(command_nibble_lo); break; + case 0x4: command_4(command_nibble_lo); break; + case 0x5: command_5(command_nibble_lo); break; + case 0x6: command_6(command_nibble_lo); break; + case 0x7: command_7(command_nibble_lo); break; + case 0x8: + switch (command_nibble_lo) + { + case 1: command_81(); break; + case 2: command_82(); repeat_loop = false; break; + case 3: command_83(); break; + case 5: command_85(); break; + case 6: command_86(); break; + default: break; // maybe generate an error? + } + break; + case 0xE: command_E(); break; + case 0xF: command_F(); break; + default: break; // maybe generate an error? + } + + } while (repeat_loop); +} + + +// -------------------------------------------------------- +// The commands supported by the U6 music file format +// -------------------------------------------------------- + +// ---------------------------------------- +// Set octave and frequency, note off +// Format: 0c nn +// c = channel, nn = packed Adlib frequency +// ---------------------------------------- +void Cu6mPlayer::command_0(int channel) +{ + unsigned char freq_byte; + byte_pair freq_word; + + freq_byte = read_song_byte(); + freq_word = expand_freq_byte(freq_byte); + set_adlib_freq(channel,freq_word); +} + + +// --------------------------------------------------- +// Set octave and frequency, old note off, new note on +// Format: 1c nn +// c = channel, nn = packed Adlib frequency +// --------------------------------------------------- +void Cu6mPlayer::command_1(int channel) +{ + unsigned char freq_byte; + byte_pair freq_word; + + vb_direction_flag[channel] = 0; + vb_current_value[channel] = 0; + + freq_byte = read_song_byte(); + freq_word = expand_freq_byte(freq_byte); + set_adlib_freq(channel,freq_word); + + freq_word.hi = freq_word.hi | 0x20; // note on + set_adlib_freq(channel,freq_word); +} + + +// ---------------------------------------- +// Set octave and frequency, note on +// Format: 2c nn +// c = channel, nn = packed Adlib frequency +// ---------------------------------------- +void Cu6mPlayer::command_2(int channel) +{ + unsigned char freq_byte; + byte_pair freq_word; + + freq_byte = read_song_byte(); + freq_word = expand_freq_byte(freq_byte); + freq_word.hi = freq_word.hi | 0x20; // note on + set_adlib_freq(channel,freq_word); +} + + +// -------------------------------------- +// Set "carrier mute factor"==not(volume) +// Format: 3c nn +// c = channel, nn = mute factor +// -------------------------------------- +void Cu6mPlayer::command_3(int channel) +{ + unsigned char mf_byte; + + carrier_mf_signed_delta[channel] = 0; + mf_byte = read_song_byte(); + set_carrier_mf(channel,mf_byte); +} + + +// ---------------------------------------- +// set "modulator mute factor"==not(volume) +// Format: 4c nn +// c = channel, nn = mute factor +// ---------------------------------------- +void Cu6mPlayer::command_4(int channel) +{ + unsigned char mf_byte; + + mf_byte = read_song_byte(); + set_modulator_mf(channel,mf_byte); +} + + +// -------------------------------------------- +// Set portamento (pitch slide) +// Format: 5c nn +// c = channel, nn = signed channel pitch delta +// -------------------------------------------- +void Cu6mPlayer::command_5(int channel) +{ + channel_freq_signed_delta[channel] = read_signed_song_byte(); +} + + +// -------------------------------------------- +// Set vibrato paramters +// Format: 6c mn +// c = channel +// m = vibrato double amplitude +// n = vibrato multiplier +// -------------------------------------------- +void Cu6mPlayer::command_6(int channel) +{ + unsigned char vb_parameters; + + vb_parameters = read_song_byte(); + vb_double_amplitude[channel] = vb_parameters >> 4; // high nibble + vb_multiplier[channel] = vb_parameters & 0xF; // low nibble +} + + +// ---------------------------------------- +// Assign Adlib instrument to Adlib channel +// Format: 7c nn +// c = channel, nn = instrument number +// ---------------------------------------- +void Cu6mPlayer::command_7(int channel) +{ + int instrument_offset = instrument_offsets[read_song_byte()]; + out_adlib_opcell(channel, false, 0x20, *(song_data + instrument_offset+0)); + out_adlib_opcell(channel, false, 0x40, *(song_data + instrument_offset+1)); + out_adlib_opcell(channel, false, 0x60, *(song_data + instrument_offset+2)); + out_adlib_opcell(channel, false, 0x80, *(song_data + instrument_offset+3)); + out_adlib_opcell(channel, false, 0xE0, *(song_data + instrument_offset+4)); + out_adlib_opcell(channel, true, 0x20, *(song_data + instrument_offset+5)); + out_adlib_opcell(channel, true, 0x40, *(song_data + instrument_offset+6)); + out_adlib_opcell(channel, true, 0x60, *(song_data + instrument_offset+7)); + out_adlib_opcell(channel, true, 0x80, *(song_data + instrument_offset+8)); + out_adlib_opcell(channel, true, 0xE0, *(song_data + instrument_offset+9)); + out_adlib(0xC0+channel, *(song_data + instrument_offset+10)); +} + + +// ------------------------------------------- +// Branch to a new subsong +// Format: 81 nn aa bb +// nn == number of times to repeat the subsong +// aa == subsong offset (low byte) +// bb == subsong offset (high byte) +// ------------------------------------------- +void Cu6mPlayer::command_81() +{ + subsong_info new_ss_info; + + new_ss_info.subsong_repetitions = read_song_byte(); + new_ss_info.subsong_start = read_song_byte(); new_ss_info.subsong_start += read_song_byte() << 8; + new_ss_info.continue_pos = song_pos; + + subsong_stack.push(new_ss_info); + song_pos = new_ss_info.subsong_start; +} + + +// ------------------------------------------------------------ +// Stop interpreting commands for this timer tick +// Format: 82 nn +// nn == delay (in timer ticks) until further data will be read +// ------------------------------------------------------------ +void Cu6mPlayer::command_82() +{ + read_delay = read_song_byte(); +} + + +// ----------------------------- +// Adlib instrument data follows +// Format: 83 nn <11 bytes> +// nn == instrument number +// ----------------------------- +void Cu6mPlayer::command_83() +{ + unsigned char instrument_number = read_song_byte(); + instrument_offsets[instrument_number] = song_pos; + song_pos += 11; +} + + +// ---------------------------------------------- +// Set -1 mute factor slide (upward volume slide) +// Format: 85 cn +// c == channel +// n == slide delay +// ---------------------------------------------- +void Cu6mPlayer::command_85() +{ + unsigned char data_byte = read_song_byte(); + int channel = data_byte >> 4; // high nibble + unsigned char slide_delay = data_byte & 0xF; // low nibble + carrier_mf_signed_delta[channel] = +1; + carrier_mf_mod_delay[channel] = slide_delay + 1; + carrier_mf_mod_delay_backup[channel] = slide_delay + 1; +} + + +// ------------------------------------------------ +// Set +1 mute factor slide (downward volume slide) +// Format: 86 cn +// c == channel +// n == slide speed +// ------------------------------------------------ +void Cu6mPlayer::command_86() +{ + unsigned char data_byte = read_song_byte(); + int channel = data_byte >> 4; // high nibble + unsigned char slide_delay = data_byte & 0xF; // low nibble + carrier_mf_signed_delta[channel] = -1; + carrier_mf_mod_delay[channel] = slide_delay + 1; + carrier_mf_mod_delay_backup[channel] = slide_delay + 1; +} + + +// -------------- +// Set loop point +// Format: E? +// -------------- +void Cu6mPlayer::command_E() +{ + loop_position = song_pos; +} + + +// --------------------------- +// Return from current subsong +// Format: F? +// --------------------------- +void Cu6mPlayer::command_F() +{ + if (!subsong_stack.empty()) + { + subsong_info temp = subsong_stack.top(); + subsong_stack.pop(); + temp.subsong_repetitions--; + if (temp.subsong_repetitions==0) + { + song_pos = temp.continue_pos; + } + else + { + song_pos = temp.subsong_start; + subsong_stack.push(temp); + } + } + else + { + song_pos = loop_position; + songend = true; + } +} + + +// -------------------- +// Additional functions +// -------------------- + +// This function decrements its argument, without allowing it to become negative. +void Cu6mPlayer::dec_clip(int& param) +{ + param--; + if (param < 0) { param = 0; } +} + + +// Returns the byte at the current song position. +// Side effect: increments song_pos. +unsigned char Cu6mPlayer::read_song_byte() +{ + unsigned char song_byte; + song_byte = song_data[song_pos]; + song_pos++; + return(song_byte); +} + + +// Same as read_song_byte(), except that it returns a signed byte +signed char Cu6mPlayer::read_signed_song_byte() +{ + unsigned char song_byte; + int signed_value; + song_byte = *(song_data + song_pos); + song_pos++; + if (song_byte <= 127) + { + signed_value = song_byte; + } + else + { + signed_value = (int)song_byte - 0x100; + } + return((signed char)signed_value); +} + + +Cu6mPlayer::byte_pair Cu6mPlayer::expand_freq_byte(unsigned char freq_byte) +{ + const byte_pair freq_table[24] = + { + {0x00,0x00}, {0x58,0x01}, {0x82,0x01}, {0xB0,0x01}, + {0xCC,0x01}, {0x03,0x02}, {0x41,0x02}, {0x86,0x02}, + {0x00,0x00}, {0x6A,0x01}, {0x96,0x01}, {0xC7,0x01}, + {0xE4,0x01}, {0x1E,0x02}, {0x5F,0x02}, {0xA8,0x02}, + {0x00,0x00}, {0x47,0x01}, {0x6E,0x01}, {0x9A,0x01}, + {0xB5,0x01}, {0xE9,0x01}, {0x24,0x02}, {0x66,0x02} + }; + + int packed_freq; + int octave; + byte_pair freq_word; + + packed_freq = freq_byte & 0x1F; + octave = freq_byte >> 5; + + // range check (not present in the original U6 music driver) + if (packed_freq >= 24) { packed_freq = 0; } + + freq_word.hi = freq_table[packed_freq].hi + (octave << 2); + freq_word.lo = freq_table[packed_freq].lo; + + return(freq_word); +} + + +void Cu6mPlayer::set_adlib_freq(int channel,Cu6mPlayer::byte_pair freq_word) +{ + out_adlib(0xA0+channel,freq_word.lo); + out_adlib(0xB0+channel,freq_word.hi); + // update the Adlib register backups + channel_freq[channel] = freq_word; +} + + +// this function sets the Adlib frequency, but does not update the register backups +void Cu6mPlayer::set_adlib_freq_no_update(int channel,Cu6mPlayer::byte_pair freq_word) +{ + out_adlib(0xA0+channel,freq_word.lo); + out_adlib(0xB0+channel,freq_word.hi); +} + + +void Cu6mPlayer::set_carrier_mf(int channel,unsigned char mute_factor) +{ + out_adlib_opcell(channel,true,0x40,mute_factor); + carrier_mf[channel] = mute_factor; +} + + +void Cu6mPlayer::set_modulator_mf(int channel,unsigned char mute_factor) +{ + out_adlib_opcell(channel,false,0x40,mute_factor); +} + + +void Cu6mPlayer::freq_slide(int channel) +{ + byte_pair freq = channel_freq[channel]; + + long freq_word = freq.lo + (freq.hi << 8) + channel_freq_signed_delta[channel]; + if (freq_word < 0) { freq_word += 0x10000; } + if (freq_word > 0xFFFF) { freq_word -= 0x10000; } + + freq.lo = freq_word & 0xFF; + freq.hi = (freq_word >> 8) & 0xFF; + set_adlib_freq(channel,freq); +} + + +void Cu6mPlayer::vibrato(int channel) +{ + byte_pair freq; + + if (vb_current_value[channel] >= vb_double_amplitude[channel]) + { vb_direction_flag[channel] = 1; } + else if (vb_current_value[channel] <= 0) + { vb_direction_flag[channel] = 0; } + + if (vb_direction_flag[channel]==0) + { vb_current_value[channel]++; } + else + { vb_current_value[channel]--; } + + long freq_word = channel_freq[channel].lo + (channel_freq[channel].hi << 8); + freq_word += (vb_current_value[channel] - (vb_double_amplitude[channel] >> 1)) + * vb_multiplier[channel]; + if (freq_word < 0) { freq_word += 0x10000; } + if (freq_word > 0xFFFF) { freq_word -= 0x10000; } + + freq.lo = freq_word & 0xFF; + freq.hi = (freq_word >> 8) & 0xFF; + set_adlib_freq_no_update(channel,freq); +} + + +void Cu6mPlayer::mf_slide(int channel) +{ + carrier_mf_mod_delay[channel]--; + if (carrier_mf_mod_delay[channel]==0) + { + carrier_mf_mod_delay[channel] = carrier_mf_mod_delay_backup[channel]; + int current_mf = carrier_mf[channel] + carrier_mf_signed_delta[channel]; + if (current_mf > 0x3F) + { + current_mf = 0x3F; + carrier_mf_signed_delta[channel] = 0; + } + else if (current_mf < 0) + { + current_mf = 0; + carrier_mf_signed_delta[channel] = 0; + } + + set_carrier_mf(channel,(unsigned char)current_mf); + } +} + + +void Cu6mPlayer::out_adlib(unsigned char adlib_register, unsigned char adlib_data) +{ + opl->write(adlib_register,adlib_data); +} + + +void Cu6mPlayer::out_adlib_opcell(int channel, bool carrier, unsigned char adlib_register, unsigned char out_byte) +{ + const unsigned char adlib_channel_to_carrier_offset[9] = + {0x03,0x04,0x05,0x0B,0x0C,0x0D,0x13,0x14,0x15}; + const unsigned char adlib_channel_to_modulator_offset[9] = + {0x00,0x01,0x02,0x08,0x09,0x0A,0x10,0x11,0x12}; + + if (carrier) + { + out_adlib(adlib_register+adlib_channel_to_carrier_offset[channel],out_byte); + } + else + { + out_adlib(adlib_register+adlib_channel_to_modulator_offset[channel],out_byte); + } +} + + +// ============================================================================================ +// +// +// The Dictionary +// +// +// ============================================================================================ + + +Cu6mPlayer::MyDict::MyDict() +{ + dict_size = default_dict_size; + dictionary = new dict_entry[dict_size-0x100]; // don't allocate space for the roots + contains = 0x102; +} + + +Cu6mPlayer::MyDict::MyDict(int max_size) +{ + dict_size = max_size; + dictionary = new dict_entry[dict_size-0x100]; // don't allocate space for the roots + contains = 0x102; +} + + +// re-initializes the dictionary +void Cu6mPlayer::MyDict::reset() +{ + contains = 0x102; +} + + +// Note: If the dictionary is already full, this function does nothing. +void Cu6mPlayer::MyDict::add(unsigned char root, int codeword) +{ + if (contains < dict_size) + { + dictionary[contains-0x100].root = root; + dictionary[contains-0x100].codeword = codeword; + contains++; + } +} + + +unsigned char Cu6mPlayer::MyDict::get_root(int codeword) +{ + return (dictionary[codeword-0x100].root); +} + + +int Cu6mPlayer::MyDict::get_codeword(int codeword) +{ + return (dictionary[codeword-0x100].codeword); +} + diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/u6m.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/u6m.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,168 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * u6m.h - Ultima 6 Music Player by Marc Winterrowd. + * This code extends the Adlib Winamp plug-in by Simon Peter + */ + +#include + +#include "player.h" + +#define default_dict_size 4096 // because maximum codeword size == 12 bits +#define max_codeword_length 12 // maximum codeword length in bits + +class Cu6mPlayer: public CPlayer +{ + public: + static CPlayer *factory(Copl *newopl); + + Cu6mPlayer(Copl *newopl) : CPlayer(newopl), song_data(0) + { + }; + + + ~Cu6mPlayer() + { + if(song_data) delete[] song_data; + }; + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype() + { + return std::string("Ultima 6 Music"); + }; + + + protected: + + struct byte_pair + { + unsigned char lo; + unsigned char hi; + }; + + struct subsong_info // information about a subsong + { + int continue_pos; + int subsong_repetitions; + int subsong_start; + }; + + struct dict_entry // dictionary entry + { + unsigned char root; + int codeword; + }; + + struct data_block // + { + long size; + unsigned char *data; + }; + + class MyDict + { + private: + // The actual number of dictionary entries allocated + // is (dictionary_size-256), because there are 256 roots + // that do not need to be stored. + int contains; // number of entries currently in the dictionary + int dict_size; // max number of entries that will fit into the dictionary + dict_entry* dictionary; + + public: + MyDict(); // use dictionary size of 4096 + MyDict(int); // let the caller specify a dictionary size + void reset(); // re-initializes the dictionary + void add(unsigned char, int); + unsigned char get_root(int); + int get_codeword(int); + }; + + + // class variables + long played_ticks; + + unsigned char* song_data; // the uncompressed .m file (the "song") + bool driver_active; // flag to prevent reentrancy + bool songend; // indicates song end + int song_pos; // current offset within the song + int loop_position; // position of the loop point + int read_delay; // delay (in timer ticks) before further song data is read + std::stack subsong_stack; + + int instrument_offsets[9]; // offsets of the adlib instrument data + // vibrato ("vb") + unsigned char vb_current_value[9]; + unsigned char vb_double_amplitude[9]; + unsigned char vb_multiplier[9]; + unsigned char vb_direction_flag[9]; + // mute factor ("mf") = not(volume) + unsigned char carrier_mf[9]; + signed char carrier_mf_signed_delta[9]; + unsigned char carrier_mf_mod_delay_backup[9]; + unsigned char carrier_mf_mod_delay[9]; + // frequency + byte_pair channel_freq[9]; // adlib freq settings for each channel + signed char channel_freq_signed_delta[9]; + + // protected functions used by update() + void command_loop(); + unsigned char read_song_byte(); + signed char read_signed_song_byte(); + void dec_clip(int&); + byte_pair expand_freq_byte(unsigned char); + void set_adlib_freq(int channel,byte_pair freq_word); + void set_adlib_freq_no_update(int channel,byte_pair freq_word); + void set_carrier_mf(int channel,unsigned char mute_factor); + void set_modulator_mf(int channel,unsigned char mute_factor); + void freq_slide(int channel); + void vibrato(int channel); + void mf_slide(int channel); + + void command_0(int channel); + void command_1(int channel); + void command_2(int channel); + void command_3(int channel); + void command_4(int channel); + void command_5(int channel); + void command_6(int channel); + void command_7(int channel); + void command_81(); + void command_82(); + void command_83(); + void command_85(); + void command_86(); + void command_E(); + void command_F(); + + void out_adlib(unsigned char adlib_register, unsigned char adlib_data); + void out_adlib_opcell(int channel, bool carrier, unsigned char adlib_register, unsigned char out_byte); + + // protected functions used by load() + bool lzw_decompress(data_block source, data_block dest); + int get_next_codeword (long& bits_read, unsigned char *source, int codeword_size); + void output_root(unsigned char root, unsigned char *destination, long& position); + void get_string(int codeword, MyDict& dictionary, std::stack& root_stack); +}; + diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/xad.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/xad.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,140 @@ +/* + Adplug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2003 Simon Peter, , et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + xad.cpp - XAD shell player by Riven the Mage +*/ + +#include "xad.h" +#include "debug.h" + +/* -------- Public Methods -------------------------------- */ + +CxadPlayer::CxadPlayer(Copl * newopl) : CPlayer(newopl) +{ + tune = 0; +} + +CxadPlayer::~CxadPlayer() +{ + if (tune) + delete [] tune; +} + +bool CxadPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + bool ret = false; + + // load header + xad.id = f->readInt(4); + f->readString(xad.title, 36); + f->readString(xad.author, 36); + xad.fmt = f->readInt(2); + xad.speed = f->readInt(1); + xad.reserved_a = f->readInt(1); + + // 'XAD!' - signed ? + if(xad.id != 0x21444158) { fp.close(f); return false; } + + // get file size + tune_size = fp.filesize(f) - 80; + + // load() + tune = new unsigned char [tune_size]; + f->readString((char *)tune, tune_size); + fp.close(f); + + ret = xadplayer_load(); + + if (ret) + rewind(0); + + return ret; +} + +void CxadPlayer::rewind(int subsong) +{ + opl->init(); + + plr.speed = xad.speed; + plr.speed_counter = 1; + plr.playing = 1; + plr.looping = 0; + + // rewind() + xadplayer_rewind(subsong); + +#ifdef DEBUG + AdPlug_LogWrite("-----------\n"); +#endif +} + +bool CxadPlayer::update() +{ + if (--plr.speed_counter) + goto update_end; + + plr.speed_counter = plr.speed; + + // update() + xadplayer_update(); + +update_end: + return (plr.playing && (!plr.looping)); +} + +float CxadPlayer::getrefresh() +{ + return xadplayer_getrefresh(); +} + +std::string CxadPlayer::gettype() +{ + return xadplayer_gettype(); +} + +std::string CxadPlayer::gettitle() +{ + return xadplayer_gettitle(); +} + +std::string CxadPlayer::getauthor() +{ + return xadplayer_getauthor(); +} + +std::string CxadPlayer::getinstrument(unsigned int i) +{ + return xadplayer_getinstrument(i); +} + +unsigned int CxadPlayer::getinstruments() +{ + return xadplayer_getinstruments(); +} + +/* -------- Protected Methods ------------------------------- */ + +void CxadPlayer::opl_write(int reg, int val) +{ + adlib[reg] = val; +#ifdef DEBUG + AdPlug_LogWrite("[ %02X ] = %02X\n",reg,val); +#endif + opl->write(reg,val); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/xad.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/xad.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,97 @@ +/* + AdPlug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2003 Simon Peter , et al. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + xad.h - XAD shell player by Riven the Mage +*/ + +#ifndef H_ADPLUG_XAD +#define H_ADPLUG_XAD + +#include "player.h" + +class CxadPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl); + + CxadPlayer(Copl * newopl); + ~CxadPlayer(); + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype(); + std::string gettitle(); + std::string getauthor(); + std::string getinstrument(unsigned int i); + unsigned int getinstruments(); + +protected: + virtual void xadplayer_rewind(int subsong) = 0; + virtual bool xadplayer_load() = 0; + virtual void xadplayer_update() = 0; + virtual float xadplayer_getrefresh() = 0; + virtual std::string xadplayer_gettype() = 0; + virtual std::string xadplayer_gettitle() + { + return std::string(xad.title); + } + virtual std::string xadplayer_getauthor() + { + return std::string(xad.author); + } + virtual std::string xadplayer_getinstrument(unsigned int i) + { + return std::string(""); + } + virtual unsigned int xadplayer_getinstruments() + { + return 0; + } + + enum { HYP=1, PSI, FLASH, BMF, RAT, HYBRID }; + + struct xad_header + { + unsigned long id; + char title[36]; + char author[36]; + unsigned short fmt; + unsigned char speed; + unsigned char reserved_a; + } xad; + + unsigned char * tune; + unsigned long tune_size; + + struct + { + int playing; + int looping; + unsigned char speed; + unsigned char speed_counter; + } plr; + + unsigned char adlib[256]; + + void opl_write(int reg, int val); +}; + +#endif diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/xsm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/xsm.cpp Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,117 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * xsm.cpp - eXtra Simple Music Player, by Simon Peter + */ + +#include + +#include "xsm.h" + +CxsmPlayer::CxsmPlayer(Copl *newopl) + : CPlayer(newopl), music(0) +{ +} + +CxsmPlayer::~CxsmPlayer() +{ + if(music) delete [] music; +} + +bool CxsmPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[6]; + int i, j; + + // check if header matches + f->readString(id, 6); songlen = f->readInt(2); + if(strncmp(id, "ofTAZ!", 6) || songlen > 3200) { fp.close(f); return false; } + + // read and set instruments + for(i = 0; i < 9; i++) { + opl->write(0x20 + op_table[i], f->readInt(1)); + opl->write(0x23 + op_table[i], f->readInt(1)); + opl->write(0x40 + op_table[i], f->readInt(1)); + opl->write(0x43 + op_table[i], f->readInt(1)); + opl->write(0x60 + op_table[i], f->readInt(1)); + opl->write(0x63 + op_table[i], f->readInt(1)); + opl->write(0x80 + op_table[i], f->readInt(1)); + opl->write(0x83 + op_table[i], f->readInt(1)); + opl->write(0xe0 + op_table[i], f->readInt(1)); + opl->write(0xe3 + op_table[i], f->readInt(1)); + opl->write(0xc0 + op_table[i], f->readInt(1)); + f->ignore(5); + } + + // read song data + music = new char [songlen * 9]; + for(i = 0; i < 9; i++) + for(j = 0; j < songlen; j++) + music[j * 9 + i] = f->readInt(1); + + // success + fp.close(f); + rewind(0); + return true; +} + +bool CxsmPlayer::update() +{ + int c; + + if(notenum >= songlen) { + songend = true; + notenum = last = 0; + } + + for(c = 0; c < 9; c++) + if(music[notenum * 9 + c] != music[last * 9 + c]) + opl->write(0xb0 + c, 0); + + for(c = 0; c < 9; c++) { + if(music[notenum * 9 + c]) + play_note(c, music[notenum * 9 + c] % 12, music[notenum * 9 + c] / 12); + else + play_note(c, 0, 0); + } + + last = notenum; + notenum++; + return !songend; +} + +void CxsmPlayer::rewind(int subsong) +{ + notenum = last = 0; + songend = false; +} + +float CxsmPlayer::getrefresh() +{ + return 5.0f; +} + +void CxsmPlayer::play_note(int c, int note, int octv) +{ + int freq = note_table[note]; + + if(!note && !octv) freq = 0; + opl->write(0xa0 + c, freq & 0xff); + opl->write(0xb0 + c, (freq / 0xff) | 32 | (octv * 4)); +} diff -r 70075730e187 -r 8df427a314a8 Plugins/Input/adplug/core/xsm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/xsm.h Fri Dec 30 16:31:39 2005 -0800 @@ -0,0 +1,46 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003 Simon Peter, , et al. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * xsm.h - eXtra Simple Music Player, by Simon Peter + */ + +#include "player.h" + +class CxsmPlayer: public CPlayer +{ +public: + static CPlayer *factory(Copl *newopl) { return new CxsmPlayer(newopl); } + + CxsmPlayer(Copl *newopl); + ~CxsmPlayer(); + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype() { return std::string("eXtra Simple Music"); } + +private: + unsigned short songlen; + char *music; + unsigned int last, notenum; + bool songend; + + void play_note(int c, int note, int octv); +}; diff -r 70075730e187 -r 8df427a314a8 configure.ac --- a/configure.ac Fri Dec 30 14:17:35 2005 -0800 +++ b/configure.ac Fri Dec 30 16:31:39 2005 -0800 @@ -326,6 +326,22 @@ fi AM_CONDITIONAL([HAVE_LIRC], test "$have_lirc" = "yes") +dnl *** AdPlug requirement (libbinio) _ZN8binfbase3posEv + +AC_ARG_ENABLE(adplug, + [ --disable-adplug disable AdPlug plugin (default=enabled)], + [enable_adplug=$enableval], + [enable_adplug="yes"] +) + +if test "$enable_lirc" = "yes"; then + AC_CHECK_LIB([binio],[_ZN8binfbase3posEv],[have_adplug=yes],[have_adplug=no]) +else + AC_MSG_RESULT([*** AdPlug plugin disabled per user request ***]) + have_adplug="no" +fi +AM_CONDITIONAL([HAVE_ADPLUG], test "$have_lirc" = "yes") + dnl *** Ogg Vorbis AC_ARG_ENABLE(vorbis, @@ -804,6 +820,8 @@ Plugins/Input/timidity/libtimidity/Makefile Plugins/Input/timidity/src/Makefile Plugins/Input/sexypsf/Makefile + Plugins/Input/adplug/Makefile + Plugins/Input/adplug/core/Makefile Plugins/Visualization/Makefile Plugins/Visualization/blur_scope/Makefile Plugins/Visualization/libvisual-proxy/Makefile @@ -871,6 +889,7 @@ echo " Commodore 64 audio (sid): $have_sidplay" echo " Game music (spc, nsf & gbs): yes" echo " PlayStation audio (sexypsf): yes" +echo " AdLib synthesizer (adplug): $have_adplug" echo echo " General" echo " -------"