Mercurial > audlegacy-plugins
changeset 952:87666f9bf6d0 trunk
[svn] Upstream commit "Vastly enhanced generic Protracker player and modified loaders accordingly.
Copl now supports a getchip() method. A2M loader enhanced for OPL3 features." manually applied by decoding the actual changes from an ocean of whitespace damage. It compiles, but do test it.
author | chainsaw |
---|---|
date | Fri, 13 Apr 2007 09:09:50 -0700 |
parents | df18b664f4e0 |
children | ae7e96e44f22 |
files | ChangeLog src/adplug/core/a2m.cxx src/adplug/core/a2m.h src/adplug/core/amd.cxx src/adplug/core/fmc.cxx src/adplug/core/opl.h src/adplug/core/player.cxx src/adplug/core/player.h src/adplug/core/protrack.cxx src/adplug/core/protrack.h src/adplug/core/rad.cxx src/adplug/core/sa2.cxx |
diffstat | 12 files changed, 393 insertions(+), 235 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Fri Apr 13 08:07:32 2007 -0700 +++ b/ChangeLog Fri Apr 13 09:09:50 2007 -0700 @@ -1,3 +1,11 @@ +2007-04-13 15:07:32 +0000 Tony Vroon <chainsaw@gentoo.org> + revision [2036] + D00 Vibrato and Slides fix by Dennis Lindroos (from upstream CVS). + trunk/src/adplug/core/d00.cxx | 11 +++++++++-- + trunk/src/adplug/core/d00.h | 4 ++-- + 2 files changed, 11 insertions(+), 4 deletions(-) + + 2007-04-13 12:23:27 +0000 Giacomo Lozito <james@develia.org> revision [2034] - curl: do NOT use signals with the new multi-thread layout, and take care of the url string value
--- a/src/adplug/core/a2m.cxx Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/a2m.cxx Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2002 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 @@ -22,13 +22,11 @@ * This loader detects and loads version 1, 4, 5 & 8 files. * * version 1-4 files: - * Following commands are ignored: - * FF1 - FF9, FAx - FEx + * 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 + * Following commands are ignored: Gxy, Hxy, Kxy - &xy */ #include "a2m.h" @@ -63,15 +61,11 @@ bool Ca2mLoader::load(VFSFile *fd, const CFileProvider &fp) { binistream *f = fp.open(fd); if(!f) return false; - struct { - char id[10]; - unsigned long crc; - unsigned char version,numpats; - } ch; + char id[10]; int i,j,k,t; unsigned int l; - unsigned char *org = 0, *orgptr; - unsigned long alength; + unsigned char *org, *orgptr, flags = 0, numpats, version; + unsigned long crc, 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}; @@ -80,29 +74,29 @@ 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); + f->readString(id, 10); crc = f->readInt(4); + version = f->readInt(1); 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)) { + if(strncmp(id,"_A2module_",10) || (version != 1 && version != 5 && + version != 4 && 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) { + nop = numpats; length = 128; restartpos = 0; + if(version < 5) { for(i=0;i<5;i++) len[i] = f->readInt(2); t = 9; - } else { + } else { // version >= 5 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) { + if(version == 1 || version == 5) { for(i=0;i<len[0]/2;i++) secdata[i] = f->readInt(2); org = new unsigned char [MAXBUF]; orgptr = org; sixdepak(secdata,org,len[0]); @@ -113,6 +107,7 @@ 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); @@ -125,56 +120,60 @@ 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) + if(version < 5) inst[i].misc = *(orgptr+i*13+11); - else - inst[i].misc = 0; + else { // version >= 5 -> OPL3 format + int pan = *(orgptr+i*13+11); + + if(pan) + inst[i].data[0] |= (pan & 3) << 4; // set pan + else + inst[i].data[0] |= 48; // enable both speakers + } + 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; org = 0; - } - delete [] secdata; secdata = 0; + bpm = *orgptr; orgptr++; + initspeed = *orgptr; orgptr++; + if(version >= 5) flags = *orgptr; + if(version == 1 || 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++) + for(i = 0; i < (version < 5 ? numpats / 16 : numpats / 8); i++) alength += len[i+2]; secdata = new unsigned short [alength / 2]; - if(ch.version == 1 || ch.version == 5) { + if(version == 1 || version == 5) { for(l=0;l<alength/2;l++) secdata[l] = f->readInt(2); - org = new unsigned char [MAXBUF * (ch.numpats / (ch.version == 1 ? 16 : 8) + 1)]; + org = new unsigned char [MAXBUF * (numpats / (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) + if(version == 1) { + if(numpats > 16) orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2; - if(ch.numpats > 32) + if(numpats > 32) orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2; - if(ch.numpats > 48) + if(numpats > 48) sixdepak(secptr,orgptr,len[4]); } else { - if(ch.numpats > 8) + if(numpats > 8) orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2; - if(ch.numpats > 16) + if(numpats > 16) orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2; - if(ch.numpats > 24) + if(numpats > 24) orgptr += sixdepak(secptr,orgptr,len[4]); secptr += len[4] / 2; - if(ch.numpats > 32) + if(numpats > 32) orgptr += sixdepak(secptr,orgptr,len[5]); secptr += len[5] / 2; - if(ch.numpats > 40) + if(numpats > 40) orgptr += sixdepak(secptr,orgptr,len[6]); secptr += len[6] / 2; - if(ch.numpats > 48) + if(numpats > 48) orgptr += sixdepak(secptr,orgptr,len[7]); secptr += len[7] / 2; - if(ch.numpats > 56) + if(numpats > 56) sixdepak(secptr,orgptr,len[8]); } delete [] secdata; secdata = 0; @@ -183,69 +182,100 @@ for(l=0;l<alength;l++) org[l] = f->readInt(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<ch.numpats;i++) + if(version < 5) { + for(i=0;i<numpats;i++) for(j=0;j<64;j++) for(k=0;k<9;k++) { - tracks[i*9+k][j].note = org[i*64*t*4+j*t*4+k*4] == 255 ? 127 : org[i*64*t*4+j*t*4+k*4]; - tracks[i*9+k][j].inst = org[i*64*t*4+j*t*4+k*4+1]; - tracks[i*9+k][j].command = convfx[org[i*64*t*4+j*t*4+k*4+2]]; - tracks[i*9+k][j].param2 = org[i*64*t*4+j*t*4+k*4+3] & 0x0f; - if(tracks[i*9+k][j].command != 14) - tracks[i*9+k][j].param1 = org[i*64*t*4+j*t*4+k*4+3] >> 4; + struct Tracks *track = &tracks[i * 9 + k][j]; + unsigned char *o = &org[i*64*t*4+j*t*4+k*4]; + + track->note = o[0] == 255 ? 127 : o[0]; + track->inst = o[1]; + track->command = convfx[o[2]]; + track->param2 = o[3] & 0x0f; + if(track->command != 14) + track->param1 = o[3] >> 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; + track->param1 = convinf1[o[3] >> 4]; + if(track->param1 == 15 && !track->param2) { // convert key-off + track->command = 8; + track->param1 = 0; + track->param2 = 0; } } - if(tracks[i*9+k][j].command == 14) { - switch(tracks[i*9+k][j].param1) { + if(track->command == 14) { + switch(track->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; + track->command = 25; + track->param1 = track->param2; + track->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; + track->command = 26; + track->param1 = track->param2; + track->param2 = 0; break; case 9: // convert volume slide down - tracks[i*9+k][j].command = 26; - tracks[i*9+k][j].param1 = 0; + track->command = 26; + track->param1 = 0; break; } } } - } else { - for(i=0;i<ch.numpats;i++) - for(j=0;j<9;j++) + } else { // version >= 5 + realloc_patterns(64, 64, 18); + + for(i=0;i<numpats;i++) + for(j=0;j<18;j++) for(k=0;k<64;k++) { - tracks[i*9+j][k].note = org[i*64*t*4+j*64*4+k*4] == 255 ? 127 : org[i*64*t*4+j*64*4+k*4]; - tracks[i*9+j][k].inst = org[i*64*t*4+j*64*4+k*4+1]; - tracks[i*9+j][k].command = newconvfx[org[i*64*t*4+j*64*4+k*4+2]]; - tracks[i*9+j][k].param1 = org[i*64*t*4+j*64*4+k*4+3] >> 4; - tracks[i*9+j][k].param2 = org[i*64*t*4+j*64*4+k*4+3] & 0x0f; + struct Tracks *track = &tracks[i * 18 + j][k]; + unsigned char *o = &org[i*64*t*4+j*64*4+k*4]; + + track->note = o[0] == 255 ? 127 : o[0]; + track->inst = o[1]; + track->command = newconvfx[o[2]]; + track->param1 = o[3] >> 4; + track->param2 = o[3] & 0x0f; + + // Convert '&' command + if(o[2] == 36) + switch(track->param1) { + case 0: // pattern delay (frames) + track->command = 29; + track->param1 = 0; + // param2 already set correctly + break; + + case 1: // pattern delay (rows) + track->command = 14; + track->param1 = 8; + // param2 already set correctly + break; + } } } - if(ch.version == 1 || ch.version == 5) + init_trackord(); + + if(version == 1 || version == 5) { - delete [] org; org = 0; + delete [] org; } else { - delete [] secdata; secdata = 0; + delete [] secdata; } - fp.close(f); - rewind(0); - return true; + + // Process flags + if(version >= 5) { + CmodPlayer::flags |= Opl3; // All versions >= 5 are OPL3 + if(flags & 8) CmodPlayer::flags |= Tremolo; // Tremolo depth + if(flags & 16) CmodPlayer::flags |= Vibrato; // Vibrato depth + } + + fp.close(f); + rewind(0); + return true; } float Ca2mLoader::getrefresh()
--- a/src/adplug/core/a2m.h Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/a2m.h Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2002 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 @@ -19,6 +19,9 @@ * a2m.h - A2M Loader by Simon Peter <dn.tlp@gmx.net> */ +#ifndef H_ADPLUG_A2MLOADER +#define H_ADPLUG_A2MLOADER + #include "protrack.h" class Ca2mLoader: public CmodPlayer @@ -78,3 +81,5 @@ dad[ADPLUG_A2M_TWICEMAX+1], freq[ADPLUG_A2M_TWICEMAX+1], *wdbuf; unsigned char *obuf, *buf; }; +#endif +
--- a/src/adplug/core/amd.cxx Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/amd.cxx Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* * 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 @@ -130,7 +130,7 @@ fp.close(f); // convert to protracker replay data - bpm = 50; restartpos = 0; activechan = 0xffff; flags = Decimal; + bpm = 50; restartpos = 0; flags = Decimal; for(i=0;i<26;i++) { // convert instruments buf = inst[i].data[0]; buf2 = inst[i].data[1];
--- a/src/adplug/core/fmc.cxx Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/fmc.cxx Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* Adplug - Replayer for many OPL2/OPL3 audio file formats. - Copyright (C) 1999 - 2003 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 @@ -149,7 +149,7 @@ } // data for Protracker - activechan = (0xffff >> (16 - header.numchan)) << (16 - header.numchan); + activechan = (0xffffffff >> (32 - header.numchan)) << (32 - header.numchan); nop = t / header.numchan; restartpos = 0;
--- a/src/adplug/core/opl.h Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/opl.h Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* * 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 @@ -45,6 +45,11 @@ currChip = n; } + virtual int getchip() // returns current OPL chip + { + return currChip; + } + virtual void init(void) = 0; // reinitialize OPL chip(s) // return this OPL chip's type
--- a/src/adplug/core/player.cxx Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/player.cxx Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2003 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
--- a/src/adplug/core/player.h Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/player.h Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2004 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 @@ -77,7 +77,7 @@ 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 + static const unsigned char op_table[9]; // the 9 operators as expected by the OPL }; #endif
--- a/src/adplug/core/protrack.cxx Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/protrack.cxx Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* * 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 @@ -21,7 +21,7 @@ * 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 + * derivatives. It is derived from the former SA2 player. If you got a * Protracker-like format, this is most certainly the player you want to use. */ @@ -43,7 +43,8 @@ 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) + nop(0), activechan(0xffffffff), flags(Standard), curchip(opl->getchip()), + nrows(0), npats(0), nchans(0) { realloc_order(128); realloc_patterns(64, 64, 9); @@ -58,16 +59,18 @@ 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; + unsigned char pattbreak=0, donote, pattnr, chan, oplchan, info1, + info2, info, pattern_delay; + unsigned short track; + unsigned long row; if(!speed) // song full stop return !songend; // effect handling (timer dependant) - for(chan=0;chan<nchans;chan++) { + for(chan = 0; chan < nchans; chan++) { + oplchan = set_opl_chip(chan); + if(arplist && arpcmd && inst[channel[chan].inst].arpstart) // special arpeggio if(channel[chan].arpspdcnt) channel[chan].arpspdcnt--; @@ -84,11 +87,11 @@ 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); + opl->write(0xe3 + op_table[oplchan], arpcmd[channel[chan].arppos] / 10 - 1); if(arpcmd[channel[chan].arppos] % 10) - opl->write(0xe0 + op_table[chan], (arpcmd[channel[chan].arppos] % 10) - 1); + opl->write(0xe0 + op_table[oplchan], (arpcmd[channel[chan].arppos] % 10) - 1); if(arpcmd[channel[chan].arppos] < 10) // ????? - opl->write(0xe0 + op_table[chan], arpcmd[channel[chan].arppos] - 1); + opl->write(0xe0 + op_table[oplchan], arpcmd[channel[chan].arppos] - 1); } } if(arpcmd[channel[chan].arppos] != 252) { @@ -185,19 +188,19 @@ } // arrangement handling - if(ord >= length) { - songend = 1; // set end-flag - ord = restartpos; - } + if(!resolve_order()) return !songend; pattnr = order[ord]; if(!rw) AdPlug_LogWrite("\nCmodPlayer::update(): Pattern: %d, Order: %d\n", pattnr, ord); AdPlug_LogWrite("CmodPlayer::update():%3d|", rw); // play row + pattern_delay = 0; row = rw; - for(chan=0;chan<nchans;chan++) { - if(!(activechan >> (15 - chan)) & 1) { // channel active? + for(chan = 0; chan < nchans; chan++) { + oplchan = set_opl_chip(chan); + + if(!(activechan >> (31 - chan)) & 1) { // channel active? AdPlug_LogWrite("N/A|"); continue; } @@ -246,30 +249,36 @@ 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]; + case 3: // tone portamento + if(tracks[track][row].note) { + if(tracks[track][row].note < 13) + channel[chan].nextfreq = notetable[tracks[track][row].note - 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(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; - } + + case 4: // vibrato (remember vars) + if(info) { + 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; @@ -277,7 +286,10 @@ 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 11: // position jump + pattbreak = 1; rw = 0; if(info < ord) songend = 1; ord = info; break; + case 12: // set volume channel[chan].vol1 = info; channel[chan].vol2 = info; @@ -287,35 +299,54 @@ channel[chan].vol2 = 63; setvolume(chan); break; - case 13: if(!pattbreak) { pattbreak = 1; rw = info; ord++; } break; // pattern break + + case 13: // pattern break + if(!pattbreak) { pattbreak = 1; rw = info; ord++; } break; + case 14: // extended command switch(info1) { - case 0: if(info2) // define cell-tremolo - regbd |= 128; - else - regbd &= 127; + case 0: // define cell-tremolo + if(info2) + regbd |= 128; + else + regbd &= 127; opl->write(0xbd,regbd); break; - case 1: if(info2) // define cell-vibrato - regbd |= 64; - else - regbd &= 191; + + case 1: // define cell-vibrato + if(info2) + regbd |= 64; + else + regbd &= 191; opl->write(0xbd,regbd); break; - case 4: vol_up_alt(chan,info2); // increase volume fine + + case 4: // increase volume fine + vol_up_alt(chan,info2); setvolume(chan); break; - case 5: vol_down_alt(chan,info2); // decrease volume fine + + case 5: // decrease volume fine + vol_down_alt(chan,info2); setvolume(chan); break; - case 6: slide_up(chan,info2); // manual slide up + + case 6: // manual slide up + slide_up(chan,info2); setfreq(chan); break; - case 7: slide_down(chan,info2); // manual slide down + + case 7: // manual slide down + slide_down(chan,info2); setfreq(chan); break; + + case 8: // pattern delay (rows) + pattern_delay = info2 * speed; + break; } break; + case 15: // SA2 set speed if(info <= 0x1f) speed = info; @@ -324,6 +355,7 @@ if(!info) songend = 1; break; + case 17: // alternate set volume channel[chan].vol1 = info; if(channel[chan].vol1 > 63) @@ -336,15 +368,18 @@ 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; @@ -352,6 +387,7 @@ channel[chan].vol2 = 63; setvolume(chan); break; + case 22: // set carrier volume if(info <= 63) channel[chan].vol1 = info; @@ -359,35 +395,45 @@ 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); + opl->write(0xe3 + op_table[oplchan],info1); if(info2 != 0x0f) - opl->write(0xe0 + op_table[chan],info2); + opl->write(0xe0 + op_table[oplchan],info2); break; + case 27: // set chip tremolo/vibrato - if (info1) + if(info1) regbd |= 128; else regbd &= 127; - if (info2) + if(info2) regbd |= 64; else regbd &= 191; opl->write(0xbd,regbd); break; + + case 29: // pattern delay (frames) + pattern_delay = info; + break; } } - del = speed - 1; // speed compensation + // speed compensation + del = speed - 1 + pattern_delay; + if(!pattbreak) { // next row (only if no manual advance) rw++; if(rw >= nrows) { @@ -395,16 +441,51 @@ ord++; } } + + resolve_order(); // so we can report songend right away + AdPlug_LogWrite("\n"); + return !songend; +} + +unsigned char CmodPlayer::set_opl_chip(unsigned char chan) + /* + * Sets OPL chip according to channel number. Channels 0-8 are on first chip, + * channels 9-17 are on second chip. Returns corresponding OPL channel + * number. + */ +{ + int newchip = chan < 9 ? 0 : 1; + + if(newchip != curchip) { + opl->setchip(newchip); + curchip = newchip; + } + + return chan % 9; +} + +bool CmodPlayer::resolve_order() + /* + * Resolves current orderlist entry, checking for jumps and loops. + * + * Returns true on correct processing, false if immediate recursive loop + * has been detected. + */ +{ if(ord < length) { - if(order[ord] >= JUMPMARKER) { // jump to order - ord = order[ord] - JUMPMARKER; - songend = 1; + while(order[ord] >= JUMPMARKER) { // jump to order + unsigned long neword = order[ord] - JUMPMARKER; + + if(neword <= ord) songend = 1; + if(neword == ord) return false; + ord = neword; } - } else + } else { songend = 1; + ord = restartpos; + } - AdPlug_LogWrite("\n"); - return !songend; + return true; } void CmodPlayer::rewind(int subsong) @@ -424,7 +505,20 @@ nop = (order[i] > nop ? order[i] : nop); opl->init(); // Reset OPL chip - opl->write(1,32); // Go to ym3812 mode + opl->write(1, 32); // Go to ym3812 mode + + // Enable OPL3 extensions if flagged + if(flags & Opl3) { + opl->setchip(1); + opl->write(1, 32); + opl->write(5, 1); + opl->setchip(0); + } + + // Enable tremolo/vibrato depth if flagged + if(flags & Tremolo) regbd |= 128; + if(flags & Vibrato) regbd |= 64; + if(regbd) opl->write(0xbd, regbd); } float CmodPlayer::getrefresh() @@ -520,38 +614,44 @@ void CmodPlayer::setvolume(unsigned char chan) { - if (flags & Faust) + unsigned char oplchan = set_opl_chip(chan); + + if(flags & Faust) setvolume_alt(chan); else { - opl->write(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)); + opl->write(0x40 + op_table[oplchan], 63-channel[chan].vol2 + (inst[channel[chan].inst].data[9] & 192)); + opl->write(0x43 + op_table[oplchan], 63-channel[chan].vol1 + (inst[channel[chan].inst].data[10] & 192)); } } void CmodPlayer::setvolume_alt(unsigned char chan) { + unsigned char oplchan = set_opl_chip(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)); + opl->write(0x40 + op_table[oplchan], (((63 - channel[chan].vol2 & 63) + ivol2) >> 1) + (inst[channel[chan].inst].data[9] & 192)); + opl->write(0x43 + op_table[oplchan], (((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); + unsigned char oplchan = set_opl_chip(chan); + + opl->write(0xa0 + oplchan, channel[chan].freq & 255); if(channel[chan].key) - opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2) | 32); + opl->write(0xb0 + oplchan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2) | 32); else - opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2)); + opl->write(0xb0 + oplchan, ((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; + unsigned char oplchan = set_opl_chip(chan); + unsigned char op = op_table[oplchan], insnr = channel[chan].inst; if(!(flags & NoKeyOn)) - opl->write(0xb0 + chan, 0); // stop old note + opl->write(0xb0 + oplchan, 0); // stop old note // set instrument data opl->write(0x20 + op, inst[insnr].data[1]); @@ -562,7 +662,7 @@ 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(0xc0 + oplchan, inst[insnr].data[0]); opl->write(0xbd, inst[insnr].misc); // set misc. register // set frequency, volume & play
--- a/src/adplug/core/protrack.h Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/protrack.h Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2002 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 @@ -27,81 +27,93 @@ class CmodPlayer: public CPlayer { public: - CmodPlayer(Copl *newopl); - virtual ~CmodPlayer(); + CmodPlayer(Copl *newopl); + virtual ~CmodPlayer(); + + bool update(); + void rewind(int subsong); + float getrefresh(); - 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; } - 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 << 0, + Faust = 1 << 1, + NoKeyOn = 1 << 2, + Opl3 = 1 << 3, + Tremolo = 1 << 4, + Vibrato = 1 << 5, + Percussion = 1 << 6 + }; -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 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 Tracks { + unsigned char note,command,inst,param2,param1; + } **tracks; - 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; + unsigned char *order, *arplist, *arpcmd, initspeed; + unsigned short tempo, **trackord, bpm, nop; + unsigned long length, restartpos, activechan; + int flags, curchip; - 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); + 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 dealloc(); + 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); -private: - static const unsigned short sa2_notetable[12]; - static const unsigned char vibratotab[32]; + void dealloc(); - unsigned char speed, del, songend, regbd; - unsigned short rows, notetable[12]; - unsigned long rw, ord, nrows, npats, nchans; + 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 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(); + void dealloc_patterns(); + bool resolve_order(); + unsigned char set_opl_chip(unsigned char chan); }; #endif
--- a/src/adplug/core/rad.cxx Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/rad.cxx Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2003 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 @@ -108,7 +108,7 @@ tracks[i][j].note++; tracks[i][j].command = convfx[tracks[i][j].command]; } - restartpos = 0; activechan = 0xffff; initspeed = radflags & 31; + restartpos = 0; initspeed = radflags & 31; bpm = radflags & 64 ? 0 : 50; flags = Decimal; rewind(0);
--- a/src/adplug/core/sa2.cxx Fri Apr 13 08:07:32 2007 -0700 +++ b/src/adplug/core/sa2.cxx Fri Apr 13 09:09:50 2007 -0700 @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2003 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 @@ -155,9 +155,7 @@ } if(sat_type & HAS_ACTIVECHANNELS) - activechan = f->readInt(2); // active channels - else - activechan = 0xffff; + activechan = f->readInt(2) << 16; // active channels AdPlug_LogWrite("Csa2Loader::load(\"%s\"): sat_type = %x, nop = %d, " "length = %d, restartpos = %d, activechan = %x, bpm = %d\n",