Mercurial > audlegacy-plugins
diff src/Input/adplug/core/rat.cxx @ 0:13389e613d67 trunk
[svn] - initial import of audacious-plugins tree (lots to do)
author | nenolod |
---|---|
date | Mon, 18 Sep 2006 01:11:49 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Input/adplug/core/rat.cxx Mon Sep 18 01:11:49 2006 -0700 @@ -0,0 +1,292 @@ +/* + * 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; +}