diff src/adplug/core/rat.cxx @ 12:3da1b8942b8b trunk

[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author nenolod
date Mon, 18 Sep 2006 03:14:20 -0700
parents src/Input/adplug/core/rat.cxx@13389e613d67
children 4709ce4e209e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/adplug/core/rat.cxx	Mon Sep 18 03:14:20 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;
+}