changeset 964:368f8ee0a95f trunk

[svn] Sync with upstream. Subsong improvements for ADL, new JBM player.
author chainsaw
date Wed, 18 Apr 2007 07:38:58 -0700
parents 9549fea94794
children f1642ee1115c
files ChangeLog src/adplug/core/Makefile src/adplug/core/adl.cxx src/adplug/core/adl.h src/adplug/core/adplug.cxx src/adplug/core/d00.cxx src/adplug/core/d00.h src/adplug/core/jbm.cxx src/adplug/core/jbm.h src/adplug/core/player.h
diffstat 10 files changed, 430 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Apr 17 14:45:19 2007 -0700
+++ b/ChangeLog	Wed Apr 18 07:38:58 2007 -0700
@@ -1,3 +1,23 @@
+2007-04-17 21:45:19 +0000  Tony Vroon <chainsaw@gentoo.org>
+  revision [2066]
+  Warning fixes from SuSe.
+  trunk/src/alarm/alarm.c                    |    5 ++-
+  trunk/src/amidi-plug/backend-alsa/b-alsa.c |    3 -
+  trunk/src/amidi-plug/i_configure-alsa.c    |    3 +
+  trunk/src/cdaudio/cddb.c                   |   38 ++++++++++++++++++++---
+  trunk/src/esd/audio.c                      |    1 
+  trunk/src/modplug/archive/arch_bz2.cxx     |   14 ++++++--
+  trunk/src/modplug/archive/arch_gzip.cxx    |   47 +++++++++++++++++++++++------
+  trunk/src/modplug/archive/arch_rar.cxx     |   21 +++++++++++-
+  trunk/src/modplug/archive/arch_zip.cxx     |    3 +
+  trunk/src/modplug/sndfile.cxx              |    6 ++-
+  trunk/src/paranormal/plugin.c              |    1 
+  trunk/src/paranormal/presets.c             |   10 +++---
+  trunk/src/wma/libffwma/mem.c               |    3 +
+  trunk/src/xspf/urlencode.c                 |    2 -
+  14 files changed, 123 insertions(+), 34 deletions(-)
+
+
 2007-04-16 08:35:24 +0000  Giacomo Lozito <james@develia.org>
   revision [2064]
   - statusicon: added support for quit button in smallmenu; also, the field is being prepared for customizable smallmenu entries
--- a/src/adplug/core/Makefile	Tue Apr 17 14:45:19 2007 -0700
+++ b/src/adplug/core/Makefile	Wed Apr 18 07:38:58 2007 -0700
@@ -9,7 +9,8 @@
 a2m.cxx adtrack.cxx amd.cxx bam.cxx d00.cxx dfm.cxx dmo.cxx hsp.cxx ksm.cxx \
 mad.cxx mid.cxx mkj.cxx cff.cxx dtm.cxx fmc.cxx mtk.cxx rad.cxx raw.cxx \
 sa2.cxx s3m.cxx xad.cxx flash.cxx bmf.cxx hybrid.cxx hyp.cxx psi.cxx rat.cxx \
-u6m.cxx rol.cxx xsm.cxx dro.cxx lds.cxx temuopl.cxx msc.cxx rix.cxx adl.cxx
+u6m.cxx rol.cxx xsm.cxx dro.cxx lds.cxx temuopl.cxx msc.cxx rix.cxx adl.cxx \
+jbm.cxx
 
 SOURCES = $(C_SOURCES) $(CXX_SOURCES)
 
@@ -18,7 +19,7 @@
 protrack.h rad.h raw.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 fprovide.h \
 database.h players.h xsm.h adlibemu.h kemuopl.h dro.h dmo.h s3m.h temuopl.h \
-msc.h rix.h adl.h
+msc.h rix.h adl.h jbm.h
 
 CXXFLAGS += $(PICFLAGS) $(BINIO_CFLAGS) -I../../../../intl -I../../../.. -Dstricmp=strcasecmp $(BEEP_DEFINES)
 CFLAGS += $(PICFLAGS) $(BINIO_CFLAGS) -I../../../../intl -I../../../.. -Dstricmp=strcasecmp $(BEEP_DEFINES)
--- a/src/adplug/core/adl.cxx	Tue Apr 17 14:45:19 2007 -0700
+++ b/src/adplug/core/adl.cxx	Wed Apr 18 07:38:58 2007 -0700
@@ -2807,17 +2807,22 @@
 
   //    _soundFileLoaded = file;
 
-  for (int i = 0; i < 200; i++)
-    if (_trackEntries[i] != 0xff)
+  // find last subsong
+  for(int i = 199; i >= 0; i--)
+    if(_trackEntries[i] != 0xff) {
       numsubsongs = i + 1;
-
+      break;
+    }
   fp.close (f);
+  cursubsong = 2;
+  rewind();
   return true;
 }
 
 void
 CadlPlayer::rewind (int subsong)
 {
+  if(subsong == -1) subsong = cursubsong;
   opl->init ();
   opl->write (1, 32);
   playSoundEffect (subsong);
--- a/src/adplug/core/adl.h	Tue Apr 17 14:45:19 2007 -0700
+++ b/src/adplug/core/adl.h	Wed Apr 18 07:38:58 2007 -0700
@@ -1,6 +1,20 @@
 /*
  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2007 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  * 
  * adl.h - ADL player adaption by Simon Peter <dn.tlp@gmx.net>
  */
@@ -24,7 +38,7 @@
 
   bool load(VFSFile *fd, const CFileProvider &fp);
   bool update();
-  void rewind(int subsong);
+  void rewind(int subsong = -1);
 
   // refresh rate is fixed at 72Hz
   float getrefresh()
@@ -33,6 +47,7 @@
     }
 
   unsigned int getsubsongs();
+  unsigned int getsubsong() { return cursubsong; }
   std::string gettype() { return std::string("Westwood ADL"); }
 
  private:
--- a/src/adplug/core/adplug.cxx	Tue Apr 17 14:45:19 2007 -0700
+++ b/src/adplug/core/adplug.cxx	Wed Apr 18 07:38:58 2007 -0700
@@ -64,6 +64,7 @@
 #include "msc.h"
 #include "rix.h"
 #include "adl.h"
+#include "jbm.h"
 
 /***** Defines *****/
 
@@ -112,6 +113,7 @@
   CPlayerDesc (CmscPlayer::factory, "Adlib MSC Player", ".msc\0"),
   CPlayerDesc (CrixPlayer::factory, "Softstar RIX OPL Music", ".rix\0"),
   CPlayerDesc (CadlPlayer::factory, "Westwood ADL", ".adl\0"),
+  CPlayerDesc (CjbmPlayer::factory, "Johannes Bjerregaard", ".jbm\0"),
   CPlayerDesc ()
 };
 
--- a/src/adplug/core/d00.cxx	Tue Apr 17 14:45:19 2007 -0700
+++ b/src/adplug/core/d00.cxx	Wed Apr 18 07:38:58 2007 -0700
@@ -485,6 +485,8 @@
   } *tpoin;
   int i;
 
+  if(subsong == -1) subsong = cursubsong;
+
   if (version > 1)
   {                             // do nothing if subsong > number of subsongs
     if (subsong >= header->subsongs)
@@ -524,6 +526,7 @@
   songend = 0;
   opl->init ();
   opl->write (1, 32);           // reset OPL chip
+  cursubsong = subsong;
 }
 
 std::string Cd00Player::gettype ()
--- a/src/adplug/core/d00.h	Tue Apr 17 14:45:19 2007 -0700
+++ b/src/adplug/core/d00.h	Wed Apr 18 07:38:58 2007 -0700
@@ -89,7 +89,7 @@
 		unsigned char duration,ptr;
 	} *levpuls;
 
-	unsigned char songend,version;
+	unsigned char songend,version,cursubsong;
 	char *datainfo;
 	unsigned short *seqptr;
 	d00header *header;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/adplug/core/jbm.cxx	Wed Apr 18 07:38:58 2007 -0700
@@ -0,0 +1,294 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2007 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Johannes Bjerregaard's JBM Adlib Music Format player for AdPlug
+ * Written by Dennis Lindroos <lindroos@nls.fi>, February-March 2007
+ * - Designed and coded from scratch (only frequency-table taken from MUSIC.BIN)
+ * - The percussion mode is buggy (?) but i'm not good enough to find them
+ *   and honestly i think the melodic-mode tunes are much better ;)
+ *
+ * This version doesn't use the binstr.h functions (coded with custom func.)
+ * This is my first attempt on writing a musicplayer for AdPlug, and i'm not
+ * coding C++ very often.. 
+ *
+ * Released under the terms of the GNU General Public License.
+ */
+
+#include "jbm.h"
+
+static const unsigned short notetable[96] = {
+  0x0158, 0x016d, 0x0183, 0x019a, 0x01b2, 0x01cc, 0x01e7, 0x0204,
+  0x0223, 0x0244, 0x0266, 0x028b, 0x0558, 0x056d, 0x0583, 0x059a,
+  0x05b2, 0x05cc, 0x05e7, 0x0604, 0x0623, 0x0644, 0x0666, 0x068b,
+  0x0958, 0x096d, 0x0983, 0x099a, 0x09b2, 0x09cc, 0x09e7, 0x0a04,
+  0x0a23, 0x0a44, 0x0a66, 0x0a8b, 0x0d58, 0x0d6d, 0x0d83, 0x0d9a,
+  0x0db2, 0x0dcc, 0x0de7, 0x0e04, 0x0e23, 0x0e44, 0x0e66, 0x0e8b,
+  0x1158, 0x116d, 0x1183, 0x119a, 0x11b2, 0x11cc, 0x11e7, 0x1204,
+  0x1223, 0x1244, 0x1266, 0x128b, 0x1558, 0x156d, 0x1583, 0x159a,
+  0x15b2, 0x15cc, 0x15e7, 0x1604, 0x1623, 0x1644, 0x1666, 0x168b,
+  0x1958, 0x196d, 0x1983, 0x199a, 0x19b2, 0x19cc, 0x19e7, 0x1a04,
+  0x1a23, 0x1a44, 0x1a66, 0x1a8b, 0x1d58, 0x1d6d, 0x1d83, 0x1d9a,
+  0x1db2, 0x1dcc, 0x1de7, 0x1e04, 0x1e23, 0x1e44, 0x1e66, 0x1e8b
+};
+
+static const unsigned char percmx_tab[4] = { 0x14, 0x12, 0x15, 0x11 };
+static const unsigned char perchn_tab[5] = { 6, 7, 8, 8, 7 };
+static unsigned char percmaskoff[5] = { 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
+static unsigned char percmaskon[5] =  { 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+static inline unsigned short GET_WORD(unsigned char *b, int x)
+{
+  return ((unsigned short)(b[x+1] << 8) | b[x]);
+}
+
+/*** public methods *************************************/
+
+CPlayer *CjbmPlayer::factory(Copl *newopl)
+{
+  return new CjbmPlayer(newopl);
+}
+
+bool CjbmPlayer::load(VFSFile * fd, const CFileProvider & fp)
+{
+  binistream *f = fp.open (fd);
+  std::string filename (fd->uri);
+  int		filelen = fp.filesize(f);
+  int		i;
+
+  if (!filelen || !fp.extension(filename, ".jbm")) goto loaderr;
+
+  // Allocate memory buffer m[] and read entire file into it
+
+  m = new unsigned char[filelen];
+  if (f->readString((char *)m, filelen) != filelen) goto loaderr;
+
+  fp.close(f);
+
+  // The known .jbm files always seem to start with the number 0x0002
+
+  if (GET_WORD(m, 0) != 0x0002)
+    return false;
+
+  // Song tempo
+
+  i = GET_WORD(m, 2);
+  timer = 1193810.0 / (i ? i : 0xffff);
+
+  seqtable = GET_WORD(m, 4);
+  instable = GET_WORD(m, 6);
+
+  // The flags word has atleast 1 bit, the Adlib's rhythm mode, but
+  // currently we don't support that :(
+
+  flags = GET_WORD(m, 8);
+
+  // Instrument datas are directly addressed with m[] 
+
+  inscount = (filelen - instable) >> 4;
+
+  // Voice' and sequence pointers
+
+  seqcount = 0xffff;
+  for (i = 0; i < 11; i++) {
+    voice[i].trkpos = voice[i].trkstart = GET_WORD(m, 10 + (i<<1));
+    if (voice[i].trkpos && voice[i].trkpos < seqcount)
+      seqcount = voice[i].trkpos;
+  }
+  seqcount = (seqcount - seqtable) >> 1;
+  sequences = new unsigned short[seqcount];
+  for (i = 0; i < seqcount; i++) 
+    sequences[i] = GET_WORD(m, seqtable + (i<<1));
+
+  rewind(0);
+  return true;
+ loaderr:
+  fp.close(f);
+  return false;
+}
+
+bool CjbmPlayer::update()
+{
+  short c, spos, frq;
+
+  for (c = 0; c < 11; c++) {
+    if (!voice[c].trkpos)		// Unused channel
+      continue;
+
+    if (--voice[c].delay)
+      continue;
+
+    // Turn current note/percussion off
+
+    if (voice[c].note&0x7f)
+      opl_noteonoff(c, &voice[c], 0);
+
+    // Process events until we have a note
+
+    spos = voice[c].seqpos;
+    while(!voice[c].delay) {
+      switch(m[spos]) {
+      case 0xFD:	// Set Instrument
+	voice[c].instr = m[spos+1];
+	set_opl_instrument(c, &voice[c]);
+	spos+=2;
+	break;
+      case 0xFF:	// End of Sequence
+	voice[c].seqno = m[++voice[c].trkpos];
+	if (voice[c].seqno == 0xff) {
+	  voice[c].trkpos = voice[c].trkstart;
+	  voice[c].seqno = m[voice[c].trkpos];
+	  //voicemask &= 0x7ff-(1<<c);
+	  voicemask &= ~(1<<c);
+	}
+	spos = voice[c].seqpos = sequences[voice[c].seqno];
+	break;
+      default:	// Note Event
+	if ((m[spos] & 127) > 95)
+	  return 0;
+
+	voice[c].note = m[spos];
+	voice[c].vol = m[spos+1];
+	voice[c].delay =
+	  (m[spos+2] + (m[spos+3]<<8)) + 1;
+
+	frq = notetable[voice[c].note&127];
+	voice[c].frq[0] = (unsigned char)frq;
+	voice[c].frq[1] = frq >> 8;
+	spos+=4;
+      }
+    }
+    voice[c].seqpos = spos;
+
+    // Write new volume to the carrier operator, or percussion
+
+    if (flags&1 && c > 6)
+      opl->write(0x40 + percmx_tab[c-7], voice[c].vol ^ 0x3f);
+    else
+      opl->write(0x43 + op_table[c], voice[c].vol ^ 0x3f);
+
+    // Write new frequencies and Gate bit
+
+    opl_noteonoff(c, &voice[c], !(voice[c].note & 0x80));
+  }
+  return (voicemask);
+}
+
+void CjbmPlayer::rewind(int subsong)
+{
+  int c;
+
+  voicemask = 0;
+
+  for (c = 0; c < 11; c++) {
+    voice[c].trkpos = voice[c].trkstart;
+
+    if (!voice[c].trkpos) continue;
+
+    voicemask |= (1<<c);
+
+    voice[c].seqno = m[voice[c].trkpos];
+    voice[c].seqpos = sequences[voice[c].seqno];
+
+    voice[c].note = 0;
+    voice[c].delay = 1;
+  }
+
+  opl->init();
+  opl->write(0x01, 32);
+
+  // Set rhythm mode if flags bit #0 is set
+  // AM and Vibrato are full depths (taken from DosBox RAW output)
+  bdreg = 0xC0 | (flags&1)<<5;
+
+  opl->write(0xbd, bdreg);
+
+#if 0
+  if (flags&1) {
+    voice[7].frq[0] = 0x58; voice[7].frq[1] = 0x09; // XXX
+    voice[8].frq[0] = 0x04; voice[8].frq[1] = 0x0a; // XXX
+    opl_noteonoff(7, &voice[7], 0);
+    opl_noteonoff(8, &voice[8], 0);
+  }
+#endif
+
+  return;
+}
+
+/*** private methods ************************************/
+
+void CjbmPlayer::opl_noteonoff(int channel, JBMVoice *v, bool state)
+{
+  if (flags&1 && channel > 5) {
+    // Percussion
+    opl->write(0xa0 + perchn_tab[channel-6], voice[channel].frq[0]);
+    opl->write(0xb0 + perchn_tab[channel-6], voice[channel].frq[1]);
+    opl->write(0xbd,
+	       state ? bdreg | percmaskon[channel-6] :
+	       bdreg & percmaskoff[channel-6]);
+  } else {
+    // Melodic mode or Rhythm mode melodic channels
+    opl->write(0xa0 + channel, voice[channel].frq[0]);
+    opl->write(0xb0 + channel,
+	       state ? voice[channel].frq[1] | 0x20 :
+	       voice[channel].frq[1] & 0x1f);
+  }
+  return;
+}
+
+
+void CjbmPlayer::set_opl_instrument(int channel, JBMVoice *v)
+{
+  short i = instable + (v->instr << 4);
+
+  // Sanity check on instr number - or we'll be reading outside m[] !
+
+  if (v->instr >= inscount)
+    return;
+
+  // For rhythm mode, multiplexed drums. I don't care about waveforms!
+  if ((flags&1) & (channel > 6)) {
+    opl->write(0x20 + percmx_tab[channel-7], m[i+0]);
+    opl->write(0x40 + percmx_tab[channel-7], m[i+1] ^ 0x3f);
+    opl->write(0x60 + percmx_tab[channel-7], m[i+2]);
+    opl->write(0x80 + percmx_tab[channel-7], m[i+3]);
+
+    opl->write(0xc0 + perchn_tab[channel-6], m[i+8]&15);
+    return;
+  }
+
+  // AM/VIB/EG/KSR/FRQMUL, KSL/OUTPUT, ADSR for 1st operator
+  opl->write(0x20 + op_table[channel], m[i+0]);
+  opl->write(0x40 + op_table[channel], m[i+1] ^ 0x3f);
+  opl->write(0x60 + op_table[channel], m[i+2]);
+  opl->write(0x80 + op_table[channel], m[i+3]);
+
+  // AM/VIB/EG/KSR/FRQMUL, KSL/OUTPUT, ADSR for 2nd operator
+  opl->write(0x23 + op_table[channel], m[i+4]);
+  opl->write(0x43 + op_table[channel], m[i+5] ^ 0x3f);
+  opl->write(0x63 + op_table[channel], m[i+6]);
+  opl->write(0x83 + op_table[channel], m[i+7]);
+
+  // WAVEFORM for operators
+  opl->write(0xe0 + op_table[channel], (m[i+8]>>4)&3);
+  opl->write(0xe3 + op_table[channel], (m[i+8]>>6)&3);
+
+  // FEEDBACK/FM mode
+  opl->write(0xc0 + channel, m[i+8]&15);
+	
+  return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/adplug/core/jbm.h	Wed Apr 18 07:38:58 2007 -0700
@@ -0,0 +1,80 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2007 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * jbm.h - JBM Player by Dennis Lindroos <lindroos@nls.fi>
+ */
+
+#ifndef H_ADPLUG_JBMPLAYER
+#define H_ADPLUG_JBMPLAYER
+
+#include "player.h"
+
+class CjbmPlayer: public CPlayer
+{
+ public:
+  static CPlayer *factory(Copl *newopl);
+
+  CjbmPlayer(Copl *newopl) : CPlayer(newopl), m(0)
+    { }
+  ~CjbmPlayer()
+    { if(m != NULL) delete [] m; }
+
+  bool load(VFSFile *fd, const CFileProvider &fp);
+  bool update();
+  void rewind(int subsong);
+
+  float getrefresh()
+    { return timer; }
+
+  std::string gettype()
+    {
+      return std::string(flags&1 ? "JBM Adlib Music [rhythm mode]" :
+			 "JBM Adlib Music");
+    }
+  std::string getauthor()
+    { return std::string("Johannes Bjerregaard"); }
+
+ protected:
+
+  unsigned char *m;
+  float timer;
+  unsigned short flags, voicemask;
+  unsigned short seqtable, seqcount;
+  unsigned short instable, inscount;
+  unsigned short *sequences;
+  unsigned char bdreg; 
+
+  typedef struct {
+    unsigned short trkpos, trkstart, seqpos;
+    unsigned char seqno, note;
+    short vol;
+    short delay;
+    short instr;
+    unsigned char frq[2];
+    unsigned char ivol, dummy;
+  } JBMVoice;
+
+  JBMVoice voice[11];
+
+ private:
+  //void calc_opl_frequency(JBMVoice *);
+  void set_opl_instrument(int, JBMVoice *); 
+  void opl_noteonoff(int, JBMVoice *, bool);
+};
+
+#endif
--- a/src/adplug/core/player.h	Tue Apr 17 14:45:19 2007 -0700
+++ b/src/adplug/core/player.h	Wed Apr 18 07:38:58 2007 -0700
@@ -67,6 +67,8 @@
 	{ return 0; }
 	virtual unsigned int getsubsongs()	// returns number of subsongs
 	{ return 1; }
+	virtual unsigned int getsubsong()       // returns current subsong
+	{ return 0; }
 	virtual unsigned int getinstruments()	// returns number of instruments
 	{ return 0; }
 	virtual std::string getinstrument(unsigned int n)	// returns n-th instrument name