Mercurial > audlegacy-plugins
view src/adplug/core/rat.cxx @ 1086:cd854e8ced20 trunk
[svn] - vtx: convert to plugin API v2
author | nenolod |
---|---|
date | Thu, 24 May 2007 23:09:03 -0700 |
parents | 4709ce4e209e |
children |
line wrap: on
line source
/* * Adplug - Replayer for many OPL2/OPL3 audio file formats. * Copyright (C) 1999 - 2003 Simon Peter, <dn.tlp@gmx.net>, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * [xad] RAT player, by Riven the Mage <riven@ok.ru> */ /* - 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 short patseg = (rat.hdr.patseg[1] << 8) + rat.hdr.patseg[0]; unsigned char *event_ptr = &tune[patseg << 4]; for (int i = 0; i < rat.hdr.numpat; i++) for (int j = 0; j < 64; j++) for (int k = 0; k < rat.hdr.numchan; k++) { memcpy (&rat.tracks[i][j][k], event_ptr, sizeof (rat_event)); event_ptr += sizeof (rat_event); } return true; } void CxadratPlayer::xadplayer_rewind (int subsong) { int i; rat.order_pos = rat.hdr.order_start; rat.pattern_pos = 0; rat.volume = rat.hdr.volume; plr.speed = rat.hdr.speed; // clear channel data memset (&rat.channel, 0, sizeof (rat.channel[0]) * 9); // init OPL opl_write (0x01, 0x20); opl_write (0x08, 0x00); opl_write (0xBD, 0x00); // set default frequencies for (i = 0; i < 9; i++) { opl_write (0xA0 + i, 0x00); opl_write (0xA3 + i, 0x00); opl_write (0xB0 + i, 0x00); opl_write (0xB3 + i, 0x00); } // set default volumes for (i = 0; i < 0x1F; i++) opl_write (0x40 + i, 0x3F); } void CxadratPlayer::xadplayer_update () { int i; rat_event event; // process events for (i = 0; i < rat.hdr.numchan; i++) { memcpy (&event, &rat.tracks[rat.order[rat.order_pos]][rat.pattern_pos][i], sizeof (rat_event)); #ifdef DEBUG AdPlug_LogWrite ("order %02X, pattern %02X, row %02X, channel %02X, event %02X %02X %02X %02X %02X:\n", rat.order_pos, rat.order[rat.order_pos], rat.pattern_pos, i, event.note, event.instrument, event.volume, event.fx, event.fxp); #endif // is instrument ? if (event.instrument != 0xFF) { rat.channel[i].instrument = event.instrument - 1; rat.channel[i].volume = rat.inst[event.instrument - 1].volume; } // is volume ? if (event.volume != 0xFF) rat.channel[i].volume = event.volume; // is note ? if (event.note != 0xFF) { // mute channel opl_write (0xB0 + i, 0x00); opl_write (0xA0 + i, 0x00); // if note != 0xFE then play if (event.note != 0xFE) { unsigned char ins = rat.channel[i].instrument; // synthesis/feedback opl_write (0xC0 + i, rat.inst[ins].connect); // controls opl_write (0x20 + rat_adlib_bases[i], rat.inst[ins].mod_ctrl); opl_write (0x20 + rat_adlib_bases[i + 9], rat.inst[ins].car_ctrl); // volumes opl_write (0x40 + rat_adlib_bases[i], __rat_calc_volume (rat.inst[ins].mod_volume, rat.channel[i].volume, rat.volume)); opl_write (0x40 + rat_adlib_bases[i + 9], __rat_calc_volume (rat.inst[ins].car_volume, rat.channel[i].volume, rat.volume)); // attack/decay opl_write (0x60 + rat_adlib_bases[i], rat.inst[ins].mod_AD); opl_write (0x60 + rat_adlib_bases[i + 9], rat.inst[ins].car_AD); // sustain/release opl_write (0x80 + rat_adlib_bases[i], rat.inst[ins].mod_SR); opl_write (0x80 + rat_adlib_bases[i + 9], rat.inst[ins].car_SR); // waveforms opl_write (0xE0 + rat_adlib_bases[i], rat.inst[ins].mod_wave); opl_write (0xE0 + rat_adlib_bases[i + 9], rat.inst[ins].car_wave); // octave/frequency unsigned short insfreq = (rat.inst[ins].freq[1] << 8) + rat.inst[ins].freq[0]; unsigned short freq = insfreq * rat_notes[event.note & 0x0F] / 0x20AB; opl_write (0xA0 + i, freq & 0xFF); opl_write (0xB0 + i, (freq >> 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 < rat.hdr.numchan; i++) { unsigned char old_order_pos = rat.order_pos; switch (rat.channel[i].fx) { case 0x01: // 0x01: Set Speed plr.speed = rat.channel[i].fxp; break; case 0x02: // 0x02: Position Jump if (rat.channel[i].fxp < rat.hdr.order_end) rat.order_pos = rat.channel[i].fxp; else rat.order_pos = 0; // jumpback ? if (rat.order_pos <= old_order_pos) plr.looping = 1; rat.pattern_pos = 0; break; case 0x03: // 0x03: Pattern Break (?) rat.pattern_pos = 0x40; break; } rat.channel[i].fx = 0; } // end of pattern ? if (rat.pattern_pos >= 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; }