Mercurial > audlegacy
changeset 1713:a4d7227231e3 trunk
[svn] More .cpp -> .cxx. Noticed by Chainsaw. Shame on me that I forgot some ;).
author | js |
---|---|
date | Sat, 16 Sep 2006 07:33:28 -0700 |
parents | 2e7c9f6d9923 |
children | 1d2539762092 |
files | ChangeLog Plugins/Input/adplug/core/Makefile.in Plugins/Input/adplug/core/a2m.cpp Plugins/Input/adplug/core/a2m.cxx Plugins/Input/adplug/core/adl.cpp Plugins/Input/adplug/core/adl.cxx Plugins/Input/adplug/core/adplug.cpp Plugins/Input/adplug/core/adplug.cxx Plugins/Input/adplug/core/adtrack.cpp Plugins/Input/adplug/core/adtrack.cxx Plugins/Input/adplug/core/amd.cpp Plugins/Input/adplug/core/amd.cxx Plugins/Input/adplug/core/bam.cpp Plugins/Input/adplug/core/bam.cxx Plugins/Input/adplug/core/bmf.cpp Plugins/Input/adplug/core/bmf.cxx Plugins/Input/adplug/core/cff.cpp Plugins/Input/adplug/core/cff.cxx Plugins/Input/adplug/core/d00.cpp Plugins/Input/adplug/core/d00.cxx Plugins/Input/adplug/core/database.cpp Plugins/Input/adplug/core/database.cxx Plugins/Input/adplug/core/dfm.cpp Plugins/Input/adplug/core/dfm.cxx Plugins/Input/adplug/core/diskopl.cpp Plugins/Input/adplug/core/diskopl.cxx Plugins/Input/adplug/core/dmo.cpp Plugins/Input/adplug/core/dmo.cxx Plugins/Input/adplug/core/dro.cpp Plugins/Input/adplug/core/dro.cxx Plugins/Input/adplug/core/dtm.cpp Plugins/Input/adplug/core/dtm.cxx Plugins/Input/adplug/core/emuopl.cpp Plugins/Input/adplug/core/emuopl.cxx Plugins/Input/adplug/core/flash.cpp Plugins/Input/adplug/core/flash.cxx Plugins/Input/adplug/core/fmc.cpp Plugins/Input/adplug/core/fmc.cxx Plugins/Input/adplug/core/fprovide.cpp Plugins/Input/adplug/core/fprovide.cxx Plugins/Input/adplug/core/hsc.cpp Plugins/Input/adplug/core/hsc.cxx Plugins/Input/adplug/core/hsp.cpp Plugins/Input/adplug/core/hsp.cxx Plugins/Input/adplug/core/hybrid.cpp Plugins/Input/adplug/core/hybrid.cxx Plugins/Input/adplug/core/hyp.cpp Plugins/Input/adplug/core/hyp.cxx Plugins/Input/adplug/core/imf.cpp Plugins/Input/adplug/core/imf.cxx Plugins/Input/adplug/core/ksm.cpp Plugins/Input/adplug/core/ksm.cxx Plugins/Input/adplug/core/lds.cpp Plugins/Input/adplug/core/lds.cxx Plugins/Input/adplug/core/mad.cpp Plugins/Input/adplug/core/mad.cxx Plugins/Input/adplug/core/mid.cpp Plugins/Input/adplug/core/mid.cxx Plugins/Input/adplug/core/mkj.cpp Plugins/Input/adplug/core/mkj.cxx Plugins/Input/adplug/core/msc.cpp Plugins/Input/adplug/core/msc.cxx Plugins/Input/adplug/core/mtk.cpp Plugins/Input/adplug/core/mtk.cxx Plugins/Input/adplug/core/player.cpp Plugins/Input/adplug/core/player.cxx Plugins/Input/adplug/core/players.cpp Plugins/Input/adplug/core/players.cxx Plugins/Input/adplug/core/protrack.cpp Plugins/Input/adplug/core/protrack.cxx Plugins/Input/adplug/core/psi.cpp Plugins/Input/adplug/core/psi.cxx Plugins/Input/adplug/core/rad.cpp Plugins/Input/adplug/core/rad.cxx Plugins/Input/adplug/core/rat.cpp Plugins/Input/adplug/core/rat.cxx Plugins/Input/adplug/core/raw.cpp Plugins/Input/adplug/core/raw.cxx Plugins/Input/adplug/core/rix.cpp Plugins/Input/adplug/core/rix.cxx Plugins/Input/adplug/core/rol.cpp Plugins/Input/adplug/core/rol.cxx Plugins/Input/adplug/core/s3m.cpp Plugins/Input/adplug/core/s3m.cxx Plugins/Input/adplug/core/sa2.cpp Plugins/Input/adplug/core/sa2.cxx Plugins/Input/adplug/core/sng.cpp Plugins/Input/adplug/core/sng.cxx Plugins/Input/adplug/core/temuopl.cpp Plugins/Input/adplug/core/temuopl.cxx Plugins/Input/adplug/core/u6m.cpp Plugins/Input/adplug/core/u6m.cxx Plugins/Input/adplug/core/xad.cpp Plugins/Input/adplug/core/xad.cxx Plugins/Input/adplug/core/xsm.cpp Plugins/Input/adplug/core/xsm.cxx Plugins/Input/modplug/Makefile.in Plugins/Input/modplug/archive/Makefile.in Plugins/Input/modplug/archive/arch_bz2.cpp Plugins/Input/modplug/archive/arch_bz2.cxx Plugins/Input/modplug/archive/arch_gzip.cpp Plugins/Input/modplug/archive/arch_gzip.cxx Plugins/Input/modplug/archive/arch_rar.cpp Plugins/Input/modplug/archive/arch_rar.cxx Plugins/Input/modplug/archive/arch_raw.cpp Plugins/Input/modplug/archive/arch_raw.cxx Plugins/Input/modplug/archive/arch_zip.cpp Plugins/Input/modplug/archive/arch_zip.cxx Plugins/Input/modplug/archive/archive.cpp Plugins/Input/modplug/archive/archive.cxx Plugins/Input/modplug/archive/open.cpp Plugins/Input/modplug/archive/open.cxx Plugins/Input/modplug/gui/Makefile.in Plugins/Input/modplug/gui/callbacks.cpp Plugins/Input/modplug/gui/callbacks.cxx Plugins/Input/modplug/gui/interface.cpp Plugins/Input/modplug/gui/interface.cxx Plugins/Input/modplug/gui/main.cpp Plugins/Input/modplug/gui/main.cxx Plugins/Input/modplug/gui/support.cpp Plugins/Input/modplug/gui/support.cxx Plugins/Input/modplug/modplugbmp.cpp Plugins/Input/modplug/modplugbmp.cxx Plugins/Input/modplug/plugin.cpp Plugins/Input/modplug/plugin.cxx |
diffstat | 125 files changed, 19481 insertions(+), 19472 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Sat Sep 16 07:18:18 2006 -0700 +++ b/ChangeLog Sat Sep 16 07:33:28 2006 -0700 @@ -1,3 +1,12 @@ +2006-09-16 14:18:18 +0000 Tony Vroon <chainsaw@gentoo.org> + revision [2361] + Use the VFS layer. + + Changes: Modified: + +10 -10 trunk/Plugins/Input/console/abstract_file.cxx + +11 -10 trunk/Plugins/Input/console/abstract_file.h + + 2006-09-16 04:36:31 +0000 Yoshiki Yazawa <yaz@cc.rim.or.jp> revision [2359] - no more busy loop if a file in playlist disappears.
--- a/Plugins/Input/adplug/core/Makefile.in Sat Sep 16 07:18:18 2006 -0700 +++ b/Plugins/Input/adplug/core/Makefile.in Sat Sep 16 07:33:28 2006 -0700 @@ -3,13 +3,13 @@ OBJECTIVE_LIBS_NOINST = libadplugcore.a -SOURCES = adplug.cpp emuopl.cpp fmopl.c diskopl.cpp debug.c fprovide.cpp \ -player.cpp database.cpp hsc.cpp sng.cpp imf.cpp players.cpp protrack.cpp \ -a2m.cpp adtrack.cpp amd.cpp bam.cpp d00.cpp dfm.cpp dmo.cpp hsp.cpp ksm.cpp \ -mad.cpp mid.cpp mkj.cpp cff.cpp dtm.cpp fmc.cpp mtk.cpp rad.cpp raw.cpp \ -sa2.cpp s3m.cpp xad.cpp flash.cpp bmf.cpp hybrid.cpp hyp.cpp psi.cpp rat.cpp \ -u6m.cpp rol.cpp xsm.cpp adlibemu.c dro.cpp lds.cpp temuopl.cpp msc.cpp rix.cpp \ -adl.cpp +SOURCES = adplug.cxx emuopl.cxx fmopl.c diskopl.cxx debug.c fprovide.cxx \ +player.cxx database.cxx hsc.cxx sng.cxx imf.cxx players.cxx protrack.cxx \ +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 adlibemu.c dro.cxx lds.cxx temuopl.cxx msc.cxx rix.cxx \ +adl.cxx noinst_HEADERS = adplug.h emuopl.h fmopl.h silentopl.h opl.h diskopl.h \ a2m.h amd.h bam.h d00.h dfm.h hsc.h hsp.h imf.h ksm.h lds.h mid.h mkj.h mtk.h \ @@ -21,6 +21,6 @@ CXXFLAGS += $(PICFLAGS) $(BINIO_CFLAGS) -I../../../../intl -I../../../.. -Dstricmp=strcasecmp CFLAGS += $(PICFLAGS) $(BINIO_CFLAGS) -I../../../../intl -I../../../.. -Dstricmp=strcasecmp -OBJECTS = ${SOURCES:.c=.o} ${SOURCES:.cpp=.o} +OBJECTS = ${SOURCES:.c=.o} ${SOURCES:.cxx=.o} include ../../../../mk/objective.mk
--- a/Plugins/Input/adplug/core/a2m.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,449 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2002 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 - * - * a2m.cpp - A2M Loader by Simon Peter <dn.tlp@gmx.net> - * - * NOTES: - * This loader detects and loads version 1, 4, 5 & 8 files. - * - * version 1-4 files: - * 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 - */ - -#include "a2m.h" - -const unsigned int Ca2mLoader::MAXFREQ = 2000, -Ca2mLoader::MINCOPY = ADPLUG_A2M_MINCOPY, -Ca2mLoader::MAXCOPY = ADPLUG_A2M_MAXCOPY, -Ca2mLoader::COPYRANGES = ADPLUG_A2M_COPYRANGES, -Ca2mLoader::CODESPERRANGE = ADPLUG_A2M_CODESPERRANGE, -Ca2mLoader::TERMINATE = 256, -Ca2mLoader::FIRSTCODE = ADPLUG_A2M_FIRSTCODE, -Ca2mLoader::MAXCHAR = FIRSTCODE + COPYRANGES * CODESPERRANGE - 1, -Ca2mLoader::SUCCMAX = MAXCHAR + 1, -Ca2mLoader::TWICEMAX = ADPLUG_A2M_TWICEMAX, -Ca2mLoader::ROOT = 1, Ca2mLoader::MAXBUF = 42 * 1024, -Ca2mLoader::MAXDISTANCE = 21389, Ca2mLoader::MAXSIZE = 21389 + MAXCOPY; - -const unsigned short Ca2mLoader::bitvalue[14] = - {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192}; - -const signed short Ca2mLoader::copybits[COPYRANGES] = - {4, 6, 8, 10, 12, 14}; - -const signed short Ca2mLoader::copymin[COPYRANGES] = - {0, 16, 80, 336, 1360, 5456}; - -CPlayer *Ca2mLoader::factory(Copl *newopl) -{ - return new Ca2mLoader(newopl); -} - -bool Ca2mLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - struct { - char id[10]; - unsigned long crc; - unsigned char version,numpats; - } ch; - int i,j,k,t; - unsigned int l; - unsigned char *org = 0, *orgptr; - unsigned long 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}; - const unsigned char newconvfx[] = {0,1,2,3,4,5,6,23,24,21,10,11,17,13,7,19, - 255,255,22,25,255,15,255,255,255,255,255, - 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); - - // file validation section - if(strncmp(ch.id,"_A2module_",10) || (ch.version != 1 && ch.version != 5 && - ch.version != 4 && ch.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) { - for(i=0;i<5;i++) len[i] = f->readInt(2); - t = 9; - } else { - 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) { - 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]); - } else { - orgptr = (unsigned char *)secdata; - for(i=0;i<len[0];i++) orgptr[i] = f->readInt(1); - } - 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); - inst[i].data[2] = *(orgptr+i*13+1); - inst[i].data[3] = *(orgptr+i*13+4); - inst[i].data[4] = *(orgptr+i*13+5); - inst[i].data[5] = *(orgptr+i*13+6); - inst[i].data[6] = *(orgptr+i*13+7); - inst[i].data[7] = *(orgptr+i*13+8); - 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) - inst[i].misc = *(orgptr+i*13+11); - else - inst[i].misc = 0; - 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; - 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++) - alength += len[i+2]; - - secdata = new unsigned short [alength / 2]; - if(ch.version == 1 || ch.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)]; - orgptr = org; secptr = secdata; - orgptr += sixdepak(secptr,orgptr,len[1]); secptr += len[1] / 2; - if(ch.version == 1) { - if(ch.numpats > 16) - orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2; - if(ch.numpats > 32) - orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2; - if(ch.numpats > 48) - sixdepak(secptr,orgptr,len[4]); - } else { - if(ch.numpats > 8) - orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2; - if(ch.numpats > 16) - orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2; - if(ch.numpats > 24) - orgptr += sixdepak(secptr,orgptr,len[4]); secptr += len[4] / 2; - if(ch.numpats > 32) - orgptr += sixdepak(secptr,orgptr,len[5]); secptr += len[5] / 2; - if(ch.numpats > 40) - orgptr += sixdepak(secptr,orgptr,len[6]); secptr += len[6] / 2; - if(ch.numpats > 48) - orgptr += sixdepak(secptr,orgptr,len[7]); secptr += len[7] / 2; - if(ch.numpats > 56) - sixdepak(secptr,orgptr,len[8]); - } - delete [] secdata; - } else { - org = (unsigned char *)secdata; - 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++) - 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; - 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; - } - } - if(tracks[i*9+k][j].command == 14) { - switch(tracks[i*9+k][j].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; - 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; - break; - case 9: // convert volume slide down - tracks[i*9+k][j].command = 26; - tracks[i*9+k][j].param1 = 0; - break; - } - } - } - } else { - for(i=0;i<ch.numpats;i++) - for(j=0;j<9;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; - } - } - - if(ch.version == 1 || ch.version == 5) - delete [] org; - else - delete [] secdata; - fp.close(f); - rewind(0); - return true; -} - -float Ca2mLoader::getrefresh() -{ - if(tempo != 18) - return (float) (tempo); - else - return 18.2f; -} - -/*** private methods *************************************/ - -void Ca2mLoader::inittree() -{ - unsigned short i; - - for(i=2;i<=TWICEMAX;i++) { - dad[i] = i / 2; - freq[i] = 1; - } - - for(i=1;i<=MAXCHAR;i++) { - leftc[i] = 2 * i; - rghtc[i] = 2 * i + 1; - } -} - -void Ca2mLoader::updatefreq(unsigned short a,unsigned short b) -{ - do { - freq[dad[a]] = freq[a] + freq[b]; - a = dad[a]; - if(a != ROOT) - if(leftc[dad[a]] == a) - b = rghtc[dad[a]]; - else - b = leftc[dad[a]]; - } while(a != ROOT); - - if(freq[ROOT] == MAXFREQ) - for(a=1;a<=TWICEMAX;a++) - freq[a] >>= 1; -} - -void Ca2mLoader::updatemodel(unsigned short code) -{ - unsigned short a=code+SUCCMAX,b,c,code1,code2; - - freq[a]++; - if(dad[a] != ROOT) { - code1 = dad[a]; - if(leftc[code1] == a) - updatefreq(a,rghtc[code1]); - else - updatefreq(a,leftc[code1]); - - do { - code2 = dad[code1]; - if(leftc[code2] == code1) - b = rghtc[code2]; - else - b = leftc[code2]; - - if(freq[a] > freq[b]) { - if(leftc[code2] == code1) - rghtc[code2] = a; - else - leftc[code2] = a; - - if(leftc[code1] == a) { - leftc[code1] = b; - c = rghtc[code1]; - } else { - rghtc[code1] = b; - c = leftc[code1]; - } - - dad[b] = code1; - dad[a] = code2; - updatefreq(b,c); - a = b; - } - - a = dad[a]; - code1 = dad[a]; - } while(code1 != ROOT); - } -} - -unsigned short Ca2mLoader::inputcode(unsigned short bits) -{ - unsigned short i,code=0; - - for(i=1;i<=bits;i++) { - if(!ibitcount) { - if(ibitcount == MAXBUF) - ibufcount = 0; - ibitbuffer = wdbuf[ibufcount]; - ibufcount++; - ibitcount = 15; - } else - ibitcount--; - - if(ibitbuffer > 0x7fff) - code |= bitvalue[i-1]; - ibitbuffer <<= 1; - } - - return code; -} - -unsigned short Ca2mLoader::uncompress() -{ - unsigned short a=1; - - do { - if(!ibitcount) { - if(ibufcount == MAXBUF) - ibufcount = 0; - ibitbuffer = wdbuf[ibufcount]; - ibufcount++; - ibitcount = 15; - } else - ibitcount--; - - if(ibitbuffer > 0x7fff) - a = rghtc[a]; - else - a = leftc[a]; - ibitbuffer <<= 1; - } while(a <= MAXCHAR); - - a -= SUCCMAX; - updatemodel(a); - return a; -} - -void Ca2mLoader::decode() -{ - unsigned short i,j,k,t,c,count=0,dist,len,index; - - inittree(); - c = uncompress(); - - while(c != TERMINATE) { - if(c < 256) { - obuf[obufcount] = (unsigned char)c; - obufcount++; - if(obufcount == MAXBUF) { - output_size = MAXBUF; - obufcount = 0; - } - - buf[count] = (unsigned char)c; - count++; - if(count == MAXSIZE) - count = 0; - } else { - t = c - FIRSTCODE; - index = t / CODESPERRANGE; - len = t + MINCOPY - index * CODESPERRANGE; - dist = inputcode(copybits[index]) + len + copymin[index]; - - j = count; - k = count - dist; - if(count < dist) - k += MAXSIZE; - - for(i=0;i<=len-1;i++) { - obuf[obufcount] = buf[k]; - obufcount++; - if(obufcount == MAXBUF) { - output_size = MAXBUF; - obufcount = 0; - } - - buf[j] = buf[k]; - j++; k++; - if(j == MAXSIZE) j = 0; - if(k == MAXSIZE) k = 0; - } - - count += len; - if(count >= MAXSIZE) - count -= MAXSIZE; - } - c = uncompress(); - } - output_size = obufcount; -} - -unsigned short Ca2mLoader::sixdepak(unsigned short *source, unsigned char *dest, - unsigned short size) -{ - if((unsigned int)size + 4096 > MAXBUF) - return 0; - - buf = new unsigned char [MAXSIZE]; - input_size = size; - ibitcount = 0; ibitbuffer = 0; - obufcount = 0; ibufcount = 0; - wdbuf = source; obuf = dest; - - decode(); - delete [] buf; - return output_size; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/a2m.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,449 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 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 + * + * a2m.cpp - A2M Loader by Simon Peter <dn.tlp@gmx.net> + * + * NOTES: + * This loader detects and loads version 1, 4, 5 & 8 files. + * + * version 1-4 files: + * 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 + */ + +#include "a2m.h" + +const unsigned int Ca2mLoader::MAXFREQ = 2000, +Ca2mLoader::MINCOPY = ADPLUG_A2M_MINCOPY, +Ca2mLoader::MAXCOPY = ADPLUG_A2M_MAXCOPY, +Ca2mLoader::COPYRANGES = ADPLUG_A2M_COPYRANGES, +Ca2mLoader::CODESPERRANGE = ADPLUG_A2M_CODESPERRANGE, +Ca2mLoader::TERMINATE = 256, +Ca2mLoader::FIRSTCODE = ADPLUG_A2M_FIRSTCODE, +Ca2mLoader::MAXCHAR = FIRSTCODE + COPYRANGES * CODESPERRANGE - 1, +Ca2mLoader::SUCCMAX = MAXCHAR + 1, +Ca2mLoader::TWICEMAX = ADPLUG_A2M_TWICEMAX, +Ca2mLoader::ROOT = 1, Ca2mLoader::MAXBUF = 42 * 1024, +Ca2mLoader::MAXDISTANCE = 21389, Ca2mLoader::MAXSIZE = 21389 + MAXCOPY; + +const unsigned short Ca2mLoader::bitvalue[14] = + {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192}; + +const signed short Ca2mLoader::copybits[COPYRANGES] = + {4, 6, 8, 10, 12, 14}; + +const signed short Ca2mLoader::copymin[COPYRANGES] = + {0, 16, 80, 336, 1360, 5456}; + +CPlayer *Ca2mLoader::factory(Copl *newopl) +{ + return new Ca2mLoader(newopl); +} + +bool Ca2mLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + struct { + char id[10]; + unsigned long crc; + unsigned char version,numpats; + } ch; + int i,j,k,t; + unsigned int l; + unsigned char *org = 0, *orgptr; + unsigned long 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}; + const unsigned char newconvfx[] = {0,1,2,3,4,5,6,23,24,21,10,11,17,13,7,19, + 255,255,22,25,255,15,255,255,255,255,255, + 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); + + // file validation section + if(strncmp(ch.id,"_A2module_",10) || (ch.version != 1 && ch.version != 5 && + ch.version != 4 && ch.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) { + for(i=0;i<5;i++) len[i] = f->readInt(2); + t = 9; + } else { + 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) { + 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]); + } else { + orgptr = (unsigned char *)secdata; + for(i=0;i<len[0];i++) orgptr[i] = f->readInt(1); + } + 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); + inst[i].data[2] = *(orgptr+i*13+1); + inst[i].data[3] = *(orgptr+i*13+4); + inst[i].data[4] = *(orgptr+i*13+5); + inst[i].data[5] = *(orgptr+i*13+6); + inst[i].data[6] = *(orgptr+i*13+7); + inst[i].data[7] = *(orgptr+i*13+8); + 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) + inst[i].misc = *(orgptr+i*13+11); + else + inst[i].misc = 0; + 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; + 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++) + alength += len[i+2]; + + secdata = new unsigned short [alength / 2]; + if(ch.version == 1 || ch.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)]; + orgptr = org; secptr = secdata; + orgptr += sixdepak(secptr,orgptr,len[1]); secptr += len[1] / 2; + if(ch.version == 1) { + if(ch.numpats > 16) + orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2; + if(ch.numpats > 32) + orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2; + if(ch.numpats > 48) + sixdepak(secptr,orgptr,len[4]); + } else { + if(ch.numpats > 8) + orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2; + if(ch.numpats > 16) + orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2; + if(ch.numpats > 24) + orgptr += sixdepak(secptr,orgptr,len[4]); secptr += len[4] / 2; + if(ch.numpats > 32) + orgptr += sixdepak(secptr,orgptr,len[5]); secptr += len[5] / 2; + if(ch.numpats > 40) + orgptr += sixdepak(secptr,orgptr,len[6]); secptr += len[6] / 2; + if(ch.numpats > 48) + orgptr += sixdepak(secptr,orgptr,len[7]); secptr += len[7] / 2; + if(ch.numpats > 56) + sixdepak(secptr,orgptr,len[8]); + } + delete [] secdata; + } else { + org = (unsigned char *)secdata; + 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++) + 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; + 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; + } + } + if(tracks[i*9+k][j].command == 14) { + switch(tracks[i*9+k][j].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; + 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; + break; + case 9: // convert volume slide down + tracks[i*9+k][j].command = 26; + tracks[i*9+k][j].param1 = 0; + break; + } + } + } + } else { + for(i=0;i<ch.numpats;i++) + for(j=0;j<9;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; + } + } + + if(ch.version == 1 || ch.version == 5) + delete [] org; + else + delete [] secdata; + fp.close(f); + rewind(0); + return true; +} + +float Ca2mLoader::getrefresh() +{ + if(tempo != 18) + return (float) (tempo); + else + return 18.2f; +} + +/*** private methods *************************************/ + +void Ca2mLoader::inittree() +{ + unsigned short i; + + for(i=2;i<=TWICEMAX;i++) { + dad[i] = i / 2; + freq[i] = 1; + } + + for(i=1;i<=MAXCHAR;i++) { + leftc[i] = 2 * i; + rghtc[i] = 2 * i + 1; + } +} + +void Ca2mLoader::updatefreq(unsigned short a,unsigned short b) +{ + do { + freq[dad[a]] = freq[a] + freq[b]; + a = dad[a]; + if(a != ROOT) + if(leftc[dad[a]] == a) + b = rghtc[dad[a]]; + else + b = leftc[dad[a]]; + } while(a != ROOT); + + if(freq[ROOT] == MAXFREQ) + for(a=1;a<=TWICEMAX;a++) + freq[a] >>= 1; +} + +void Ca2mLoader::updatemodel(unsigned short code) +{ + unsigned short a=code+SUCCMAX,b,c,code1,code2; + + freq[a]++; + if(dad[a] != ROOT) { + code1 = dad[a]; + if(leftc[code1] == a) + updatefreq(a,rghtc[code1]); + else + updatefreq(a,leftc[code1]); + + do { + code2 = dad[code1]; + if(leftc[code2] == code1) + b = rghtc[code2]; + else + b = leftc[code2]; + + if(freq[a] > freq[b]) { + if(leftc[code2] == code1) + rghtc[code2] = a; + else + leftc[code2] = a; + + if(leftc[code1] == a) { + leftc[code1] = b; + c = rghtc[code1]; + } else { + rghtc[code1] = b; + c = leftc[code1]; + } + + dad[b] = code1; + dad[a] = code2; + updatefreq(b,c); + a = b; + } + + a = dad[a]; + code1 = dad[a]; + } while(code1 != ROOT); + } +} + +unsigned short Ca2mLoader::inputcode(unsigned short bits) +{ + unsigned short i,code=0; + + for(i=1;i<=bits;i++) { + if(!ibitcount) { + if(ibitcount == MAXBUF) + ibufcount = 0; + ibitbuffer = wdbuf[ibufcount]; + ibufcount++; + ibitcount = 15; + } else + ibitcount--; + + if(ibitbuffer > 0x7fff) + code |= bitvalue[i-1]; + ibitbuffer <<= 1; + } + + return code; +} + +unsigned short Ca2mLoader::uncompress() +{ + unsigned short a=1; + + do { + if(!ibitcount) { + if(ibufcount == MAXBUF) + ibufcount = 0; + ibitbuffer = wdbuf[ibufcount]; + ibufcount++; + ibitcount = 15; + } else + ibitcount--; + + if(ibitbuffer > 0x7fff) + a = rghtc[a]; + else + a = leftc[a]; + ibitbuffer <<= 1; + } while(a <= MAXCHAR); + + a -= SUCCMAX; + updatemodel(a); + return a; +} + +void Ca2mLoader::decode() +{ + unsigned short i,j,k,t,c,count=0,dist,len,index; + + inittree(); + c = uncompress(); + + while(c != TERMINATE) { + if(c < 256) { + obuf[obufcount] = (unsigned char)c; + obufcount++; + if(obufcount == MAXBUF) { + output_size = MAXBUF; + obufcount = 0; + } + + buf[count] = (unsigned char)c; + count++; + if(count == MAXSIZE) + count = 0; + } else { + t = c - FIRSTCODE; + index = t / CODESPERRANGE; + len = t + MINCOPY - index * CODESPERRANGE; + dist = inputcode(copybits[index]) + len + copymin[index]; + + j = count; + k = count - dist; + if(count < dist) + k += MAXSIZE; + + for(i=0;i<=len-1;i++) { + obuf[obufcount] = buf[k]; + obufcount++; + if(obufcount == MAXBUF) { + output_size = MAXBUF; + obufcount = 0; + } + + buf[j] = buf[k]; + j++; k++; + if(j == MAXSIZE) j = 0; + if(k == MAXSIZE) k = 0; + } + + count += len; + if(count >= MAXSIZE) + count -= MAXSIZE; + } + c = uncompress(); + } + output_size = obufcount; +} + +unsigned short Ca2mLoader::sixdepak(unsigned short *source, unsigned char *dest, + unsigned short size) +{ + if((unsigned int)size + 4096 > MAXBUF) + return 0; + + buf = new unsigned char [MAXSIZE]; + input_size = size; + ibitcount = 0; ibitbuffer = 0; + obufcount = 0; ibufcount = 0; + wdbuf = source; obuf = dest; + + decode(); + delete [] buf; + return output_size; +}
--- a/Plugins/Input/adplug/core/adl.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2427 +0,0 @@ -/* - * adl.cpp - ADL player adaption by Simon Peter <dn.tlp@gmx.net> - * - * Original ADL player by Torbjorn Andersson and Johannes Schickel - * 'lordhoto' <lordhoto at scummvm dot org> of the ScummVM project. - */ - -/* ScummVM - Scumm Interpreter - * - * This file is licensed under both GPL and LGPL - * Copyright (C) 2006 The ScummVM project - * Copyright (C) 2006 Torbjorn Andersson and Johannes Schickel - * - * GPL License - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program 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 General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * LPGL License - * - * 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 - * - */ - -#include <inttypes.h> -#include <stdarg.h> -#include <assert.h> - -#include "adl.h" -#include "debug.h" - -#ifdef ADL_DEBUG -# define warning(...) AdPlug_LogWrite(__VA_ARGS__); \ -AdPlug_LogWrite("\n") - -# define debugC(i1, i2, ...) AdPlug_LogWrite(__VA_ARGS__); \ -AdPlug_LogWrite("\n") -#else -# define kDebugLevelSound 1 - -static inline void warning(const char *str, ...) -{ -} - -static inline void debugC(int i1, int i2, const char *str, ...) -{ -} -#endif - -// #define warning(...) -// #define debugC(i1, i2, ...) - -#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0]))) - -// Basic Adlib Programming: -// http://www.gamedev.net/reference/articles/article446.asp - -#define CALLBACKS_PER_SECOND 72 - -typedef uint8_t uint8; -typedef int8_t int8; -typedef uint16_t uint16; -typedef int16_t int16; -typedef uint32_t uint32; -typedef int32_t int32; -typedef uint8_t byte; - -static inline uint16 READ_LE_UINT16(const void *ptr) { - const byte *b = (const byte *)ptr; - return (b[1] << 8) + b[0]; -} - -static inline uint16 READ_BE_UINT16(const void *ptr) { - const byte *b = (const byte *)ptr; - return (b[0] << 8) + b[1]; -} - -class AdlibDriver { -public: - AdlibDriver(Copl *opl); - ~AdlibDriver(); - - int callback(int opcode, ...); - void callback(); - - // AudioStream API - // int readBuffer(int16 *buffer, const int numSamples) { - // int32 samplesLeft = numSamples; - // memset(buffer, 0, sizeof(int16) * numSamples); - // while (samplesLeft) { - // if (!_samplesTillCallback) { - // callback(); - // _samplesTillCallback = _samplesPerCallback; - // _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; - // if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) { - // _samplesTillCallback++; - // _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND; - // } - // } - - // int32 render = MIN(samplesLeft, _samplesTillCallback); - // samplesLeft -= render; - // _samplesTillCallback -= render; - // YM3812UpdateOne(_adlib, buffer, render); - // buffer += render; - // } - // return numSamples; - // } - - bool isStereo() const { return false; } - bool endOfData() const { return false; } - // int getRate() const { return _mixer->getOutputRate(); } - - struct OpcodeEntry { - typedef int (AdlibDriver::*DriverOpcode)(va_list &list); - DriverOpcode function; - const char *name; - }; - - void setupOpcodeList(); - const OpcodeEntry *_opcodeList; - int _opcodesEntries; - - int snd_ret0x100(va_list &list); - int snd_ret0x1983(va_list &list); - int snd_initDriver(va_list &list); - int snd_deinitDriver(va_list &list); - int snd_setSoundData(va_list &list); - int snd_unkOpcode1(va_list &list); - int snd_startSong(va_list &list); - int snd_unkOpcode2(va_list &list); - int snd_unkOpcode3(va_list &list); - int snd_readByte(va_list &list); - int snd_writeByte(va_list &list); - int snd_getSoundTrigger(va_list &list); - int snd_unkOpcode4(va_list &list); - int snd_dummy(va_list &list); - int snd_getNullvar4(va_list &list); - int snd_setNullvar3(va_list &list); - int snd_setFlag(va_list &list); - int snd_clearFlag(va_list &list); - - // These variables have not yet been named, but some of them are partly - // known nevertheless: - // - // unk16 - Sound-related. Possibly some sort of pitch bend. - // unk18 - Sound-effect. Used for secondaryEffect1() - // unk19 - Sound-effect. Used for secondaryEffect1() - // unk20 - Sound-effect. Used for secondaryEffect1() - // unk21 - Sound-effect. Used for secondaryEffect1() - // unk22 - Sound-effect. Used for secondaryEffect1() - // unk29 - Sound-effect. Used for primaryEffect1() - // unk30 - Sound-effect. Used for primaryEffect1() - // unk31 - Sound-effect. Used for primaryEffect1() - // unk32 - Sound-effect. Used for primaryEffect2() - // unk33 - Sound-effect. Used for primaryEffect2() - // unk34 - Sound-effect. Used for primaryEffect2() - // unk35 - Sound-effect. Used for primaryEffect2() - // unk36 - Sound-effect. Used for primaryEffect2() - // unk37 - Sound-effect. Used for primaryEffect2() - // unk38 - Sound-effect. Used for primaryEffect2() - // unk39 - Currently unused, except for updateCallback56() - // unk40 - Currently unused, except for updateCallback56() - // unk41 - Sound-effect. Used for primaryEffect2() - - struct Channel { - uint8 opExtraLevel2; - uint8 *dataptr; - uint8 duration; - uint8 repeatCounter; - int8 baseOctave; - uint8 priority; - uint8 dataptrStackPos; - uint8 *dataptrStack[4]; - int8 baseNote; - uint8 unk29; - uint8 unk31; - uint16 unk30; - uint16 unk37; - uint8 unk33; - uint8 unk34; - uint8 unk35; - uint8 unk36; - uint8 unk32; - uint8 unk41; - uint8 unk38; - uint8 opExtraLevel1; - uint8 spacing2; - uint8 baseFreq; - uint8 tempo; - uint8 position; - uint8 regAx; - uint8 regBx; - typedef void (AdlibDriver::*Callback)(Channel&); - Callback primaryEffect; - Callback secondaryEffect; - uint8 fractionalSpacing; - uint8 opLevel1; - uint8 opLevel2; - uint8 opExtraLevel3; - uint8 twoChan; - uint8 unk39; - uint8 unk40; - uint8 spacing1; - uint8 durationRandomness; - uint8 unk19; - uint8 unk18; - int8 unk20; - int8 unk21; - uint8 unk22; - uint16 offset; - uint8 tempoReset; - uint8 rawNote; - int8 unk16; - }; - - void primaryEffect1(Channel &channel); - void primaryEffect2(Channel &channel); - void secondaryEffect1(Channel &channel); - - void resetAdlibState(); - void writeOPL(byte reg, byte val); - void initChannel(Channel &channel); - void noteOff(Channel &channel); - void unkOutput2(uint8 num); - - uint16 getRandomNr(); - void setupDuration(uint8 duration, Channel &channel); - - void setupNote(uint8 rawNote, Channel &channel, bool flag = false); - void setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel); - void noteOn(Channel &channel); - - void adjustVolume(Channel &channel); - - uint8 calculateOpLevel1(Channel &channel); - uint8 calculateOpLevel2(Channel &channel); - - uint16 checkValue(int16 val) { - if (val < 0) - val = 0; - else if (val > 0x3F) - val = 0x3F; - return val; - } - - // The sound data has at least two lookup tables: - // - // * One for programs, starting at offset 0. - // * One for instruments, starting at offset 500. - - uint8 *getProgram(int progId) { - return _soundData + READ_LE_UINT16(_soundData + 2 * progId); - } - - uint8 *getInstrument(int instrumentId) { - return _soundData + READ_LE_UINT16(_soundData + 500 + 2 * instrumentId); - } - - void setupPrograms(); - void executePrograms(); - - struct ParserOpcode { - typedef int (AdlibDriver::*POpcode)(uint8 *&dataptr, Channel &channel, uint8 value); - POpcode function; - const char *name; - }; - - void setupParserOpcodeTable(); - const ParserOpcode *_parserOpcodeTable; - int _parserOpcodeTableSize; - - int update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value); - int update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value); - int update_jump(uint8 *&dataptr, Channel &channel, uint8 value); - int update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value); - int update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value); - int update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value); - int update_playRest(uint8 *&dataptr, Channel &channel, uint8 value); - int update_writeAdlib(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value); - int update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value); - int update_playNote(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value); - int update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value); - int update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value); - int update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value); - int update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback41(uint8 *&dataptr, Channel &channel, uint8 value); - int update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value); - int update_nop1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value); - int update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value); - int update_nop2(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value); - int update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value); - int update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value); - - // These variables have not yet been named, but some of them are partly - // known nevertheless: - // - // _unkValue1 - Unknown. Used for updating _unkValue2 - // _unkValue2 - Unknown. Used for updating _unkValue4 - // _unkValue3 - Unknown. Used for updating _unkValue2 - // _unkValue4 - Unknown. Used for updating _unkValue5 - // _unkValue5 - Unknown. Used for controlling updateCallback24(). - // _unkValue6 - Unknown. Rhythm section volume? - // _unkValue7 - Unknown. Rhythm section volume? - // _unkValue8 - Unknown. Rhythm section volume? - // _unkValue9 - Unknown. Rhythm section volume? - // _unkValue10 - Unknown. Rhythm section volume? - // _unkValue11 - Unknown. Rhythm section volume? - // _unkValue12 - Unknown. Rhythm section volume? - // _unkValue13 - Unknown. Rhythm section volume? - // _unkValue14 - Unknown. Rhythm section volume? - // _unkValue15 - Unknown. Rhythm section volume? - // _unkValue16 - Unknown. Rhythm section volume? - // _unkValue17 - Unknown. Rhythm section volume? - // _unkValue18 - Unknown. Rhythm section volume? - // _unkValue19 - Unknown. Rhythm section volume? - // _unkValue20 - Unknown. Rhythm section volume? - // _unkTable[] - Probably frequences for the 12-tone scale. - // _unkTable2[] - Unknown. Currently only used by updateCallback46() - // _unkTable2_1[] - One of the tables in _unkTable2[] - // _unkTable2_2[] - One of the tables in _unkTable2[] - // _unkTable2_3[] - One of the tables in _unkTable2[] - - int32 _samplesPerCallback; - int32 _samplesPerCallbackRemainder; - int32 _samplesTillCallback; - int32 _samplesTillCallbackRemainder; - - int _lastProcessed; - int8 _flagTrigger; - int _curChannel; - uint8 _soundTrigger; - int _soundsPlaying; - - uint16 _rnd; - - uint8 _unkValue1; - uint8 _unkValue2; - uint8 _unkValue3; - uint8 _unkValue4; - uint8 _unkValue5; - uint8 _unkValue6; - uint8 _unkValue7; - uint8 _unkValue8; - uint8 _unkValue9; - uint8 _unkValue10; - uint8 _unkValue11; - uint8 _unkValue12; - uint8 _unkValue13; - uint8 _unkValue14; - uint8 _unkValue15; - uint8 _unkValue16; - uint8 _unkValue17; - uint8 _unkValue18; - uint8 _unkValue19; - uint8 _unkValue20; - - int _flags; - - uint8 *_soundData; - - uint8 _soundIdTable[0x10]; - Channel _channels[10]; - - uint8 _vibratoAndAMDepthBits; - uint8 _rhythmSectionBits; - - uint8 _curRegOffset; - uint8 _tempo; - - const uint8 *_tablePtr1; - const uint8 *_tablePtr2; - - static const uint8 _regOffset[]; - static const uint16 _unkTable[]; - static const uint8 *_unkTable2[]; - static const uint8 _unkTable2_1[]; - static const uint8 _unkTable2_2[]; - static const uint8 _unkTable2_3[]; - static const uint8 _unkTables[][32]; - - Copl *opl; -}; - -AdlibDriver::AdlibDriver(Copl *newopl) - : opl(newopl) -{ - setupOpcodeList(); - setupParserOpcodeTable(); - - // _mixer = mixer; - - _flags = 0; - // _adlib = makeAdlibOPL(getRate()); - // assert(_adlib); - - memset(_channels, 0, sizeof(_channels)); - _soundData = 0; - - _vibratoAndAMDepthBits = _curRegOffset = 0; - - _lastProcessed = _flagTrigger = _curChannel = _rhythmSectionBits = 0; - _soundsPlaying = 0; - _rnd = 0x1234; - - _tempo = 0; - _soundTrigger = 0; - - _unkValue3 = 0xFF; - _unkValue1 = _unkValue2 = _unkValue4 = _unkValue5 = 0; - _unkValue6 = _unkValue7 = _unkValue8 = _unkValue9 = _unkValue10 = 0; - _unkValue11 = _unkValue12 = _unkValue13 = _unkValue14 = _unkValue15 = - _unkValue16 = _unkValue17 = _unkValue18 = _unkValue19 = _unkValue20 = 0; - - _tablePtr1 = _tablePtr2 = 0; - - // _mixer->setupPremix(this); - - // _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND; - // _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND; - _samplesTillCallback = 0; - _samplesTillCallbackRemainder = 0; -} - -AdlibDriver::~AdlibDriver() { - // _mixer->setupPremix(0); - // OPLDestroy(_adlib); - // _adlib = 0; -} - -int AdlibDriver::callback(int opcode, ...) { - // lock(); - if (opcode >= _opcodesEntries || opcode < 0) { - warning("AdlibDriver: calling unknown opcode '%d'", opcode); - return 0; - } - - debugC(9, kDebugLevelSound, "Calling opcode '%s' (%d)", _opcodeList[opcode].name, opcode); - - va_list args; - va_start(args, opcode); - int returnValue = (this->*(_opcodeList[opcode].function))(args); - va_end(args); - // unlock(); - return returnValue; -} - -// Opcodes - -int AdlibDriver::snd_ret0x100(va_list &list) { - return 0x100; -} - -int AdlibDriver::snd_ret0x1983(va_list &list) { - return 0x1983; -} - -int AdlibDriver::snd_initDriver(va_list &list) { - _lastProcessed = _soundsPlaying = 0; - resetAdlibState(); - return 0; -} - -int AdlibDriver::snd_deinitDriver(va_list &list) { - resetAdlibState(); - return 0; -} - -int AdlibDriver::snd_setSoundData(va_list &list) { - if (_soundData) { - delete [] _soundData; - _soundData = 0; - } - _soundData = va_arg(list, uint8*); - return 0; -} - -int AdlibDriver::snd_unkOpcode1(va_list &list) { - warning("unimplemented snd_unkOpcode1"); - return 0; -} - -int AdlibDriver::snd_startSong(va_list &list) { - int songId = va_arg(list, int); - _flags |= 8; - _flagTrigger = 1; - - uint8 *ptr = getProgram(songId); - uint8 chan = *ptr; - - if ((songId << 1) != 0) { - if (chan == 9) { - if (_flags & 2) - return 0; - } else { - if (_flags & 1) - return 0; - } - } - - _soundIdTable[_soundsPlaying++] = songId; - _soundsPlaying &= 0x0F; - - return 0; -} - -int AdlibDriver::snd_unkOpcode2(va_list &list) { - warning("unimplemented snd_unkOpcode2"); - return 0; -} - -int AdlibDriver::snd_unkOpcode3(va_list &list) { - int value = va_arg(list, int); - int loop = value; - if (value < 0) { - value = 0; - loop = 9; - } - loop -= value; - ++loop; - - while (loop--) { - _curChannel = value; - Channel &channel = _channels[_curChannel]; - channel.priority = 0; - channel.dataptr = 0; - if (value != 9) { - noteOff(channel); - } - ++value; - } - - return 0; -} - -int AdlibDriver::snd_readByte(va_list &list) { - int a = va_arg(list, int); - int b = va_arg(list, int); - uint8 *ptr = getProgram(a) + b; - return *ptr; -} - -int AdlibDriver::snd_writeByte(va_list &list) { - int a = va_arg(list, int); - int b = va_arg(list, int); - int c = va_arg(list, int); - uint8 *ptr = getProgram(a) + b; - uint8 oldValue = *ptr; - *ptr = (uint8)c; - return oldValue; -} - -int AdlibDriver::snd_getSoundTrigger(va_list &list) { - return _soundTrigger; -} - -int AdlibDriver::snd_unkOpcode4(va_list &list) { - warning("unimplemented snd_unkOpcode4"); - return 0; -} - -int AdlibDriver::snd_dummy(va_list &list) { - return 0; -} - -int AdlibDriver::snd_getNullvar4(va_list &list) { - warning("unimplemented snd_getNullvar4"); - return 0; -} - -int AdlibDriver::snd_setNullvar3(va_list &list) { - warning("unimplemented snd_setNullvar3"); - return 0; -} - -int AdlibDriver::snd_setFlag(va_list &list) { - int oldFlags = _flags; - _flags |= va_arg(list, int); - return oldFlags; -} - -int AdlibDriver::snd_clearFlag(va_list &list) { - int oldFlags = _flags; - _flags &= ~(va_arg(list, int)); - return oldFlags; -} - -// timer callback - -void AdlibDriver::callback() { - // lock(); - --_flagTrigger; - if (_flagTrigger < 0) - _flags &= ~8; - setupPrograms(); - executePrograms(); - - uint8 temp = _unkValue3; - _unkValue3 += _tempo; - if (_unkValue3 < temp) { - if (!(--_unkValue2)) { - _unkValue2 = _unkValue1; - ++_unkValue4; - } - } - // unlock(); -} - -void AdlibDriver::setupPrograms() { - while (_lastProcessed != _soundsPlaying) { - uint8 *ptr = getProgram(_soundIdTable[_lastProcessed]); - uint8 chan = *ptr++; - uint8 priority = *ptr++; - - // Only start this sound if its priority is higher than the one - // already playing. - - Channel &channel = _channels[chan]; - - if (priority >= channel.priority) { - initChannel(channel); - channel.priority = priority; - channel.dataptr = ptr; - channel.tempo = 0xFF; - channel.position = 0xFF; - channel.duration = 1; - unkOutput2(chan); - } - - ++_lastProcessed; - _lastProcessed &= 0x0F; - } -} - -// A few words on opcode parsing and timing: -// -// First of all, We simulate a timer callback 72 times per second. Each timeout -// we update each channel that has something to play. -// -// Each channel has its own individual tempo, which is added to its position. -// This will frequently cause the position to "wrap around" but that is -// intentional. In fact, it's the signal to go ahead and do more stuff with -// that channel. -// -// Each channel also has a duration, indicating how much time is left on the -// its current task. This duration is decreased by one. As long as it still has -// not reached zero, the only thing that can happen is that the note is turned -// off depending on manual or automatic note spacing. Once the duration reaches -// zero, a new set of musical opcodes are executed. -// -// An opcode is one byte, followed by a variable number of parameters. Since -// most opcodes have at least one one-byte parameter, we read that as well. Any -// opcode that doesn't have that one parameter is responsible for moving the -// data pointer back again. -// -// If the most significant bit of the opcode is 1, it's a function; call it. -// The opcode functions return either 0 (continue), 1 (stop) or 2 (stop, and do -// not run the effects callbacks). -// -// If the most significant bit of the opcode is 0, it's a note, and the first -// parameter is its duration. (There are cases where the duration is modified -// but that's an exception.) The note opcode is assumed to return 1, and is the -// last opcode unless its duration is zero. -// -// Finally, most of the times that the callback is called, it will invoke the -// effects callbacks. The final opcode in a set can prevent this, if it's a -// function and it returns anything other than 1. - -void AdlibDriver::executePrograms() { - // Each channel runs its own program. There are ten channels: One for - // each Adlib channel (0-8), plus one "control channel" (9) which is - // the one that tells the other channels what to do. - - for (_curChannel = 9; _curChannel >= 0; --_curChannel) { - int result = 1; - - if (!_channels[_curChannel].dataptr) { - continue; - } - - Channel &channel = _channels[_curChannel]; - _curRegOffset = _regOffset[_curChannel]; - - if (channel.tempoReset) { - channel.tempo = _tempo; - } - - uint8 backup = channel.position; - channel.position += channel.tempo; - if (channel.position < backup) { - if (--channel.duration) { - if (channel.duration == channel.spacing2) - noteOff(channel); - if (channel.duration == channel.spacing1 && _curChannel != 9) - noteOff(channel); - } else { - // An opcode is not allowed to modify its own - // data pointer except through the 'dataptr' - // parameter. To enforce that, we have to work - // on a copy of the data pointer. - // - // This fixes a subtle music bug where the - // wrong music would play when getting the - // quill in Kyra 1. - uint8 *dataptr = channel.dataptr; - while (dataptr) { - uint8 opcode = *dataptr++; - uint8 param = *dataptr++; - - if (opcode & 0x80) { - opcode &= 0x7F; - if (opcode >= _parserOpcodeTableSize) - opcode = _parserOpcodeTableSize - 1; - debugC(9, kDebugLevelSound, "Calling opcode '%s' (%d) (channel: %d)", _parserOpcodeTable[opcode].name, opcode, _curChannel); - result = (this->*(_parserOpcodeTable[opcode].function))(dataptr, channel, param); - channel.dataptr = dataptr; - if (result) - break; - } else { - debugC(9, kDebugLevelSound, "Note on opcode 0x%02X (duration: %d) (channel: %d)", opcode, param, _curChannel); - setupNote(opcode, channel); - noteOn(channel); - setupDuration(param, channel); - if (param) { - channel.dataptr = dataptr; - break; - } - } - } - } - } - - if (result == 1) { - if (channel.primaryEffect) - (this->*(channel.primaryEffect))(channel); - if (channel.secondaryEffect) - (this->*(channel.secondaryEffect))(channel); - } - } -} - -// - -void AdlibDriver::resetAdlibState() { - debugC(9, kDebugLevelSound, "resetAdlibState()"); - _rnd = 0x1234; - - // Authorize the control of the waveforms - writeOPL(0x01, 0x20); - - // Select FM music mode - writeOPL(0x08, 0x00); - - // I would guess the main purpose of this is to turn off the rhythm, - // thus allowing us to use 9 melodic voices instead of 6. - writeOPL(0xBD, 0x00); - - int loop = 10; - while (loop--) { - if (loop != 9) { - // Silence the channel - writeOPL(0x40 + _regOffset[loop], 0x3F); - writeOPL(0x43 + _regOffset[loop], 0x3F); - } - initChannel(_channels[loop]); - } -} - -// Old calling style: output0x388(0xABCD) -// New calling style: writeOPL(0xAB, 0xCD) - -void AdlibDriver::writeOPL(byte reg, byte val) { - opl->write(reg, val); -} - -void AdlibDriver::initChannel(Channel &channel) { - debugC(9, kDebugLevelSound, "initChannel(%lu)", (long)(&channel - _channels)); - memset(&channel.dataptr, 0, sizeof(Channel) - ((char*)&channel.dataptr - (char*)&channel)); - - channel.tempo = 0xFF; - channel.priority = 0; - // normally here are nullfuncs but we set 0 for now - channel.primaryEffect = 0; - channel.secondaryEffect = 0; - channel.spacing1 = 1; -} - -void AdlibDriver::noteOff(Channel &channel) { - debugC(9, kDebugLevelSound, "noteOff(%lu)", (long)(&channel - _channels)); - - // The control channel has no corresponding Adlib channel - - if (_curChannel >= 9) - return; - - // When the rhythm section is enabled, channels 6, 7 and 8 are special. - - if (_rhythmSectionBits && _curChannel >= 6) - return; - - // This means the "Key On" bit will always be 0 - channel.regBx &= 0xDF; - - // Octave / F-Number / Key-On - writeOPL(0xB0 + _curChannel, channel.regBx); -} - -void AdlibDriver::unkOutput2(uint8 chan) { - debugC(9, kDebugLevelSound, "unkOutput2(%d)", chan); - - // The control channel has no corresponding Adlib channel - - if (chan >= 9) - return; - - // I believe this has to do with channels 6, 7, and 8 being special - // when Adlib's rhythm section is enabled. - - if (_rhythmSectionBits && chan >= 6) - return; - - uint8 offset = _regOffset[chan]; - - // The channel is cleared: First the attack/delay rate, then the - // sustain level/release rate, and finally the note is turned off. - - writeOPL(0x60 + offset, 0xFF); - writeOPL(0x63 + offset, 0xFF); - - writeOPL(0x80 + offset, 0xFF); - writeOPL(0x83 + offset, 0xFF); - - writeOPL(0xB0 + chan, 0x00); - - // ...and then the note is turned on again, with whatever value is - // still lurking in the A0 + chan register, but everything else - - // including the two most significant frequency bit, and the octave - - // set to zero. - // - // This is very strange behaviour, and causes problems with the ancient - // FMOPL code we borrowed from AdPlug. I've added a workaround. See - // fmopl.cpp for more details. - // - // More recent versions of the MAME FMOPL don't seem to have this - // problem, but cannot currently be used because of licensing and - // performance issues. - // - // Ken Silverman's Adlib emulator (which can be found on his Web page - - // http://www.advsys.net/ken - and as part of AdPlug) also seems to be - // immune, but is apparently not as feature complete as MAME's. - - writeOPL(0xB0 + chan, 0x20); -} - -// I believe this is a random number generator. It actually does seem to -// generate an even distribution of almost all numbers from 0 through 65535, -// though in my tests some numbers were never generated. - -uint16 AdlibDriver::getRandomNr() { - _rnd += 0x9248; - uint16 lowBits = _rnd & 7; - _rnd >>= 3; - _rnd |= (lowBits << 13); - return _rnd; -} - -void AdlibDriver::setupDuration(uint8 duration, Channel &channel) { - debugC(9, kDebugLevelSound, "setupDuration(%d, %lu)", duration, (long)(&channel - _channels)); - if (channel.durationRandomness) { - channel.duration = duration + (getRandomNr() & channel.durationRandomness); - return; - } - if (channel.fractionalSpacing) { - channel.spacing2 = (duration >> 3) * channel.fractionalSpacing; - } - channel.duration = duration; -} - -// This function may or may not play the note. It's usually followed by a call -// to noteOn(), which will always play the current note. - -void AdlibDriver::setupNote(uint8 rawNote, Channel &channel, bool flag) { - debugC(9, kDebugLevelSound, "setupNote(%d, %lu)", rawNote, (long)(&channel - _channels)); - - channel.rawNote = rawNote; - - int8 note = (rawNote & 0x0F) + channel.baseNote; - int8 octave = ((rawNote + channel.baseOctave) >> 4) & 0x0F; - - // There are only twelve notes. If we go outside that, we have to - // adjust the note and octave. - - if (note >= 12) { - note -= 12; - octave++; - } else if (note < 0) { - note += 12; - octave--; - } - - // The calculation of frequency looks quite different from the original - // disassembly at a first glance, but when you consider that the - // largest possible value would be 0x0246 + 0xFF + 0x47 (and that's if - // baseFreq is unsigned), freq is still a 10-bit value, just as it - // should be to fit in the Ax and Bx registers. - // - // If it were larger than that, it could have overflowed into the - // octave bits, and that could possibly have been used in some sound. - // But as it is now, I can't see any way it would happen. - - uint16 freq = _unkTable[note] + channel.baseFreq; - - // When called from callback 41, the behaviour is slightly different: - // We adjust the frequency, even when channel.unk16 is 0. - - if (channel.unk16 || flag) { - const uint8 *table; - - if (channel.unk16 >= 0) { - table = _unkTables[(channel.rawNote & 0x0F) + 2]; - freq += table[channel.unk16]; - } else { - table = _unkTables[channel.rawNote & 0x0F]; - freq -= table[-channel.unk16]; - } - } - - channel.regAx = freq & 0xFF; - channel.regBx = (channel.regBx & 0x20) | (octave << 2) | ((freq >> 8) & 0x03); - - // Keep the note on or off - writeOPL(0xA0 + _curChannel, channel.regAx); - writeOPL(0xB0 + _curChannel, channel.regBx); -} - -void AdlibDriver::setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel) { - debugC(9, kDebugLevelSound, "setupInstrument(%d, %p, %lu)", regOffset, (const void *)dataptr, (long)(&channel - _channels)); - // Amplitude Modulation / Vibrato / Envelope Generator Type / - // Keyboard Scaling Rate / Modulator Frequency Multiple - writeOPL(0x20 + regOffset, *dataptr++); - writeOPL(0x23 + regOffset, *dataptr++); - - uint8 temp = *dataptr++; - - // Feedback / Algorithm - - // It is very likely that _curChannel really does refer to the same - // channel as regOffset, but there's only one Cx register per channel. - - writeOPL(0xC0 + _curChannel, temp); - - // The algorithm bit. I don't pretend to understand this fully, but - // "If set to 0, operator 1 modulates operator 2. In this case, - // operator 2 is the only one producing sound. If set to 1, both - // operators produce sound directly. Complex sounds are more easily - // created if the algorithm is set to 0." - - channel.twoChan = temp & 1; - - // Waveform Select - writeOPL(0xE0 + regOffset, *dataptr++); - writeOPL(0xE3 + regOffset, *dataptr++); - - channel.opLevel1 = *dataptr++; - channel.opLevel2 = *dataptr++; - - // Level Key Scaling / Total Level - writeOPL(0x40 + regOffset, calculateOpLevel1(channel)); - writeOPL(0x43 + regOffset, calculateOpLevel2(channel)); - - // Attack Rate / Decay Rate - writeOPL(0x60 + regOffset, *dataptr++); - writeOPL(0x63 + regOffset, *dataptr++); - - // Sustain Level / Release Rate - writeOPL(0x80 + regOffset, *dataptr++); - writeOPL(0x83 + regOffset, *dataptr++); -} - -// Apart from playing the note, this function also updates the variables for -// primary effect 2. - -void AdlibDriver::noteOn(Channel &channel) { - debugC(9, kDebugLevelSound, "noteOn(%lu)", (long)(&channel - _channels)); - - // The "note on" bit is set, and the current note is played. - - channel.regBx |= 0x20; - writeOPL(0xB0 + _curChannel, channel.regBx); - - int8 shift = 9 - channel.unk33; - uint16 temp = channel.regAx | (channel.regBx << 8); - channel.unk37 = ((temp & 0x3FF) >> shift) & 0xFF; - channel.unk38 = channel.unk36; -} - -void AdlibDriver::adjustVolume(Channel &channel) { - debugC(9, kDebugLevelSound, "adjustVolume(%lu)", (long)(&channel - _channels)); - // Level Key Scaling / Total Level - - writeOPL(0x43 + _regOffset[_curChannel], calculateOpLevel2(channel)); - if (channel.twoChan) - writeOPL(0x40 + _regOffset[_curChannel], calculateOpLevel1(channel)); -} - -// This is presumably only used for some sound effects, e.g. Malcolm blowing up -// the trees in the intro (but not the effect where he "booby-traps" the big -// tree) and turning Kallak to stone. Related functions and variables: -// -// update_setupPrimaryEffect1() -// - Initialises unk29, unk30 and unk31 -// - unk29 is not further modified -// - unk30 is not further modified, except by update_removePrimaryEffect1() -// -// update_removePrimaryEffect1() -// - Deinitialises unk30 -// -// unk29 - determines how often the notes are played -// unk30 - modifies the frequency -// unk31 - determines how often the notes are played - -void AdlibDriver::primaryEffect1(Channel &channel) { - debugC(9, kDebugLevelSound, "Calling primaryEffect1 (channel: %d)", _curChannel); - uint8 temp = channel.unk31; - channel.unk31 += channel.unk29; - if (channel.unk31 >= temp) - return; - - // Initialise unk1 to the current frequency - uint16 unk1 = ((channel.regBx & 3) << 8) | channel.regAx; - - // This is presumably to shift the "note on" bit so far to the left - // that it won't be affected by any of the calculations below. - uint16 unk2 = ((channel.regBx & 0x20) << 8) | (channel.regBx & 0x1C); - - int16 unk3 = (int16)channel.unk30; - - if (unk3 >= 0) { - unk1 += unk3; - if (unk1 >= 734) { - // The new frequency is too high. Shift it down and go - // up one octave. - unk1 >>= 1; - if (!(unk1 & 0x3FF)) - ++unk1; - unk2 = (unk2 & 0xFF00) | ((unk2 + 4) & 0xFF); - unk2 &= 0xFF1C; - } - } else { - unk1 += unk3; - if (unk1 < 388) { - // The new frequency is too low. Shift it up and go - // down one octave. - unk1 <<= 1; - if (!(unk1 & 0x3FF)) - --unk1; - unk2 = (unk2 & 0xFF00) | ((unk2 - 4) & 0xFF); - unk2 &= 0xFF1C; - } - } - - // Make sure that the new frequency is still a 10-bit value. - unk1 &= 0x3FF; - - writeOPL(0xA0 + _curChannel, unk1 & 0xFF); - channel.regAx = unk1 & 0xFF; - - // Shift down the "note on" bit again. - uint8 value = unk1 >> 8; - value |= (unk2 >> 8) & 0xFF; - value |= unk2 & 0xFF; - - writeOPL(0xB0 + _curChannel, value); - channel.regBx = value; -} - -// This is presumably only used for some sound effects, e.g. Malcolm entering -// and leaving Kallak's hut. Related functions and variables: -// -// update_setupPrimaryEffect2() -// - Initialises unk32, unk33, unk34, unk35 and unk36 -// - unk32 is not further modified -// - unk33 is not further modified -// - unk34 is a countdown that gets reinitialised to unk35 on zero -// - unk35 is based on unk34 and not further modified -// - unk36 is not further modified -// -// noteOn() -// - Plays the current note -// - Updates unk37 with a new (lower?) frequency -// - Copies unk36 to unk38. The unk38 variable is a countdown. -// -// unk32 - determines how often the notes are played -// unk33 - modifies the frequency -// unk34 - countdown, updates frequency on zero -// unk35 - initialiser for unk34 countdown -// unk36 - initialiser for unk38 countdown -// unk37 - frequency -// unk38 - countdown, begins playing on zero -// unk41 - determines how often the notes are played -// -// Note that unk41 is never initialised. Not that it should matter much, but it -// is a bit sloppy. - -void AdlibDriver::primaryEffect2(Channel &channel) { - debugC(9, kDebugLevelSound, "Calling primaryEffect2 (channel: %d)", _curChannel); - if (channel.unk38) { - --channel.unk38; - return; - } - - uint8 temp = channel.unk41; - channel.unk41 += channel.unk32; - if (channel.unk41 < temp) { - uint16 unk1 = channel.unk37; - if (!(--channel.unk34)) { - unk1 ^= 0xFFFF; - ++unk1; - channel.unk37 = unk1; - channel.unk34 = channel.unk35; - } - - uint16 unk2 = (channel.regAx | (channel.regBx << 8)) & 0x3FF; - unk2 += unk1; - - channel.regAx = unk2 & 0xFF; - channel.regBx = (channel.regBx & 0xFC) | (unk2 >> 8); - - // Octave / F-Number / Key-On - writeOPL(0xA0 + _curChannel, channel.regAx); - writeOPL(0xB0 + _curChannel, channel.regBx); - } -} - -// I don't know where this is used. The same operation is performed several -// times on the current channel, using a chunk of the _soundData[] buffer for -// parameters. The parameters are used starting at the end of the chunk. -// -// Since we use _curRegOffset to specify the final register, it's quite -// unlikely that this function is ever used to play notes. It's probably only -// used to modify the sound. Another thing that supports this idea is that it -// can be combined with any of the effects callbacks above. -// -// Related functions and variables: -// -// update_setupSecondaryEffect1() -// - Initialies unk18, unk19, unk20, unk21, unk22 and offset -// - unk19 is not further modified -// - unk20 is not further modified -// - unk22 is not further modified -// - offset is not further modified -// -// unk18 - determines how often the operation is performed -// unk19 - determines how often the operation is performed -// unk20 - the start index into the data chunk -// unk21 - the current index into the data chunk -// unk22 - the operation to perform -// offset - the offset to the data chunk - -void AdlibDriver::secondaryEffect1(Channel &channel) { - debugC(9, kDebugLevelSound, "Calling secondaryEffect1 (channel: %d)", _curChannel); - uint8 temp = channel.unk18; - channel.unk18 += channel.unk19; - if (channel.unk18 < temp) { - if (--channel.unk21 < 0) { - channel.unk21 = channel.unk20; - } - writeOPL(channel.unk22 + _curRegOffset, _soundData[channel.offset + channel.unk21]); - } -} - -uint8 AdlibDriver::calculateOpLevel1(Channel &channel) { - int8 value = channel.opLevel1 & 0x3F; - - if (channel.twoChan) { - value += channel.opExtraLevel1; - value += channel.opExtraLevel2; - value += channel.opExtraLevel3; - } - - // Preserve the scaling level bits from opLevel1 - - return checkValue(value) | (channel.opLevel1 & 0xC0); -} - -uint8 AdlibDriver::calculateOpLevel2(Channel &channel) { - int8 value = channel.opLevel2 & 0x3F; - - value += channel.opExtraLevel1; - value += channel.opExtraLevel2; - value += channel.opExtraLevel3; - - // Preserve the scaling level bits from opLevel2 - - return checkValue(value) | (channel.opLevel2 & 0xC0); -} - -// parser opcodes - -int AdlibDriver::update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.repeatCounter = value; - return 0; -} - -int AdlibDriver::update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value) { - ++dataptr; - if (--channel.repeatCounter) { - int16 add = READ_LE_UINT16(dataptr - 2); - dataptr += add; - } - return 0; -} - -int AdlibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value) { - if (value == 0xFF) - return 0; - - uint8 *ptr = getProgram(value); - uint8 chan = *ptr++; - uint8 priority = *ptr++; - - Channel &channel2 = _channels[chan]; - - if (priority >= channel2.priority) { - _flagTrigger = 1; - _flags |= 8; - initChannel(channel2); - channel2.priority = priority; - channel2.dataptr = ptr; - channel2.tempo = 0xFF; - channel2.position = 0xFF; - channel2.duration = 1; - unkOutput2(chan); - } - - return 0; -} - -int AdlibDriver::update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.spacing1 = value; - return 0; -} - -int AdlibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) { - --dataptr; - int16 add = READ_LE_UINT16(dataptr); dataptr += 2; - dataptr += add; - return 0; -} - -int AdlibDriver::update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) { - --dataptr; - int16 add = READ_LE_UINT16(dataptr); dataptr += 2; - channel.dataptrStack[channel.dataptrStackPos++] = dataptr; - dataptr += add; - return 0; -} - -int AdlibDriver::update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) { - dataptr = channel.dataptrStack[--channel.dataptrStackPos]; - return 0; -} - -int AdlibDriver::update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.baseOctave = value; - return 0; -} - -int AdlibDriver::update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.priority = 0; - if (_curChannel != 9) { - noteOff(channel); - } - dataptr = 0; - return 2; -} - -int AdlibDriver::update_playRest(uint8 *&dataptr, Channel &channel, uint8 value) { - setupDuration(value, channel); - noteOff(channel); - return (value != 0); -} - -int AdlibDriver::update_writeAdlib(uint8 *&dataptr, Channel &channel, uint8 value) { - writeOPL(value, *dataptr++); - return 0; -} - -int AdlibDriver::update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value) { - setupNote(value, channel); - value = *dataptr++; - setupDuration(value, channel); - return (value != 0); -} - -int AdlibDriver::update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.baseNote = value; - return 0; -} - -int AdlibDriver::update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.unk18 = value; - channel.unk19 = value; - channel.unk20 = channel.unk21 = *dataptr++; - channel.unk22 = *dataptr++; - channel.offset = READ_LE_UINT16(dataptr); dataptr += 2; - channel.secondaryEffect = &AdlibDriver::secondaryEffect1; - return 0; -} - -int AdlibDriver::update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value) { - Channel &channel2 = _channels[value]; - channel2.duration = 0; - channel2.priority = 0; - channel2.dataptr = 0; - return 0; -} - -int AdlibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value) { - uint8 *ptr = getProgram(value); - uint8 chan = *ptr; - - if (!_channels[chan].dataptr) { - return 0; - } - - dataptr -= 2; - return 2; -} - -int AdlibDriver::update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value) { - setupInstrument(_curRegOffset, getInstrument(value), channel); - return 0; -} - -int AdlibDriver::update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.unk29 = value; - channel.unk30 = READ_BE_UINT16(dataptr); - dataptr += 2; - channel.primaryEffect = &AdlibDriver::primaryEffect1; - channel.unk31 = 0xFF; - return 0; -} - -int AdlibDriver::update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { - --dataptr; - channel.primaryEffect = 0; - channel.unk30 = 0; - return 0; -} - -int AdlibDriver::update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.baseFreq = value; - return 0; -} - -int AdlibDriver::update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.unk32 = value; - channel.unk33 = *dataptr++; - uint8 temp = *dataptr++; - channel.unk34 = temp + 1; - channel.unk35 = temp << 1; - channel.unk36 = *dataptr++; - channel.primaryEffect = &AdlibDriver::primaryEffect2; - return 0; -} - -int AdlibDriver::update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.priority = value; - return 0; -} - -int AdlibDriver::updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value) { - value >>= 1; - _unkValue1 = _unkValue2 = value; - _unkValue3 = 0xFF; - _unkValue4 = _unkValue5 = 0; - return 0; -} - -int AdlibDriver::updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value) { - if (_unkValue5) { - if (_unkValue4 & value) { - _unkValue5 = 0; - return 0; - } - } - - if (!(value & _unkValue4)) { - ++_unkValue5; - } - - dataptr -= 2; - channel.duration = 1; - return 2; -} - -int AdlibDriver::update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.opExtraLevel1 = value; - adjustVolume(channel); - return 0; -} - -int AdlibDriver::update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value) { - setupDuration(value, channel); - return (value != 0); -} - -int AdlibDriver::update_playNote(uint8 *&dataptr, Channel &channel, uint8 value) { - setupDuration(value, channel); - noteOn(channel); - return (value != 0); -} - -int AdlibDriver::update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.fractionalSpacing = value & 7; - return 0; -} - -int AdlibDriver::update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value) { - _tempo = value; - return 0; -} - -int AdlibDriver::update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { - --dataptr; - channel.secondaryEffect = 0; - return 0; -} - -int AdlibDriver::update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.tempo = value; - return 0; -} - -int AdlibDriver::update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.opExtraLevel3 = value; - return 0; -} - -int AdlibDriver::update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) { - int channelBackUp = _curChannel; - - _curChannel = value; - Channel &channel2 = _channels[value]; - channel2.opExtraLevel2 = *dataptr++; - adjustVolume(channel2); - - _curChannel = channelBackUp; - return 0; -} - -int AdlibDriver::update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) { - int channelBackUp = _curChannel; - - _curChannel = value; - Channel &channel2 = _channels[value]; - channel2.opExtraLevel2 += *dataptr++; - adjustVolume(channel2); - - _curChannel = channelBackUp; - return 0; -} - -// Apart from initialising to zero, these two functions are the only ones that -// modify _vibratoAndAMDepthBits. - -int AdlibDriver::update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value) { - if (value & 1) - _vibratoAndAMDepthBits |= 0x80; - else - _vibratoAndAMDepthBits &= 0x7F; - - writeOPL(0xBD, _vibratoAndAMDepthBits); - return 0; -} - -int AdlibDriver::update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value) { - if (value & 1) - _vibratoAndAMDepthBits |= 0x40; - else - _vibratoAndAMDepthBits &= 0xBF; - - writeOPL(0xBD, _vibratoAndAMDepthBits); - return 0; -} - -int AdlibDriver::update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.opExtraLevel1 += value; - adjustVolume(channel); - return 0; -} - -int AdlibDriver::updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value) { - int channelBackUp = _curChannel; - - _curChannel = value; - Channel &channel2 = _channels[value]; - channel2.duration = channel2.priority = 0; - channel2.dataptr = 0; - channel2.opExtraLevel2 = 0; - - if (value != 9) { - uint8 outValue = _regOffset[value]; - - // Feedback strength / Connection type - writeOPL(0xC0 + _curChannel, 0x00); - - // Key scaling level / Operator output level - writeOPL(0x43 + outValue, 0x3F); - - // Sustain Level / Release Rate - writeOPL(0x83 + outValue, 0xFF); - - // Key On / Octave / Frequency - writeOPL(0xB0 + _curChannel, 0x00); - } - - _curChannel = channelBackUp; - return 0; -} - -int AdlibDriver::updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value) { - uint16 unk = *dataptr++; - unk |= value << 8; - unk &= getRandomNr(); - - uint16 unk2 = ((channel.regBx & 0x1F) << 8) | channel.regAx; - unk2 += unk; - unk2 |= ((channel.regBx & 0x20) << 8); - - // Frequency - writeOPL(0xA0 + _curChannel, unk2 & 0xFF); - - // Key On / Octave / Frequency - writeOPL(0xB0 + _curChannel, (unk2 & 0xFF00) >> 8); - - return 0; -} - -int AdlibDriver::update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) { - --dataptr; - channel.primaryEffect = 0; - return 0; -} - -int AdlibDriver::updateCallback41(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.unk16 = value; - setupNote(channel.rawNote, channel, true); - return 0; -} - -int AdlibDriver::update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value) { - --dataptr; - channel.tempo = _tempo; - return 0; -} - -int AdlibDriver::update_nop1(uint8 *&dataptr, Channel &channel, uint8 value) { - --dataptr; - return 0; -} - -int AdlibDriver::update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.durationRandomness = value; - return 0; -} - -int AdlibDriver::update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) { - int tempo = channel.tempo + (int8)value; - - if (tempo <= 0) - tempo = 1; - else if (tempo > 255) - tempo = 255; - - channel.tempo = tempo; - return 0; -} - -int AdlibDriver::updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value) { - uint8 entry = *dataptr++; - _tablePtr1 = _unkTable2[entry++]; - _tablePtr2 = _unkTable2[entry]; - if (value == 2) { - // Frequency - writeOPL(0xA0, _tablePtr2[0]); - } - return 0; -} - -// TODO: This is really the same as update_nop1(), so they should be combined -// into one single update_nop(). - -int AdlibDriver::update_nop2(uint8 *&dataptr, Channel &channel, uint8 value) { - --dataptr; - return 0; -} - -int AdlibDriver::update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) { - int channelBackUp = _curChannel; - int regOffsetBackUp = _curRegOffset; - - _curChannel = 6; - _curRegOffset = _regOffset[6]; - - setupInstrument(_curRegOffset, getInstrument(value), channel); - _unkValue6 = channel.opLevel2; - - _curChannel = 7; - _curRegOffset = _regOffset[7]; - - setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel); - _unkValue7 = channel.opLevel1; - _unkValue8 = channel.opLevel2; - - _curChannel = 8; - _curRegOffset = _regOffset[8]; - - setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel); - _unkValue9 = channel.opLevel1; - _unkValue10 = channel.opLevel2; - - // Octave / F-Number / Key-On for channels 6, 7 and 8 - - _channels[6].regBx = *dataptr++ & 0x2F; - writeOPL(0xB6, _channels[6].regBx); - writeOPL(0xA6, *dataptr++); - - _channels[7].regBx = *dataptr++ & 0x2F; - writeOPL(0xB7, _channels[7].regBx); - writeOPL(0xA7, *dataptr++); - - _channels[8].regBx = *dataptr++ & 0x2F; - writeOPL(0xB8, _channels[8].regBx); - writeOPL(0xA8, *dataptr++); - - _rhythmSectionBits = 0x20; - - _curRegOffset = regOffsetBackUp; - _curChannel = channelBackUp; - return 0; -} - -int AdlibDriver::update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) { - // Any instrument that we want to play, and which was already playing, - // is temporarily keyed off. Instruments that were off already, or - // which we don't want to play, retain their old on/off status. This is - // probably so that the instrument's envelope is played from its - // beginning again... - - writeOPL(0xBD, (_rhythmSectionBits & ~(value & 0x1F)) | 0x20); - - // ...but since we only set the rhythm instrument bits, and never clear - // them (until the entire rhythm section is disabled), I'm not sure how - // useful the cleverness above is. We could perhaps simply turn off all - // the rhythm instruments instead. - - _rhythmSectionBits |= value; - - writeOPL(0xBD, _vibratoAndAMDepthBits | 0x20 | _rhythmSectionBits); - return 0; -} - -int AdlibDriver::update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) { - --dataptr; - _rhythmSectionBits = 0; - - // All the rhythm bits are cleared. The AM and Vibrato depth bits - // remain unchanged. - - writeOPL(0xBD, _vibratoAndAMDepthBits); - return 0; -} - -int AdlibDriver::updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value) { - uint8 value2 = *dataptr++; - - if (value & 1) { - _unkValue12 = value2; - - // Channel 7, op1: Level Key Scaling / Total Level - writeOPL(0x51, checkValue(value2 + _unkValue7 + _unkValue11 + _unkValue12)); - } - - if (value & 2) { - _unkValue14 = value2; - - // Channel 8, op2: Level Key Scaling / Total Level - writeOPL(0x55, checkValue(value2 + _unkValue10 + _unkValue13 + _unkValue14)); - } - - if (value & 4) { - _unkValue15 = value2; - - // Channel 8, op1: Level Key Scaling / Total Level - writeOPL(0x52, checkValue(value2 + _unkValue9 + _unkValue16 + _unkValue15)); - } - - if (value & 8) { - _unkValue18 = value2; - - // Channel 7, op2: Level Key Scaling / Total Level - writeOPL(0x54, checkValue(value2 + _unkValue8 + _unkValue17 + _unkValue18)); - } - - if (value & 16) { - _unkValue20 = value2; - - // Channel 6, op2: Level Key Scaling / Total Level - writeOPL(0x53, checkValue(value2 + _unkValue6 + _unkValue19 + _unkValue20)); - } - - return 0; -} - -int AdlibDriver::updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value) { - uint8 value2 = *dataptr++; - - if (value & 1) { - _unkValue11 = checkValue(value2 + _unkValue7 + _unkValue11 + _unkValue12); - - // Channel 7, op1: Level Key Scaling / Total Level - writeOPL(0x51, _unkValue11); - } - - if (value & 2) { - _unkValue13 = checkValue(value2 + _unkValue10 + _unkValue13 + _unkValue14); - - // Channel 8, op2: Level Key Scaling / Total Level - writeOPL(0x55, _unkValue13); - } - - if (value & 4) { - _unkValue16 = checkValue(value2 + _unkValue9 + _unkValue16 + _unkValue15); - - // Channel 8, op1: Level Key Scaling / Total Level - writeOPL(0x52, _unkValue16); - } - - if (value & 8) { - _unkValue17 = checkValue(value2 + _unkValue8 + _unkValue17 + _unkValue18); - - // Channel 7, op2: Level Key Scaling / Total Level - writeOPL(0x54, _unkValue17); - } - - if (value & 16) { - _unkValue19 = checkValue(value2 + _unkValue6 + _unkValue19 + _unkValue20); - - // Channel 6, op2: Level Key Scaling / Total Level - writeOPL(0x53, _unkValue19); - } - - return 0; -} - -int AdlibDriver::updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value) { - uint8 value2 = *dataptr++; - - if (value & 1) { - _unkValue11 = value2; - - // Channel 7, op1: Level Key Scaling / Total Level - writeOPL(0x51, checkValue(value2 + _unkValue7 + _unkValue12)); - } - - if (value & 2) { - _unkValue13 = value2; - - // Channel 8, op2: Level Key Scaling / Total Level - writeOPL(0x55, checkValue(value2 + _unkValue10 + _unkValue14)); - } - - if (value & 4) { - _unkValue16 = value2; - - // Channel 8, op1: Level Key Scaling / Total Level - writeOPL(0x52, checkValue(value2 + _unkValue9 + _unkValue15)); - } - - if (value & 8) { - _unkValue17 = value2; - - // Channel 7, op2: Level Key Scaling / Total Level - writeOPL(0x54, checkValue(value2 + _unkValue8 + _unkValue18)); - } - - if (value & 16) { - _unkValue19 = value2; - - // Channel 6, op2: Level Key Scaling / Total Level - writeOPL(0x53, checkValue(value2 + _unkValue6 + _unkValue20)); - } - - return 0; -} - -int AdlibDriver::update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value) { - _soundTrigger = value; - return 0; -} - -int AdlibDriver::update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.tempoReset = value; - return 0; -} - -int AdlibDriver::updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value) { - channel.unk39 = value; - channel.unk40 = *dataptr++; - return 0; -} - -// static res - -#define COMMAND(x) { &AdlibDriver::x, #x } - -void AdlibDriver::setupOpcodeList() { - static const OpcodeEntry opcodeList[] = { - COMMAND(snd_ret0x100), - COMMAND(snd_ret0x1983), - COMMAND(snd_initDriver), - COMMAND(snd_deinitDriver), - COMMAND(snd_setSoundData), - COMMAND(snd_unkOpcode1), - COMMAND(snd_startSong), - COMMAND(snd_unkOpcode2), - COMMAND(snd_unkOpcode3), - COMMAND(snd_readByte), - COMMAND(snd_writeByte), - COMMAND(snd_getSoundTrigger), - COMMAND(snd_unkOpcode4), - COMMAND(snd_dummy), - COMMAND(snd_getNullvar4), - COMMAND(snd_setNullvar3), - COMMAND(snd_setFlag), - COMMAND(snd_clearFlag) - }; - - _opcodeList = opcodeList; - _opcodesEntries = ARRAYSIZE(opcodeList); -} - -void AdlibDriver::setupParserOpcodeTable() { - static const ParserOpcode parserOpcodeTable[] = { - // 0 - COMMAND(update_setRepeat), - COMMAND(update_checkRepeat), - COMMAND(update_setupProgram), - COMMAND(update_setNoteSpacing), - - // 4 - COMMAND(update_jump), - COMMAND(update_jumpToSubroutine), - COMMAND(update_returnFromSubroutine), - COMMAND(update_setBaseOctave), - - // 8 - COMMAND(update_stopChannel), - COMMAND(update_playRest), - COMMAND(update_writeAdlib), - COMMAND(update_setupNoteAndDuration), - - // 12 - COMMAND(update_setBaseNote), - COMMAND(update_setupSecondaryEffect1), - COMMAND(update_stopOtherChannel), - COMMAND(update_waitForEndOfProgram), - - // 16 - COMMAND(update_setupInstrument), - COMMAND(update_setupPrimaryEffect1), - COMMAND(update_removePrimaryEffect1), - COMMAND(update_setBaseFreq), - - // 20 - COMMAND(update_stopChannel), - COMMAND(update_setupPrimaryEffect2), - COMMAND(update_stopChannel), - COMMAND(update_stopChannel), - - // 24 - COMMAND(update_stopChannel), - COMMAND(update_stopChannel), - COMMAND(update_setPriority), - COMMAND(update_stopChannel), - - // 28 - COMMAND(updateCallback23), - COMMAND(updateCallback24), - COMMAND(update_setExtraLevel1), - COMMAND(update_stopChannel), - - // 32 - COMMAND(update_setupDuration), - COMMAND(update_playNote), - COMMAND(update_stopChannel), - COMMAND(update_stopChannel), - - // 36 - COMMAND(update_setFractionalNoteSpacing), - COMMAND(update_stopChannel), - COMMAND(update_setTempo), - COMMAND(update_removeSecondaryEffect1), - - // 40 - COMMAND(update_stopChannel), - COMMAND(update_setChannelTempo), - COMMAND(update_stopChannel), - COMMAND(update_setExtraLevel3), - - // 44 - COMMAND(update_setExtraLevel2), - COMMAND(update_changeExtraLevel2), - COMMAND(update_setAMDepth), - COMMAND(update_setVibratoDepth), - - // 48 - COMMAND(update_changeExtraLevel1), - COMMAND(update_stopChannel), - COMMAND(update_stopChannel), - COMMAND(updateCallback38), - - // 52 - COMMAND(update_stopChannel), - COMMAND(updateCallback39), - COMMAND(update_removePrimaryEffect2), - COMMAND(update_stopChannel), - - // 56 - COMMAND(update_stopChannel), - COMMAND(updateCallback41), - COMMAND(update_resetToGlobalTempo), - COMMAND(update_nop1), - - // 60 - COMMAND(update_setDurationRandomness), - COMMAND(update_changeChannelTempo), - COMMAND(update_stopChannel), - COMMAND(updateCallback46), - - // 64 - COMMAND(update_nop2), - COMMAND(update_setupRhythmSection), - COMMAND(update_playRhythmSection), - COMMAND(update_removeRhythmSection), - - // 68 - COMMAND(updateCallback51), - COMMAND(updateCallback52), - COMMAND(updateCallback53), - COMMAND(update_setSoundTrigger), - - // 72 - COMMAND(update_setTempoReset), - COMMAND(updateCallback56), - COMMAND(update_stopChannel) - }; - - _parserOpcodeTable = parserOpcodeTable; - _parserOpcodeTableSize = ARRAYSIZE(parserOpcodeTable); -} -#undef COMMAND - -// This table holds the register offset for operator 1 for each of the nine -// channels. To get the register offset for operator 2, simply add 3. - -const uint8 AdlibDriver::_regOffset[] = { - 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, - 0x12 -}; - -// Given the size of this table, and the range of its values, it's probably the -// F-Numbers (10 bits) for the notes of the 12-tone scale. However, it does not -// match the table in the Adlib documentation I've seen. - -const uint16 AdlibDriver::_unkTable[] = { - 0x0134, 0x0147, 0x015A, 0x016F, 0x0184, 0x019C, 0x01B4, 0x01CE, 0x01E9, - 0x0207, 0x0225, 0x0246 -}; - -// These tables are currently only used by updateCallback46(), which only ever -// uses the first element of one of the sub-tables. - -const uint8 *AdlibDriver::_unkTable2[] = { - AdlibDriver::_unkTable2_1, - AdlibDriver::_unkTable2_2, - AdlibDriver::_unkTable2_1, - AdlibDriver::_unkTable2_2, - AdlibDriver::_unkTable2_3, - AdlibDriver::_unkTable2_2 -}; - -const uint8 AdlibDriver::_unkTable2_1[] = { - 0x50, 0x50, 0x4F, 0x4F, 0x4E, 0x4E, 0x4D, 0x4D, - 0x4C, 0x4C, 0x4B, 0x4B, 0x4A, 0x4A, 0x49, 0x49, - 0x48, 0x48, 0x47, 0x47, 0x46, 0x46, 0x45, 0x45, - 0x44, 0x44, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41, - 0x40, 0x40, 0x3F, 0x3F, 0x3E, 0x3E, 0x3D, 0x3D, - 0x3C, 0x3C, 0x3B, 0x3B, 0x3A, 0x3A, 0x39, 0x39, - 0x38, 0x38, 0x37, 0x37, 0x36, 0x36, 0x35, 0x35, - 0x34, 0x34, 0x33, 0x33, 0x32, 0x32, 0x31, 0x31, - 0x30, 0x30, 0x2F, 0x2F, 0x2E, 0x2E, 0x2D, 0x2D, - 0x2C, 0x2C, 0x2B, 0x2B, 0x2A, 0x2A, 0x29, 0x29, - 0x28, 0x28, 0x27, 0x27, 0x26, 0x26, 0x25, 0x25, - 0x24, 0x24, 0x23, 0x23, 0x22, 0x22, 0x21, 0x21, - 0x20, 0x20, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, 0x1D, - 0x1C, 0x1C, 0x1B, 0x1B, 0x1A, 0x1A, 0x19, 0x19, - 0x18, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, - 0x14, 0x14, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, - 0x10, 0x10 -}; - -// no don't ask me WHY this table exsits! -const uint8 AdlibDriver::_unkTable2_2[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x6F, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F -}; - -const uint8 AdlibDriver::_unkTable2_3[] = { - 0x40, 0x40, 0x40, 0x3F, 0x3F, 0x3F, 0x3E, 0x3E, - 0x3E, 0x3D, 0x3D, 0x3D, 0x3C, 0x3C, 0x3C, 0x3B, - 0x3B, 0x3B, 0x3A, 0x3A, 0x3A, 0x39, 0x39, 0x39, - 0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x36, - 0x36, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x33, - 0x33, 0x33, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31, - 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x2E, - 0x2E, 0x2D, 0x2D, 0x2D, 0x2C, 0x2C, 0x2C, 0x2B, - 0x2B, 0x2B, 0x2A, 0x2A, 0x2A, 0x29, 0x29, 0x29, - 0x28, 0x28, 0x28, 0x27, 0x27, 0x27, 0x26, 0x26, - 0x26, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x23, - 0x23, 0x23, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, - 0x20, 0x20, 0x20, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, - 0x1E, 0x1D, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1B, - 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x19, - 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x16, 0x16, - 0x16, 0x15 -}; - -// This table is used to modify the frequency of the notes, depending on the -// note value and unk16. In theory, we could very well try to access memory -// outside this table, but in reality that probably won't happen. -// -// This could be some sort of pitch bend, but I have yet to see it used for -// anything so it's hard to say. - -const uint8 AdlibDriver::_unkTables[][32] = { - // 0 - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21 }, - // 1 - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x09, - 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x1A, - 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x22, 0x24 }, - // 2 - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x09, - 0x0A, 0x0C, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x19, 0x1A, 0x1C, 0x1D, - 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26 }, - // 3 - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0A, - 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x1A, 0x1C, 0x1D, - 0x1E, 0x1F, 0x20, 0x21, 0x23, 0x25, 0x27, 0x28 }, - // 4 - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0A, - 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x11, 0x13, 0x15, - 0x16, 0x17, 0x18, 0x19, 0x1B, 0x1D, 0x1F, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x28, 0x2A }, - // 5 - { 0x00, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x15, - 0x16, 0x17, 0x18, 0x19, 0x1B, 0x1D, 0x1F, 0x20, - 0x21, 0x22, 0x23, 0x25, 0x27, 0x29, 0x2B, 0x2D }, - // 6 - { 0x00, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x15, - 0x16, 0x17, 0x18, 0x1A, 0x1C, 0x1E, 0x21, 0x24, - 0x25, 0x26, 0x27, 0x29, 0x2B, 0x2D, 0x2F, 0x30 }, - // 7 - { 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x15, 0x18, - 0x19, 0x1A, 0x1C, 0x1D, 0x1F, 0x21, 0x23, 0x25, - 0x26, 0x27, 0x29, 0x2B, 0x2D, 0x2F, 0x30, 0x32 }, - // 8 - { 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0D, - 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x14, 0x17, 0x1A, - 0x19, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x25, 0x28, - 0x29, 0x2A, 0x2B, 0x2D, 0x2F, 0x31, 0x33, 0x35 }, - // 9 - { 0x00, 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0E, - 0x0F, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1B, - 0x1C, 0x1D, 0x1E, 0x20, 0x22, 0x24, 0x26, 0x29, - 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x39 }, - // 10 - { 0x00, 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0E, - 0x0F, 0x10, 0x12, 0x14, 0x16, 0x19, 0x1B, 0x1E, - 0x1F, 0x21, 0x23, 0x25, 0x27, 0x29, 0x2B, 0x2D, - 0x2E, 0x2F, 0x31, 0x32, 0x34, 0x36, 0x39, 0x3C }, - // 11 - { 0x00, 0x01, 0x03, 0x05, 0x07, 0x0A, 0x0C, 0x0F, - 0x10, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1E, - 0x1F, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2B, 0x2E, - 0x2F, 0x30, 0x32, 0x34, 0x36, 0x39, 0x3C, 0x3F }, - // 12 - { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0D, 0x10, - 0x11, 0x12, 0x14, 0x16, 0x18, 0x1B, 0x1E, 0x21, - 0x22, 0x23, 0x25, 0x27, 0x29, 0x2C, 0x2F, 0x32, - 0x33, 0x34, 0x36, 0x38, 0x3B, 0x34, 0x41, 0x44 }, - // 13 - { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0D, 0x11, - 0x12, 0x13, 0x15, 0x17, 0x1A, 0x1D, 0x20, 0x23, - 0x24, 0x25, 0x27, 0x29, 0x2C, 0x2F, 0x32, 0x35, - 0x36, 0x37, 0x39, 0x3B, 0x3E, 0x41, 0x44, 0x47 } -}; - -// #pragma mark - - -// At the time of writing, the only known case where Kyra 1 uses sound triggers -// is in the castle, to cycle between three different songs. - -const int CadlPlayer::_kyra1SoundTriggers[] = { - 0, 4, 5, 3 -}; - -const int CadlPlayer::_kyra1NumSoundTriggers = ARRAYSIZE(CadlPlayer::_kyra1SoundTriggers); - -CadlPlayer::CadlPlayer(Copl *newopl) - : CPlayer(newopl), numsubsongs(0), _trackEntries(), _soundDataPtr(0) -{ - memset(_trackEntries, 0, sizeof(_trackEntries)); - _driver = new AdlibDriver(newopl); - assert(_driver); - - _sfxPlayingSound = -1; - // _soundFileLoaded = ""; - - _soundTriggers = _kyra1SoundTriggers; - _numSoundTriggers = _kyra1NumSoundTriggers; - - init(); -} - -CadlPlayer::~CadlPlayer() { - delete [] _soundDataPtr; - delete _driver; -} - -bool CadlPlayer::init() { - _driver->callback(2); - _driver->callback(16, int(4)); - return true; -} - -void CadlPlayer::process() { - uint8 trigger = _driver->callback(11); - - if (trigger < _numSoundTriggers) { - int soundId = _soundTriggers[trigger]; - - if (soundId) { - playTrack(soundId); - } - } else { - warning("Unknown sound trigger %d", trigger); - // TODO: At this point, we really want to clear the trigger... - } -} - -// void CadlPlayer::setVolume(int volume) { -// } - -// int CadlPlayer::getVolume() { -// return 0; -// } - -// void CadlPlayer::loadMusicFile(const char *file) { -// loadSoundFile(file); -// } - -void CadlPlayer::playTrack(uint8 track) { - play(track); -} - -// void CadlPlayer::haltTrack() { -// unk1(); -// unk2(); -// //_engine->_system->delayMillis(3 * 60); -// } - -void CadlPlayer::playSoundEffect(uint8_t track) { - play(track); -} - -void CadlPlayer::play(uint8_t track) { - uint8 soundId = _trackEntries[track]; - if ((int8)soundId == -1 || !_soundDataPtr) - return; - soundId &= 0xFF; - _driver->callback(16, 0); - // while ((_driver->callback(16, 0) & 8)) { - // We call the system delay and not the game delay to avoid concurrency issues. - // _engine->_system->delayMillis(10); - // } - if (_sfxPlayingSound != -1) { - // Restore the sounds's normal values. - _driver->callback(10, _sfxPlayingSound, int(1), int(_sfxPriority)); - _driver->callback(10, _sfxPlayingSound, int(3), int(_sfxFourthByteOfSong)); - _sfxPlayingSound = -1; - } - - int chan = _driver->callback(9, soundId, int(0)); - - if (chan != 9) { - _sfxPlayingSound = soundId; - _sfxPriority = _driver->callback(9, soundId, int(1)); - _sfxFourthByteOfSong = _driver->callback(9, soundId, int(3)); - - // In the cases I've seen, the mysterious fourth byte has been - // the parameter for the update_setExtraLevel3() callback. - // - // The extra level is part of the channels "total level", which - // is a six-bit value where larger values means softer volume. - // - // So what seems to be happening here is that sounds which are - // started by this function are given a slightly lower priority - // and a slightly higher (i.e. softer) extra level 3 than they - // would have if they were started from anywhere else. Strange. - - int newVal = ((((-_sfxFourthByteOfSong) + 63) * 0xFF) >> 8) & 0xFF; - newVal = -newVal + 63; - _driver->callback(10, soundId, int(3), newVal); - newVal = ((_sfxPriority * 0xFF) >> 8) & 0xFF; - _driver->callback(10, soundId, int(1), newVal); - } - - _driver->callback(6, soundId); -} - -// void CadlPlayer::beginFadeOut() { -// playSoundEffect(1); -// } - -bool CadlPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); - - // file validation section - if(!f || !fp.extension(filename, ".adl")) { - fp.close(f); - return false; - } - - // if (_soundFileLoaded == file) - // return; - - // if (_soundDataPtr) { - // haltTrack(); - // } - - uint8 *file_data = 0; uint32 file_size = 0; - - // char filename[25]; - // sprintf(filename, "%s.ADL", file); - - // file_data = _engine->resource()->fileData(filename, &file_size); - // if (!file_data) { - // warning("Couldn't find music file: '%s'", filename); - // return; - // } - - unk2(); - unk1(); - - file_size = fp.filesize(f); - file_data = new uint8 [file_size]; - f->readString((char *)file_data, file_size); - - _driver->callback(8, int(-1)); - _soundDataPtr = 0; - - uint8 *p = file_data; - memcpy(_trackEntries, p, 120*sizeof(uint8)); - p += 120; - - int soundDataSize = file_size - 120; - - _soundDataPtr = new uint8[soundDataSize]; - assert(_soundDataPtr); - - memcpy(_soundDataPtr, p, soundDataSize*sizeof(uint8)); - - delete [] file_data; - file_data = p = 0; - file_size = 0; - - _driver->callback(4, _soundDataPtr); - - // _soundFileLoaded = file; - - for(int i = 0; i < 200; i++) - if(_trackEntries[i] != 0xff) - numsubsongs = i + 1; - - fp.close(f); - return true; -} - -void CadlPlayer::rewind(int subsong) -{ - opl->init(); - opl->write(1,32); - playSoundEffect(subsong); - cursubsong = subsong; - update(); -} - -unsigned int CadlPlayer::getsubsongs() -{ - return numsubsongs; -} - -bool CadlPlayer::update() -{ - bool songend = true; - -// if(_trackEntries[cursubsong] == 0xff) -// return false; - - _driver->callback(); - - for(int i = 0; i < 10; i++) - if(_driver->_channels[i].dataptr != NULL) - songend = false; - - return !songend; -} - -void CadlPlayer::unk1() { - playSoundEffect(0); - //_engine->_system->delayMillis(5 * 60); -} - -void CadlPlayer::unk2() { - playSoundEffect(0); -} - -CPlayer *CadlPlayer::factory(Copl *newopl) -{ - return new CadlPlayer(newopl); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/adl.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,2427 @@ +/* + * adl.cpp - ADL player adaption by Simon Peter <dn.tlp@gmx.net> + * + * Original ADL player by Torbjorn Andersson and Johannes Schickel + * 'lordhoto' <lordhoto at scummvm dot org> of the ScummVM project. + */ + +/* ScummVM - Scumm Interpreter + * + * This file is licensed under both GPL and LGPL + * Copyright (C) 2006 The ScummVM project + * Copyright (C) 2006 Torbjorn Andersson and Johannes Schickel + * + * GPL License + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * LPGL License + * + * 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 + * + */ + +#include <inttypes.h> +#include <stdarg.h> +#include <assert.h> + +#include "adl.h" +#include "debug.h" + +#ifdef ADL_DEBUG +# define warning(...) AdPlug_LogWrite(__VA_ARGS__); \ +AdPlug_LogWrite("\n") + +# define debugC(i1, i2, ...) AdPlug_LogWrite(__VA_ARGS__); \ +AdPlug_LogWrite("\n") +#else +# define kDebugLevelSound 1 + +static inline void warning(const char *str, ...) +{ +} + +static inline void debugC(int i1, int i2, const char *str, ...) +{ +} +#endif + +// #define warning(...) +// #define debugC(i1, i2, ...) + +#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0]))) + +// Basic Adlib Programming: +// http://www.gamedev.net/reference/articles/article446.asp + +#define CALLBACKS_PER_SECOND 72 + +typedef uint8_t uint8; +typedef int8_t int8; +typedef uint16_t uint16; +typedef int16_t int16; +typedef uint32_t uint32; +typedef int32_t int32; +typedef uint8_t byte; + +static inline uint16 READ_LE_UINT16(const void *ptr) { + const byte *b = (const byte *)ptr; + return (b[1] << 8) + b[0]; +} + +static inline uint16 READ_BE_UINT16(const void *ptr) { + const byte *b = (const byte *)ptr; + return (b[0] << 8) + b[1]; +} + +class AdlibDriver { +public: + AdlibDriver(Copl *opl); + ~AdlibDriver(); + + int callback(int opcode, ...); + void callback(); + + // AudioStream API + // int readBuffer(int16 *buffer, const int numSamples) { + // int32 samplesLeft = numSamples; + // memset(buffer, 0, sizeof(int16) * numSamples); + // while (samplesLeft) { + // if (!_samplesTillCallback) { + // callback(); + // _samplesTillCallback = _samplesPerCallback; + // _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; + // if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) { + // _samplesTillCallback++; + // _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND; + // } + // } + + // int32 render = MIN(samplesLeft, _samplesTillCallback); + // samplesLeft -= render; + // _samplesTillCallback -= render; + // YM3812UpdateOne(_adlib, buffer, render); + // buffer += render; + // } + // return numSamples; + // } + + bool isStereo() const { return false; } + bool endOfData() const { return false; } + // int getRate() const { return _mixer->getOutputRate(); } + + struct OpcodeEntry { + typedef int (AdlibDriver::*DriverOpcode)(va_list &list); + DriverOpcode function; + const char *name; + }; + + void setupOpcodeList(); + const OpcodeEntry *_opcodeList; + int _opcodesEntries; + + int snd_ret0x100(va_list &list); + int snd_ret0x1983(va_list &list); + int snd_initDriver(va_list &list); + int snd_deinitDriver(va_list &list); + int snd_setSoundData(va_list &list); + int snd_unkOpcode1(va_list &list); + int snd_startSong(va_list &list); + int snd_unkOpcode2(va_list &list); + int snd_unkOpcode3(va_list &list); + int snd_readByte(va_list &list); + int snd_writeByte(va_list &list); + int snd_getSoundTrigger(va_list &list); + int snd_unkOpcode4(va_list &list); + int snd_dummy(va_list &list); + int snd_getNullvar4(va_list &list); + int snd_setNullvar3(va_list &list); + int snd_setFlag(va_list &list); + int snd_clearFlag(va_list &list); + + // These variables have not yet been named, but some of them are partly + // known nevertheless: + // + // unk16 - Sound-related. Possibly some sort of pitch bend. + // unk18 - Sound-effect. Used for secondaryEffect1() + // unk19 - Sound-effect. Used for secondaryEffect1() + // unk20 - Sound-effect. Used for secondaryEffect1() + // unk21 - Sound-effect. Used for secondaryEffect1() + // unk22 - Sound-effect. Used for secondaryEffect1() + // unk29 - Sound-effect. Used for primaryEffect1() + // unk30 - Sound-effect. Used for primaryEffect1() + // unk31 - Sound-effect. Used for primaryEffect1() + // unk32 - Sound-effect. Used for primaryEffect2() + // unk33 - Sound-effect. Used for primaryEffect2() + // unk34 - Sound-effect. Used for primaryEffect2() + // unk35 - Sound-effect. Used for primaryEffect2() + // unk36 - Sound-effect. Used for primaryEffect2() + // unk37 - Sound-effect. Used for primaryEffect2() + // unk38 - Sound-effect. Used for primaryEffect2() + // unk39 - Currently unused, except for updateCallback56() + // unk40 - Currently unused, except for updateCallback56() + // unk41 - Sound-effect. Used for primaryEffect2() + + struct Channel { + uint8 opExtraLevel2; + uint8 *dataptr; + uint8 duration; + uint8 repeatCounter; + int8 baseOctave; + uint8 priority; + uint8 dataptrStackPos; + uint8 *dataptrStack[4]; + int8 baseNote; + uint8 unk29; + uint8 unk31; + uint16 unk30; + uint16 unk37; + uint8 unk33; + uint8 unk34; + uint8 unk35; + uint8 unk36; + uint8 unk32; + uint8 unk41; + uint8 unk38; + uint8 opExtraLevel1; + uint8 spacing2; + uint8 baseFreq; + uint8 tempo; + uint8 position; + uint8 regAx; + uint8 regBx; + typedef void (AdlibDriver::*Callback)(Channel&); + Callback primaryEffect; + Callback secondaryEffect; + uint8 fractionalSpacing; + uint8 opLevel1; + uint8 opLevel2; + uint8 opExtraLevel3; + uint8 twoChan; + uint8 unk39; + uint8 unk40; + uint8 spacing1; + uint8 durationRandomness; + uint8 unk19; + uint8 unk18; + int8 unk20; + int8 unk21; + uint8 unk22; + uint16 offset; + uint8 tempoReset; + uint8 rawNote; + int8 unk16; + }; + + void primaryEffect1(Channel &channel); + void primaryEffect2(Channel &channel); + void secondaryEffect1(Channel &channel); + + void resetAdlibState(); + void writeOPL(byte reg, byte val); + void initChannel(Channel &channel); + void noteOff(Channel &channel); + void unkOutput2(uint8 num); + + uint16 getRandomNr(); + void setupDuration(uint8 duration, Channel &channel); + + void setupNote(uint8 rawNote, Channel &channel, bool flag = false); + void setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel); + void noteOn(Channel &channel); + + void adjustVolume(Channel &channel); + + uint8 calculateOpLevel1(Channel &channel); + uint8 calculateOpLevel2(Channel &channel); + + uint16 checkValue(int16 val) { + if (val < 0) + val = 0; + else if (val > 0x3F) + val = 0x3F; + return val; + } + + // The sound data has at least two lookup tables: + // + // * One for programs, starting at offset 0. + // * One for instruments, starting at offset 500. + + uint8 *getProgram(int progId) { + return _soundData + READ_LE_UINT16(_soundData + 2 * progId); + } + + uint8 *getInstrument(int instrumentId) { + return _soundData + READ_LE_UINT16(_soundData + 500 + 2 * instrumentId); + } + + void setupPrograms(); + void executePrograms(); + + struct ParserOpcode { + typedef int (AdlibDriver::*POpcode)(uint8 *&dataptr, Channel &channel, uint8 value); + POpcode function; + const char *name; + }; + + void setupParserOpcodeTable(); + const ParserOpcode *_parserOpcodeTable; + int _parserOpcodeTableSize; + + int update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value); + int update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value); + int update_jump(uint8 *&dataptr, Channel &channel, uint8 value); + int update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value); + int update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value); + int update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value); + int update_playRest(uint8 *&dataptr, Channel &channel, uint8 value); + int update_writeAdlib(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); + int update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value); + int update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); + int update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value); + int update_playNote(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value); + int update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value); + int update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value); + int update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value); + int update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback41(uint8 *&dataptr, Channel &channel, uint8 value); + int update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value); + int update_nop1(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value); + int update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value); + int update_nop2(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value); + int update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value); + int update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value); + + // These variables have not yet been named, but some of them are partly + // known nevertheless: + // + // _unkValue1 - Unknown. Used for updating _unkValue2 + // _unkValue2 - Unknown. Used for updating _unkValue4 + // _unkValue3 - Unknown. Used for updating _unkValue2 + // _unkValue4 - Unknown. Used for updating _unkValue5 + // _unkValue5 - Unknown. Used for controlling updateCallback24(). + // _unkValue6 - Unknown. Rhythm section volume? + // _unkValue7 - Unknown. Rhythm section volume? + // _unkValue8 - Unknown. Rhythm section volume? + // _unkValue9 - Unknown. Rhythm section volume? + // _unkValue10 - Unknown. Rhythm section volume? + // _unkValue11 - Unknown. Rhythm section volume? + // _unkValue12 - Unknown. Rhythm section volume? + // _unkValue13 - Unknown. Rhythm section volume? + // _unkValue14 - Unknown. Rhythm section volume? + // _unkValue15 - Unknown. Rhythm section volume? + // _unkValue16 - Unknown. Rhythm section volume? + // _unkValue17 - Unknown. Rhythm section volume? + // _unkValue18 - Unknown. Rhythm section volume? + // _unkValue19 - Unknown. Rhythm section volume? + // _unkValue20 - Unknown. Rhythm section volume? + // _unkTable[] - Probably frequences for the 12-tone scale. + // _unkTable2[] - Unknown. Currently only used by updateCallback46() + // _unkTable2_1[] - One of the tables in _unkTable2[] + // _unkTable2_2[] - One of the tables in _unkTable2[] + // _unkTable2_3[] - One of the tables in _unkTable2[] + + int32 _samplesPerCallback; + int32 _samplesPerCallbackRemainder; + int32 _samplesTillCallback; + int32 _samplesTillCallbackRemainder; + + int _lastProcessed; + int8 _flagTrigger; + int _curChannel; + uint8 _soundTrigger; + int _soundsPlaying; + + uint16 _rnd; + + uint8 _unkValue1; + uint8 _unkValue2; + uint8 _unkValue3; + uint8 _unkValue4; + uint8 _unkValue5; + uint8 _unkValue6; + uint8 _unkValue7; + uint8 _unkValue8; + uint8 _unkValue9; + uint8 _unkValue10; + uint8 _unkValue11; + uint8 _unkValue12; + uint8 _unkValue13; + uint8 _unkValue14; + uint8 _unkValue15; + uint8 _unkValue16; + uint8 _unkValue17; + uint8 _unkValue18; + uint8 _unkValue19; + uint8 _unkValue20; + + int _flags; + + uint8 *_soundData; + + uint8 _soundIdTable[0x10]; + Channel _channels[10]; + + uint8 _vibratoAndAMDepthBits; + uint8 _rhythmSectionBits; + + uint8 _curRegOffset; + uint8 _tempo; + + const uint8 *_tablePtr1; + const uint8 *_tablePtr2; + + static const uint8 _regOffset[]; + static const uint16 _unkTable[]; + static const uint8 *_unkTable2[]; + static const uint8 _unkTable2_1[]; + static const uint8 _unkTable2_2[]; + static const uint8 _unkTable2_3[]; + static const uint8 _unkTables[][32]; + + Copl *opl; +}; + +AdlibDriver::AdlibDriver(Copl *newopl) + : opl(newopl) +{ + setupOpcodeList(); + setupParserOpcodeTable(); + + // _mixer = mixer; + + _flags = 0; + // _adlib = makeAdlibOPL(getRate()); + // assert(_adlib); + + memset(_channels, 0, sizeof(_channels)); + _soundData = 0; + + _vibratoAndAMDepthBits = _curRegOffset = 0; + + _lastProcessed = _flagTrigger = _curChannel = _rhythmSectionBits = 0; + _soundsPlaying = 0; + _rnd = 0x1234; + + _tempo = 0; + _soundTrigger = 0; + + _unkValue3 = 0xFF; + _unkValue1 = _unkValue2 = _unkValue4 = _unkValue5 = 0; + _unkValue6 = _unkValue7 = _unkValue8 = _unkValue9 = _unkValue10 = 0; + _unkValue11 = _unkValue12 = _unkValue13 = _unkValue14 = _unkValue15 = + _unkValue16 = _unkValue17 = _unkValue18 = _unkValue19 = _unkValue20 = 0; + + _tablePtr1 = _tablePtr2 = 0; + + // _mixer->setupPremix(this); + + // _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND; + // _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND; + _samplesTillCallback = 0; + _samplesTillCallbackRemainder = 0; +} + +AdlibDriver::~AdlibDriver() { + // _mixer->setupPremix(0); + // OPLDestroy(_adlib); + // _adlib = 0; +} + +int AdlibDriver::callback(int opcode, ...) { + // lock(); + if (opcode >= _opcodesEntries || opcode < 0) { + warning("AdlibDriver: calling unknown opcode '%d'", opcode); + return 0; + } + + debugC(9, kDebugLevelSound, "Calling opcode '%s' (%d)", _opcodeList[opcode].name, opcode); + + va_list args; + va_start(args, opcode); + int returnValue = (this->*(_opcodeList[opcode].function))(args); + va_end(args); + // unlock(); + return returnValue; +} + +// Opcodes + +int AdlibDriver::snd_ret0x100(va_list &list) { + return 0x100; +} + +int AdlibDriver::snd_ret0x1983(va_list &list) { + return 0x1983; +} + +int AdlibDriver::snd_initDriver(va_list &list) { + _lastProcessed = _soundsPlaying = 0; + resetAdlibState(); + return 0; +} + +int AdlibDriver::snd_deinitDriver(va_list &list) { + resetAdlibState(); + return 0; +} + +int AdlibDriver::snd_setSoundData(va_list &list) { + if (_soundData) { + delete [] _soundData; + _soundData = 0; + } + _soundData = va_arg(list, uint8*); + return 0; +} + +int AdlibDriver::snd_unkOpcode1(va_list &list) { + warning("unimplemented snd_unkOpcode1"); + return 0; +} + +int AdlibDriver::snd_startSong(va_list &list) { + int songId = va_arg(list, int); + _flags |= 8; + _flagTrigger = 1; + + uint8 *ptr = getProgram(songId); + uint8 chan = *ptr; + + if ((songId << 1) != 0) { + if (chan == 9) { + if (_flags & 2) + return 0; + } else { + if (_flags & 1) + return 0; + } + } + + _soundIdTable[_soundsPlaying++] = songId; + _soundsPlaying &= 0x0F; + + return 0; +} + +int AdlibDriver::snd_unkOpcode2(va_list &list) { + warning("unimplemented snd_unkOpcode2"); + return 0; +} + +int AdlibDriver::snd_unkOpcode3(va_list &list) { + int value = va_arg(list, int); + int loop = value; + if (value < 0) { + value = 0; + loop = 9; + } + loop -= value; + ++loop; + + while (loop--) { + _curChannel = value; + Channel &channel = _channels[_curChannel]; + channel.priority = 0; + channel.dataptr = 0; + if (value != 9) { + noteOff(channel); + } + ++value; + } + + return 0; +} + +int AdlibDriver::snd_readByte(va_list &list) { + int a = va_arg(list, int); + int b = va_arg(list, int); + uint8 *ptr = getProgram(a) + b; + return *ptr; +} + +int AdlibDriver::snd_writeByte(va_list &list) { + int a = va_arg(list, int); + int b = va_arg(list, int); + int c = va_arg(list, int); + uint8 *ptr = getProgram(a) + b; + uint8 oldValue = *ptr; + *ptr = (uint8)c; + return oldValue; +} + +int AdlibDriver::snd_getSoundTrigger(va_list &list) { + return _soundTrigger; +} + +int AdlibDriver::snd_unkOpcode4(va_list &list) { + warning("unimplemented snd_unkOpcode4"); + return 0; +} + +int AdlibDriver::snd_dummy(va_list &list) { + return 0; +} + +int AdlibDriver::snd_getNullvar4(va_list &list) { + warning("unimplemented snd_getNullvar4"); + return 0; +} + +int AdlibDriver::snd_setNullvar3(va_list &list) { + warning("unimplemented snd_setNullvar3"); + return 0; +} + +int AdlibDriver::snd_setFlag(va_list &list) { + int oldFlags = _flags; + _flags |= va_arg(list, int); + return oldFlags; +} + +int AdlibDriver::snd_clearFlag(va_list &list) { + int oldFlags = _flags; + _flags &= ~(va_arg(list, int)); + return oldFlags; +} + +// timer callback + +void AdlibDriver::callback() { + // lock(); + --_flagTrigger; + if (_flagTrigger < 0) + _flags &= ~8; + setupPrograms(); + executePrograms(); + + uint8 temp = _unkValue3; + _unkValue3 += _tempo; + if (_unkValue3 < temp) { + if (!(--_unkValue2)) { + _unkValue2 = _unkValue1; + ++_unkValue4; + } + } + // unlock(); +} + +void AdlibDriver::setupPrograms() { + while (_lastProcessed != _soundsPlaying) { + uint8 *ptr = getProgram(_soundIdTable[_lastProcessed]); + uint8 chan = *ptr++; + uint8 priority = *ptr++; + + // Only start this sound if its priority is higher than the one + // already playing. + + Channel &channel = _channels[chan]; + + if (priority >= channel.priority) { + initChannel(channel); + channel.priority = priority; + channel.dataptr = ptr; + channel.tempo = 0xFF; + channel.position = 0xFF; + channel.duration = 1; + unkOutput2(chan); + } + + ++_lastProcessed; + _lastProcessed &= 0x0F; + } +} + +// A few words on opcode parsing and timing: +// +// First of all, We simulate a timer callback 72 times per second. Each timeout +// we update each channel that has something to play. +// +// Each channel has its own individual tempo, which is added to its position. +// This will frequently cause the position to "wrap around" but that is +// intentional. In fact, it's the signal to go ahead and do more stuff with +// that channel. +// +// Each channel also has a duration, indicating how much time is left on the +// its current task. This duration is decreased by one. As long as it still has +// not reached zero, the only thing that can happen is that the note is turned +// off depending on manual or automatic note spacing. Once the duration reaches +// zero, a new set of musical opcodes are executed. +// +// An opcode is one byte, followed by a variable number of parameters. Since +// most opcodes have at least one one-byte parameter, we read that as well. Any +// opcode that doesn't have that one parameter is responsible for moving the +// data pointer back again. +// +// If the most significant bit of the opcode is 1, it's a function; call it. +// The opcode functions return either 0 (continue), 1 (stop) or 2 (stop, and do +// not run the effects callbacks). +// +// If the most significant bit of the opcode is 0, it's a note, and the first +// parameter is its duration. (There are cases where the duration is modified +// but that's an exception.) The note opcode is assumed to return 1, and is the +// last opcode unless its duration is zero. +// +// Finally, most of the times that the callback is called, it will invoke the +// effects callbacks. The final opcode in a set can prevent this, if it's a +// function and it returns anything other than 1. + +void AdlibDriver::executePrograms() { + // Each channel runs its own program. There are ten channels: One for + // each Adlib channel (0-8), plus one "control channel" (9) which is + // the one that tells the other channels what to do. + + for (_curChannel = 9; _curChannel >= 0; --_curChannel) { + int result = 1; + + if (!_channels[_curChannel].dataptr) { + continue; + } + + Channel &channel = _channels[_curChannel]; + _curRegOffset = _regOffset[_curChannel]; + + if (channel.tempoReset) { + channel.tempo = _tempo; + } + + uint8 backup = channel.position; + channel.position += channel.tempo; + if (channel.position < backup) { + if (--channel.duration) { + if (channel.duration == channel.spacing2) + noteOff(channel); + if (channel.duration == channel.spacing1 && _curChannel != 9) + noteOff(channel); + } else { + // An opcode is not allowed to modify its own + // data pointer except through the 'dataptr' + // parameter. To enforce that, we have to work + // on a copy of the data pointer. + // + // This fixes a subtle music bug where the + // wrong music would play when getting the + // quill in Kyra 1. + uint8 *dataptr = channel.dataptr; + while (dataptr) { + uint8 opcode = *dataptr++; + uint8 param = *dataptr++; + + if (opcode & 0x80) { + opcode &= 0x7F; + if (opcode >= _parserOpcodeTableSize) + opcode = _parserOpcodeTableSize - 1; + debugC(9, kDebugLevelSound, "Calling opcode '%s' (%d) (channel: %d)", _parserOpcodeTable[opcode].name, opcode, _curChannel); + result = (this->*(_parserOpcodeTable[opcode].function))(dataptr, channel, param); + channel.dataptr = dataptr; + if (result) + break; + } else { + debugC(9, kDebugLevelSound, "Note on opcode 0x%02X (duration: %d) (channel: %d)", opcode, param, _curChannel); + setupNote(opcode, channel); + noteOn(channel); + setupDuration(param, channel); + if (param) { + channel.dataptr = dataptr; + break; + } + } + } + } + } + + if (result == 1) { + if (channel.primaryEffect) + (this->*(channel.primaryEffect))(channel); + if (channel.secondaryEffect) + (this->*(channel.secondaryEffect))(channel); + } + } +} + +// + +void AdlibDriver::resetAdlibState() { + debugC(9, kDebugLevelSound, "resetAdlibState()"); + _rnd = 0x1234; + + // Authorize the control of the waveforms + writeOPL(0x01, 0x20); + + // Select FM music mode + writeOPL(0x08, 0x00); + + // I would guess the main purpose of this is to turn off the rhythm, + // thus allowing us to use 9 melodic voices instead of 6. + writeOPL(0xBD, 0x00); + + int loop = 10; + while (loop--) { + if (loop != 9) { + // Silence the channel + writeOPL(0x40 + _regOffset[loop], 0x3F); + writeOPL(0x43 + _regOffset[loop], 0x3F); + } + initChannel(_channels[loop]); + } +} + +// Old calling style: output0x388(0xABCD) +// New calling style: writeOPL(0xAB, 0xCD) + +void AdlibDriver::writeOPL(byte reg, byte val) { + opl->write(reg, val); +} + +void AdlibDriver::initChannel(Channel &channel) { + debugC(9, kDebugLevelSound, "initChannel(%lu)", (long)(&channel - _channels)); + memset(&channel.dataptr, 0, sizeof(Channel) - ((char*)&channel.dataptr - (char*)&channel)); + + channel.tempo = 0xFF; + channel.priority = 0; + // normally here are nullfuncs but we set 0 for now + channel.primaryEffect = 0; + channel.secondaryEffect = 0; + channel.spacing1 = 1; +} + +void AdlibDriver::noteOff(Channel &channel) { + debugC(9, kDebugLevelSound, "noteOff(%lu)", (long)(&channel - _channels)); + + // The control channel has no corresponding Adlib channel + + if (_curChannel >= 9) + return; + + // When the rhythm section is enabled, channels 6, 7 and 8 are special. + + if (_rhythmSectionBits && _curChannel >= 6) + return; + + // This means the "Key On" bit will always be 0 + channel.regBx &= 0xDF; + + // Octave / F-Number / Key-On + writeOPL(0xB0 + _curChannel, channel.regBx); +} + +void AdlibDriver::unkOutput2(uint8 chan) { + debugC(9, kDebugLevelSound, "unkOutput2(%d)", chan); + + // The control channel has no corresponding Adlib channel + + if (chan >= 9) + return; + + // I believe this has to do with channels 6, 7, and 8 being special + // when Adlib's rhythm section is enabled. + + if (_rhythmSectionBits && chan >= 6) + return; + + uint8 offset = _regOffset[chan]; + + // The channel is cleared: First the attack/delay rate, then the + // sustain level/release rate, and finally the note is turned off. + + writeOPL(0x60 + offset, 0xFF); + writeOPL(0x63 + offset, 0xFF); + + writeOPL(0x80 + offset, 0xFF); + writeOPL(0x83 + offset, 0xFF); + + writeOPL(0xB0 + chan, 0x00); + + // ...and then the note is turned on again, with whatever value is + // still lurking in the A0 + chan register, but everything else - + // including the two most significant frequency bit, and the octave - + // set to zero. + // + // This is very strange behaviour, and causes problems with the ancient + // FMOPL code we borrowed from AdPlug. I've added a workaround. See + // fmopl.cpp for more details. + // + // More recent versions of the MAME FMOPL don't seem to have this + // problem, but cannot currently be used because of licensing and + // performance issues. + // + // Ken Silverman's Adlib emulator (which can be found on his Web page - + // http://www.advsys.net/ken - and as part of AdPlug) also seems to be + // immune, but is apparently not as feature complete as MAME's. + + writeOPL(0xB0 + chan, 0x20); +} + +// I believe this is a random number generator. It actually does seem to +// generate an even distribution of almost all numbers from 0 through 65535, +// though in my tests some numbers were never generated. + +uint16 AdlibDriver::getRandomNr() { + _rnd += 0x9248; + uint16 lowBits = _rnd & 7; + _rnd >>= 3; + _rnd |= (lowBits << 13); + return _rnd; +} + +void AdlibDriver::setupDuration(uint8 duration, Channel &channel) { + debugC(9, kDebugLevelSound, "setupDuration(%d, %lu)", duration, (long)(&channel - _channels)); + if (channel.durationRandomness) { + channel.duration = duration + (getRandomNr() & channel.durationRandomness); + return; + } + if (channel.fractionalSpacing) { + channel.spacing2 = (duration >> 3) * channel.fractionalSpacing; + } + channel.duration = duration; +} + +// This function may or may not play the note. It's usually followed by a call +// to noteOn(), which will always play the current note. + +void AdlibDriver::setupNote(uint8 rawNote, Channel &channel, bool flag) { + debugC(9, kDebugLevelSound, "setupNote(%d, %lu)", rawNote, (long)(&channel - _channels)); + + channel.rawNote = rawNote; + + int8 note = (rawNote & 0x0F) + channel.baseNote; + int8 octave = ((rawNote + channel.baseOctave) >> 4) & 0x0F; + + // There are only twelve notes. If we go outside that, we have to + // adjust the note and octave. + + if (note >= 12) { + note -= 12; + octave++; + } else if (note < 0) { + note += 12; + octave--; + } + + // The calculation of frequency looks quite different from the original + // disassembly at a first glance, but when you consider that the + // largest possible value would be 0x0246 + 0xFF + 0x47 (and that's if + // baseFreq is unsigned), freq is still a 10-bit value, just as it + // should be to fit in the Ax and Bx registers. + // + // If it were larger than that, it could have overflowed into the + // octave bits, and that could possibly have been used in some sound. + // But as it is now, I can't see any way it would happen. + + uint16 freq = _unkTable[note] + channel.baseFreq; + + // When called from callback 41, the behaviour is slightly different: + // We adjust the frequency, even when channel.unk16 is 0. + + if (channel.unk16 || flag) { + const uint8 *table; + + if (channel.unk16 >= 0) { + table = _unkTables[(channel.rawNote & 0x0F) + 2]; + freq += table[channel.unk16]; + } else { + table = _unkTables[channel.rawNote & 0x0F]; + freq -= table[-channel.unk16]; + } + } + + channel.regAx = freq & 0xFF; + channel.regBx = (channel.regBx & 0x20) | (octave << 2) | ((freq >> 8) & 0x03); + + // Keep the note on or off + writeOPL(0xA0 + _curChannel, channel.regAx); + writeOPL(0xB0 + _curChannel, channel.regBx); +} + +void AdlibDriver::setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel) { + debugC(9, kDebugLevelSound, "setupInstrument(%d, %p, %lu)", regOffset, (const void *)dataptr, (long)(&channel - _channels)); + // Amplitude Modulation / Vibrato / Envelope Generator Type / + // Keyboard Scaling Rate / Modulator Frequency Multiple + writeOPL(0x20 + regOffset, *dataptr++); + writeOPL(0x23 + regOffset, *dataptr++); + + uint8 temp = *dataptr++; + + // Feedback / Algorithm + + // It is very likely that _curChannel really does refer to the same + // channel as regOffset, but there's only one Cx register per channel. + + writeOPL(0xC0 + _curChannel, temp); + + // The algorithm bit. I don't pretend to understand this fully, but + // "If set to 0, operator 1 modulates operator 2. In this case, + // operator 2 is the only one producing sound. If set to 1, both + // operators produce sound directly. Complex sounds are more easily + // created if the algorithm is set to 0." + + channel.twoChan = temp & 1; + + // Waveform Select + writeOPL(0xE0 + regOffset, *dataptr++); + writeOPL(0xE3 + regOffset, *dataptr++); + + channel.opLevel1 = *dataptr++; + channel.opLevel2 = *dataptr++; + + // Level Key Scaling / Total Level + writeOPL(0x40 + regOffset, calculateOpLevel1(channel)); + writeOPL(0x43 + regOffset, calculateOpLevel2(channel)); + + // Attack Rate / Decay Rate + writeOPL(0x60 + regOffset, *dataptr++); + writeOPL(0x63 + regOffset, *dataptr++); + + // Sustain Level / Release Rate + writeOPL(0x80 + regOffset, *dataptr++); + writeOPL(0x83 + regOffset, *dataptr++); +} + +// Apart from playing the note, this function also updates the variables for +// primary effect 2. + +void AdlibDriver::noteOn(Channel &channel) { + debugC(9, kDebugLevelSound, "noteOn(%lu)", (long)(&channel - _channels)); + + // The "note on" bit is set, and the current note is played. + + channel.regBx |= 0x20; + writeOPL(0xB0 + _curChannel, channel.regBx); + + int8 shift = 9 - channel.unk33; + uint16 temp = channel.regAx | (channel.regBx << 8); + channel.unk37 = ((temp & 0x3FF) >> shift) & 0xFF; + channel.unk38 = channel.unk36; +} + +void AdlibDriver::adjustVolume(Channel &channel) { + debugC(9, kDebugLevelSound, "adjustVolume(%lu)", (long)(&channel - _channels)); + // Level Key Scaling / Total Level + + writeOPL(0x43 + _regOffset[_curChannel], calculateOpLevel2(channel)); + if (channel.twoChan) + writeOPL(0x40 + _regOffset[_curChannel], calculateOpLevel1(channel)); +} + +// This is presumably only used for some sound effects, e.g. Malcolm blowing up +// the trees in the intro (but not the effect where he "booby-traps" the big +// tree) and turning Kallak to stone. Related functions and variables: +// +// update_setupPrimaryEffect1() +// - Initialises unk29, unk30 and unk31 +// - unk29 is not further modified +// - unk30 is not further modified, except by update_removePrimaryEffect1() +// +// update_removePrimaryEffect1() +// - Deinitialises unk30 +// +// unk29 - determines how often the notes are played +// unk30 - modifies the frequency +// unk31 - determines how often the notes are played + +void AdlibDriver::primaryEffect1(Channel &channel) { + debugC(9, kDebugLevelSound, "Calling primaryEffect1 (channel: %d)", _curChannel); + uint8 temp = channel.unk31; + channel.unk31 += channel.unk29; + if (channel.unk31 >= temp) + return; + + // Initialise unk1 to the current frequency + uint16 unk1 = ((channel.regBx & 3) << 8) | channel.regAx; + + // This is presumably to shift the "note on" bit so far to the left + // that it won't be affected by any of the calculations below. + uint16 unk2 = ((channel.regBx & 0x20) << 8) | (channel.regBx & 0x1C); + + int16 unk3 = (int16)channel.unk30; + + if (unk3 >= 0) { + unk1 += unk3; + if (unk1 >= 734) { + // The new frequency is too high. Shift it down and go + // up one octave. + unk1 >>= 1; + if (!(unk1 & 0x3FF)) + ++unk1; + unk2 = (unk2 & 0xFF00) | ((unk2 + 4) & 0xFF); + unk2 &= 0xFF1C; + } + } else { + unk1 += unk3; + if (unk1 < 388) { + // The new frequency is too low. Shift it up and go + // down one octave. + unk1 <<= 1; + if (!(unk1 & 0x3FF)) + --unk1; + unk2 = (unk2 & 0xFF00) | ((unk2 - 4) & 0xFF); + unk2 &= 0xFF1C; + } + } + + // Make sure that the new frequency is still a 10-bit value. + unk1 &= 0x3FF; + + writeOPL(0xA0 + _curChannel, unk1 & 0xFF); + channel.regAx = unk1 & 0xFF; + + // Shift down the "note on" bit again. + uint8 value = unk1 >> 8; + value |= (unk2 >> 8) & 0xFF; + value |= unk2 & 0xFF; + + writeOPL(0xB0 + _curChannel, value); + channel.regBx = value; +} + +// This is presumably only used for some sound effects, e.g. Malcolm entering +// and leaving Kallak's hut. Related functions and variables: +// +// update_setupPrimaryEffect2() +// - Initialises unk32, unk33, unk34, unk35 and unk36 +// - unk32 is not further modified +// - unk33 is not further modified +// - unk34 is a countdown that gets reinitialised to unk35 on zero +// - unk35 is based on unk34 and not further modified +// - unk36 is not further modified +// +// noteOn() +// - Plays the current note +// - Updates unk37 with a new (lower?) frequency +// - Copies unk36 to unk38. The unk38 variable is a countdown. +// +// unk32 - determines how often the notes are played +// unk33 - modifies the frequency +// unk34 - countdown, updates frequency on zero +// unk35 - initialiser for unk34 countdown +// unk36 - initialiser for unk38 countdown +// unk37 - frequency +// unk38 - countdown, begins playing on zero +// unk41 - determines how often the notes are played +// +// Note that unk41 is never initialised. Not that it should matter much, but it +// is a bit sloppy. + +void AdlibDriver::primaryEffect2(Channel &channel) { + debugC(9, kDebugLevelSound, "Calling primaryEffect2 (channel: %d)", _curChannel); + if (channel.unk38) { + --channel.unk38; + return; + } + + uint8 temp = channel.unk41; + channel.unk41 += channel.unk32; + if (channel.unk41 < temp) { + uint16 unk1 = channel.unk37; + if (!(--channel.unk34)) { + unk1 ^= 0xFFFF; + ++unk1; + channel.unk37 = unk1; + channel.unk34 = channel.unk35; + } + + uint16 unk2 = (channel.regAx | (channel.regBx << 8)) & 0x3FF; + unk2 += unk1; + + channel.regAx = unk2 & 0xFF; + channel.regBx = (channel.regBx & 0xFC) | (unk2 >> 8); + + // Octave / F-Number / Key-On + writeOPL(0xA0 + _curChannel, channel.regAx); + writeOPL(0xB0 + _curChannel, channel.regBx); + } +} + +// I don't know where this is used. The same operation is performed several +// times on the current channel, using a chunk of the _soundData[] buffer for +// parameters. The parameters are used starting at the end of the chunk. +// +// Since we use _curRegOffset to specify the final register, it's quite +// unlikely that this function is ever used to play notes. It's probably only +// used to modify the sound. Another thing that supports this idea is that it +// can be combined with any of the effects callbacks above. +// +// Related functions and variables: +// +// update_setupSecondaryEffect1() +// - Initialies unk18, unk19, unk20, unk21, unk22 and offset +// - unk19 is not further modified +// - unk20 is not further modified +// - unk22 is not further modified +// - offset is not further modified +// +// unk18 - determines how often the operation is performed +// unk19 - determines how often the operation is performed +// unk20 - the start index into the data chunk +// unk21 - the current index into the data chunk +// unk22 - the operation to perform +// offset - the offset to the data chunk + +void AdlibDriver::secondaryEffect1(Channel &channel) { + debugC(9, kDebugLevelSound, "Calling secondaryEffect1 (channel: %d)", _curChannel); + uint8 temp = channel.unk18; + channel.unk18 += channel.unk19; + if (channel.unk18 < temp) { + if (--channel.unk21 < 0) { + channel.unk21 = channel.unk20; + } + writeOPL(channel.unk22 + _curRegOffset, _soundData[channel.offset + channel.unk21]); + } +} + +uint8 AdlibDriver::calculateOpLevel1(Channel &channel) { + int8 value = channel.opLevel1 & 0x3F; + + if (channel.twoChan) { + value += channel.opExtraLevel1; + value += channel.opExtraLevel2; + value += channel.opExtraLevel3; + } + + // Preserve the scaling level bits from opLevel1 + + return checkValue(value) | (channel.opLevel1 & 0xC0); +} + +uint8 AdlibDriver::calculateOpLevel2(Channel &channel) { + int8 value = channel.opLevel2 & 0x3F; + + value += channel.opExtraLevel1; + value += channel.opExtraLevel2; + value += channel.opExtraLevel3; + + // Preserve the scaling level bits from opLevel2 + + return checkValue(value) | (channel.opLevel2 & 0xC0); +} + +// parser opcodes + +int AdlibDriver::update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.repeatCounter = value; + return 0; +} + +int AdlibDriver::update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value) { + ++dataptr; + if (--channel.repeatCounter) { + int16 add = READ_LE_UINT16(dataptr - 2); + dataptr += add; + } + return 0; +} + +int AdlibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value) { + if (value == 0xFF) + return 0; + + uint8 *ptr = getProgram(value); + uint8 chan = *ptr++; + uint8 priority = *ptr++; + + Channel &channel2 = _channels[chan]; + + if (priority >= channel2.priority) { + _flagTrigger = 1; + _flags |= 8; + initChannel(channel2); + channel2.priority = priority; + channel2.dataptr = ptr; + channel2.tempo = 0xFF; + channel2.position = 0xFF; + channel2.duration = 1; + unkOutput2(chan); + } + + return 0; +} + +int AdlibDriver::update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.spacing1 = value; + return 0; +} + +int AdlibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) { + --dataptr; + int16 add = READ_LE_UINT16(dataptr); dataptr += 2; + dataptr += add; + return 0; +} + +int AdlibDriver::update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) { + --dataptr; + int16 add = READ_LE_UINT16(dataptr); dataptr += 2; + channel.dataptrStack[channel.dataptrStackPos++] = dataptr; + dataptr += add; + return 0; +} + +int AdlibDriver::update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) { + dataptr = channel.dataptrStack[--channel.dataptrStackPos]; + return 0; +} + +int AdlibDriver::update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.baseOctave = value; + return 0; +} + +int AdlibDriver::update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.priority = 0; + if (_curChannel != 9) { + noteOff(channel); + } + dataptr = 0; + return 2; +} + +int AdlibDriver::update_playRest(uint8 *&dataptr, Channel &channel, uint8 value) { + setupDuration(value, channel); + noteOff(channel); + return (value != 0); +} + +int AdlibDriver::update_writeAdlib(uint8 *&dataptr, Channel &channel, uint8 value) { + writeOPL(value, *dataptr++); + return 0; +} + +int AdlibDriver::update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value) { + setupNote(value, channel); + value = *dataptr++; + setupDuration(value, channel); + return (value != 0); +} + +int AdlibDriver::update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.baseNote = value; + return 0; +} + +int AdlibDriver::update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.unk18 = value; + channel.unk19 = value; + channel.unk20 = channel.unk21 = *dataptr++; + channel.unk22 = *dataptr++; + channel.offset = READ_LE_UINT16(dataptr); dataptr += 2; + channel.secondaryEffect = &AdlibDriver::secondaryEffect1; + return 0; +} + +int AdlibDriver::update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value) { + Channel &channel2 = _channels[value]; + channel2.duration = 0; + channel2.priority = 0; + channel2.dataptr = 0; + return 0; +} + +int AdlibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value) { + uint8 *ptr = getProgram(value); + uint8 chan = *ptr; + + if (!_channels[chan].dataptr) { + return 0; + } + + dataptr -= 2; + return 2; +} + +int AdlibDriver::update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value) { + setupInstrument(_curRegOffset, getInstrument(value), channel); + return 0; +} + +int AdlibDriver::update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.unk29 = value; + channel.unk30 = READ_BE_UINT16(dataptr); + dataptr += 2; + channel.primaryEffect = &AdlibDriver::primaryEffect1; + channel.unk31 = 0xFF; + return 0; +} + +int AdlibDriver::update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { + --dataptr; + channel.primaryEffect = 0; + channel.unk30 = 0; + return 0; +} + +int AdlibDriver::update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.baseFreq = value; + return 0; +} + +int AdlibDriver::update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.unk32 = value; + channel.unk33 = *dataptr++; + uint8 temp = *dataptr++; + channel.unk34 = temp + 1; + channel.unk35 = temp << 1; + channel.unk36 = *dataptr++; + channel.primaryEffect = &AdlibDriver::primaryEffect2; + return 0; +} + +int AdlibDriver::update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.priority = value; + return 0; +} + +int AdlibDriver::updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value) { + value >>= 1; + _unkValue1 = _unkValue2 = value; + _unkValue3 = 0xFF; + _unkValue4 = _unkValue5 = 0; + return 0; +} + +int AdlibDriver::updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value) { + if (_unkValue5) { + if (_unkValue4 & value) { + _unkValue5 = 0; + return 0; + } + } + + if (!(value & _unkValue4)) { + ++_unkValue5; + } + + dataptr -= 2; + channel.duration = 1; + return 2; +} + +int AdlibDriver::update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.opExtraLevel1 = value; + adjustVolume(channel); + return 0; +} + +int AdlibDriver::update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value) { + setupDuration(value, channel); + return (value != 0); +} + +int AdlibDriver::update_playNote(uint8 *&dataptr, Channel &channel, uint8 value) { + setupDuration(value, channel); + noteOn(channel); + return (value != 0); +} + +int AdlibDriver::update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.fractionalSpacing = value & 7; + return 0; +} + +int AdlibDriver::update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value) { + _tempo = value; + return 0; +} + +int AdlibDriver::update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { + --dataptr; + channel.secondaryEffect = 0; + return 0; +} + +int AdlibDriver::update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.tempo = value; + return 0; +} + +int AdlibDriver::update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.opExtraLevel3 = value; + return 0; +} + +int AdlibDriver::update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) { + int channelBackUp = _curChannel; + + _curChannel = value; + Channel &channel2 = _channels[value]; + channel2.opExtraLevel2 = *dataptr++; + adjustVolume(channel2); + + _curChannel = channelBackUp; + return 0; +} + +int AdlibDriver::update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) { + int channelBackUp = _curChannel; + + _curChannel = value; + Channel &channel2 = _channels[value]; + channel2.opExtraLevel2 += *dataptr++; + adjustVolume(channel2); + + _curChannel = channelBackUp; + return 0; +} + +// Apart from initialising to zero, these two functions are the only ones that +// modify _vibratoAndAMDepthBits. + +int AdlibDriver::update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value) { + if (value & 1) + _vibratoAndAMDepthBits |= 0x80; + else + _vibratoAndAMDepthBits &= 0x7F; + + writeOPL(0xBD, _vibratoAndAMDepthBits); + return 0; +} + +int AdlibDriver::update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value) { + if (value & 1) + _vibratoAndAMDepthBits |= 0x40; + else + _vibratoAndAMDepthBits &= 0xBF; + + writeOPL(0xBD, _vibratoAndAMDepthBits); + return 0; +} + +int AdlibDriver::update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.opExtraLevel1 += value; + adjustVolume(channel); + return 0; +} + +int AdlibDriver::updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value) { + int channelBackUp = _curChannel; + + _curChannel = value; + Channel &channel2 = _channels[value]; + channel2.duration = channel2.priority = 0; + channel2.dataptr = 0; + channel2.opExtraLevel2 = 0; + + if (value != 9) { + uint8 outValue = _regOffset[value]; + + // Feedback strength / Connection type + writeOPL(0xC0 + _curChannel, 0x00); + + // Key scaling level / Operator output level + writeOPL(0x43 + outValue, 0x3F); + + // Sustain Level / Release Rate + writeOPL(0x83 + outValue, 0xFF); + + // Key On / Octave / Frequency + writeOPL(0xB0 + _curChannel, 0x00); + } + + _curChannel = channelBackUp; + return 0; +} + +int AdlibDriver::updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value) { + uint16 unk = *dataptr++; + unk |= value << 8; + unk &= getRandomNr(); + + uint16 unk2 = ((channel.regBx & 0x1F) << 8) | channel.regAx; + unk2 += unk; + unk2 |= ((channel.regBx & 0x20) << 8); + + // Frequency + writeOPL(0xA0 + _curChannel, unk2 & 0xFF); + + // Key On / Octave / Frequency + writeOPL(0xB0 + _curChannel, (unk2 & 0xFF00) >> 8); + + return 0; +} + +int AdlibDriver::update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) { + --dataptr; + channel.primaryEffect = 0; + return 0; +} + +int AdlibDriver::updateCallback41(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.unk16 = value; + setupNote(channel.rawNote, channel, true); + return 0; +} + +int AdlibDriver::update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value) { + --dataptr; + channel.tempo = _tempo; + return 0; +} + +int AdlibDriver::update_nop1(uint8 *&dataptr, Channel &channel, uint8 value) { + --dataptr; + return 0; +} + +int AdlibDriver::update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.durationRandomness = value; + return 0; +} + +int AdlibDriver::update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) { + int tempo = channel.tempo + (int8)value; + + if (tempo <= 0) + tempo = 1; + else if (tempo > 255) + tempo = 255; + + channel.tempo = tempo; + return 0; +} + +int AdlibDriver::updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value) { + uint8 entry = *dataptr++; + _tablePtr1 = _unkTable2[entry++]; + _tablePtr2 = _unkTable2[entry]; + if (value == 2) { + // Frequency + writeOPL(0xA0, _tablePtr2[0]); + } + return 0; +} + +// TODO: This is really the same as update_nop1(), so they should be combined +// into one single update_nop(). + +int AdlibDriver::update_nop2(uint8 *&dataptr, Channel &channel, uint8 value) { + --dataptr; + return 0; +} + +int AdlibDriver::update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) { + int channelBackUp = _curChannel; + int regOffsetBackUp = _curRegOffset; + + _curChannel = 6; + _curRegOffset = _regOffset[6]; + + setupInstrument(_curRegOffset, getInstrument(value), channel); + _unkValue6 = channel.opLevel2; + + _curChannel = 7; + _curRegOffset = _regOffset[7]; + + setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel); + _unkValue7 = channel.opLevel1; + _unkValue8 = channel.opLevel2; + + _curChannel = 8; + _curRegOffset = _regOffset[8]; + + setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel); + _unkValue9 = channel.opLevel1; + _unkValue10 = channel.opLevel2; + + // Octave / F-Number / Key-On for channels 6, 7 and 8 + + _channels[6].regBx = *dataptr++ & 0x2F; + writeOPL(0xB6, _channels[6].regBx); + writeOPL(0xA6, *dataptr++); + + _channels[7].regBx = *dataptr++ & 0x2F; + writeOPL(0xB7, _channels[7].regBx); + writeOPL(0xA7, *dataptr++); + + _channels[8].regBx = *dataptr++ & 0x2F; + writeOPL(0xB8, _channels[8].regBx); + writeOPL(0xA8, *dataptr++); + + _rhythmSectionBits = 0x20; + + _curRegOffset = regOffsetBackUp; + _curChannel = channelBackUp; + return 0; +} + +int AdlibDriver::update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) { + // Any instrument that we want to play, and which was already playing, + // is temporarily keyed off. Instruments that were off already, or + // which we don't want to play, retain their old on/off status. This is + // probably so that the instrument's envelope is played from its + // beginning again... + + writeOPL(0xBD, (_rhythmSectionBits & ~(value & 0x1F)) | 0x20); + + // ...but since we only set the rhythm instrument bits, and never clear + // them (until the entire rhythm section is disabled), I'm not sure how + // useful the cleverness above is. We could perhaps simply turn off all + // the rhythm instruments instead. + + _rhythmSectionBits |= value; + + writeOPL(0xBD, _vibratoAndAMDepthBits | 0x20 | _rhythmSectionBits); + return 0; +} + +int AdlibDriver::update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) { + --dataptr; + _rhythmSectionBits = 0; + + // All the rhythm bits are cleared. The AM and Vibrato depth bits + // remain unchanged. + + writeOPL(0xBD, _vibratoAndAMDepthBits); + return 0; +} + +int AdlibDriver::updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value) { + uint8 value2 = *dataptr++; + + if (value & 1) { + _unkValue12 = value2; + + // Channel 7, op1: Level Key Scaling / Total Level + writeOPL(0x51, checkValue(value2 + _unkValue7 + _unkValue11 + _unkValue12)); + } + + if (value & 2) { + _unkValue14 = value2; + + // Channel 8, op2: Level Key Scaling / Total Level + writeOPL(0x55, checkValue(value2 + _unkValue10 + _unkValue13 + _unkValue14)); + } + + if (value & 4) { + _unkValue15 = value2; + + // Channel 8, op1: Level Key Scaling / Total Level + writeOPL(0x52, checkValue(value2 + _unkValue9 + _unkValue16 + _unkValue15)); + } + + if (value & 8) { + _unkValue18 = value2; + + // Channel 7, op2: Level Key Scaling / Total Level + writeOPL(0x54, checkValue(value2 + _unkValue8 + _unkValue17 + _unkValue18)); + } + + if (value & 16) { + _unkValue20 = value2; + + // Channel 6, op2: Level Key Scaling / Total Level + writeOPL(0x53, checkValue(value2 + _unkValue6 + _unkValue19 + _unkValue20)); + } + + return 0; +} + +int AdlibDriver::updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value) { + uint8 value2 = *dataptr++; + + if (value & 1) { + _unkValue11 = checkValue(value2 + _unkValue7 + _unkValue11 + _unkValue12); + + // Channel 7, op1: Level Key Scaling / Total Level + writeOPL(0x51, _unkValue11); + } + + if (value & 2) { + _unkValue13 = checkValue(value2 + _unkValue10 + _unkValue13 + _unkValue14); + + // Channel 8, op2: Level Key Scaling / Total Level + writeOPL(0x55, _unkValue13); + } + + if (value & 4) { + _unkValue16 = checkValue(value2 + _unkValue9 + _unkValue16 + _unkValue15); + + // Channel 8, op1: Level Key Scaling / Total Level + writeOPL(0x52, _unkValue16); + } + + if (value & 8) { + _unkValue17 = checkValue(value2 + _unkValue8 + _unkValue17 + _unkValue18); + + // Channel 7, op2: Level Key Scaling / Total Level + writeOPL(0x54, _unkValue17); + } + + if (value & 16) { + _unkValue19 = checkValue(value2 + _unkValue6 + _unkValue19 + _unkValue20); + + // Channel 6, op2: Level Key Scaling / Total Level + writeOPL(0x53, _unkValue19); + } + + return 0; +} + +int AdlibDriver::updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value) { + uint8 value2 = *dataptr++; + + if (value & 1) { + _unkValue11 = value2; + + // Channel 7, op1: Level Key Scaling / Total Level + writeOPL(0x51, checkValue(value2 + _unkValue7 + _unkValue12)); + } + + if (value & 2) { + _unkValue13 = value2; + + // Channel 8, op2: Level Key Scaling / Total Level + writeOPL(0x55, checkValue(value2 + _unkValue10 + _unkValue14)); + } + + if (value & 4) { + _unkValue16 = value2; + + // Channel 8, op1: Level Key Scaling / Total Level + writeOPL(0x52, checkValue(value2 + _unkValue9 + _unkValue15)); + } + + if (value & 8) { + _unkValue17 = value2; + + // Channel 7, op2: Level Key Scaling / Total Level + writeOPL(0x54, checkValue(value2 + _unkValue8 + _unkValue18)); + } + + if (value & 16) { + _unkValue19 = value2; + + // Channel 6, op2: Level Key Scaling / Total Level + writeOPL(0x53, checkValue(value2 + _unkValue6 + _unkValue20)); + } + + return 0; +} + +int AdlibDriver::update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value) { + _soundTrigger = value; + return 0; +} + +int AdlibDriver::update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.tempoReset = value; + return 0; +} + +int AdlibDriver::updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value) { + channel.unk39 = value; + channel.unk40 = *dataptr++; + return 0; +} + +// static res + +#define COMMAND(x) { &AdlibDriver::x, #x } + +void AdlibDriver::setupOpcodeList() { + static const OpcodeEntry opcodeList[] = { + COMMAND(snd_ret0x100), + COMMAND(snd_ret0x1983), + COMMAND(snd_initDriver), + COMMAND(snd_deinitDriver), + COMMAND(snd_setSoundData), + COMMAND(snd_unkOpcode1), + COMMAND(snd_startSong), + COMMAND(snd_unkOpcode2), + COMMAND(snd_unkOpcode3), + COMMAND(snd_readByte), + COMMAND(snd_writeByte), + COMMAND(snd_getSoundTrigger), + COMMAND(snd_unkOpcode4), + COMMAND(snd_dummy), + COMMAND(snd_getNullvar4), + COMMAND(snd_setNullvar3), + COMMAND(snd_setFlag), + COMMAND(snd_clearFlag) + }; + + _opcodeList = opcodeList; + _opcodesEntries = ARRAYSIZE(opcodeList); +} + +void AdlibDriver::setupParserOpcodeTable() { + static const ParserOpcode parserOpcodeTable[] = { + // 0 + COMMAND(update_setRepeat), + COMMAND(update_checkRepeat), + COMMAND(update_setupProgram), + COMMAND(update_setNoteSpacing), + + // 4 + COMMAND(update_jump), + COMMAND(update_jumpToSubroutine), + COMMAND(update_returnFromSubroutine), + COMMAND(update_setBaseOctave), + + // 8 + COMMAND(update_stopChannel), + COMMAND(update_playRest), + COMMAND(update_writeAdlib), + COMMAND(update_setupNoteAndDuration), + + // 12 + COMMAND(update_setBaseNote), + COMMAND(update_setupSecondaryEffect1), + COMMAND(update_stopOtherChannel), + COMMAND(update_waitForEndOfProgram), + + // 16 + COMMAND(update_setupInstrument), + COMMAND(update_setupPrimaryEffect1), + COMMAND(update_removePrimaryEffect1), + COMMAND(update_setBaseFreq), + + // 20 + COMMAND(update_stopChannel), + COMMAND(update_setupPrimaryEffect2), + COMMAND(update_stopChannel), + COMMAND(update_stopChannel), + + // 24 + COMMAND(update_stopChannel), + COMMAND(update_stopChannel), + COMMAND(update_setPriority), + COMMAND(update_stopChannel), + + // 28 + COMMAND(updateCallback23), + COMMAND(updateCallback24), + COMMAND(update_setExtraLevel1), + COMMAND(update_stopChannel), + + // 32 + COMMAND(update_setupDuration), + COMMAND(update_playNote), + COMMAND(update_stopChannel), + COMMAND(update_stopChannel), + + // 36 + COMMAND(update_setFractionalNoteSpacing), + COMMAND(update_stopChannel), + COMMAND(update_setTempo), + COMMAND(update_removeSecondaryEffect1), + + // 40 + COMMAND(update_stopChannel), + COMMAND(update_setChannelTempo), + COMMAND(update_stopChannel), + COMMAND(update_setExtraLevel3), + + // 44 + COMMAND(update_setExtraLevel2), + COMMAND(update_changeExtraLevel2), + COMMAND(update_setAMDepth), + COMMAND(update_setVibratoDepth), + + // 48 + COMMAND(update_changeExtraLevel1), + COMMAND(update_stopChannel), + COMMAND(update_stopChannel), + COMMAND(updateCallback38), + + // 52 + COMMAND(update_stopChannel), + COMMAND(updateCallback39), + COMMAND(update_removePrimaryEffect2), + COMMAND(update_stopChannel), + + // 56 + COMMAND(update_stopChannel), + COMMAND(updateCallback41), + COMMAND(update_resetToGlobalTempo), + COMMAND(update_nop1), + + // 60 + COMMAND(update_setDurationRandomness), + COMMAND(update_changeChannelTempo), + COMMAND(update_stopChannel), + COMMAND(updateCallback46), + + // 64 + COMMAND(update_nop2), + COMMAND(update_setupRhythmSection), + COMMAND(update_playRhythmSection), + COMMAND(update_removeRhythmSection), + + // 68 + COMMAND(updateCallback51), + COMMAND(updateCallback52), + COMMAND(updateCallback53), + COMMAND(update_setSoundTrigger), + + // 72 + COMMAND(update_setTempoReset), + COMMAND(updateCallback56), + COMMAND(update_stopChannel) + }; + + _parserOpcodeTable = parserOpcodeTable; + _parserOpcodeTableSize = ARRAYSIZE(parserOpcodeTable); +} +#undef COMMAND + +// This table holds the register offset for operator 1 for each of the nine +// channels. To get the register offset for operator 2, simply add 3. + +const uint8 AdlibDriver::_regOffset[] = { + 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, + 0x12 +}; + +// Given the size of this table, and the range of its values, it's probably the +// F-Numbers (10 bits) for the notes of the 12-tone scale. However, it does not +// match the table in the Adlib documentation I've seen. + +const uint16 AdlibDriver::_unkTable[] = { + 0x0134, 0x0147, 0x015A, 0x016F, 0x0184, 0x019C, 0x01B4, 0x01CE, 0x01E9, + 0x0207, 0x0225, 0x0246 +}; + +// These tables are currently only used by updateCallback46(), which only ever +// uses the first element of one of the sub-tables. + +const uint8 *AdlibDriver::_unkTable2[] = { + AdlibDriver::_unkTable2_1, + AdlibDriver::_unkTable2_2, + AdlibDriver::_unkTable2_1, + AdlibDriver::_unkTable2_2, + AdlibDriver::_unkTable2_3, + AdlibDriver::_unkTable2_2 +}; + +const uint8 AdlibDriver::_unkTable2_1[] = { + 0x50, 0x50, 0x4F, 0x4F, 0x4E, 0x4E, 0x4D, 0x4D, + 0x4C, 0x4C, 0x4B, 0x4B, 0x4A, 0x4A, 0x49, 0x49, + 0x48, 0x48, 0x47, 0x47, 0x46, 0x46, 0x45, 0x45, + 0x44, 0x44, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41, + 0x40, 0x40, 0x3F, 0x3F, 0x3E, 0x3E, 0x3D, 0x3D, + 0x3C, 0x3C, 0x3B, 0x3B, 0x3A, 0x3A, 0x39, 0x39, + 0x38, 0x38, 0x37, 0x37, 0x36, 0x36, 0x35, 0x35, + 0x34, 0x34, 0x33, 0x33, 0x32, 0x32, 0x31, 0x31, + 0x30, 0x30, 0x2F, 0x2F, 0x2E, 0x2E, 0x2D, 0x2D, + 0x2C, 0x2C, 0x2B, 0x2B, 0x2A, 0x2A, 0x29, 0x29, + 0x28, 0x28, 0x27, 0x27, 0x26, 0x26, 0x25, 0x25, + 0x24, 0x24, 0x23, 0x23, 0x22, 0x22, 0x21, 0x21, + 0x20, 0x20, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, 0x1D, + 0x1C, 0x1C, 0x1B, 0x1B, 0x1A, 0x1A, 0x19, 0x19, + 0x18, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, + 0x14, 0x14, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, + 0x10, 0x10 +}; + +// no don't ask me WHY this table exsits! +const uint8 AdlibDriver::_unkTable2_2[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x6F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F +}; + +const uint8 AdlibDriver::_unkTable2_3[] = { + 0x40, 0x40, 0x40, 0x3F, 0x3F, 0x3F, 0x3E, 0x3E, + 0x3E, 0x3D, 0x3D, 0x3D, 0x3C, 0x3C, 0x3C, 0x3B, + 0x3B, 0x3B, 0x3A, 0x3A, 0x3A, 0x39, 0x39, 0x39, + 0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x36, + 0x36, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x33, + 0x33, 0x33, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31, + 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x2E, + 0x2E, 0x2D, 0x2D, 0x2D, 0x2C, 0x2C, 0x2C, 0x2B, + 0x2B, 0x2B, 0x2A, 0x2A, 0x2A, 0x29, 0x29, 0x29, + 0x28, 0x28, 0x28, 0x27, 0x27, 0x27, 0x26, 0x26, + 0x26, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x23, + 0x23, 0x23, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, + 0x20, 0x20, 0x20, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, + 0x1E, 0x1D, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1B, + 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x19, + 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x16, 0x16, + 0x16, 0x15 +}; + +// This table is used to modify the frequency of the notes, depending on the +// note value and unk16. In theory, we could very well try to access memory +// outside this table, but in reality that probably won't happen. +// +// This could be some sort of pitch bend, but I have yet to see it used for +// anything so it's hard to say. + +const uint8 AdlibDriver::_unkTables[][32] = { + // 0 + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21 }, + // 1 + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x09, + 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x1A, + 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x22, 0x24 }, + // 2 + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x09, + 0x0A, 0x0C, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x19, 0x1A, 0x1C, 0x1D, + 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26 }, + // 3 + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x1A, 0x1C, 0x1D, + 0x1E, 0x1F, 0x20, 0x21, 0x23, 0x25, 0x27, 0x28 }, + // 4 + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x11, 0x13, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1B, 0x1D, 0x1F, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x28, 0x2A }, + // 5 + { 0x00, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1B, 0x1D, 0x1F, 0x20, + 0x21, 0x22, 0x23, 0x25, 0x27, 0x29, 0x2B, 0x2D }, + // 6 + { 0x00, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x15, + 0x16, 0x17, 0x18, 0x1A, 0x1C, 0x1E, 0x21, 0x24, + 0x25, 0x26, 0x27, 0x29, 0x2B, 0x2D, 0x2F, 0x30 }, + // 7 + { 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x15, 0x18, + 0x19, 0x1A, 0x1C, 0x1D, 0x1F, 0x21, 0x23, 0x25, + 0x26, 0x27, 0x29, 0x2B, 0x2D, 0x2F, 0x30, 0x32 }, + // 8 + { 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x14, 0x17, 0x1A, + 0x19, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x25, 0x28, + 0x29, 0x2A, 0x2B, 0x2D, 0x2F, 0x31, 0x33, 0x35 }, + // 9 + { 0x00, 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0E, + 0x0F, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x20, 0x22, 0x24, 0x26, 0x29, + 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x39 }, + // 10 + { 0x00, 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0E, + 0x0F, 0x10, 0x12, 0x14, 0x16, 0x19, 0x1B, 0x1E, + 0x1F, 0x21, 0x23, 0x25, 0x27, 0x29, 0x2B, 0x2D, + 0x2E, 0x2F, 0x31, 0x32, 0x34, 0x36, 0x39, 0x3C }, + // 11 + { 0x00, 0x01, 0x03, 0x05, 0x07, 0x0A, 0x0C, 0x0F, + 0x10, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1E, + 0x1F, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2B, 0x2E, + 0x2F, 0x30, 0x32, 0x34, 0x36, 0x39, 0x3C, 0x3F }, + // 12 + { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0D, 0x10, + 0x11, 0x12, 0x14, 0x16, 0x18, 0x1B, 0x1E, 0x21, + 0x22, 0x23, 0x25, 0x27, 0x29, 0x2C, 0x2F, 0x32, + 0x33, 0x34, 0x36, 0x38, 0x3B, 0x34, 0x41, 0x44 }, + // 13 + { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0D, 0x11, + 0x12, 0x13, 0x15, 0x17, 0x1A, 0x1D, 0x20, 0x23, + 0x24, 0x25, 0x27, 0x29, 0x2C, 0x2F, 0x32, 0x35, + 0x36, 0x37, 0x39, 0x3B, 0x3E, 0x41, 0x44, 0x47 } +}; + +// #pragma mark - + +// At the time of writing, the only known case where Kyra 1 uses sound triggers +// is in the castle, to cycle between three different songs. + +const int CadlPlayer::_kyra1SoundTriggers[] = { + 0, 4, 5, 3 +}; + +const int CadlPlayer::_kyra1NumSoundTriggers = ARRAYSIZE(CadlPlayer::_kyra1SoundTriggers); + +CadlPlayer::CadlPlayer(Copl *newopl) + : CPlayer(newopl), numsubsongs(0), _trackEntries(), _soundDataPtr(0) +{ + memset(_trackEntries, 0, sizeof(_trackEntries)); + _driver = new AdlibDriver(newopl); + assert(_driver); + + _sfxPlayingSound = -1; + // _soundFileLoaded = ""; + + _soundTriggers = _kyra1SoundTriggers; + _numSoundTriggers = _kyra1NumSoundTriggers; + + init(); +} + +CadlPlayer::~CadlPlayer() { + delete [] _soundDataPtr; + delete _driver; +} + +bool CadlPlayer::init() { + _driver->callback(2); + _driver->callback(16, int(4)); + return true; +} + +void CadlPlayer::process() { + uint8 trigger = _driver->callback(11); + + if (trigger < _numSoundTriggers) { + int soundId = _soundTriggers[trigger]; + + if (soundId) { + playTrack(soundId); + } + } else { + warning("Unknown sound trigger %d", trigger); + // TODO: At this point, we really want to clear the trigger... + } +} + +// void CadlPlayer::setVolume(int volume) { +// } + +// int CadlPlayer::getVolume() { +// return 0; +// } + +// void CadlPlayer::loadMusicFile(const char *file) { +// loadSoundFile(file); +// } + +void CadlPlayer::playTrack(uint8 track) { + play(track); +} + +// void CadlPlayer::haltTrack() { +// unk1(); +// unk2(); +// //_engine->_system->delayMillis(3 * 60); +// } + +void CadlPlayer::playSoundEffect(uint8_t track) { + play(track); +} + +void CadlPlayer::play(uint8_t track) { + uint8 soundId = _trackEntries[track]; + if ((int8)soundId == -1 || !_soundDataPtr) + return; + soundId &= 0xFF; + _driver->callback(16, 0); + // while ((_driver->callback(16, 0) & 8)) { + // We call the system delay and not the game delay to avoid concurrency issues. + // _engine->_system->delayMillis(10); + // } + if (_sfxPlayingSound != -1) { + // Restore the sounds's normal values. + _driver->callback(10, _sfxPlayingSound, int(1), int(_sfxPriority)); + _driver->callback(10, _sfxPlayingSound, int(3), int(_sfxFourthByteOfSong)); + _sfxPlayingSound = -1; + } + + int chan = _driver->callback(9, soundId, int(0)); + + if (chan != 9) { + _sfxPlayingSound = soundId; + _sfxPriority = _driver->callback(9, soundId, int(1)); + _sfxFourthByteOfSong = _driver->callback(9, soundId, int(3)); + + // In the cases I've seen, the mysterious fourth byte has been + // the parameter for the update_setExtraLevel3() callback. + // + // The extra level is part of the channels "total level", which + // is a six-bit value where larger values means softer volume. + // + // So what seems to be happening here is that sounds which are + // started by this function are given a slightly lower priority + // and a slightly higher (i.e. softer) extra level 3 than they + // would have if they were started from anywhere else. Strange. + + int newVal = ((((-_sfxFourthByteOfSong) + 63) * 0xFF) >> 8) & 0xFF; + newVal = -newVal + 63; + _driver->callback(10, soundId, int(3), newVal); + newVal = ((_sfxPriority * 0xFF) >> 8) & 0xFF; + _driver->callback(10, soundId, int(1), newVal); + } + + _driver->callback(6, soundId); +} + +// void CadlPlayer::beginFadeOut() { +// playSoundEffect(1); +// } + +bool CadlPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); + + // file validation section + if(!f || !fp.extension(filename, ".adl")) { + fp.close(f); + return false; + } + + // if (_soundFileLoaded == file) + // return; + + // if (_soundDataPtr) { + // haltTrack(); + // } + + uint8 *file_data = 0; uint32 file_size = 0; + + // char filename[25]; + // sprintf(filename, "%s.ADL", file); + + // file_data = _engine->resource()->fileData(filename, &file_size); + // if (!file_data) { + // warning("Couldn't find music file: '%s'", filename); + // return; + // } + + unk2(); + unk1(); + + file_size = fp.filesize(f); + file_data = new uint8 [file_size]; + f->readString((char *)file_data, file_size); + + _driver->callback(8, int(-1)); + _soundDataPtr = 0; + + uint8 *p = file_data; + memcpy(_trackEntries, p, 120*sizeof(uint8)); + p += 120; + + int soundDataSize = file_size - 120; + + _soundDataPtr = new uint8[soundDataSize]; + assert(_soundDataPtr); + + memcpy(_soundDataPtr, p, soundDataSize*sizeof(uint8)); + + delete [] file_data; + file_data = p = 0; + file_size = 0; + + _driver->callback(4, _soundDataPtr); + + // _soundFileLoaded = file; + + for(int i = 0; i < 200; i++) + if(_trackEntries[i] != 0xff) + numsubsongs = i + 1; + + fp.close(f); + return true; +} + +void CadlPlayer::rewind(int subsong) +{ + opl->init(); + opl->write(1,32); + playSoundEffect(subsong); + cursubsong = subsong; + update(); +} + +unsigned int CadlPlayer::getsubsongs() +{ + return numsubsongs; +} + +bool CadlPlayer::update() +{ + bool songend = true; + +// if(_trackEntries[cursubsong] == 0xff) +// return false; + + _driver->callback(); + + for(int i = 0; i < 10; i++) + if(_driver->_channels[i].dataptr != NULL) + songend = false; + + return !songend; +} + +void CadlPlayer::unk1() { + playSoundEffect(0); + //_engine->_system->delayMillis(5 * 60); +} + +void CadlPlayer::unk2() { + playSoundEffect(0); +} + +CPlayer *CadlPlayer::factory(Copl *newopl) +{ + return new CadlPlayer(newopl); +}
--- a/Plugins/Input/adplug/core/adplug.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2005 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 - * - * adplug.cpp - CAdPlug utility class, by Simon Peter <dn.tlp@gmx.net> - */ - -#include <string> -#include <binfile.h> - -#include "adplug.h" -#include "debug.h" - -/***** Replayer includes *****/ - -#include "hsc.h" -#include "amd.h" -#include "a2m.h" -#include "imf.h" -#include "sng.h" -#include "adtrack.h" -#include "bam.h" -#include "d00.h" -#include "dfm.h" -#include "hsp.h" -#include "ksm.h" -#include "mad.h" -#include "mid.h" -#include "mkj.h" -#include "cff.h" -#include "dmo.h" -#include "s3m.h" -#include "dtm.h" -#include "fmc.h" -#include "mtk.h" -#include "rad.h" -#include "raw.h" -#include "sa2.h" -#include "bmf.h" -#include "flash.h" -#include "hybrid.h" -#include "hyp.h" -#include "psi.h" -#include "rat.h" -#include "lds.h" -#include "u6m.h" -#include "rol.h" -#include "xsm.h" -#include "dro.h" -#include "msc.h" -#include "rix.h" -#include "adl.h" - -/***** Defines *****/ - -#define VERSION "1.6" // AdPlug library version string - -/***** CAdPlug *****/ - -// List of all players that come with the standard AdPlug distribution -const CPlayerDesc CAdPlug::allplayers[] = { - CPlayerDesc(ChscPlayer::factory, "HSC-Tracker", ".hsc\0"), - CPlayerDesc(CsngPlayer::factory, "SNGPlay", ".sng\0"), - CPlayerDesc(CimfPlayer::factory, "Apogee IMF", ".imf\0.wlf\0.adlib\0"), - CPlayerDesc(Ca2mLoader::factory, "Adlib Tracker 2", ".a2m\0"), - CPlayerDesc(CadtrackLoader::factory, "Adlib Tracker", ".sng\0"), - CPlayerDesc(CamdLoader::factory, "AMUSIC", ".amd\0"), - CPlayerDesc(CbamPlayer::factory, "Bob's Adlib Music", ".bam\0"), - CPlayerDesc(Cd00Player::factory, "Packed EdLib", ".d00\0"), - CPlayerDesc(CdfmLoader::factory, "Digital-FM", ".dfm\0"), - CPlayerDesc(ChspLoader::factory, "HSC Packed", ".hsp\0"), - CPlayerDesc(CksmPlayer::factory, "Ken Silverman Music", ".ksm\0"), - CPlayerDesc(CmadLoader::factory, "Mlat Adlib Tracker", ".mad\0"), - CPlayerDesc(CmidPlayer::factory, "MIDI", ".cmf\0.sci\0.laa\0"), - CPlayerDesc(CmkjPlayer::factory, "MKJamz", ".mkj\0"), - CPlayerDesc(CcffLoader::factory, "Boomtracker", ".cff\0"), - CPlayerDesc(CdmoLoader::factory, "TwinTeam", ".dmo\0"), - CPlayerDesc(Cs3mPlayer::factory, "Scream Tracker 3", ".s3m\0"), - CPlayerDesc(CdtmLoader::factory, "DeFy Adlib Tracker", ".dtm\0"), - CPlayerDesc(CfmcLoader::factory, "Faust Music Creator", ".sng\0"), - CPlayerDesc(CmtkLoader::factory, "MPU-401 Trakker", ".mtk\0"), - CPlayerDesc(CradLoader::factory, "Reality Adlib Tracker", ".rad\0"), - CPlayerDesc(CrawPlayer::factory, "RdosPlay RAW", ".raw\0"), - CPlayerDesc(Csa2Loader::factory, "Surprise! Adlib Tracker", ".sat\0.sa2\0"), - CPlayerDesc(CxadbmfPlayer::factory, "BMF Adlib Tracker", ".xad\0"), - CPlayerDesc(CxadflashPlayer::factory, "Flash", ".xad\0"), - CPlayerDesc(CxadhybridPlayer::factory, "Hybrid", ".xad\0"), - CPlayerDesc(CxadhypPlayer::factory, "Hypnosis", ".xad\0"), - CPlayerDesc(CxadpsiPlayer::factory, "PSI", ".xad\0"), - CPlayerDesc(CxadratPlayer::factory, "rat", ".xad\0"), - CPlayerDesc(CldsPlayer::factory, "LOUDNESS Sound System", ".lds\0"), - CPlayerDesc(Cu6mPlayer::factory, "Ultima 6 Music", ".m\0"), - CPlayerDesc(CrolPlayer::factory, "Adlib Visual Composer", ".rol\0"), - CPlayerDesc(CxsmPlayer::factory, "eXtra Simple Music", ".xsm\0"), - CPlayerDesc(CdroPlayer::factory, "DOSBox Raw OPL", ".dro\0"), - 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() -}; - -const CPlayers &CAdPlug::init_players(const CPlayerDesc pd[]) -{ - static CPlayers initplayers; - unsigned int i; - - for(i = 0; pd[i].factory; i++) - initplayers.push_back(&pd[i]); - - return initplayers; -} - -const CPlayers CAdPlug::players = CAdPlug::init_players(CAdPlug::allplayers); -CAdPlugDatabase *CAdPlug::database = 0; - -CPlayer *CAdPlug::factory(const std::string &fn, Copl *opl, const CPlayers &pl, - const CFileProvider &fp) -{ - CPlayer *p; - CPlayers::const_iterator i; - unsigned int j; - - AdPlug_LogWrite("*** CAdPlug::factory(\"%s\",opl,fp) ***\n", fn.c_str()); - - // Try a direct hit by file extension - for(i = pl.begin(); i != pl.end(); i++) - for(j = 0; (*i)->get_extension(j); j++) - if(fp.extension(fn, (*i)->get_extension(j))) { - AdPlug_LogWrite("Trying direct hit: %s\n", (*i)->filetype.c_str()); - if((p = (*i)->factory(opl))) - if(p->load(fn, fp)) { - AdPlug_LogWrite("got it!\n"); - AdPlug_LogWrite("--- CAdPlug::factory ---\n"); - return p; - } else - delete p; - } - - // Try all players, one by one - for(i = pl.begin(); i != pl.end(); i++) { - AdPlug_LogWrite("Trying: %s\n", (*i)->filetype.c_str()); - if((p = (*i)->factory(opl))) - if(p->load(fn, fp)) { - AdPlug_LogWrite("got it!\n"); - AdPlug_LogWrite("--- CAdPlug::factory ---\n"); - return p; - } else - delete p; - } - - // Unknown file - AdPlug_LogWrite("End of list!\n"); - AdPlug_LogWrite("--- CAdPlug::factory ---\n"); - return 0; -} - -void CAdPlug::set_database(CAdPlugDatabase *db) -{ - database = db; -} - -std::string CAdPlug::get_version() -{ - return std::string(VERSION); -} - -void CAdPlug::debug_output(const std::string &filename) -{ - AdPlug_LogFile(filename.c_str()); - AdPlug_LogWrite("CAdPlug::debug_output(\"%s\"): Redirected.\n",filename.c_str()); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/adplug.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,185 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2005 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 + * + * adplug.cpp - CAdPlug utility class, by Simon Peter <dn.tlp@gmx.net> + */ + +#include <string> +#include <binfile.h> + +#include "adplug.h" +#include "debug.h" + +/***** Replayer includes *****/ + +#include "hsc.h" +#include "amd.h" +#include "a2m.h" +#include "imf.h" +#include "sng.h" +#include "adtrack.h" +#include "bam.h" +#include "d00.h" +#include "dfm.h" +#include "hsp.h" +#include "ksm.h" +#include "mad.h" +#include "mid.h" +#include "mkj.h" +#include "cff.h" +#include "dmo.h" +#include "s3m.h" +#include "dtm.h" +#include "fmc.h" +#include "mtk.h" +#include "rad.h" +#include "raw.h" +#include "sa2.h" +#include "bmf.h" +#include "flash.h" +#include "hybrid.h" +#include "hyp.h" +#include "psi.h" +#include "rat.h" +#include "lds.h" +#include "u6m.h" +#include "rol.h" +#include "xsm.h" +#include "dro.h" +#include "msc.h" +#include "rix.h" +#include "adl.h" + +/***** Defines *****/ + +#define VERSION "1.6" // AdPlug library version string + +/***** CAdPlug *****/ + +// List of all players that come with the standard AdPlug distribution +const CPlayerDesc CAdPlug::allplayers[] = { + CPlayerDesc(ChscPlayer::factory, "HSC-Tracker", ".hsc\0"), + CPlayerDesc(CsngPlayer::factory, "SNGPlay", ".sng\0"), + CPlayerDesc(CimfPlayer::factory, "Apogee IMF", ".imf\0.wlf\0.adlib\0"), + CPlayerDesc(Ca2mLoader::factory, "Adlib Tracker 2", ".a2m\0"), + CPlayerDesc(CadtrackLoader::factory, "Adlib Tracker", ".sng\0"), + CPlayerDesc(CamdLoader::factory, "AMUSIC", ".amd\0"), + CPlayerDesc(CbamPlayer::factory, "Bob's Adlib Music", ".bam\0"), + CPlayerDesc(Cd00Player::factory, "Packed EdLib", ".d00\0"), + CPlayerDesc(CdfmLoader::factory, "Digital-FM", ".dfm\0"), + CPlayerDesc(ChspLoader::factory, "HSC Packed", ".hsp\0"), + CPlayerDesc(CksmPlayer::factory, "Ken Silverman Music", ".ksm\0"), + CPlayerDesc(CmadLoader::factory, "Mlat Adlib Tracker", ".mad\0"), + CPlayerDesc(CmidPlayer::factory, "MIDI", ".cmf\0.sci\0.laa\0"), + CPlayerDesc(CmkjPlayer::factory, "MKJamz", ".mkj\0"), + CPlayerDesc(CcffLoader::factory, "Boomtracker", ".cff\0"), + CPlayerDesc(CdmoLoader::factory, "TwinTeam", ".dmo\0"), + CPlayerDesc(Cs3mPlayer::factory, "Scream Tracker 3", ".s3m\0"), + CPlayerDesc(CdtmLoader::factory, "DeFy Adlib Tracker", ".dtm\0"), + CPlayerDesc(CfmcLoader::factory, "Faust Music Creator", ".sng\0"), + CPlayerDesc(CmtkLoader::factory, "MPU-401 Trakker", ".mtk\0"), + CPlayerDesc(CradLoader::factory, "Reality Adlib Tracker", ".rad\0"), + CPlayerDesc(CrawPlayer::factory, "RdosPlay RAW", ".raw\0"), + CPlayerDesc(Csa2Loader::factory, "Surprise! Adlib Tracker", ".sat\0.sa2\0"), + CPlayerDesc(CxadbmfPlayer::factory, "BMF Adlib Tracker", ".xad\0"), + CPlayerDesc(CxadflashPlayer::factory, "Flash", ".xad\0"), + CPlayerDesc(CxadhybridPlayer::factory, "Hybrid", ".xad\0"), + CPlayerDesc(CxadhypPlayer::factory, "Hypnosis", ".xad\0"), + CPlayerDesc(CxadpsiPlayer::factory, "PSI", ".xad\0"), + CPlayerDesc(CxadratPlayer::factory, "rat", ".xad\0"), + CPlayerDesc(CldsPlayer::factory, "LOUDNESS Sound System", ".lds\0"), + CPlayerDesc(Cu6mPlayer::factory, "Ultima 6 Music", ".m\0"), + CPlayerDesc(CrolPlayer::factory, "Adlib Visual Composer", ".rol\0"), + CPlayerDesc(CxsmPlayer::factory, "eXtra Simple Music", ".xsm\0"), + CPlayerDesc(CdroPlayer::factory, "DOSBox Raw OPL", ".dro\0"), + 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() +}; + +const CPlayers &CAdPlug::init_players(const CPlayerDesc pd[]) +{ + static CPlayers initplayers; + unsigned int i; + + for(i = 0; pd[i].factory; i++) + initplayers.push_back(&pd[i]); + + return initplayers; +} + +const CPlayers CAdPlug::players = CAdPlug::init_players(CAdPlug::allplayers); +CAdPlugDatabase *CAdPlug::database = 0; + +CPlayer *CAdPlug::factory(const std::string &fn, Copl *opl, const CPlayers &pl, + const CFileProvider &fp) +{ + CPlayer *p; + CPlayers::const_iterator i; + unsigned int j; + + AdPlug_LogWrite("*** CAdPlug::factory(\"%s\",opl,fp) ***\n", fn.c_str()); + + // Try a direct hit by file extension + for(i = pl.begin(); i != pl.end(); i++) + for(j = 0; (*i)->get_extension(j); j++) + if(fp.extension(fn, (*i)->get_extension(j))) { + AdPlug_LogWrite("Trying direct hit: %s\n", (*i)->filetype.c_str()); + if((p = (*i)->factory(opl))) + if(p->load(fn, fp)) { + AdPlug_LogWrite("got it!\n"); + AdPlug_LogWrite("--- CAdPlug::factory ---\n"); + return p; + } else + delete p; + } + + // Try all players, one by one + for(i = pl.begin(); i != pl.end(); i++) { + AdPlug_LogWrite("Trying: %s\n", (*i)->filetype.c_str()); + if((p = (*i)->factory(opl))) + if(p->load(fn, fp)) { + AdPlug_LogWrite("got it!\n"); + AdPlug_LogWrite("--- CAdPlug::factory ---\n"); + return p; + } else + delete p; + } + + // Unknown file + AdPlug_LogWrite("End of list!\n"); + AdPlug_LogWrite("--- CAdPlug::factory ---\n"); + return 0; +} + +void CAdPlug::set_database(CAdPlugDatabase *db) +{ + database = db; +} + +std::string CAdPlug::get_version() +{ + return std::string(VERSION); +} + +void CAdPlug::debug_output(const std::string &filename) +{ + AdPlug_LogFile(filename.c_str()); + AdPlug_LogWrite("CAdPlug::debug_output(\"%s\"): Redirected.\n",filename.c_str()); +}
--- a/Plugins/Input/adplug/core/adtrack.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -/* - * 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 - * - * adtrack.cpp - Adlib Tracker 1.0 Loader by Simon Peter <dn.tlp@gmx.net> - * - * NOTES: - * The original Adlib Tracker 1.0 is behaving a little different from the - * official spec: The 'octave' integer from the instrument file is stored - * "minus 1" from the actual value, underflowing from 0 to 0xffff. - * - * I also noticed that my player is playing everything transposed a few tones - * higher than the original tracker. As far as i can see, my player perfectly - * follows the official spec, so it "must" be the tracker that does something - * wrong here... - */ - -#include <stdlib.h> -#include <string.h> - -#include "adtrack.h" -#include "debug.h" - -/*** Public methods ***/ - -CPlayer *CadtrackLoader::factory(Copl *newopl) -{ - return new CadtrackLoader(newopl); -} - -bool CadtrackLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - binistream *instf; - char note[2]; - unsigned short rwp; - unsigned char chp, octave, pnote = 0; - int i,j; - AdTrackInst myinst; - - // file validation - if(!fp.extension(filename, ".sng") || fp.filesize(f) != 36000) - { fp.close(f); return false; } - - // check for instruments file - std::string instfilename(filename, 0, filename.find_last_of('.')); - instfilename += ".ins"; - AdPlug_LogWrite("CadtrackLoader::load(,\"%s\"): Checking for \"%s\"...\n", - filename.c_str(), instfilename.c_str()); - instf = fp.open(instfilename); - if(!instf || fp.filesize(instf) != 468) { fp.close(f); return false; } - - // give CmodPlayer a hint on what we're up to - realloc_patterns(1,1000,9); realloc_instruments(9); realloc_order(1); - init_trackord(); flags = NoKeyOn; - (*order) = 0; length = 1; restartpos = 0; bpm = 120; initspeed = 3; - - // load instruments from instruments file - for(i=0;i<9;i++) { - for(j=0;j<2;j++) { - myinst.op[j].appampmod = instf->readInt(2); - myinst.op[j].appvib = instf->readInt(2); - myinst.op[j].maintsuslvl = instf->readInt(2); - myinst.op[j].keybscale = instf->readInt(2); - myinst.op[j].octave = instf->readInt(2); - myinst.op[j].freqrisevollvldn = instf->readInt(2); - myinst.op[j].softness = instf->readInt(2); - myinst.op[j].attack = instf->readInt(2); - myinst.op[j].decay = instf->readInt(2); - myinst.op[j].release = instf->readInt(2); - myinst.op[j].sustain = instf->readInt(2); - myinst.op[j].feedback = instf->readInt(2); - myinst.op[j].waveform = instf->readInt(2); - } - convert_instrument(i, &myinst); - } - fp.close(instf); - - // load file - for(rwp=0;rwp<1000;rwp++) - for(chp=0;chp<9;chp++) { - // read next record - f->readString(note, 2); octave = f->readInt(1); f->ignore(); - switch(*note) { - case 'C': if(note[1] == '#') pnote = 2; else pnote = 1; break; - case 'D': if(note[1] == '#') pnote = 4; else pnote = 3; break; - case 'E': pnote = 5; break; - case 'F': if(note[1] == '#') pnote = 7; else pnote = 6; break; - case 'G': if(note[1] == '#') pnote = 9; else pnote = 8; break; - case 'A': if(note[1] == '#') pnote = 11; else pnote = 10; break; - case 'B': pnote = 12; break; - case '\0': - if(note[1] == '\0') - tracks[chp][rwp].note = 127; - else { - fp.close(f); - return false; - } - break; - default: fp.close(f); return false; - } - if((*note) != '\0') { - tracks[chp][rwp].note = pnote + (octave * 12); - tracks[chp][rwp].inst = chp + 1; - } - } - - fp.close(f); - rewind(0); - return true; -} - -float CadtrackLoader::getrefresh() -{ - return 18.2f; -} - -/*** Private methods ***/ - -void CadtrackLoader::convert_instrument(unsigned int n, AdTrackInst *i) -{ - // Carrier "Amp Mod / Vib / Env Type / KSR / Multiple" register - inst[n].data[2] = i->op[Carrier].appampmod ? 1 << 7 : 0; - inst[n].data[2] += i->op[Carrier].appvib ? 1 << 6 : 0; - inst[n].data[2] += i->op[Carrier].maintsuslvl ? 1 << 5 : 0; - inst[n].data[2] += i->op[Carrier].keybscale ? 1 << 4 : 0; - inst[n].data[2] += (i->op[Carrier].octave + 1) & 0xffff; // Bug in original tracker - // Modulator... - inst[n].data[1] = i->op[Modulator].appampmod ? 1 << 7 : 0; - inst[n].data[1] += i->op[Modulator].appvib ? 1 << 6 : 0; - inst[n].data[1] += i->op[Modulator].maintsuslvl ? 1 << 5 : 0; - inst[n].data[1] += i->op[Modulator].keybscale ? 1 << 4 : 0; - inst[n].data[1] += (i->op[Modulator].octave + 1) & 0xffff; // Bug in original tracker - - // Carrier "Key Scaling / Level" register - inst[n].data[10] = (i->op[Carrier].freqrisevollvldn & 3) << 6; - inst[n].data[10] += i->op[Carrier].softness & 63; - // Modulator... - inst[n].data[9] = (i->op[Modulator].freqrisevollvldn & 3) << 6; - inst[n].data[9] += i->op[Modulator].softness & 63; - - // Carrier "Attack / Decay" register - inst[n].data[4] = (i->op[Carrier].attack & 0x0f) << 4; - inst[n].data[4] += i->op[Carrier].decay & 0x0f; - // Modulator... - inst[n].data[3] = (i->op[Modulator].attack & 0x0f) << 4; - inst[n].data[3] += i->op[Modulator].decay & 0x0f; - - // Carrier "Release / Sustain" register - inst[n].data[6] = (i->op[Carrier].release & 0x0f) << 4; - inst[n].data[6] += i->op[Carrier].sustain & 0x0f; - // Modulator... - inst[n].data[5] = (i->op[Modulator].release & 0x0f) << 4; - inst[n].data[5] += i->op[Modulator].sustain & 0x0f; - - // Channel "Feedback / Connection" register - inst[n].data[0] = (i->op[Carrier].feedback & 7) << 1; - - // Carrier/Modulator "Wave Select" registers - inst[n].data[8] = i->op[Carrier].waveform & 3; - inst[n].data[7] = i->op[Modulator].waveform & 3; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/adtrack.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,176 @@ +/* + * 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 + * + * adtrack.cpp - Adlib Tracker 1.0 Loader by Simon Peter <dn.tlp@gmx.net> + * + * NOTES: + * The original Adlib Tracker 1.0 is behaving a little different from the + * official spec: The 'octave' integer from the instrument file is stored + * "minus 1" from the actual value, underflowing from 0 to 0xffff. + * + * I also noticed that my player is playing everything transposed a few tones + * higher than the original tracker. As far as i can see, my player perfectly + * follows the official spec, so it "must" be the tracker that does something + * wrong here... + */ + +#include <stdlib.h> +#include <string.h> + +#include "adtrack.h" +#include "debug.h" + +/*** Public methods ***/ + +CPlayer *CadtrackLoader::factory(Copl *newopl) +{ + return new CadtrackLoader(newopl); +} + +bool CadtrackLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + binistream *instf; + char note[2]; + unsigned short rwp; + unsigned char chp, octave, pnote = 0; + int i,j; + AdTrackInst myinst; + + // file validation + if(!fp.extension(filename, ".sng") || fp.filesize(f) != 36000) + { fp.close(f); return false; } + + // check for instruments file + std::string instfilename(filename, 0, filename.find_last_of('.')); + instfilename += ".ins"; + AdPlug_LogWrite("CadtrackLoader::load(,\"%s\"): Checking for \"%s\"...\n", + filename.c_str(), instfilename.c_str()); + instf = fp.open(instfilename); + if(!instf || fp.filesize(instf) != 468) { fp.close(f); return false; } + + // give CmodPlayer a hint on what we're up to + realloc_patterns(1,1000,9); realloc_instruments(9); realloc_order(1); + init_trackord(); flags = NoKeyOn; + (*order) = 0; length = 1; restartpos = 0; bpm = 120; initspeed = 3; + + // load instruments from instruments file + for(i=0;i<9;i++) { + for(j=0;j<2;j++) { + myinst.op[j].appampmod = instf->readInt(2); + myinst.op[j].appvib = instf->readInt(2); + myinst.op[j].maintsuslvl = instf->readInt(2); + myinst.op[j].keybscale = instf->readInt(2); + myinst.op[j].octave = instf->readInt(2); + myinst.op[j].freqrisevollvldn = instf->readInt(2); + myinst.op[j].softness = instf->readInt(2); + myinst.op[j].attack = instf->readInt(2); + myinst.op[j].decay = instf->readInt(2); + myinst.op[j].release = instf->readInt(2); + myinst.op[j].sustain = instf->readInt(2); + myinst.op[j].feedback = instf->readInt(2); + myinst.op[j].waveform = instf->readInt(2); + } + convert_instrument(i, &myinst); + } + fp.close(instf); + + // load file + for(rwp=0;rwp<1000;rwp++) + for(chp=0;chp<9;chp++) { + // read next record + f->readString(note, 2); octave = f->readInt(1); f->ignore(); + switch(*note) { + case 'C': if(note[1] == '#') pnote = 2; else pnote = 1; break; + case 'D': if(note[1] == '#') pnote = 4; else pnote = 3; break; + case 'E': pnote = 5; break; + case 'F': if(note[1] == '#') pnote = 7; else pnote = 6; break; + case 'G': if(note[1] == '#') pnote = 9; else pnote = 8; break; + case 'A': if(note[1] == '#') pnote = 11; else pnote = 10; break; + case 'B': pnote = 12; break; + case '\0': + if(note[1] == '\0') + tracks[chp][rwp].note = 127; + else { + fp.close(f); + return false; + } + break; + default: fp.close(f); return false; + } + if((*note) != '\0') { + tracks[chp][rwp].note = pnote + (octave * 12); + tracks[chp][rwp].inst = chp + 1; + } + } + + fp.close(f); + rewind(0); + return true; +} + +float CadtrackLoader::getrefresh() +{ + return 18.2f; +} + +/*** Private methods ***/ + +void CadtrackLoader::convert_instrument(unsigned int n, AdTrackInst *i) +{ + // Carrier "Amp Mod / Vib / Env Type / KSR / Multiple" register + inst[n].data[2] = i->op[Carrier].appampmod ? 1 << 7 : 0; + inst[n].data[2] += i->op[Carrier].appvib ? 1 << 6 : 0; + inst[n].data[2] += i->op[Carrier].maintsuslvl ? 1 << 5 : 0; + inst[n].data[2] += i->op[Carrier].keybscale ? 1 << 4 : 0; + inst[n].data[2] += (i->op[Carrier].octave + 1) & 0xffff; // Bug in original tracker + // Modulator... + inst[n].data[1] = i->op[Modulator].appampmod ? 1 << 7 : 0; + inst[n].data[1] += i->op[Modulator].appvib ? 1 << 6 : 0; + inst[n].data[1] += i->op[Modulator].maintsuslvl ? 1 << 5 : 0; + inst[n].data[1] += i->op[Modulator].keybscale ? 1 << 4 : 0; + inst[n].data[1] += (i->op[Modulator].octave + 1) & 0xffff; // Bug in original tracker + + // Carrier "Key Scaling / Level" register + inst[n].data[10] = (i->op[Carrier].freqrisevollvldn & 3) << 6; + inst[n].data[10] += i->op[Carrier].softness & 63; + // Modulator... + inst[n].data[9] = (i->op[Modulator].freqrisevollvldn & 3) << 6; + inst[n].data[9] += i->op[Modulator].softness & 63; + + // Carrier "Attack / Decay" register + inst[n].data[4] = (i->op[Carrier].attack & 0x0f) << 4; + inst[n].data[4] += i->op[Carrier].decay & 0x0f; + // Modulator... + inst[n].data[3] = (i->op[Modulator].attack & 0x0f) << 4; + inst[n].data[3] += i->op[Modulator].decay & 0x0f; + + // Carrier "Release / Sustain" register + inst[n].data[6] = (i->op[Carrier].release & 0x0f) << 4; + inst[n].data[6] += i->op[Carrier].sustain & 0x0f; + // Modulator... + inst[n].data[5] = (i->op[Modulator].release & 0x0f) << 4; + inst[n].data[5] += i->op[Modulator].sustain & 0x0f; + + // Channel "Feedback / Connection" register + inst[n].data[0] = (i->op[Carrier].feedback & 7) << 1; + + // Carrier/Modulator "Wave Select" registers + inst[n].data[8] = i->op[Carrier].waveform & 3; + inst[n].data[7] = i->op[Modulator].waveform & 3; +}
--- a/Plugins/Input/adplug/core/amd.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,193 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 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 - * - * amd.cpp - AMD Loader by Simon Peter <dn.tlp@gmx.net> - */ - -#include <string.h> - -#include "amd.h" -#include "debug.h" - -CPlayer *CamdLoader::factory(Copl *newopl) -{ - return new CamdLoader(newopl); -} - -bool CamdLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - struct { - char id[9]; - unsigned char version; - } header; - int i, j, k, t, numtrax, maxi = 0; - unsigned char buf, buf2, buf3; - const unsigned char convfx[10] = {0,1,2,9,17,11,13,18,3,14}; - const unsigned char convvol[64] = { - 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 9, 0xa, 0xa, 0xb, - 0xc, 0xc, 0xd, 0xe, 0xe, 0xf, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x14, - 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21, - 0x22, 0x23, 0x25, 0x26, 0x28, 0x29, 0x2b, 0x2d, 0x2e, 0x30, 0x32, 0x35, - 0x37, 0x3a, 0x3c, 0x3f - }; - - // file validation section - if(fp.filesize(f) < 1072) { fp.close(f); return false; } - f->seek(1062); f->readString(header.id, 9); - header.version = f->readInt(1); - if(strncmp(header.id, "<o\xefQU\xeeRoR", 9) && - strncmp(header.id, "MaDoKaN96", 9)) { fp.close(f); return false; } - - // load section - memset(inst, 0, sizeof(inst)); - f->seek(0); - f->readString(songname, sizeof(songname)); - f->readString(author, sizeof(author)); - for(i = 0; i < 26; i++) { - f->readString(instname[i], 23); - for(j = 0; j < 11; j++) inst[i].data[j] = f->readInt(1); - } - length = f->readInt(1); nop = f->readInt(1) + 1; - for(i=0;i<128;i++) order[i] = f->readInt(1); - f->seek(10, binio::Add); - if(header.version == 0x10) { // unpacked module - maxi = nop * 9; - for(i=0;i<64*9;i++) - trackord[i/9][i%9] = i+1; - t = 0; - while(!f->ateof()) { - for(j=0;j<64;j++) - for(i=t;i<t+9;i++) { - buf = f->readInt(1); - tracks[i][j].param2 = (buf&127) % 10; - tracks[i][j].param1 = (buf&127) / 10; - buf = f->readInt(1); - tracks[i][j].inst = buf >> 4; - tracks[i][j].command = buf & 0x0f; - buf = f->readInt(1); - if(buf >> 4) // fix bug in AMD save routine - tracks[i][j].note = ((buf & 14) >> 1) * 12 + (buf >> 4); - else - tracks[i][j].note = 0; - tracks[i][j].inst += (buf & 1) << 4; - } - t += 9; - } - } else { // packed module - for(i=0;i<nop;i++) - for(j=0;j<9;j++) - trackord[i][j] = f->readInt(2) + 1; - numtrax = f->readInt(2); - for(k=0;k<numtrax;k++) { - i = f->readInt(2); - if(i > 575) i = 575; // fix corrupted modules - maxi = (i + 1 > maxi ? i + 1 : maxi); - j = 0; - do { - buf = f->readInt(1); - if(buf & 128) { - for(t = j; t < j + (buf & 127) && t < 64; t++) { - tracks[i][t].command = 0; - tracks[i][t].inst = 0; - tracks[i][t].note = 0; - tracks[i][t].param1 = 0; - tracks[i][t].param2 = 0; - } - j += buf & 127; - continue; - } - tracks[i][j].param2 = buf % 10; - tracks[i][j].param1 = buf / 10; - buf = f->readInt(1); - tracks[i][j].inst = buf >> 4; - tracks[i][j].command = buf & 0x0f; - buf = f->readInt(1); - if(buf >> 4) // fix bug in AMD save routine - tracks[i][j].note = ((buf & 14) >> 1) * 12 + (buf >> 4); - else - tracks[i][j].note = 0; - tracks[i][j].inst += (buf & 1) << 4; - j++; - } while(j<64); - } - } - fp.close(f); - - // convert to protracker replay data - bpm = 50; restartpos = 0; activechan = 0xffff; flags = Decimal; - for(i=0;i<26;i++) { // convert instruments - buf = inst[i].data[0]; - buf2 = inst[i].data[1]; - inst[i].data[0] = inst[i].data[10]; - inst[i].data[1] = buf; - buf = inst[i].data[2]; - inst[i].data[2] = inst[i].data[5]; - buf3 = inst[i].data[3]; - inst[i].data[3] = buf; - buf = inst[i].data[4]; - inst[i].data[4] = inst[i].data[7]; - inst[i].data[5] = buf3; - buf3 = inst[i].data[6]; - inst[i].data[6] = inst[i].data[8]; - inst[i].data[7] = buf; - inst[i].data[8] = inst[i].data[9]; - inst[i].data[9] = buf2; - inst[i].data[10] = buf3; - for(j=0;j<23;j++) // convert names - if(instname[i][j] == '\xff') - instname[i][j] = '\x20'; - } - for(i=0;i<maxi;i++) // convert patterns - for(j=0;j<64;j++) { - tracks[i][j].command = convfx[tracks[i][j].command]; - // extended command - if(tracks[i][j].command == 14) { - if(tracks[i][j].param1 == 2) { - tracks[i][j].command = 10; - tracks[i][j].param1 = tracks[i][j].param2; - tracks[i][j].param2 = 0; - } - - if(tracks[i][j].param1 == 3) { - tracks[i][j].command = 10; - tracks[i][j].param1 = 0; - } - } - - // fix volume - if(tracks[i][j].command == 17) { - int vol = convvol[tracks[i][j].param1 * 10 + tracks[i][j].param2]; - - if(vol > 63) vol = 63; - tracks[i][j].param1 = vol / 10; - tracks[i][j].param2 = vol % 10; - } - } - - rewind(0); - return true; -} - -float CamdLoader::getrefresh() -{ - if(tempo) - return (float) (tempo); - else - return 18.2f; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/amd.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,193 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2006 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 + * + * amd.cpp - AMD Loader by Simon Peter <dn.tlp@gmx.net> + */ + +#include <string.h> + +#include "amd.h" +#include "debug.h" + +CPlayer *CamdLoader::factory(Copl *newopl) +{ + return new CamdLoader(newopl); +} + +bool CamdLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + struct { + char id[9]; + unsigned char version; + } header; + int i, j, k, t, numtrax, maxi = 0; + unsigned char buf, buf2, buf3; + const unsigned char convfx[10] = {0,1,2,9,17,11,13,18,3,14}; + const unsigned char convvol[64] = { + 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 9, 0xa, 0xa, 0xb, + 0xc, 0xc, 0xd, 0xe, 0xe, 0xf, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21, + 0x22, 0x23, 0x25, 0x26, 0x28, 0x29, 0x2b, 0x2d, 0x2e, 0x30, 0x32, 0x35, + 0x37, 0x3a, 0x3c, 0x3f + }; + + // file validation section + if(fp.filesize(f) < 1072) { fp.close(f); return false; } + f->seek(1062); f->readString(header.id, 9); + header.version = f->readInt(1); + if(strncmp(header.id, "<o\xefQU\xeeRoR", 9) && + strncmp(header.id, "MaDoKaN96", 9)) { fp.close(f); return false; } + + // load section + memset(inst, 0, sizeof(inst)); + f->seek(0); + f->readString(songname, sizeof(songname)); + f->readString(author, sizeof(author)); + for(i = 0; i < 26; i++) { + f->readString(instname[i], 23); + for(j = 0; j < 11; j++) inst[i].data[j] = f->readInt(1); + } + length = f->readInt(1); nop = f->readInt(1) + 1; + for(i=0;i<128;i++) order[i] = f->readInt(1); + f->seek(10, binio::Add); + if(header.version == 0x10) { // unpacked module + maxi = nop * 9; + for(i=0;i<64*9;i++) + trackord[i/9][i%9] = i+1; + t = 0; + while(!f->ateof()) { + for(j=0;j<64;j++) + for(i=t;i<t+9;i++) { + buf = f->readInt(1); + tracks[i][j].param2 = (buf&127) % 10; + tracks[i][j].param1 = (buf&127) / 10; + buf = f->readInt(1); + tracks[i][j].inst = buf >> 4; + tracks[i][j].command = buf & 0x0f; + buf = f->readInt(1); + if(buf >> 4) // fix bug in AMD save routine + tracks[i][j].note = ((buf & 14) >> 1) * 12 + (buf >> 4); + else + tracks[i][j].note = 0; + tracks[i][j].inst += (buf & 1) << 4; + } + t += 9; + } + } else { // packed module + for(i=0;i<nop;i++) + for(j=0;j<9;j++) + trackord[i][j] = f->readInt(2) + 1; + numtrax = f->readInt(2); + for(k=0;k<numtrax;k++) { + i = f->readInt(2); + if(i > 575) i = 575; // fix corrupted modules + maxi = (i + 1 > maxi ? i + 1 : maxi); + j = 0; + do { + buf = f->readInt(1); + if(buf & 128) { + for(t = j; t < j + (buf & 127) && t < 64; t++) { + tracks[i][t].command = 0; + tracks[i][t].inst = 0; + tracks[i][t].note = 0; + tracks[i][t].param1 = 0; + tracks[i][t].param2 = 0; + } + j += buf & 127; + continue; + } + tracks[i][j].param2 = buf % 10; + tracks[i][j].param1 = buf / 10; + buf = f->readInt(1); + tracks[i][j].inst = buf >> 4; + tracks[i][j].command = buf & 0x0f; + buf = f->readInt(1); + if(buf >> 4) // fix bug in AMD save routine + tracks[i][j].note = ((buf & 14) >> 1) * 12 + (buf >> 4); + else + tracks[i][j].note = 0; + tracks[i][j].inst += (buf & 1) << 4; + j++; + } while(j<64); + } + } + fp.close(f); + + // convert to protracker replay data + bpm = 50; restartpos = 0; activechan = 0xffff; flags = Decimal; + for(i=0;i<26;i++) { // convert instruments + buf = inst[i].data[0]; + buf2 = inst[i].data[1]; + inst[i].data[0] = inst[i].data[10]; + inst[i].data[1] = buf; + buf = inst[i].data[2]; + inst[i].data[2] = inst[i].data[5]; + buf3 = inst[i].data[3]; + inst[i].data[3] = buf; + buf = inst[i].data[4]; + inst[i].data[4] = inst[i].data[7]; + inst[i].data[5] = buf3; + buf3 = inst[i].data[6]; + inst[i].data[6] = inst[i].data[8]; + inst[i].data[7] = buf; + inst[i].data[8] = inst[i].data[9]; + inst[i].data[9] = buf2; + inst[i].data[10] = buf3; + for(j=0;j<23;j++) // convert names + if(instname[i][j] == '\xff') + instname[i][j] = '\x20'; + } + for(i=0;i<maxi;i++) // convert patterns + for(j=0;j<64;j++) { + tracks[i][j].command = convfx[tracks[i][j].command]; + // extended command + if(tracks[i][j].command == 14) { + if(tracks[i][j].param1 == 2) { + tracks[i][j].command = 10; + tracks[i][j].param1 = tracks[i][j].param2; + tracks[i][j].param2 = 0; + } + + if(tracks[i][j].param1 == 3) { + tracks[i][j].command = 10; + tracks[i][j].param1 = 0; + } + } + + // fix volume + if(tracks[i][j].command == 17) { + int vol = convvol[tracks[i][j].param1 * 10 + tracks[i][j].param2]; + + if(vol > 63) vol = 63; + tracks[i][j].param1 = vol / 10; + tracks[i][j].param2 = vol % 10; + } + } + + rewind(0); + return true; +} + +float CamdLoader::getrefresh() +{ + if(tempo) + return (float) (tempo); + else + return 18.2f; +}
--- a/Plugins/Input/adplug/core/bam.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -/* - * 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 - * - * bam.cpp - Bob's Adlib Music Player, by Simon Peter <dn.tlp@gmx.net> - * - * NOTES: - * In my player, the loop counter is stored with the label. This can be - * dangerous for some situations (see below), but there shouldn't be any BAM - * files triggering this situation. - * - * From SourceForge Bug #476088: - * ----------------------------- - * Using just one loop counter for each label, my player can't - * handle files that loop twice to the same label (if that's at - * all possible with BAM). Imagine the following situation: - * - * ... [*] ---- [<- *] ---- [<- *] ... - * ^ ^ ^ ^ ^ ^ ^ - * | | | | | | | - * +---|----+-----|-----+-----|----+--- normal song data - * +----------|-----------|-------- label 1 - * +-----------+-------- loop points to label 1 - * - * both loop points loop to the same label. Storing the loop - * count with the label would cause chaos with the counter, - * when the player executes the inner jump. - * ------------------ - * Not to worry. my reference implementation of BAM does not - * support the multiple loop situation you describe, and - * neither do any BAM-creation programs. Then both loops point - * to the same label, the inner loop's counter is just allowed - * to clobber the outer loop's counter. No stack is neccisary. - */ - -#include <string.h> -#include "bam.h" - -const unsigned short CbamPlayer::freq[] = {172,182,193,205,217,230,243,258,274, -290,307,326,345,365,387,410,435,460,489,517,547,580,614,651,1369,1389,1411, -1434,1459,1484,1513,1541,1571,1604,1638,1675,2393,2413,2435,2458,2483,2508, -2537,2565,2595,2628,2662,2699,3417,3437,3459,3482,3507,3532,3561,3589,3619, -3652,3686,3723,4441,4461,4483,4506,4531,4556,4585,4613,4643,4676,4710,4747, -5465,5485,5507,5530,5555,5580,5609,5637,5667,5700,5734,5771,6489,6509,6531, -6554,6579,6604,6633,6661,6691,6724,6758,6795,7513,7533,7555,7578,7603,7628, -7657,7685,7715,7748,7782,7819,7858,7898,7942,7988,8037,8089,8143,8191,8191, -8191,8191,8191,8191,8191,8191,8191,8191,8191,8191}; - -CPlayer *CbamPlayer::factory(Copl *newopl) -{ - return new CbamPlayer(newopl); -} - -bool CbamPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - char id[4]; - unsigned int i; - - size = fp.filesize(f) - 4; // filesize minus header - f->readString(id, 4); - if(strncmp(id,"CBMF",4)) { fp.close(f); return false; } - - song = new unsigned char [size]; - for(i = 0; i < size; i++) song[i] = f->readInt(1); - - fp.close(f); - rewind(0); - return true; -} - -bool CbamPlayer::update() -{ - unsigned char cmd,c; - - if(del) { - del--; - return !songend; - } - - if(pos >= size) { // EOF detection - pos = 0; - songend = true; - } - - while(song[pos] < 128) { - cmd = song[pos] & 240; - c = song[pos] & 15; - switch(cmd) { - case 0: // stop song - pos = 0; - songend = true; - break; - case 16: // start note - if(c < 9) { - opl->write(0xa0 + c, freq[song[++pos]] & 255); - opl->write(0xb0 + c, (freq[song[pos]] >> 8) + 32); - } else - pos++; - pos++; - break; - case 32: // stop note - if(c < 9) - opl->write(0xb0 + c, 0); - pos++; - break; - case 48: // define instrument - if(c < 9) { - opl->write(0x20 + op_table[c],song[pos+1]); - opl->write(0x23 + op_table[c],song[pos+2]); - opl->write(0x40 + op_table[c],song[pos+3]); - opl->write(0x43 + op_table[c],song[pos+4]); - opl->write(0x60 + op_table[c],song[pos+5]); - opl->write(0x63 + op_table[c],song[pos+6]); - opl->write(0x80 + op_table[c],song[pos+7]); - opl->write(0x83 + op_table[c],song[pos+8]); - opl->write(0xe0 + op_table[c],song[pos+9]); - opl->write(0xe3 + op_table[c],song[pos+10]); - opl->write(0xc0 + c,song[pos+11]); - } - pos += 12; - break; - case 80: // set label - label[c].target = ++pos; - label[c].defined = true; - break; - case 96: // jump - if(label[c].defined) - switch(song[pos+1]) { - case 254: // infinite loop - if(label[c].defined) { - pos = label[c].target; - songend = true; - break; - } - // fall through... - case 255: // chorus - if(!chorus && label[c].defined) { - chorus = true; - gosub = pos + 2; - pos = label[c].target; - break; - } - // fall through... - case 0: // end of loop - pos += 2; - break; - default: // finite loop - if(!label[c].count) { // loop elapsed - label[c].count = 255; - pos += 2; - break; - } - if(label[c].count < 255) // loop defined - label[c].count--; - else // loop undefined - label[c].count = song[pos+1] - 1; - pos = label[c].target; - break; - } - break; - case 112: // end of chorus - if(chorus) { - pos = gosub; - chorus = false; - } else - pos++; - break; - default: // reserved command (skip) - pos++; - break; - } - } - if(song[pos] >= 128) { // wait - del = song[pos] - 127; - pos++; - } - return !songend; -} - -void CbamPlayer::rewind(int subsong) -{ - int i; - - pos = 0; songend = false; del = 0; gosub = 0; chorus = false; - memset(label, 0, sizeof(label)); label[0].defined = true; - for(i = 0; i < 16; i++) label[i].count = 255; // 255 = undefined - opl->init(); opl->write(1,32); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/bam.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,203 @@ +/* + * 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 + * + * bam.cpp - Bob's Adlib Music Player, by Simon Peter <dn.tlp@gmx.net> + * + * NOTES: + * In my player, the loop counter is stored with the label. This can be + * dangerous for some situations (see below), but there shouldn't be any BAM + * files triggering this situation. + * + * From SourceForge Bug #476088: + * ----------------------------- + * Using just one loop counter for each label, my player can't + * handle files that loop twice to the same label (if that's at + * all possible with BAM). Imagine the following situation: + * + * ... [*] ---- [<- *] ---- [<- *] ... + * ^ ^ ^ ^ ^ ^ ^ + * | | | | | | | + * +---|----+-----|-----+-----|----+--- normal song data + * +----------|-----------|-------- label 1 + * +-----------+-------- loop points to label 1 + * + * both loop points loop to the same label. Storing the loop + * count with the label would cause chaos with the counter, + * when the player executes the inner jump. + * ------------------ + * Not to worry. my reference implementation of BAM does not + * support the multiple loop situation you describe, and + * neither do any BAM-creation programs. Then both loops point + * to the same label, the inner loop's counter is just allowed + * to clobber the outer loop's counter. No stack is neccisary. + */ + +#include <string.h> +#include "bam.h" + +const unsigned short CbamPlayer::freq[] = {172,182,193,205,217,230,243,258,274, +290,307,326,345,365,387,410,435,460,489,517,547,580,614,651,1369,1389,1411, +1434,1459,1484,1513,1541,1571,1604,1638,1675,2393,2413,2435,2458,2483,2508, +2537,2565,2595,2628,2662,2699,3417,3437,3459,3482,3507,3532,3561,3589,3619, +3652,3686,3723,4441,4461,4483,4506,4531,4556,4585,4613,4643,4676,4710,4747, +5465,5485,5507,5530,5555,5580,5609,5637,5667,5700,5734,5771,6489,6509,6531, +6554,6579,6604,6633,6661,6691,6724,6758,6795,7513,7533,7555,7578,7603,7628, +7657,7685,7715,7748,7782,7819,7858,7898,7942,7988,8037,8089,8143,8191,8191, +8191,8191,8191,8191,8191,8191,8191,8191,8191,8191}; + +CPlayer *CbamPlayer::factory(Copl *newopl) +{ + return new CbamPlayer(newopl); +} + +bool CbamPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[4]; + unsigned int i; + + size = fp.filesize(f) - 4; // filesize minus header + f->readString(id, 4); + if(strncmp(id,"CBMF",4)) { fp.close(f); return false; } + + song = new unsigned char [size]; + for(i = 0; i < size; i++) song[i] = f->readInt(1); + + fp.close(f); + rewind(0); + return true; +} + +bool CbamPlayer::update() +{ + unsigned char cmd,c; + + if(del) { + del--; + return !songend; + } + + if(pos >= size) { // EOF detection + pos = 0; + songend = true; + } + + while(song[pos] < 128) { + cmd = song[pos] & 240; + c = song[pos] & 15; + switch(cmd) { + case 0: // stop song + pos = 0; + songend = true; + break; + case 16: // start note + if(c < 9) { + opl->write(0xa0 + c, freq[song[++pos]] & 255); + opl->write(0xb0 + c, (freq[song[pos]] >> 8) + 32); + } else + pos++; + pos++; + break; + case 32: // stop note + if(c < 9) + opl->write(0xb0 + c, 0); + pos++; + break; + case 48: // define instrument + if(c < 9) { + opl->write(0x20 + op_table[c],song[pos+1]); + opl->write(0x23 + op_table[c],song[pos+2]); + opl->write(0x40 + op_table[c],song[pos+3]); + opl->write(0x43 + op_table[c],song[pos+4]); + opl->write(0x60 + op_table[c],song[pos+5]); + opl->write(0x63 + op_table[c],song[pos+6]); + opl->write(0x80 + op_table[c],song[pos+7]); + opl->write(0x83 + op_table[c],song[pos+8]); + opl->write(0xe0 + op_table[c],song[pos+9]); + opl->write(0xe3 + op_table[c],song[pos+10]); + opl->write(0xc0 + c,song[pos+11]); + } + pos += 12; + break; + case 80: // set label + label[c].target = ++pos; + label[c].defined = true; + break; + case 96: // jump + if(label[c].defined) + switch(song[pos+1]) { + case 254: // infinite loop + if(label[c].defined) { + pos = label[c].target; + songend = true; + break; + } + // fall through... + case 255: // chorus + if(!chorus && label[c].defined) { + chorus = true; + gosub = pos + 2; + pos = label[c].target; + break; + } + // fall through... + case 0: // end of loop + pos += 2; + break; + default: // finite loop + if(!label[c].count) { // loop elapsed + label[c].count = 255; + pos += 2; + break; + } + if(label[c].count < 255) // loop defined + label[c].count--; + else // loop undefined + label[c].count = song[pos+1] - 1; + pos = label[c].target; + break; + } + break; + case 112: // end of chorus + if(chorus) { + pos = gosub; + chorus = false; + } else + pos++; + break; + default: // reserved command (skip) + pos++; + break; + } + } + if(song[pos] >= 128) { // wait + del = song[pos] - 127; + pos++; + } + return !songend; +} + +void CbamPlayer::rewind(int subsong) +{ + int i; + + pos = 0; songend = false; del = 0; gosub = 0; chorus = false; + memset(label, 0, sizeof(label)); label[0].defined = true; + for(i = 0; i < 16; i++) label[i].count = 255; // 255 = undefined + opl->init(); opl->write(1,32); +}
--- a/Plugins/Input/adplug/core/bmf.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,596 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2003, 2006 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] BMF player, by Riven the Mage <riven@ok.ru> - */ - -/* - - discovery - - - file(s) : GAMESNET.COM - type : GamesNet advertising intro - tune : by (?)The Brain [Razor 1911] - player : ver.0.9b by Hammer - - file(s) : 2FAST4U.COM - type : Ford Knox BBStro - tune : by The Brain [Razor 1911] - player : ver.1.1 by ? - comment : in original player at 9th channel the feedback adlib register is not C8 but C6. - - file(s) : DATURA.COM - type : Datura BBStro - tune : by The Brain [Razor 1911] - player : ver.1.2 by ? - comment : inaccurate replaying, because constant outport; in original player it can be 380 or 382. -*/ - -#include "bmf.h" -#include "debug.h" - -const unsigned char CxadbmfPlayer::bmf_adlib_registers[117] = -{ - 0x20, 0x23, 0x40, 0x43, 0x60, 0x63, 0x80, 0x83, 0xA0, 0xB0, 0xC0, 0xE0, 0xE3, - 0x21, 0x24, 0x41, 0x44, 0x61, 0x64, 0x81, 0x84, 0xA1, 0xB1, 0xC1, 0xE1, 0xE4, - 0x22, 0x25, 0x42, 0x45, 0x62, 0x65, 0x82, 0x85, 0xA2, 0xB2, 0xC2, 0xE2, 0xE5, - 0x28, 0x2B, 0x48, 0x4B, 0x68, 0x6B, 0x88, 0x8B, 0xA3, 0xB3, 0xC3, 0xE8, 0xEB, - 0x29, 0x2C, 0x49, 0x4C, 0x69, 0x6C, 0x89, 0x8C, 0xA4, 0xB4, 0xC4, 0xE9, 0xEC, - 0x2A, 0x2D, 0x4A, 0x4D, 0x6A, 0x6D, 0x8A, 0x8D, 0xA5, 0xB5, 0xC5, 0xEA, 0xED, - 0x30, 0x33, 0x50, 0x53, 0x70, 0x73, 0x90, 0x93, 0xA6, 0xB6, 0xC6, 0xF0, 0xF3, - 0x31, 0x34, 0x51, 0x54, 0x71, 0x74, 0x91, 0x94, 0xA7, 0xB7, 0xC7, 0xF1, 0xF4, - 0x32, 0x35, 0x52, 0x55, 0x72, 0x75, 0x92, 0x95, 0xA8, 0xB8, 0xC8, 0xF2, 0xF5 -}; - -const unsigned short CxadbmfPlayer::bmf_notes[12] = -{ - 0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287 -}; - -/* for 1.1 */ -const unsigned short CxadbmfPlayer::bmf_notes_2[12] = -{ - 0x159, 0x16D, 0x183, 0x19A, 0x1B2, 0x1CC, 0x1E8, 0x205, 0x223, 0x244, 0x267, 0x28B -}; - -const unsigned char CxadbmfPlayer::bmf_default_instrument[13] = -{ - 0x01, 0x01, 0x3F, 0x3F, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -CPlayer *CxadbmfPlayer::factory(Copl *newopl) -{ - return new CxadbmfPlayer(newopl); -} - -bool CxadbmfPlayer::xadplayer_load() -{ - unsigned short ptr = 0; - int i; - - if(xad.fmt != BMF) - return false; - -#ifdef DEBUG - AdPlug_LogWrite("\nbmf_load():\n\n"); -#endif - if (!strncmp((char *)&tune[0],"BMF1.2",6)) - { - bmf.version = BMF1_2; - bmf.timer = 70.0f; - } - else if (!strncmp((char *)&tune[0],"BMF1.1",6)) - { - bmf.version = BMF1_1; - bmf.timer = 60.0f; - } - else - { - bmf.version = BMF0_9B; - bmf.timer = 18.2f; - } - - // copy title & author - if (bmf.version > BMF0_9B) - { - ptr = 6; - - strncpy(bmf.title,(char *)&tune[ptr],36); - - while (tune[ptr]) { ptr++; } - ptr++; - - strncpy(bmf.author,(char *)&tune[ptr],36); - - while (tune[ptr]) { ptr++; } - ptr++; - } - else - { - strncpy(bmf.title,xad.title,36); - strncpy(bmf.author,xad.author,36); - } - - // speed - if (bmf.version > BMF0_9B) - bmf.speed = tune[ptr++]; - else - bmf.speed = ((tune[ptr++] << 8) / 3) >> 8; // strange, yeh ? - - // load instruments - if (bmf.version > BMF0_9B) - { - unsigned long iflags = (tune[ptr] << 24) | (tune[ptr+1] << 16) | (tune[ptr+2] << 8) | tune[ptr+3]; - ptr+=4; - - for(i=0;i<32;i++) - if (iflags & (1 << (31-i))) - { - strcpy(bmf.instruments[i].name, (char *)&tune[ptr]); - memcpy(bmf.instruments[i].data, &tune[ptr+11], 13); - ptr += 24; - } - else - { - bmf.instruments[i].name[0] = 0; - - if (bmf.version == BMF1_1) - for(int j=0;j<13;j++) - bmf.instruments[i].data[j] = bmf_default_instrument[j]; - else - for(int j=0;j<13;j++) - bmf.instruments[i].data[j] = 0; - } - } - else - { - ptr = 6; - - for(i=0;i<32;i++) - { - bmf.instruments[i].name[0] = 0; - memcpy(bmf.instruments[tune[ptr]].data, &tune[ptr+2],13); // bug no.1 (no instrument-table-end detection) - ptr+=15; - } - } - - // load streams - if (bmf.version > BMF0_9B) - { - unsigned long sflags = (tune[ptr] << 24) | (tune[ptr+1] << 16) | (tune[ptr+2] << 8) | tune[ptr+3]; - ptr+=4; - - for(i=0;i<9;i++) - if (sflags & (1 << (31-i))) - ptr+=__bmf_convert_stream(&tune[ptr],i); - else - bmf.streams[i][0].cmd = 0xFF; - } - else - { - for(i=0;i<tune[5];i++) - ptr+=__bmf_convert_stream(&tune[ptr],i); - - for(i=tune[5];i<9;i++) - bmf.streams[i][0].cmd = 0xFF; - } - - return true; -} - -void CxadbmfPlayer::xadplayer_rewind(int subsong) -{ - int i,j; - - for(i=0; i<9; i++) - { - bmf.channel[i].stream_position = 0; - bmf.channel[i].delay = 0; - bmf.channel[i].loop_position = 0; - bmf.channel[i].loop_counter = 0; - } - - plr.speed = bmf.speed; -#ifdef DEBUG - AdPlug_LogWrite("speed: %x\n",plr.speed); -#endif - - bmf.active_streams = 9; - - // OPL initialization - if (bmf.version > BMF0_9B) - { - opl_write(0x01, 0x20); - - /* 1.1 */ - if (bmf.version == BMF1_1) - for(i=0;i<9;i++) - for(j=0;j<13;j++) - opl_write(bmf_adlib_registers[13*i+j], bmf_default_instrument[j]); - /* 1.2 */ - else if (bmf.version == BMF1_2) - for(i=0x20; i<0x100; i++) - opl_write(i,0xFF); // very interesting, really! - } - - /* ALL */ - - opl_write(0x08, 0x00); - opl_write(0xBD, 0xC0); -} - -void CxadbmfPlayer::xadplayer_update() -{ - for(int i=0;i<9;i++) - if (bmf.channel[i].stream_position != 0xFFFF) - if (bmf.channel[i].delay) - bmf.channel[i].delay--; - else - { -#ifdef DEBUG - AdPlug_LogWrite("channel %02X:\n", i); -#endif - bmf_event event; - - // process so-called cross-events - while (true) - { - memcpy(&event, &bmf.streams[i][bmf.channel[i].stream_position], sizeof(bmf_event)); -#ifdef DEBUG - AdPlug_LogWrite("%02X %02X %02X %02X %02X %02X\n", - event.note,event.delay,event.volume,event.instrument, - event.cmd,event.cmd_data); -#endif - - if (event.cmd == 0xFF) - { - bmf.channel[i].stream_position = 0xFFFF; - bmf.active_streams--; - break; - } - else if (event.cmd == 0xFE) - { - bmf.channel[i].loop_position = bmf.channel[i].stream_position+1; - bmf.channel[i].loop_counter = event.cmd_data; - } - else if (event.cmd == 0xFD) - { - if (bmf.channel[i].loop_counter) - { - bmf.channel[i].stream_position = bmf.channel[i].loop_position-1; - bmf.channel[i].loop_counter--; - } - } - else - break; - - bmf.channel[i].stream_position++; - } // while (true) - - // process normal event - unsigned short pos = bmf.channel[i].stream_position; - - if (pos != 0xFFFF) - { - bmf.channel[i].delay = bmf.streams[i][pos].delay; - - // command ? - if (bmf.streams[i][pos].cmd) - { - unsigned char cmd = bmf.streams[i][pos].cmd; - - // 0x01: Set Modulator Volume - if (cmd == 0x01) - { - unsigned char reg = bmf_adlib_registers[13*i+2]; - - opl_write(reg, (adlib[reg] | 0x3F) - bmf.streams[i][pos].cmd_data); - } - // 0x10: Set Speed - else if (cmd == 0x10) - { - plr.speed = bmf.streams[i][pos].cmd_data; - plr.speed_counter = plr.speed; - } - } // if (bmf.streams[i][pos].cmd) - - // instrument ? - if (bmf.streams[i][pos].instrument) - { - unsigned char ins = bmf.streams[i][pos].instrument-1; - - if (bmf.version != BMF1_1) - opl_write(0xB0+i, adlib[0xB0+i] & 0xDF); - - for(int j=0;j<13;j++) - opl_write(bmf_adlib_registers[i*13+j], bmf.instruments[ins].data[j]); - } // if (bmf.streams[i][pos].instrument) - - // volume ? - if (bmf.streams[i][pos].volume) - { - unsigned char vol = bmf.streams[i][pos].volume-1; - unsigned char reg = bmf_adlib_registers[13*i+3]; - - opl_write(reg, (adlib[reg] | 0x3F) - vol); - } // if (bmf.streams[i][pos].volume) - - // note ? - if (bmf.streams[i][pos].note) - { - unsigned short note = bmf.streams[i][pos].note; - unsigned short freq = 0; - - // mute channel - opl_write(0xB0+i, adlib[0xB0+i] & 0xDF); - - // get frequency - if (bmf.version == BMF1_1) - { - if (note <= 0x60) - freq = bmf_notes_2[--note % 12]; - } - else - { - if (note != 0x7F) - freq = bmf_notes[--note % 12]; - } - - // play note - if (freq) - { - opl_write(0xB0+i, (freq >> 8) | ((note / 12) << 2) | 0x20); - opl_write(0xA0+i, freq & 0xFF); - } - } // if (bmf.streams[i][pos].note) - - bmf.channel[i].stream_position++; - } // if (pos != 0xFFFF) - - } // if (!bmf.channel[i].delay) - - // is module loop ? - if (!bmf.active_streams) - { - for(int j=0;j<9;j++) - bmf.channel[j].stream_position = 0; - - bmf.active_streams = 9; - - plr.looping = 1; - } -} - -float CxadbmfPlayer::xadplayer_getrefresh() -{ - return bmf.timer; -} - -std::string CxadbmfPlayer::xadplayer_gettype() -{ - return std::string("xad: BMF Adlib Tracker"); -} - -std::string CxadbmfPlayer::xadplayer_gettitle() -{ - return std::string(bmf.title); -} - -std::string CxadbmfPlayer::xadplayer_getauthor() -{ - return std::string(bmf.author); -} - -unsigned int CxadbmfPlayer::xadplayer_getinstruments() -{ - return 32; -} - -std::string CxadbmfPlayer::xadplayer_getinstrument(unsigned int i) -{ - return std::string(bmf.instruments[i].name); -} - -/* -------- Internal Functions ---------------------------- */ - -int CxadbmfPlayer::__bmf_convert_stream(unsigned char *stream, int channel) -{ -#ifdef DEBUG - AdPlug_LogWrite("channel %02X (note,delay,volume,instrument,command,command_data):\n",channel); - unsigned char *last = stream; -#endif - unsigned char *stream_start = stream; - - int pos = 0; - - while (true) - { - memset(&bmf.streams[channel][pos], 0, sizeof(bmf_event)); - - bool is_cmd = false; - - if (*stream == 0xFE) - { - // 0xFE -> 0xFF: End of Stream - bmf.streams[channel][pos].cmd = 0xFF; - - stream++; - - break; - } - else if (*stream == 0xFC) - { - // 0xFC -> 0xFE xx: Save Loop Position - bmf.streams[channel][pos].cmd = 0xFE; - bmf.streams[channel][pos].cmd_data = (*(stream+1) & ((bmf.version == BMF0_9B) ? 0x7F : 0x3F)) - 1; - - stream+=2; - } - else if (*stream == 0x7D) - { - // 0x7D -> 0xFD: Loop Saved Position - bmf.streams[channel][pos].cmd = 0xFD; - - stream++; - } - else - { - if (*stream & 0x80) - { - if (*(stream+1) & 0x80) - { - if (*(stream+1) & 0x40) - { - // byte0: 1aaaaaaa = NOTE - bmf.streams[channel][pos].note = *stream & 0x7F; - // byte1: 11bbbbbb = DELAY - bmf.streams[channel][pos].delay = *(stream+1) & 0x3F; - // byte2: cccccccc = COMMAND - - stream+=2; - - is_cmd = true; - } - else - { - // byte0: 1aaaaaaa = NOTE - bmf.streams[channel][pos].note = *stream & 0x7F; - // byte1: 11bbbbbb = DELAY - bmf.streams[channel][pos].delay = *(stream+1) & 0x3F; - - stream+=2; - } // if (*(stream+1) & 0x40) - } - else - { - // byte0: 1aaaaaaa = NOTE - bmf.streams[channel][pos].note = *stream & 0x7F; - // byte1: 0bbbbbbb = COMMAND - - stream++; - - is_cmd = true; - } // if (*(stream+1) & 0x80) - } - else - { - // byte0: 0aaaaaaa = NOTE - bmf.streams[channel][pos].note = *stream & 0x7F; - - stream++; - } // if (*stream & 0x80) - } // if (*stream == 0xFE) - - // is command ? - if (is_cmd) - { - - /* ALL */ - - if ((0x20 <= *stream) && (*stream <= 0x3F)) - { - // 0x20 or higher; 0x3F or lower: Set Instrument - bmf.streams[channel][pos].instrument = *stream - 0x20 + 1; - - stream++; - } - else if (0x40 <= *stream) - { - // 0x40 or higher: Set Volume - bmf.streams[channel][pos].volume = *stream - 0x40 + 1; - - stream++; - } - else - { - - /* 0.9b */ - - if (bmf.version == BMF0_9B) - if (*stream < 0x20) - { - // 0x1F or lower: ? - stream++; - } - - /* 1.2 */ - - if (bmf.version == BMF1_2) - if (*stream == 0x01) - { - // 0x01: Set Modulator Volume -> 0x01 - bmf.streams[channel][pos].cmd = 0x01; - bmf.streams[channel][pos].cmd_data = *(stream+1); - - stream+=2; - } - else if (*stream == 0x02) - { - // 0x02: ? - stream+=2; - } - else if (*stream == 0x03) - { - // 0x03: ? - stream+=2; - } - else if (*stream == 0x04) - { - // 0x04: Set Speed -> 0x10 - bmf.streams[channel][pos].cmd = 0x10; - bmf.streams[channel][pos].cmd_data = *(stream+1); - - stream+=2; - } - else if (*stream == 0x05) - { - // 0x05: Set Carrier Volume (port 380) - bmf.streams[channel][pos].volume = *(stream+1) + 1; - - stream+=2; - } - else if (*stream == 0x06) - { - // 0x06: Set Carrier Volume (port 382) - bmf.streams[channel][pos].volume = *(stream+1) + 1; - - stream+=2; - } // if (bmf.version == BMF1_2) - - } // if ((0x20 <= *stream) && (*stream <= 0x3F)) - - } // if (is_cmd) - -#ifdef DEBUG - AdPlug_LogWrite("%02X %02X %02X %02X %02X %02X <---- ", - bmf.streams[channel][pos].note, - bmf.streams[channel][pos].delay, - bmf.streams[channel][pos].volume, - bmf.streams[channel][pos].instrument, - bmf.streams[channel][pos].cmd, - bmf.streams[channel][pos].cmd_data - ); - for(int zz=0;zz<(stream-last);zz++) - AdPlug_LogWrite("%02X ",last[zz]); - AdPlug_LogWrite("\n"); - last=stream; -#endif - pos++; - } // while (true) - - return (stream - stream_start); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/bmf.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,596 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2003, 2006 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] BMF player, by Riven the Mage <riven@ok.ru> + */ + +/* + - discovery - + + file(s) : GAMESNET.COM + type : GamesNet advertising intro + tune : by (?)The Brain [Razor 1911] + player : ver.0.9b by Hammer + + file(s) : 2FAST4U.COM + type : Ford Knox BBStro + tune : by The Brain [Razor 1911] + player : ver.1.1 by ? + comment : in original player at 9th channel the feedback adlib register is not C8 but C6. + + file(s) : DATURA.COM + type : Datura BBStro + tune : by The Brain [Razor 1911] + player : ver.1.2 by ? + comment : inaccurate replaying, because constant outport; in original player it can be 380 or 382. +*/ + +#include "bmf.h" +#include "debug.h" + +const unsigned char CxadbmfPlayer::bmf_adlib_registers[117] = +{ + 0x20, 0x23, 0x40, 0x43, 0x60, 0x63, 0x80, 0x83, 0xA0, 0xB0, 0xC0, 0xE0, 0xE3, + 0x21, 0x24, 0x41, 0x44, 0x61, 0x64, 0x81, 0x84, 0xA1, 0xB1, 0xC1, 0xE1, 0xE4, + 0x22, 0x25, 0x42, 0x45, 0x62, 0x65, 0x82, 0x85, 0xA2, 0xB2, 0xC2, 0xE2, 0xE5, + 0x28, 0x2B, 0x48, 0x4B, 0x68, 0x6B, 0x88, 0x8B, 0xA3, 0xB3, 0xC3, 0xE8, 0xEB, + 0x29, 0x2C, 0x49, 0x4C, 0x69, 0x6C, 0x89, 0x8C, 0xA4, 0xB4, 0xC4, 0xE9, 0xEC, + 0x2A, 0x2D, 0x4A, 0x4D, 0x6A, 0x6D, 0x8A, 0x8D, 0xA5, 0xB5, 0xC5, 0xEA, 0xED, + 0x30, 0x33, 0x50, 0x53, 0x70, 0x73, 0x90, 0x93, 0xA6, 0xB6, 0xC6, 0xF0, 0xF3, + 0x31, 0x34, 0x51, 0x54, 0x71, 0x74, 0x91, 0x94, 0xA7, 0xB7, 0xC7, 0xF1, 0xF4, + 0x32, 0x35, 0x52, 0x55, 0x72, 0x75, 0x92, 0x95, 0xA8, 0xB8, 0xC8, 0xF2, 0xF5 +}; + +const unsigned short CxadbmfPlayer::bmf_notes[12] = +{ + 0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287 +}; + +/* for 1.1 */ +const unsigned short CxadbmfPlayer::bmf_notes_2[12] = +{ + 0x159, 0x16D, 0x183, 0x19A, 0x1B2, 0x1CC, 0x1E8, 0x205, 0x223, 0x244, 0x267, 0x28B +}; + +const unsigned char CxadbmfPlayer::bmf_default_instrument[13] = +{ + 0x01, 0x01, 0x3F, 0x3F, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +CPlayer *CxadbmfPlayer::factory(Copl *newopl) +{ + return new CxadbmfPlayer(newopl); +} + +bool CxadbmfPlayer::xadplayer_load() +{ + unsigned short ptr = 0; + int i; + + if(xad.fmt != BMF) + return false; + +#ifdef DEBUG + AdPlug_LogWrite("\nbmf_load():\n\n"); +#endif + if (!strncmp((char *)&tune[0],"BMF1.2",6)) + { + bmf.version = BMF1_2; + bmf.timer = 70.0f; + } + else if (!strncmp((char *)&tune[0],"BMF1.1",6)) + { + bmf.version = BMF1_1; + bmf.timer = 60.0f; + } + else + { + bmf.version = BMF0_9B; + bmf.timer = 18.2f; + } + + // copy title & author + if (bmf.version > BMF0_9B) + { + ptr = 6; + + strncpy(bmf.title,(char *)&tune[ptr],36); + + while (tune[ptr]) { ptr++; } + ptr++; + + strncpy(bmf.author,(char *)&tune[ptr],36); + + while (tune[ptr]) { ptr++; } + ptr++; + } + else + { + strncpy(bmf.title,xad.title,36); + strncpy(bmf.author,xad.author,36); + } + + // speed + if (bmf.version > BMF0_9B) + bmf.speed = tune[ptr++]; + else + bmf.speed = ((tune[ptr++] << 8) / 3) >> 8; // strange, yeh ? + + // load instruments + if (bmf.version > BMF0_9B) + { + unsigned long iflags = (tune[ptr] << 24) | (tune[ptr+1] << 16) | (tune[ptr+2] << 8) | tune[ptr+3]; + ptr+=4; + + for(i=0;i<32;i++) + if (iflags & (1 << (31-i))) + { + strcpy(bmf.instruments[i].name, (char *)&tune[ptr]); + memcpy(bmf.instruments[i].data, &tune[ptr+11], 13); + ptr += 24; + } + else + { + bmf.instruments[i].name[0] = 0; + + if (bmf.version == BMF1_1) + for(int j=0;j<13;j++) + bmf.instruments[i].data[j] = bmf_default_instrument[j]; + else + for(int j=0;j<13;j++) + bmf.instruments[i].data[j] = 0; + } + } + else + { + ptr = 6; + + for(i=0;i<32;i++) + { + bmf.instruments[i].name[0] = 0; + memcpy(bmf.instruments[tune[ptr]].data, &tune[ptr+2],13); // bug no.1 (no instrument-table-end detection) + ptr+=15; + } + } + + // load streams + if (bmf.version > BMF0_9B) + { + unsigned long sflags = (tune[ptr] << 24) | (tune[ptr+1] << 16) | (tune[ptr+2] << 8) | tune[ptr+3]; + ptr+=4; + + for(i=0;i<9;i++) + if (sflags & (1 << (31-i))) + ptr+=__bmf_convert_stream(&tune[ptr],i); + else + bmf.streams[i][0].cmd = 0xFF; + } + else + { + for(i=0;i<tune[5];i++) + ptr+=__bmf_convert_stream(&tune[ptr],i); + + for(i=tune[5];i<9;i++) + bmf.streams[i][0].cmd = 0xFF; + } + + return true; +} + +void CxadbmfPlayer::xadplayer_rewind(int subsong) +{ + int i,j; + + for(i=0; i<9; i++) + { + bmf.channel[i].stream_position = 0; + bmf.channel[i].delay = 0; + bmf.channel[i].loop_position = 0; + bmf.channel[i].loop_counter = 0; + } + + plr.speed = bmf.speed; +#ifdef DEBUG + AdPlug_LogWrite("speed: %x\n",plr.speed); +#endif + + bmf.active_streams = 9; + + // OPL initialization + if (bmf.version > BMF0_9B) + { + opl_write(0x01, 0x20); + + /* 1.1 */ + if (bmf.version == BMF1_1) + for(i=0;i<9;i++) + for(j=0;j<13;j++) + opl_write(bmf_adlib_registers[13*i+j], bmf_default_instrument[j]); + /* 1.2 */ + else if (bmf.version == BMF1_2) + for(i=0x20; i<0x100; i++) + opl_write(i,0xFF); // very interesting, really! + } + + /* ALL */ + + opl_write(0x08, 0x00); + opl_write(0xBD, 0xC0); +} + +void CxadbmfPlayer::xadplayer_update() +{ + for(int i=0;i<9;i++) + if (bmf.channel[i].stream_position != 0xFFFF) + if (bmf.channel[i].delay) + bmf.channel[i].delay--; + else + { +#ifdef DEBUG + AdPlug_LogWrite("channel %02X:\n", i); +#endif + bmf_event event; + + // process so-called cross-events + while (true) + { + memcpy(&event, &bmf.streams[i][bmf.channel[i].stream_position], sizeof(bmf_event)); +#ifdef DEBUG + AdPlug_LogWrite("%02X %02X %02X %02X %02X %02X\n", + event.note,event.delay,event.volume,event.instrument, + event.cmd,event.cmd_data); +#endif + + if (event.cmd == 0xFF) + { + bmf.channel[i].stream_position = 0xFFFF; + bmf.active_streams--; + break; + } + else if (event.cmd == 0xFE) + { + bmf.channel[i].loop_position = bmf.channel[i].stream_position+1; + bmf.channel[i].loop_counter = event.cmd_data; + } + else if (event.cmd == 0xFD) + { + if (bmf.channel[i].loop_counter) + { + bmf.channel[i].stream_position = bmf.channel[i].loop_position-1; + bmf.channel[i].loop_counter--; + } + } + else + break; + + bmf.channel[i].stream_position++; + } // while (true) + + // process normal event + unsigned short pos = bmf.channel[i].stream_position; + + if (pos != 0xFFFF) + { + bmf.channel[i].delay = bmf.streams[i][pos].delay; + + // command ? + if (bmf.streams[i][pos].cmd) + { + unsigned char cmd = bmf.streams[i][pos].cmd; + + // 0x01: Set Modulator Volume + if (cmd == 0x01) + { + unsigned char reg = bmf_adlib_registers[13*i+2]; + + opl_write(reg, (adlib[reg] | 0x3F) - bmf.streams[i][pos].cmd_data); + } + // 0x10: Set Speed + else if (cmd == 0x10) + { + plr.speed = bmf.streams[i][pos].cmd_data; + plr.speed_counter = plr.speed; + } + } // if (bmf.streams[i][pos].cmd) + + // instrument ? + if (bmf.streams[i][pos].instrument) + { + unsigned char ins = bmf.streams[i][pos].instrument-1; + + if (bmf.version != BMF1_1) + opl_write(0xB0+i, adlib[0xB0+i] & 0xDF); + + for(int j=0;j<13;j++) + opl_write(bmf_adlib_registers[i*13+j], bmf.instruments[ins].data[j]); + } // if (bmf.streams[i][pos].instrument) + + // volume ? + if (bmf.streams[i][pos].volume) + { + unsigned char vol = bmf.streams[i][pos].volume-1; + unsigned char reg = bmf_adlib_registers[13*i+3]; + + opl_write(reg, (adlib[reg] | 0x3F) - vol); + } // if (bmf.streams[i][pos].volume) + + // note ? + if (bmf.streams[i][pos].note) + { + unsigned short note = bmf.streams[i][pos].note; + unsigned short freq = 0; + + // mute channel + opl_write(0xB0+i, adlib[0xB0+i] & 0xDF); + + // get frequency + if (bmf.version == BMF1_1) + { + if (note <= 0x60) + freq = bmf_notes_2[--note % 12]; + } + else + { + if (note != 0x7F) + freq = bmf_notes[--note % 12]; + } + + // play note + if (freq) + { + opl_write(0xB0+i, (freq >> 8) | ((note / 12) << 2) | 0x20); + opl_write(0xA0+i, freq & 0xFF); + } + } // if (bmf.streams[i][pos].note) + + bmf.channel[i].stream_position++; + } // if (pos != 0xFFFF) + + } // if (!bmf.channel[i].delay) + + // is module loop ? + if (!bmf.active_streams) + { + for(int j=0;j<9;j++) + bmf.channel[j].stream_position = 0; + + bmf.active_streams = 9; + + plr.looping = 1; + } +} + +float CxadbmfPlayer::xadplayer_getrefresh() +{ + return bmf.timer; +} + +std::string CxadbmfPlayer::xadplayer_gettype() +{ + return std::string("xad: BMF Adlib Tracker"); +} + +std::string CxadbmfPlayer::xadplayer_gettitle() +{ + return std::string(bmf.title); +} + +std::string CxadbmfPlayer::xadplayer_getauthor() +{ + return std::string(bmf.author); +} + +unsigned int CxadbmfPlayer::xadplayer_getinstruments() +{ + return 32; +} + +std::string CxadbmfPlayer::xadplayer_getinstrument(unsigned int i) +{ + return std::string(bmf.instruments[i].name); +} + +/* -------- Internal Functions ---------------------------- */ + +int CxadbmfPlayer::__bmf_convert_stream(unsigned char *stream, int channel) +{ +#ifdef DEBUG + AdPlug_LogWrite("channel %02X (note,delay,volume,instrument,command,command_data):\n",channel); + unsigned char *last = stream; +#endif + unsigned char *stream_start = stream; + + int pos = 0; + + while (true) + { + memset(&bmf.streams[channel][pos], 0, sizeof(bmf_event)); + + bool is_cmd = false; + + if (*stream == 0xFE) + { + // 0xFE -> 0xFF: End of Stream + bmf.streams[channel][pos].cmd = 0xFF; + + stream++; + + break; + } + else if (*stream == 0xFC) + { + // 0xFC -> 0xFE xx: Save Loop Position + bmf.streams[channel][pos].cmd = 0xFE; + bmf.streams[channel][pos].cmd_data = (*(stream+1) & ((bmf.version == BMF0_9B) ? 0x7F : 0x3F)) - 1; + + stream+=2; + } + else if (*stream == 0x7D) + { + // 0x7D -> 0xFD: Loop Saved Position + bmf.streams[channel][pos].cmd = 0xFD; + + stream++; + } + else + { + if (*stream & 0x80) + { + if (*(stream+1) & 0x80) + { + if (*(stream+1) & 0x40) + { + // byte0: 1aaaaaaa = NOTE + bmf.streams[channel][pos].note = *stream & 0x7F; + // byte1: 11bbbbbb = DELAY + bmf.streams[channel][pos].delay = *(stream+1) & 0x3F; + // byte2: cccccccc = COMMAND + + stream+=2; + + is_cmd = true; + } + else + { + // byte0: 1aaaaaaa = NOTE + bmf.streams[channel][pos].note = *stream & 0x7F; + // byte1: 11bbbbbb = DELAY + bmf.streams[channel][pos].delay = *(stream+1) & 0x3F; + + stream+=2; + } // if (*(stream+1) & 0x40) + } + else + { + // byte0: 1aaaaaaa = NOTE + bmf.streams[channel][pos].note = *stream & 0x7F; + // byte1: 0bbbbbbb = COMMAND + + stream++; + + is_cmd = true; + } // if (*(stream+1) & 0x80) + } + else + { + // byte0: 0aaaaaaa = NOTE + bmf.streams[channel][pos].note = *stream & 0x7F; + + stream++; + } // if (*stream & 0x80) + } // if (*stream == 0xFE) + + // is command ? + if (is_cmd) + { + + /* ALL */ + + if ((0x20 <= *stream) && (*stream <= 0x3F)) + { + // 0x20 or higher; 0x3F or lower: Set Instrument + bmf.streams[channel][pos].instrument = *stream - 0x20 + 1; + + stream++; + } + else if (0x40 <= *stream) + { + // 0x40 or higher: Set Volume + bmf.streams[channel][pos].volume = *stream - 0x40 + 1; + + stream++; + } + else + { + + /* 0.9b */ + + if (bmf.version == BMF0_9B) + if (*stream < 0x20) + { + // 0x1F or lower: ? + stream++; + } + + /* 1.2 */ + + if (bmf.version == BMF1_2) + if (*stream == 0x01) + { + // 0x01: Set Modulator Volume -> 0x01 + bmf.streams[channel][pos].cmd = 0x01; + bmf.streams[channel][pos].cmd_data = *(stream+1); + + stream+=2; + } + else if (*stream == 0x02) + { + // 0x02: ? + stream+=2; + } + else if (*stream == 0x03) + { + // 0x03: ? + stream+=2; + } + else if (*stream == 0x04) + { + // 0x04: Set Speed -> 0x10 + bmf.streams[channel][pos].cmd = 0x10; + bmf.streams[channel][pos].cmd_data = *(stream+1); + + stream+=2; + } + else if (*stream == 0x05) + { + // 0x05: Set Carrier Volume (port 380) + bmf.streams[channel][pos].volume = *(stream+1) + 1; + + stream+=2; + } + else if (*stream == 0x06) + { + // 0x06: Set Carrier Volume (port 382) + bmf.streams[channel][pos].volume = *(stream+1) + 1; + + stream+=2; + } // if (bmf.version == BMF1_2) + + } // if ((0x20 <= *stream) && (*stream <= 0x3F)) + + } // if (is_cmd) + +#ifdef DEBUG + AdPlug_LogWrite("%02X %02X %02X %02X %02X %02X <---- ", + bmf.streams[channel][pos].note, + bmf.streams[channel][pos].delay, + bmf.streams[channel][pos].volume, + bmf.streams[channel][pos].instrument, + bmf.streams[channel][pos].cmd, + bmf.streams[channel][pos].cmd_data + ); + for(int zz=0;zz<(stream-last);zz++) + AdPlug_LogWrite("%02X ",last[zz]); + AdPlug_LogWrite("\n"); + last=stream; +#endif + pos++; + } // while (true) + + return (stream - stream_start); +}
--- a/Plugins/Input/adplug/core/cff.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,507 +0,0 @@ -/* - AdPlug - Replayer for many OPL2/OPL3 audio file formats. - Copyright (C) 1999 - 2006 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 - - cff.cpp - BoomTracker loader by Riven the Mage <riven@ok.ru> -*/ -/* - NOTE: Conversion of slides is not 100% accurate. Original volume slides - have effect on carrier volume only. Also, original arpeggio, frequency & volume - slides use previous effect data instead of current. -*/ - -#include <stdlib.h> - -#include "cff.h" - -/* -------- Public Methods -------------------------------- */ - -CPlayer *CcffLoader::factory(Copl *newopl) -{ - return new CcffLoader(newopl); -} - -bool CcffLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 }; - const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE }; - - int i,j,k,t=0; - - // '<CUD-FM-File>' - signed ? - f->readString(header.id, 16); - header.version = f->readInt(1); header.size = f->readInt(2); - header.packed = f->readInt(1); f->readString((char *)header.reserved, 12); - if (memcmp(header.id,"<CUD-FM-File>""\x1A\xDE\xE0",16)) - { fp.close(f); return false; } - - unsigned char *module = new unsigned char [0x10000]; - - // packed ? - if (header.packed) - { - cff_unpacker *unpacker = new cff_unpacker; - - unsigned char *packed_module = new unsigned char [header.size + 4]; - - memset(packed_module,0,header.size + 4); - - f->readString((char *)packed_module, header.size); - fp.close(f); - - if (!unpacker->unpack(packed_module,module)) - { - delete unpacker; - delete packed_module; - delete module; - return false; - } - - delete unpacker; - delete packed_module; - - if (memcmp(&module[0x5E1],"CUD-FM-File - SEND A POSTCARD -",31)) - { - delete module; - return false; - } - } - else - { - f->readString((char *)module, header.size); - fp.close(f); - } - - // init CmodPlayer - realloc_instruments(47); - realloc_order(64); - realloc_patterns(36,64,9); - init_notetable(conv_note); - init_trackord(); - - // load instruments - for (i=0;i<47;i++) - { - memcpy(&instruments[i],&module[i*32],sizeof(cff_instrument)); - - for (j=0;j<11;j++) - inst[i].data[conv_inst[j]] = instruments[i].data[j]; - - instruments[i].name[20] = 0; - } - - // number of patterns - nop = module[0x5E0]; - - // load title & author - memcpy(song_title,&module[0x614],20); - memcpy(song_author,&module[0x600],20); - - // load order - memcpy(order,&module[0x628],64); - - // load tracks - for (i=0;i<nop;i++) - { - unsigned char old_event_byte2[9]; - - memset(old_event_byte2,0,9); - - for (j=0;j<9;j++) - { - for (k=0;k<64;k++) - { - cff_event *event = (cff_event *)&module[0x669 + ((i*64+k)*9+j)*3]; - - // convert note - if (event->byte0 == 0x6D) - tracks[t][k].note = 127; - else - if (event->byte0) - tracks[t][k].note = event->byte0; - - if (event->byte2) - old_event_byte2[j] = event->byte2; - - // convert effect - switch (event->byte1) - { - case 'I': // set instrument - tracks[t][k].inst = event->byte2 + 1; - tracks[t][k].param1 = tracks[t][k].param2 = 0; - break; - - case 'H': // set tempo - tracks[t][k].command = 7; - if (event->byte2 < 16) - { - tracks[t][k].param1 = 0x07; - tracks[t][k].param2 = 0x0D; - } - break; - - case 'A': // set speed - tracks[t][k].command = 19; - tracks[t][k].param1 = event->byte2 >> 4; - tracks[t][k].param2 = event->byte2 & 15; - break; - - case 'L': // pattern break - tracks[t][k].command = 13; - tracks[t][k].param1 = event->byte2 >> 4; - tracks[t][k].param2 = event->byte2 & 15; - break; - - case 'K': // order jump - tracks[t][k].command = 11; - tracks[t][k].param1 = event->byte2 >> 4; - tracks[t][k].param2 = event->byte2 & 15; - break; - - case 'M': // set vibrato/tremolo - tracks[t][k].command = 27; - tracks[t][k].param1 = event->byte2 >> 4; - tracks[t][k].param2 = event->byte2 & 15; - break; - - case 'C': // set modulator volume - tracks[t][k].command = 21; - tracks[t][k].param1 = (0x3F - event->byte2) >> 4; - tracks[t][k].param2 = (0x3F - event->byte2) & 15; - break; - - case 'G': // set carrier volume - tracks[t][k].command = 22; - tracks[t][k].param1 = (0x3F - event->byte2) >> 4; - tracks[t][k].param2 = (0x3F - event->byte2) & 15; - break; - - case 'B': // set carrier waveform - tracks[t][k].command = 25; - tracks[t][k].param1 = event->byte2; - tracks[t][k].param2 = 0x0F; - break; - - case 'E': // fine frequency slide down - tracks[t][k].command = 24; - tracks[t][k].param1 = old_event_byte2[j] >> 4; - tracks[t][k].param2 = old_event_byte2[j] & 15; - break; - - case 'F': // fine frequency slide up - tracks[t][k].command = 23; - tracks[t][k].param1 = old_event_byte2[j] >> 4; - tracks[t][k].param2 = old_event_byte2[j] & 15; - break; - - case 'D': // fine volume slide - tracks[t][k].command = 14; - if (old_event_byte2[j] & 15) - { - // slide down - tracks[t][k].param1 = 5; - tracks[t][k].param2 = old_event_byte2[j] & 15; - } - else - { - // slide up - tracks[t][k].param1 = 4; - tracks[t][k].param2 = old_event_byte2[j] >> 4; - } - break; - - case 'J': // arpeggio - tracks[t][k].param1 = old_event_byte2[j] >> 4; - tracks[t][k].param2 = old_event_byte2[j] & 15; - break; - } - } - - t++; - } - } - - delete [] module; - - // order loop - restartpos = 0; - - // order length - for (i=0;i<64;i++) - { - if (order[i] >= 0x80) - { - length = i; - break; - } - } - - // default tempo - bpm = 0x7D; - - rewind(0); - - return true; -} - -void CcffLoader::rewind(int subsong) -{ - CmodPlayer::rewind(subsong); - - // default instruments - for (int i=0;i<9;i++) - { - channel[i].inst = i; - - channel[i].vol1 = 63 - (inst[i].data[10] & 63); - channel[i].vol2 = 63 - (inst[i].data[9] & 63); - } -} - -std::string CcffLoader::gettype() -{ - if (header.packed) - return std::string("BoomTracker 4, packed"); - else - return std::string("BoomTracker 4"); -} - -std::string CcffLoader::gettitle() -{ - return std::string(song_title,20); -} - -std::string CcffLoader::getauthor() -{ - return std::string(song_author,20); -} - -std::string CcffLoader::getinstrument(unsigned int n) -{ - return std::string(instruments[n].name); -} - -unsigned int CcffLoader::getinstruments() -{ - return 47; -} - -/* -------- Private Methods ------------------------------- */ - -#ifdef _WIN32 -#pragma warning(disable:4244) -#pragma warning(disable:4018) -#endif - -/* - Lempel-Ziv-Tyr ;-) -*/ -long CcffLoader::cff_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf) -{ - if (memcmp(ibuf,"YsComp""\x07""CUD1997""\x1A\x04",16)) - return 0; - - input = ibuf + 16; - output = obuf; - - output_length = 0; - - heap = (unsigned char *)malloc(0x10000); - dictionary = (unsigned char **)malloc(sizeof(unsigned char *)*0x8000); - - memset(heap,0,0x10000); - memset(dictionary,0,0x8000); - - cleanup(); - if(!startup()) - goto out; - - // LZW - while (1) - { - new_code = get_code(); - - // 0x00: end of data - if (new_code == 0) - break; - - // 0x01: end of block - if (new_code == 1) - { - cleanup(); - if(!startup()) - goto out; - - continue; - } - - // 0x02: expand code length - if (new_code == 2) - { - code_length++; - - continue; - } - - // 0x03: RLE - if (new_code == 3) - { - unsigned char old_code_length = code_length; - - code_length = 2; - - unsigned char repeat_length = get_code() + 1; - - code_length = 4 << get_code(); - - unsigned long repeat_counter = get_code(); - - if(output_length + repeat_counter * repeat_length > 0x10000) { - output_length = 0; - goto out; - } - - for (unsigned int i=0;i<repeat_counter*repeat_length;i++) - output[output_length++] = output[output_length - repeat_length]; - - code_length = old_code_length; - - if(!startup()) - goto out; - - continue; - } - - if (new_code >= (0x104 + dictionary_length)) - { - // dictionary <- old.code.string + old.code.char - the_string[++the_string[0]] = the_string[1]; - } - else - { - // dictionary <- old.code.string + new.code.char - unsigned char temp_string[256]; - - translate_code(new_code,temp_string); - - the_string[++the_string[0]] = temp_string[1]; - } - - expand_dictionary(the_string); - - // output <- new.code.string - translate_code(new_code,the_string); - - if(output_length + the_string[0] > 0x10000) { - output_length = 0; - goto out; - } - - for (int i=0;i<the_string[0];i++) - output[output_length++] = the_string[i+1]; - - old_code = new_code; - } - - out: - free(heap); - free(dictionary); - return output_length; -} - -unsigned long CcffLoader::cff_unpacker::get_code() -{ - unsigned long code; - - while (bits_left < code_length) - { - bits_buffer |= ((*input++) << bits_left); - bits_left += 8; - } - - code = bits_buffer & ((1 << code_length) - 1); - - bits_buffer >>= code_length; - bits_left -= code_length; - - return code; -} - -void CcffLoader::cff_unpacker::translate_code(unsigned long code, unsigned char *string) -{ - unsigned char translated_string[256]; - - if (code >= 0x104) - { - memcpy(translated_string,dictionary[code - 0x104],(*(dictionary[code - 0x104])) + 1); - } - else - { - translated_string[0] = 1; - translated_string[1] = (code - 4) & 0xFF; - } - - memcpy(string,translated_string,256); -} - -void CcffLoader::cff_unpacker::cleanup() -{ - code_length = 9; - - bits_buffer = 0; - bits_left = 0; - - heap_length = 0; - dictionary_length = 0; -} - -int CcffLoader::cff_unpacker::startup() -{ - old_code = get_code(); - - translate_code(old_code,the_string); - - if(output_length + the_string[0] > 0x10000) { - output_length = 0; - return 0; - } - - for (int i=0;i<the_string[0];i++) - output[output_length++] = the_string[i+1]; - - return 1; -} - -void CcffLoader::cff_unpacker::expand_dictionary(unsigned char *string) -{ - if (string[0] >= 0xF0) - return; - - memcpy(&heap[heap_length],string,string[0] + 1); - - dictionary[dictionary_length] = &heap[heap_length]; - - dictionary_length++; - - heap_length += (string[0] + 1); -} - -#ifdef _WIN32 -#pragma warning(default:4244) -#pragma warning(default:4018) -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/cff.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,507 @@ +/* + AdPlug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2006 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 + + cff.cpp - BoomTracker loader by Riven the Mage <riven@ok.ru> +*/ +/* + NOTE: Conversion of slides is not 100% accurate. Original volume slides + have effect on carrier volume only. Also, original arpeggio, frequency & volume + slides use previous effect data instead of current. +*/ + +#include <stdlib.h> + +#include "cff.h" + +/* -------- Public Methods -------------------------------- */ + +CPlayer *CcffLoader::factory(Copl *newopl) +{ + return new CcffLoader(newopl); +} + +bool CcffLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 }; + const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE }; + + int i,j,k,t=0; + + // '<CUD-FM-File>' - signed ? + f->readString(header.id, 16); + header.version = f->readInt(1); header.size = f->readInt(2); + header.packed = f->readInt(1); f->readString((char *)header.reserved, 12); + if (memcmp(header.id,"<CUD-FM-File>""\x1A\xDE\xE0",16)) + { fp.close(f); return false; } + + unsigned char *module = new unsigned char [0x10000]; + + // packed ? + if (header.packed) + { + cff_unpacker *unpacker = new cff_unpacker; + + unsigned char *packed_module = new unsigned char [header.size + 4]; + + memset(packed_module,0,header.size + 4); + + f->readString((char *)packed_module, header.size); + fp.close(f); + + if (!unpacker->unpack(packed_module,module)) + { + delete unpacker; + delete packed_module; + delete module; + return false; + } + + delete unpacker; + delete packed_module; + + if (memcmp(&module[0x5E1],"CUD-FM-File - SEND A POSTCARD -",31)) + { + delete module; + return false; + } + } + else + { + f->readString((char *)module, header.size); + fp.close(f); + } + + // init CmodPlayer + realloc_instruments(47); + realloc_order(64); + realloc_patterns(36,64,9); + init_notetable(conv_note); + init_trackord(); + + // load instruments + for (i=0;i<47;i++) + { + memcpy(&instruments[i],&module[i*32],sizeof(cff_instrument)); + + for (j=0;j<11;j++) + inst[i].data[conv_inst[j]] = instruments[i].data[j]; + + instruments[i].name[20] = 0; + } + + // number of patterns + nop = module[0x5E0]; + + // load title & author + memcpy(song_title,&module[0x614],20); + memcpy(song_author,&module[0x600],20); + + // load order + memcpy(order,&module[0x628],64); + + // load tracks + for (i=0;i<nop;i++) + { + unsigned char old_event_byte2[9]; + + memset(old_event_byte2,0,9); + + for (j=0;j<9;j++) + { + for (k=0;k<64;k++) + { + cff_event *event = (cff_event *)&module[0x669 + ((i*64+k)*9+j)*3]; + + // convert note + if (event->byte0 == 0x6D) + tracks[t][k].note = 127; + else + if (event->byte0) + tracks[t][k].note = event->byte0; + + if (event->byte2) + old_event_byte2[j] = event->byte2; + + // convert effect + switch (event->byte1) + { + case 'I': // set instrument + tracks[t][k].inst = event->byte2 + 1; + tracks[t][k].param1 = tracks[t][k].param2 = 0; + break; + + case 'H': // set tempo + tracks[t][k].command = 7; + if (event->byte2 < 16) + { + tracks[t][k].param1 = 0x07; + tracks[t][k].param2 = 0x0D; + } + break; + + case 'A': // set speed + tracks[t][k].command = 19; + tracks[t][k].param1 = event->byte2 >> 4; + tracks[t][k].param2 = event->byte2 & 15; + break; + + case 'L': // pattern break + tracks[t][k].command = 13; + tracks[t][k].param1 = event->byte2 >> 4; + tracks[t][k].param2 = event->byte2 & 15; + break; + + case 'K': // order jump + tracks[t][k].command = 11; + tracks[t][k].param1 = event->byte2 >> 4; + tracks[t][k].param2 = event->byte2 & 15; + break; + + case 'M': // set vibrato/tremolo + tracks[t][k].command = 27; + tracks[t][k].param1 = event->byte2 >> 4; + tracks[t][k].param2 = event->byte2 & 15; + break; + + case 'C': // set modulator volume + tracks[t][k].command = 21; + tracks[t][k].param1 = (0x3F - event->byte2) >> 4; + tracks[t][k].param2 = (0x3F - event->byte2) & 15; + break; + + case 'G': // set carrier volume + tracks[t][k].command = 22; + tracks[t][k].param1 = (0x3F - event->byte2) >> 4; + tracks[t][k].param2 = (0x3F - event->byte2) & 15; + break; + + case 'B': // set carrier waveform + tracks[t][k].command = 25; + tracks[t][k].param1 = event->byte2; + tracks[t][k].param2 = 0x0F; + break; + + case 'E': // fine frequency slide down + tracks[t][k].command = 24; + tracks[t][k].param1 = old_event_byte2[j] >> 4; + tracks[t][k].param2 = old_event_byte2[j] & 15; + break; + + case 'F': // fine frequency slide up + tracks[t][k].command = 23; + tracks[t][k].param1 = old_event_byte2[j] >> 4; + tracks[t][k].param2 = old_event_byte2[j] & 15; + break; + + case 'D': // fine volume slide + tracks[t][k].command = 14; + if (old_event_byte2[j] & 15) + { + // slide down + tracks[t][k].param1 = 5; + tracks[t][k].param2 = old_event_byte2[j] & 15; + } + else + { + // slide up + tracks[t][k].param1 = 4; + tracks[t][k].param2 = old_event_byte2[j] >> 4; + } + break; + + case 'J': // arpeggio + tracks[t][k].param1 = old_event_byte2[j] >> 4; + tracks[t][k].param2 = old_event_byte2[j] & 15; + break; + } + } + + t++; + } + } + + delete [] module; + + // order loop + restartpos = 0; + + // order length + for (i=0;i<64;i++) + { + if (order[i] >= 0x80) + { + length = i; + break; + } + } + + // default tempo + bpm = 0x7D; + + rewind(0); + + return true; +} + +void CcffLoader::rewind(int subsong) +{ + CmodPlayer::rewind(subsong); + + // default instruments + for (int i=0;i<9;i++) + { + channel[i].inst = i; + + channel[i].vol1 = 63 - (inst[i].data[10] & 63); + channel[i].vol2 = 63 - (inst[i].data[9] & 63); + } +} + +std::string CcffLoader::gettype() +{ + if (header.packed) + return std::string("BoomTracker 4, packed"); + else + return std::string("BoomTracker 4"); +} + +std::string CcffLoader::gettitle() +{ + return std::string(song_title,20); +} + +std::string CcffLoader::getauthor() +{ + return std::string(song_author,20); +} + +std::string CcffLoader::getinstrument(unsigned int n) +{ + return std::string(instruments[n].name); +} + +unsigned int CcffLoader::getinstruments() +{ + return 47; +} + +/* -------- Private Methods ------------------------------- */ + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4018) +#endif + +/* + Lempel-Ziv-Tyr ;-) +*/ +long CcffLoader::cff_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf) +{ + if (memcmp(ibuf,"YsComp""\x07""CUD1997""\x1A\x04",16)) + return 0; + + input = ibuf + 16; + output = obuf; + + output_length = 0; + + heap = (unsigned char *)malloc(0x10000); + dictionary = (unsigned char **)malloc(sizeof(unsigned char *)*0x8000); + + memset(heap,0,0x10000); + memset(dictionary,0,0x8000); + + cleanup(); + if(!startup()) + goto out; + + // LZW + while (1) + { + new_code = get_code(); + + // 0x00: end of data + if (new_code == 0) + break; + + // 0x01: end of block + if (new_code == 1) + { + cleanup(); + if(!startup()) + goto out; + + continue; + } + + // 0x02: expand code length + if (new_code == 2) + { + code_length++; + + continue; + } + + // 0x03: RLE + if (new_code == 3) + { + unsigned char old_code_length = code_length; + + code_length = 2; + + unsigned char repeat_length = get_code() + 1; + + code_length = 4 << get_code(); + + unsigned long repeat_counter = get_code(); + + if(output_length + repeat_counter * repeat_length > 0x10000) { + output_length = 0; + goto out; + } + + for (unsigned int i=0;i<repeat_counter*repeat_length;i++) + output[output_length++] = output[output_length - repeat_length]; + + code_length = old_code_length; + + if(!startup()) + goto out; + + continue; + } + + if (new_code >= (0x104 + dictionary_length)) + { + // dictionary <- old.code.string + old.code.char + the_string[++the_string[0]] = the_string[1]; + } + else + { + // dictionary <- old.code.string + new.code.char + unsigned char temp_string[256]; + + translate_code(new_code,temp_string); + + the_string[++the_string[0]] = temp_string[1]; + } + + expand_dictionary(the_string); + + // output <- new.code.string + translate_code(new_code,the_string); + + if(output_length + the_string[0] > 0x10000) { + output_length = 0; + goto out; + } + + for (int i=0;i<the_string[0];i++) + output[output_length++] = the_string[i+1]; + + old_code = new_code; + } + + out: + free(heap); + free(dictionary); + return output_length; +} + +unsigned long CcffLoader::cff_unpacker::get_code() +{ + unsigned long code; + + while (bits_left < code_length) + { + bits_buffer |= ((*input++) << bits_left); + bits_left += 8; + } + + code = bits_buffer & ((1 << code_length) - 1); + + bits_buffer >>= code_length; + bits_left -= code_length; + + return code; +} + +void CcffLoader::cff_unpacker::translate_code(unsigned long code, unsigned char *string) +{ + unsigned char translated_string[256]; + + if (code >= 0x104) + { + memcpy(translated_string,dictionary[code - 0x104],(*(dictionary[code - 0x104])) + 1); + } + else + { + translated_string[0] = 1; + translated_string[1] = (code - 4) & 0xFF; + } + + memcpy(string,translated_string,256); +} + +void CcffLoader::cff_unpacker::cleanup() +{ + code_length = 9; + + bits_buffer = 0; + bits_left = 0; + + heap_length = 0; + dictionary_length = 0; +} + +int CcffLoader::cff_unpacker::startup() +{ + old_code = get_code(); + + translate_code(old_code,the_string); + + if(output_length + the_string[0] > 0x10000) { + output_length = 0; + return 0; + } + + for (int i=0;i<the_string[0];i++) + output[output_length++] = the_string[i+1]; + + return 1; +} + +void CcffLoader::cff_unpacker::expand_dictionary(unsigned char *string) +{ + if (string[0] >= 0xF0) + return; + + memcpy(&heap[heap_length],string,string[0] + 1); + + dictionary[dictionary_length] = &heap[heap_length]; + + dictionary_length++; + + heap_length += (string[0] + 1); +} + +#ifdef _WIN32 +#pragma warning(default:4244) +#pragma warning(default:4018) +#endif
--- a/Plugins/Input/adplug/core/d00.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,538 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 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 - * - * d00.c - D00 Player by Simon Peter <dn.tlp@gmx.net> - * - * NOTES: - * Sorry for the goto's, but the code looks so much nicer now. - * I tried it with while loops but it was just a mess. If you - * can come up with a nicer solution, just tell me. - * - * BUGS: - * Hard restart SR is sometimes wrong - */ - -#include <string.h> -#include <stdio.h> -#include <inttypes.h> - -#include "debug.h" -#include "d00.h" - -#define HIBYTE(val) (val >> 8) -#define LOBYTE(val) (val & 0xff) - -static const unsigned short notetable[12] = // D00 note table - {340,363,385,408,432,458,485,514,544,577,611,647}; - -static inline uint16_t LE_WORD(const uint16_t *val) -{ - const uint8_t *b = (const uint8_t *)val; - return (b[1] << 8) + b[0]; -} - -/*** public methods *************************************/ - -CPlayer *Cd00Player::factory(Copl *newopl) -{ - return new Cd00Player(newopl); -} - -bool Cd00Player::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - d00header *checkhead; - d00header1 *ch; - unsigned long filesize; - int i,ver1=0; - char *str; - - // file validation section - checkhead = new d00header; - f->readString((char *)checkhead, sizeof(d00header)); - - // Check for version 2-4 header - if(strncmp(checkhead->id,"JCH\x26\x02\x66",6) || checkhead->type || - !checkhead->subsongs || checkhead->soundcard) { - // Check for version 0 or 1 header (and .d00 file extension) - delete checkhead; - if(!fp.extension(filename, ".d00")) { fp.close(f); return false; } - ch = new d00header1; - f->seek(0); f->readString((char *)ch, sizeof(d00header1)); - if(ch->version > 1 || !ch->subsongs) - { delete ch; fp.close(f); return false; } - delete ch; - ver1 = 1; - } else - delete checkhead; - - AdPlug_LogWrite("Cd00Player::load(f,\"%s\"): %s format D00 file detected!\n", - filename.c_str(), ver1 ? "Old" : "New"); - - // load section - filesize = fp.filesize(f); f->seek(0); - filedata = new char [filesize + 1]; // 1 byte is needed for old-style DataInfo block - f->readString((char *)filedata, filesize); - fp.close(f); - if(!ver1) { // version 2 and above - header = (struct d00header *)filedata; - version = header->version; - datainfo = (char *)filedata + LE_WORD(&header->infoptr); - inst = (struct Sinsts *)((char *)filedata + LE_WORD(&header->instptr)); - seqptr = (unsigned short *)((char *)filedata + LE_WORD(&header->seqptr)); - for(i=31;i>=0;i--) // erase whitespace - if(header->songname[i] == ' ') - header->songname[i] = '\0'; - else - break; - for(i=31;i>=0;i--) - if(header->author[i] == ' ') - header->author[i] = '\0'; - else - break; - } else { // version 1 - header1 = (struct d00header1 *)filedata; - version = header1->version; - datainfo = (char *)filedata + LE_WORD(&header1->infoptr); - inst = (struct Sinsts *)((char *)filedata + LE_WORD(&header1->instptr)); - seqptr = (unsigned short *)((char *)filedata + LE_WORD(&header1->seqptr)); - } - switch(version) { - case 0: - levpuls = 0; - spfx = 0; - header1->speed = 70; // v0 files default to 70Hz - break; - case 1: - levpuls = (struct Slevpuls *)((char *)filedata + LE_WORD(&header1->lpulptr)); - spfx = 0; - break; - case 2: - levpuls = (struct Slevpuls *)((char *)filedata + LE_WORD(&header->spfxptr)); - spfx = 0; - break; - case 3: - spfx = 0; - levpuls = 0; - break; - case 4: - spfx = (struct Sspfx *)((char *)filedata + LE_WORD(&header->spfxptr)); - levpuls = 0; - break; - } - if((str = strstr(datainfo,"\xff\xff"))) - while((*str == '\xff' || *str == ' ') && str >= datainfo) { - *str = '\0'; str--; - } - else // old-style block - memset((char *)filedata+filesize,0,1); - - rewind(0); - return true; -} - -bool Cd00Player::update() -{ - unsigned char c,cnt,trackend=0,fx,note; - unsigned short ord,*patt,buf,fxop,pattpos; - - // effect handling (timer dependant) - for(c=0;c<9;c++) { - channel[c].slideval += channel[c].slide; setfreq(c); // sliding - vibrato(c); // vibrato - - if(channel[c].spfx != 0xffff) { // SpFX - if(channel[c].fxdel) - channel[c].fxdel--; - else { - channel[c].spfx = LE_WORD(&spfx[channel[c].spfx].ptr); - channel[c].fxdel = spfx[channel[c].spfx].duration; - channel[c].inst = LE_WORD(&spfx[channel[c].spfx].instnr) & 0xfff; - if(spfx[channel[c].spfx].modlev != 0xff) - channel[c].modvol = spfx[channel[c].spfx].modlev; - setinst(c); - if(LE_WORD(&spfx[channel[c].spfx].instnr) & 0x8000) // locked frequency - note = spfx[channel[c].spfx].halfnote; - else // unlocked frequency - note = spfx[channel[c].spfx].halfnote + channel[c].note; - channel[c].freq = notetable[note%12] + ((note/12) << 10); - setfreq(c); - } - channel[c].modvol += spfx[channel[c].spfx].modlevadd; channel[c].modvol &= 63; - setvolume(c); - } - - if(channel[c].levpuls != 0xff) // Levelpuls - if(channel[c].frameskip) - channel[c].frameskip--; - else { - channel[c].frameskip = inst[channel[c].inst].timer; - if(channel[c].fxdel) - channel[c].fxdel--; - else { - channel[c].levpuls = levpuls[channel[c].levpuls].ptr - 1; - channel[c].fxdel = levpuls[channel[c].levpuls].duration; - if(levpuls[channel[c].levpuls].level != 0xff) - channel[c].modvol = levpuls[channel[c].levpuls].level; - } - channel[c].modvol += levpuls[channel[c].levpuls].voladd; channel[c].modvol &= 63; - setvolume(c); - } - } - - // song handling - for(c=0;c<9;c++) - if(version < 3 ? channel[c].del : channel[c].del <= 0x7f) { - if(version == 4) // v4: hard restart SR - if(channel[c].del == inst[channel[c].inst].timer) - if(channel[c].nextnote) - opl->write(0x83 + op_table[c], inst[channel[c].inst].sr); - if(version < 3) - channel[c].del--; - else - if(channel[c].speed) - channel[c].del += channel[c].speed; - else { - channel[c].seqend = 1; - continue; - } - } else { - if(channel[c].speed) { - if(version < 3) - channel[c].del = channel[c].speed; - else { - channel[c].del &= 0x7f; - channel[c].del += channel[c].speed; - } - } else { - channel[c].seqend = 1; - continue; - } - if(channel[c].rhcnt) { // process pending REST/HOLD events - channel[c].rhcnt--; - continue; - } - readorder: // process arrangement (orderlist) - ord = LE_WORD(&channel[c].order[channel[c].ordpos]); - switch(ord) { - case 0xfffe: channel[c].seqend = 1; continue; // end of arrangement stream - case 0xffff: // jump to order - channel[c].ordpos = LE_WORD(&channel[c].order[channel[c].ordpos + 1]); - channel[c].seqend = 1; - goto readorder; - default: - if(ord >= 0x9000) { // set speed - channel[c].speed = ord & 0xff; - ord = LE_WORD(&channel[c].order[channel[c].ordpos - 1]); - channel[c].ordpos++; - } else - if(ord >= 0x8000) { // transpose track - channel[c].transpose = ord & 0xff; - if(ord & 0x100) - channel[c].transpose = -channel[c].transpose; - ord = LE_WORD(&channel[c].order[++channel[c].ordpos]); - } - patt = (unsigned short *)((char *)filedata + LE_WORD(&seqptr[ord])); - break; - } - readseq: // process sequence (pattern) - if(!version) // v0: always initialize rhcnt - channel[c].rhcnt = channel[c].irhcnt; - pattpos = LE_WORD(&patt[channel[c].pattpos]); - if(pattpos == 0xffff) { // pattern ended? - channel[c].pattpos = 0; - channel[c].ordpos++; - goto readorder; - } - cnt = HIBYTE(pattpos); - note = LOBYTE(pattpos); - fx = pattpos >> 12; - fxop = pattpos & 0x0fff; - channel[c].pattpos++; pattpos = LE_WORD(&patt[channel[c].pattpos]); - channel[c].nextnote = LOBYTE(pattpos) & 0x7f; - if(version ? cnt < 0x40 : !fx) { // note event - switch(note) { - case 0: // REST event - case 0x80: - if(!note || version) { - channel[c].key = 0; - setfreq(c); - } - // fall through... - case 0x7e: // HOLD event - if(version) - channel[c].rhcnt = cnt; - channel[c].nextnote = 0; - break; - default: // play note - // restart fx - channel[c].slideval = 0; channel[c].slide = 0; channel[c].vibdepth = 0; - - if(version) { // note handling for v1 and above - if(note > 0x80) // locked note (no channel transpose) - note -= 0x80; - else // unlocked note - note += channel[c].transpose; - channel[c].note = note; // remember note for SpFX - - if(channel[c].ispfx != 0xffff && cnt < 0x20) { // reset SpFX - channel[c].spfx = channel[c].ispfx; - if(LE_WORD(&spfx[channel[c].spfx].instnr) & 0x8000) // locked frequency - note = spfx[channel[c].spfx].halfnote; - else // unlocked frequency - note += spfx[channel[c].spfx].halfnote; - channel[c].inst = LE_WORD(&spfx[channel[c].spfx].instnr) & 0xfff; - channel[c].fxdel = spfx[channel[c].spfx].duration; - if(spfx[channel[c].spfx].modlev != 0xff) - channel[c].modvol = spfx[channel[c].spfx].modlev; - else - channel[c].modvol = inst[channel[c].inst].data[7] & 63; - } - - if(channel[c].ilevpuls != 0xff && cnt < 0x20) { // reset LevelPuls - channel[c].levpuls = channel[c].ilevpuls; - channel[c].fxdel = levpuls[channel[c].levpuls].duration; - channel[c].frameskip = inst[channel[c].inst].timer; - if(levpuls[channel[c].levpuls].level != 0xff) - channel[c].modvol = levpuls[channel[c].levpuls].level; - else - channel[c].modvol = inst[channel[c].inst].data[7] & 63; - } - - channel[c].freq = notetable[note%12] + ((note/12) << 10); - if(cnt < 0x20) // normal note - playnote(c); - else { // tienote - setfreq(c); - cnt -= 0x20; // make count proper - } - channel[c].rhcnt = cnt; - } else { // note handling for v0 - if(cnt < 2) // unlocked note - note += channel[c].transpose; - channel[c].note = note; - - channel[c].freq = notetable[note%12] + ((note/12) << 10); - if(cnt == 1) // tienote - setfreq(c); - else // normal note - playnote(c); - } - break; - } - continue; // event is complete - } else { // effect event - switch(fx) { - case 6: // Cut/Stop Voice - buf = channel[c].inst; - channel[c].inst = 0; - playnote(c); - channel[c].inst = buf; - channel[c].rhcnt = fxop; - continue; // no note follows this event - case 7: // Vibrato - channel[c].vibspeed = fxop & 0xff; - channel[c].vibdepth = fxop >> 8; - channel[c].trigger = fxop >> 9; - break; - case 8: // v0: Duration - if(!version) - channel[c].irhcnt = fxop; - break; - case 9: // New Level - channel[c].vol = fxop & 63; - if(channel[c].vol + channel[c].cvol < 63) // apply channel volume - channel[c].vol += channel[c].cvol; - else - channel[c].vol = 63; - setvolume(c); - break; - case 0xb: // v4: Set SpFX - if(version == 4) - channel[c].ispfx = fxop; - break; - case 0xc: // Set Instrument - channel[c].ispfx = 0xffff; - channel[c].spfx = 0xffff; - channel[c].inst = fxop; - channel[c].modvol = inst[fxop].data[7] & 63; - if(version < 3 && version && inst[fxop].tunelev) // Set LevelPuls - channel[c].ilevpuls = inst[fxop].tunelev - 1; - else { - channel[c].ilevpuls = 0xff; - channel[c].levpuls = 0xff; - } - break; - case 0xd: // Slide up - channel[c].slide = fxop; - break; - case 0xe: // Slide down - channel[c].slide = -fxop; - break; - } - goto readseq; // event is incomplete, note follows - } - } - - for(c=0;c<9;c++) - if(channel[c].seqend) - trackend++; - if(trackend == 9) - songend = 1; - - return !songend; -} - -void Cd00Player::rewind(int subsong) -{ - struct Stpoin { - unsigned short ptr[9]; - unsigned char volume[9],dummy[5]; - } *tpoin; - int i; - - if(version > 1) { // do nothing if subsong > number of subsongs - if(subsong >= header->subsongs) - return; - } else - if(subsong >= header1->subsongs) - return; - - memset(channel,0,sizeof(channel)); - if(version > 1) - tpoin = (struct Stpoin *)((char *)filedata + LE_WORD(&header->tpoin)); - else - tpoin = (struct Stpoin *)((char *)filedata + LE_WORD(&header1->tpoin)); - for(i=0;i<9;i++) { - if(LE_WORD(&tpoin[subsong].ptr[i])) { // track enabled - channel[i].speed = LE_WORD((unsigned short *) - ((char *)filedata + LE_WORD(&tpoin[subsong].ptr[i]))); - channel[i].order = (unsigned short *) - ((char *)filedata + LE_WORD(&tpoin[subsong].ptr[i]) + 2); - } else { // track disabled - channel[i].speed = 0; - channel[i].order = 0; - } - channel[i].ispfx = 0xffff; channel[i].spfx = 0xffff; // no SpFX - channel[i].ilevpuls = 0xff; channel[i].levpuls = 0xff; // no LevelPuls - channel[i].cvol = tpoin[subsong].volume[i] & 0x7f; // our player may savely ignore bit 7 - channel[i].vol = channel[i].cvol; // initialize volume - } - songend = 0; - opl->init(); opl->write(1,32); // reset OPL chip -} - -std::string Cd00Player::gettype() -{ - char tmpstr[40]; - - sprintf(tmpstr,"EdLib packed (version %d)",version > 1 ? header->version : header1->version); - return std::string(tmpstr); -} - -float Cd00Player::getrefresh() -{ - if(version > 1) - return header->speed; - else - return header1->speed; -} - -unsigned int Cd00Player::getsubsongs() -{ - if(version <= 1) // return number of subsongs - return header1->subsongs; - else - return header->subsongs; -} - -/*** private methods *************************************/ - -void Cd00Player::setvolume(unsigned char chan) -{ - unsigned char op = op_table[chan]; - unsigned short insnr = channel[chan].inst; - - opl->write(0x43 + op,(int)(63-((63-(inst[insnr].data[2] & 63))/63.0)*(63-channel[chan].vol)) + - (inst[insnr].data[2] & 192)); - if(inst[insnr].data[10] & 1) - opl->write(0x40 + op,(int)(63-((63-channel[chan].modvol)/63.0)*(63-channel[chan].vol)) + - (inst[insnr].data[7] & 192)); - else - opl->write(0x40 + op,channel[chan].modvol + (inst[insnr].data[7] & 192)); -} - -void Cd00Player::setfreq(unsigned char chan) -{ - unsigned short freq = channel[chan].freq; - - if(version == 4) // v4: apply instrument finetune - freq += inst[channel[chan].inst].tunelev; - - freq += channel[chan].slideval; - opl->write(0xa0 + chan, freq & 255); - if(channel[chan].key) - opl->write(0xb0 + chan, ((freq >> 8) & 31) | 32); - else - opl->write(0xb0 + chan, (freq >> 8) & 31); -} - -void Cd00Player::setinst(unsigned char chan) -{ - unsigned char op = op_table[chan]; - unsigned short insnr = channel[chan].inst; - - // set instrument data - opl->write(0x63 + op, inst[insnr].data[0]); - opl->write(0x83 + op, inst[insnr].data[1]); - opl->write(0x23 + op, inst[insnr].data[3]); - opl->write(0xe3 + op, inst[insnr].data[4]); - opl->write(0x60 + op, inst[insnr].data[5]); - opl->write(0x80 + op, inst[insnr].data[6]); - opl->write(0x20 + op, inst[insnr].data[8]); - opl->write(0xe0 + op, inst[insnr].data[9]); - if(version) - opl->write(0xc0 + chan, inst[insnr].data[10]); - else - opl->write(0xc0 + chan, (inst[insnr].data[10] << 1) + (inst[insnr].tunelev & 1)); -} - -void Cd00Player::playnote(unsigned char chan) -{ - // set misc vars & play - opl->write(0xb0 + chan, 0); // stop old note - setinst(chan); - channel[chan].key = 1; - setfreq(chan); - setvolume(chan); -} - -void Cd00Player::vibrato(unsigned char chan) -{ - if(!channel[chan].vibdepth) - return; - - if(channel[chan].trigger) - channel[chan].trigger--; - else { - channel[chan].trigger = channel[chan].vibdepth; - channel[chan].vibspeed = -channel[chan].vibspeed; - } - channel[chan].freq += channel[chan].vibspeed; - setfreq(chan); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/d00.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,538 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2006 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 + * + * d00.c - D00 Player by Simon Peter <dn.tlp@gmx.net> + * + * NOTES: + * Sorry for the goto's, but the code looks so much nicer now. + * I tried it with while loops but it was just a mess. If you + * can come up with a nicer solution, just tell me. + * + * BUGS: + * Hard restart SR is sometimes wrong + */ + +#include <string.h> +#include <stdio.h> +#include <inttypes.h> + +#include "debug.h" +#include "d00.h" + +#define HIBYTE(val) (val >> 8) +#define LOBYTE(val) (val & 0xff) + +static const unsigned short notetable[12] = // D00 note table + {340,363,385,408,432,458,485,514,544,577,611,647}; + +static inline uint16_t LE_WORD(const uint16_t *val) +{ + const uint8_t *b = (const uint8_t *)val; + return (b[1] << 8) + b[0]; +} + +/*** public methods *************************************/ + +CPlayer *Cd00Player::factory(Copl *newopl) +{ + return new Cd00Player(newopl); +} + +bool Cd00Player::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + d00header *checkhead; + d00header1 *ch; + unsigned long filesize; + int i,ver1=0; + char *str; + + // file validation section + checkhead = new d00header; + f->readString((char *)checkhead, sizeof(d00header)); + + // Check for version 2-4 header + if(strncmp(checkhead->id,"JCH\x26\x02\x66",6) || checkhead->type || + !checkhead->subsongs || checkhead->soundcard) { + // Check for version 0 or 1 header (and .d00 file extension) + delete checkhead; + if(!fp.extension(filename, ".d00")) { fp.close(f); return false; } + ch = new d00header1; + f->seek(0); f->readString((char *)ch, sizeof(d00header1)); + if(ch->version > 1 || !ch->subsongs) + { delete ch; fp.close(f); return false; } + delete ch; + ver1 = 1; + } else + delete checkhead; + + AdPlug_LogWrite("Cd00Player::load(f,\"%s\"): %s format D00 file detected!\n", + filename.c_str(), ver1 ? "Old" : "New"); + + // load section + filesize = fp.filesize(f); f->seek(0); + filedata = new char [filesize + 1]; // 1 byte is needed for old-style DataInfo block + f->readString((char *)filedata, filesize); + fp.close(f); + if(!ver1) { // version 2 and above + header = (struct d00header *)filedata; + version = header->version; + datainfo = (char *)filedata + LE_WORD(&header->infoptr); + inst = (struct Sinsts *)((char *)filedata + LE_WORD(&header->instptr)); + seqptr = (unsigned short *)((char *)filedata + LE_WORD(&header->seqptr)); + for(i=31;i>=0;i--) // erase whitespace + if(header->songname[i] == ' ') + header->songname[i] = '\0'; + else + break; + for(i=31;i>=0;i--) + if(header->author[i] == ' ') + header->author[i] = '\0'; + else + break; + } else { // version 1 + header1 = (struct d00header1 *)filedata; + version = header1->version; + datainfo = (char *)filedata + LE_WORD(&header1->infoptr); + inst = (struct Sinsts *)((char *)filedata + LE_WORD(&header1->instptr)); + seqptr = (unsigned short *)((char *)filedata + LE_WORD(&header1->seqptr)); + } + switch(version) { + case 0: + levpuls = 0; + spfx = 0; + header1->speed = 70; // v0 files default to 70Hz + break; + case 1: + levpuls = (struct Slevpuls *)((char *)filedata + LE_WORD(&header1->lpulptr)); + spfx = 0; + break; + case 2: + levpuls = (struct Slevpuls *)((char *)filedata + LE_WORD(&header->spfxptr)); + spfx = 0; + break; + case 3: + spfx = 0; + levpuls = 0; + break; + case 4: + spfx = (struct Sspfx *)((char *)filedata + LE_WORD(&header->spfxptr)); + levpuls = 0; + break; + } + if((str = strstr(datainfo,"\xff\xff"))) + while((*str == '\xff' || *str == ' ') && str >= datainfo) { + *str = '\0'; str--; + } + else // old-style block + memset((char *)filedata+filesize,0,1); + + rewind(0); + return true; +} + +bool Cd00Player::update() +{ + unsigned char c,cnt,trackend=0,fx,note; + unsigned short ord,*patt,buf,fxop,pattpos; + + // effect handling (timer dependant) + for(c=0;c<9;c++) { + channel[c].slideval += channel[c].slide; setfreq(c); // sliding + vibrato(c); // vibrato + + if(channel[c].spfx != 0xffff) { // SpFX + if(channel[c].fxdel) + channel[c].fxdel--; + else { + channel[c].spfx = LE_WORD(&spfx[channel[c].spfx].ptr); + channel[c].fxdel = spfx[channel[c].spfx].duration; + channel[c].inst = LE_WORD(&spfx[channel[c].spfx].instnr) & 0xfff; + if(spfx[channel[c].spfx].modlev != 0xff) + channel[c].modvol = spfx[channel[c].spfx].modlev; + setinst(c); + if(LE_WORD(&spfx[channel[c].spfx].instnr) & 0x8000) // locked frequency + note = spfx[channel[c].spfx].halfnote; + else // unlocked frequency + note = spfx[channel[c].spfx].halfnote + channel[c].note; + channel[c].freq = notetable[note%12] + ((note/12) << 10); + setfreq(c); + } + channel[c].modvol += spfx[channel[c].spfx].modlevadd; channel[c].modvol &= 63; + setvolume(c); + } + + if(channel[c].levpuls != 0xff) // Levelpuls + if(channel[c].frameskip) + channel[c].frameskip--; + else { + channel[c].frameskip = inst[channel[c].inst].timer; + if(channel[c].fxdel) + channel[c].fxdel--; + else { + channel[c].levpuls = levpuls[channel[c].levpuls].ptr - 1; + channel[c].fxdel = levpuls[channel[c].levpuls].duration; + if(levpuls[channel[c].levpuls].level != 0xff) + channel[c].modvol = levpuls[channel[c].levpuls].level; + } + channel[c].modvol += levpuls[channel[c].levpuls].voladd; channel[c].modvol &= 63; + setvolume(c); + } + } + + // song handling + for(c=0;c<9;c++) + if(version < 3 ? channel[c].del : channel[c].del <= 0x7f) { + if(version == 4) // v4: hard restart SR + if(channel[c].del == inst[channel[c].inst].timer) + if(channel[c].nextnote) + opl->write(0x83 + op_table[c], inst[channel[c].inst].sr); + if(version < 3) + channel[c].del--; + else + if(channel[c].speed) + channel[c].del += channel[c].speed; + else { + channel[c].seqend = 1; + continue; + } + } else { + if(channel[c].speed) { + if(version < 3) + channel[c].del = channel[c].speed; + else { + channel[c].del &= 0x7f; + channel[c].del += channel[c].speed; + } + } else { + channel[c].seqend = 1; + continue; + } + if(channel[c].rhcnt) { // process pending REST/HOLD events + channel[c].rhcnt--; + continue; + } + readorder: // process arrangement (orderlist) + ord = LE_WORD(&channel[c].order[channel[c].ordpos]); + switch(ord) { + case 0xfffe: channel[c].seqend = 1; continue; // end of arrangement stream + case 0xffff: // jump to order + channel[c].ordpos = LE_WORD(&channel[c].order[channel[c].ordpos + 1]); + channel[c].seqend = 1; + goto readorder; + default: + if(ord >= 0x9000) { // set speed + channel[c].speed = ord & 0xff; + ord = LE_WORD(&channel[c].order[channel[c].ordpos - 1]); + channel[c].ordpos++; + } else + if(ord >= 0x8000) { // transpose track + channel[c].transpose = ord & 0xff; + if(ord & 0x100) + channel[c].transpose = -channel[c].transpose; + ord = LE_WORD(&channel[c].order[++channel[c].ordpos]); + } + patt = (unsigned short *)((char *)filedata + LE_WORD(&seqptr[ord])); + break; + } + readseq: // process sequence (pattern) + if(!version) // v0: always initialize rhcnt + channel[c].rhcnt = channel[c].irhcnt; + pattpos = LE_WORD(&patt[channel[c].pattpos]); + if(pattpos == 0xffff) { // pattern ended? + channel[c].pattpos = 0; + channel[c].ordpos++; + goto readorder; + } + cnt = HIBYTE(pattpos); + note = LOBYTE(pattpos); + fx = pattpos >> 12; + fxop = pattpos & 0x0fff; + channel[c].pattpos++; pattpos = LE_WORD(&patt[channel[c].pattpos]); + channel[c].nextnote = LOBYTE(pattpos) & 0x7f; + if(version ? cnt < 0x40 : !fx) { // note event + switch(note) { + case 0: // REST event + case 0x80: + if(!note || version) { + channel[c].key = 0; + setfreq(c); + } + // fall through... + case 0x7e: // HOLD event + if(version) + channel[c].rhcnt = cnt; + channel[c].nextnote = 0; + break; + default: // play note + // restart fx + channel[c].slideval = 0; channel[c].slide = 0; channel[c].vibdepth = 0; + + if(version) { // note handling for v1 and above + if(note > 0x80) // locked note (no channel transpose) + note -= 0x80; + else // unlocked note + note += channel[c].transpose; + channel[c].note = note; // remember note for SpFX + + if(channel[c].ispfx != 0xffff && cnt < 0x20) { // reset SpFX + channel[c].spfx = channel[c].ispfx; + if(LE_WORD(&spfx[channel[c].spfx].instnr) & 0x8000) // locked frequency + note = spfx[channel[c].spfx].halfnote; + else // unlocked frequency + note += spfx[channel[c].spfx].halfnote; + channel[c].inst = LE_WORD(&spfx[channel[c].spfx].instnr) & 0xfff; + channel[c].fxdel = spfx[channel[c].spfx].duration; + if(spfx[channel[c].spfx].modlev != 0xff) + channel[c].modvol = spfx[channel[c].spfx].modlev; + else + channel[c].modvol = inst[channel[c].inst].data[7] & 63; + } + + if(channel[c].ilevpuls != 0xff && cnt < 0x20) { // reset LevelPuls + channel[c].levpuls = channel[c].ilevpuls; + channel[c].fxdel = levpuls[channel[c].levpuls].duration; + channel[c].frameskip = inst[channel[c].inst].timer; + if(levpuls[channel[c].levpuls].level != 0xff) + channel[c].modvol = levpuls[channel[c].levpuls].level; + else + channel[c].modvol = inst[channel[c].inst].data[7] & 63; + } + + channel[c].freq = notetable[note%12] + ((note/12) << 10); + if(cnt < 0x20) // normal note + playnote(c); + else { // tienote + setfreq(c); + cnt -= 0x20; // make count proper + } + channel[c].rhcnt = cnt; + } else { // note handling for v0 + if(cnt < 2) // unlocked note + note += channel[c].transpose; + channel[c].note = note; + + channel[c].freq = notetable[note%12] + ((note/12) << 10); + if(cnt == 1) // tienote + setfreq(c); + else // normal note + playnote(c); + } + break; + } + continue; // event is complete + } else { // effect event + switch(fx) { + case 6: // Cut/Stop Voice + buf = channel[c].inst; + channel[c].inst = 0; + playnote(c); + channel[c].inst = buf; + channel[c].rhcnt = fxop; + continue; // no note follows this event + case 7: // Vibrato + channel[c].vibspeed = fxop & 0xff; + channel[c].vibdepth = fxop >> 8; + channel[c].trigger = fxop >> 9; + break; + case 8: // v0: Duration + if(!version) + channel[c].irhcnt = fxop; + break; + case 9: // New Level + channel[c].vol = fxop & 63; + if(channel[c].vol + channel[c].cvol < 63) // apply channel volume + channel[c].vol += channel[c].cvol; + else + channel[c].vol = 63; + setvolume(c); + break; + case 0xb: // v4: Set SpFX + if(version == 4) + channel[c].ispfx = fxop; + break; + case 0xc: // Set Instrument + channel[c].ispfx = 0xffff; + channel[c].spfx = 0xffff; + channel[c].inst = fxop; + channel[c].modvol = inst[fxop].data[7] & 63; + if(version < 3 && version && inst[fxop].tunelev) // Set LevelPuls + channel[c].ilevpuls = inst[fxop].tunelev - 1; + else { + channel[c].ilevpuls = 0xff; + channel[c].levpuls = 0xff; + } + break; + case 0xd: // Slide up + channel[c].slide = fxop; + break; + case 0xe: // Slide down + channel[c].slide = -fxop; + break; + } + goto readseq; // event is incomplete, note follows + } + } + + for(c=0;c<9;c++) + if(channel[c].seqend) + trackend++; + if(trackend == 9) + songend = 1; + + return !songend; +} + +void Cd00Player::rewind(int subsong) +{ + struct Stpoin { + unsigned short ptr[9]; + unsigned char volume[9],dummy[5]; + } *tpoin; + int i; + + if(version > 1) { // do nothing if subsong > number of subsongs + if(subsong >= header->subsongs) + return; + } else + if(subsong >= header1->subsongs) + return; + + memset(channel,0,sizeof(channel)); + if(version > 1) + tpoin = (struct Stpoin *)((char *)filedata + LE_WORD(&header->tpoin)); + else + tpoin = (struct Stpoin *)((char *)filedata + LE_WORD(&header1->tpoin)); + for(i=0;i<9;i++) { + if(LE_WORD(&tpoin[subsong].ptr[i])) { // track enabled + channel[i].speed = LE_WORD((unsigned short *) + ((char *)filedata + LE_WORD(&tpoin[subsong].ptr[i]))); + channel[i].order = (unsigned short *) + ((char *)filedata + LE_WORD(&tpoin[subsong].ptr[i]) + 2); + } else { // track disabled + channel[i].speed = 0; + channel[i].order = 0; + } + channel[i].ispfx = 0xffff; channel[i].spfx = 0xffff; // no SpFX + channel[i].ilevpuls = 0xff; channel[i].levpuls = 0xff; // no LevelPuls + channel[i].cvol = tpoin[subsong].volume[i] & 0x7f; // our player may savely ignore bit 7 + channel[i].vol = channel[i].cvol; // initialize volume + } + songend = 0; + opl->init(); opl->write(1,32); // reset OPL chip +} + +std::string Cd00Player::gettype() +{ + char tmpstr[40]; + + sprintf(tmpstr,"EdLib packed (version %d)",version > 1 ? header->version : header1->version); + return std::string(tmpstr); +} + +float Cd00Player::getrefresh() +{ + if(version > 1) + return header->speed; + else + return header1->speed; +} + +unsigned int Cd00Player::getsubsongs() +{ + if(version <= 1) // return number of subsongs + return header1->subsongs; + else + return header->subsongs; +} + +/*** private methods *************************************/ + +void Cd00Player::setvolume(unsigned char chan) +{ + unsigned char op = op_table[chan]; + unsigned short insnr = channel[chan].inst; + + opl->write(0x43 + op,(int)(63-((63-(inst[insnr].data[2] & 63))/63.0)*(63-channel[chan].vol)) + + (inst[insnr].data[2] & 192)); + if(inst[insnr].data[10] & 1) + opl->write(0x40 + op,(int)(63-((63-channel[chan].modvol)/63.0)*(63-channel[chan].vol)) + + (inst[insnr].data[7] & 192)); + else + opl->write(0x40 + op,channel[chan].modvol + (inst[insnr].data[7] & 192)); +} + +void Cd00Player::setfreq(unsigned char chan) +{ + unsigned short freq = channel[chan].freq; + + if(version == 4) // v4: apply instrument finetune + freq += inst[channel[chan].inst].tunelev; + + freq += channel[chan].slideval; + opl->write(0xa0 + chan, freq & 255); + if(channel[chan].key) + opl->write(0xb0 + chan, ((freq >> 8) & 31) | 32); + else + opl->write(0xb0 + chan, (freq >> 8) & 31); +} + +void Cd00Player::setinst(unsigned char chan) +{ + unsigned char op = op_table[chan]; + unsigned short insnr = channel[chan].inst; + + // set instrument data + opl->write(0x63 + op, inst[insnr].data[0]); + opl->write(0x83 + op, inst[insnr].data[1]); + opl->write(0x23 + op, inst[insnr].data[3]); + opl->write(0xe3 + op, inst[insnr].data[4]); + opl->write(0x60 + op, inst[insnr].data[5]); + opl->write(0x80 + op, inst[insnr].data[6]); + opl->write(0x20 + op, inst[insnr].data[8]); + opl->write(0xe0 + op, inst[insnr].data[9]); + if(version) + opl->write(0xc0 + chan, inst[insnr].data[10]); + else + opl->write(0xc0 + chan, (inst[insnr].data[10] << 1) + (inst[insnr].tunelev & 1)); +} + +void Cd00Player::playnote(unsigned char chan) +{ + // set misc vars & play + opl->write(0xb0 + chan, 0); // stop old note + setinst(chan); + channel[chan].key = 1; + setfreq(chan); + setvolume(chan); +} + +void Cd00Player::vibrato(unsigned char chan) +{ + if(!channel[chan].vibdepth) + return; + + if(channel[chan].trigger) + channel[chan].trigger--; + else { + channel[chan].trigger = channel[chan].vibdepth; + channel[chan].vibspeed = -channel[chan].vibspeed; + } + channel[chan].freq += channel[chan].vibspeed; + setfreq(chan); +}
--- a/Plugins/Input/adplug/core/database.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,426 +0,0 @@ -/* - * AdPlug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (c) 1999 - 2006 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 - * - * database.cpp - AdPlug database class - * Copyright (c) 2002 Riven the Mage <riven@ok.ru> - * Copyright (c) 2002, 2003, 2006 Simon Peter <dn.tlp@gmx.net> - */ - -#include <binio.h> -#include <binfile.h> -#include <string.h> - -#include "database.h" - -#define DB_FILEID_V10 "AdPlug Module Information Database 1.0\x10" - -/***** CAdPlugDatabase *****/ - -const unsigned short CAdPlugDatabase::hash_radix = 0xfff1; // should be prime - -CAdPlugDatabase::CAdPlugDatabase() - : linear_index(0), linear_logic_length(0), linear_length(0) -{ - db_linear = new DB_Bucket * [hash_radix]; - db_hashed = new DB_Bucket * [hash_radix]; - memset(db_linear, 0, sizeof(DB_Bucket *) * hash_radix); - memset(db_hashed, 0, sizeof(DB_Bucket *) * hash_radix); -} - -CAdPlugDatabase::~CAdPlugDatabase() -{ - unsigned long i; - - for(i = 0; i < linear_length; i++) - delete db_linear[i]; - - delete [] db_linear; - delete [] db_hashed; -} - -bool CAdPlugDatabase::load(std::string db_name) -{ - binifstream f(db_name); - if(f.error()) return false; - return load(f); -} - -bool CAdPlugDatabase::load(binistream &f) -{ - unsigned int idlen = strlen(DB_FILEID_V10); - char *id = new char [idlen]; - unsigned long length; - - // Open database as little endian with IEEE floats - f.setFlag(binio::BigEndian, false); f.setFlag(binio::FloatIEEE); - - f.readString(id,idlen); - if(memcmp(id,DB_FILEID_V10,idlen)) { - delete [] id; - return false; - } - delete [] id; - length = f.readInt(4); - - // read records - for(unsigned long i = 0; i < length; i++) - insert(CRecord::factory(f)); - - return true; -} - -bool CAdPlugDatabase::save(std::string db_name) -{ - binofstream f(db_name); - if(f.error()) return false; - return save(f); -} - -bool CAdPlugDatabase::save(binostream &f) -{ - unsigned long i; - - // Save database as little endian with IEEE floats - f.setFlag(binio::BigEndian, false); f.setFlag(binio::FloatIEEE); - - f.writeString(DB_FILEID_V10); - f.writeInt(linear_logic_length, 4); - - // write records - for(i = 0; i < linear_length; i++) - if(!db_linear[i]->deleted) - db_linear[i]->record->write(f); - - return true; -} - -CAdPlugDatabase::CRecord *CAdPlugDatabase::search(CKey const &key) -{ - if(lookup(key)) return get_record(); else return 0; -} - -bool CAdPlugDatabase::lookup(CKey const &key) -{ - unsigned long index = make_hash(key); - if(!db_hashed[index]) return false; - - // immediate hit ? - DB_Bucket *bucket = db_hashed[index]; - - if(!bucket->deleted && bucket->record->key == key) { - linear_index = bucket->index; - return true; - } - - // in-chain hit ? - bucket = db_hashed[index]->chain; - - while(bucket) { - if(!bucket->deleted && bucket->record->key == key) { - linear_index = bucket->index; - return true; - } - - bucket = bucket->chain; - } - - return false; -} - -bool CAdPlugDatabase::insert(CRecord *record) -{ - long index; - - // sanity checks - if(!record) return false; // null-pointer given - if(linear_length == hash_radix) return false; // max. db size exceeded - if(lookup(record->key)) return false; // record already in db - - // make bucket - DB_Bucket *bucket = new DB_Bucket(linear_length, record); - if(!bucket) return false; - - // add to linear list - db_linear[linear_length] = bucket; - linear_logic_length++; linear_length++; - - // add to hashed list - index = make_hash(record->key); - - if(!db_hashed[index]) // First entry in hashtable - db_hashed[index] = bucket; - else { // Add entry in chained list - DB_Bucket *chain = db_hashed[index]; - - while(chain->chain) chain = chain->chain; - chain->chain = bucket; - } - - return true; -} - -void CAdPlugDatabase::wipe(CRecord *record) -{ - if(!lookup(record->key)) return; - wipe(); -} - -void CAdPlugDatabase::wipe() -{ - if(!linear_length) return; - - DB_Bucket *bucket = db_linear[linear_index]; - - if(!bucket->deleted) { - delete bucket->record; - linear_logic_length--; - bucket->deleted = true; - } -} - -CAdPlugDatabase::CRecord *CAdPlugDatabase::get_record() -{ - if(!linear_length) return 0; - return db_linear[linear_index]->record; -} - -bool CAdPlugDatabase::go_forward() -{ - if(linear_index + 1 < linear_length) { - linear_index++; - return true; - } else - return false; -} - -bool CAdPlugDatabase::go_backward() -{ - if(!linear_index) return false; - linear_index--; - return true; -} - -void CAdPlugDatabase::goto_begin() -{ - if(linear_length) linear_index = 0; -} - -void CAdPlugDatabase::goto_end() -{ - if(linear_length) linear_index = linear_length - 1; -} - -inline unsigned long CAdPlugDatabase::make_hash(CKey const &key) -{ - return (key.crc32 + key.crc16) % hash_radix; -} - -/***** CAdPlugDatabase::DB_Bucket *****/ - -CAdPlugDatabase::DB_Bucket::DB_Bucket(unsigned long nindex, CRecord *newrecord, DB_Bucket *newchain) - : index(nindex), deleted(false), chain(newchain), record(newrecord) -{ -} - -CAdPlugDatabase::DB_Bucket::~DB_Bucket() -{ - if(!deleted) delete record; -} - -/***** CAdPlugDatabase::CRecord *****/ - -CAdPlugDatabase::CRecord *CAdPlugDatabase::CRecord::factory(RecordType type) -{ - switch(type) { - case Plain: return new CPlainRecord; - case SongInfo: return new CInfoRecord; - case ClockSpeed: return new CClockRecord; - default: return 0; - } -} - -CAdPlugDatabase::CRecord *CAdPlugDatabase::CRecord::factory(binistream &in) -{ - RecordType type; - unsigned long size; - CRecord *rec; - - type = (RecordType)in.readInt(1); size = in.readInt(4); - rec = factory(type); - - if(rec) { - rec->key.crc16 = in.readInt(2); rec->key.crc32 = in.readInt(4); - rec->filetype = in.readString('\0'); rec->comment = in.readString('\0'); - rec->read_own(in); - return rec; - } else { - // skip this record, cause we don't know about it - in.seek(size, binio::Add); - return 0; - } -} - -void CAdPlugDatabase::CRecord::write(binostream &out) -{ - out.writeInt(type, 1); - out.writeInt(get_size() + filetype.length() + comment.length() + 8, 4); - out.writeInt(key.crc16, 2); out.writeInt(key.crc32, 4); - out.writeString(filetype); out.writeInt('\0', 1); - out.writeString(comment); out.writeInt('\0', 1); - - write_own(out); -} - -bool CAdPlugDatabase::CRecord::user_read(std::istream &in, std::ostream &out) -{ - return user_read_own(in, out); -} - -bool CAdPlugDatabase::CRecord::user_write(std::ostream &out) -{ - out << "Record type: "; - switch(type) { - case Plain: out << "Plain"; break; - case SongInfo: out << "SongInfo"; break; - case ClockSpeed: out << "ClockSpeed"; break; - default: out << "*** Unknown ***"; break; - } - out << std::endl; - out << "Key: " << std::hex << key.crc16 << ":" << key.crc32 << std::dec << std::endl; - out << "File type: " << filetype << std::endl; - out << "Comment: " << comment << std::endl; - - return user_write_own(out); -} - -/***** CAdPlugDatabase::CRecord::CKey *****/ - -CAdPlugDatabase::CKey::CKey(binistream &buf) -{ - make(buf); -} - -bool CAdPlugDatabase::CKey::operator==(const CKey &key) -{ - return ((crc16 == key.crc16) && (crc32 == key.crc32)); -} - -void CAdPlugDatabase::CKey::make(binistream &buf) -// Key is CRC16:CRC32 pair. CRC16 and CRC32 calculation routines (c) Zhengxi -{ - static const unsigned short magic16 = 0xa001; - static const unsigned long magic32 = 0xedb88320; - - crc16 = 0; crc32 = ~0; - - while(!buf.eof()) - { - unsigned char byte = buf.readInt(1); - - for (int j=0;j<8;j++) - { - if ((crc16 ^ byte) & 1) - crc16 = (crc16 >> 1) ^ magic16; - else - crc16 >>= 1; - - if ((crc32 ^ byte) & 1) - crc32 = (crc32 >> 1) ^ magic32; - else - crc32 >>= 1; - - byte >>= 1; - } - } - - crc16 &= 0xffff; - crc32 = ~crc32; -} - -/***** CInfoRecord *****/ - -CInfoRecord::CInfoRecord() -{ - type = SongInfo; -} - -void CInfoRecord::read_own(binistream &in) -{ - title = in.readString('\0'); - author = in.readString('\0'); -} - -void CInfoRecord::write_own(binostream &out) -{ - out.writeString(title); out.writeInt('\0', 1); - out.writeString(author); out.writeInt('\0', 1); -} - -unsigned long CInfoRecord::get_size() -{ - return title.length() + author.length() + 2; -} - -bool CInfoRecord::user_read_own(std::istream &in, std::ostream &out) -{ - out << "Title: "; in >> title; - out << "Author: "; in >> author; - return true; -} - -bool CInfoRecord::user_write_own(std::ostream &out) -{ - out << "Title: " << title << std::endl; - out << "Author: " << author << std::endl; - return true; -} - -/***** CClockRecord *****/ - -CClockRecord::CClockRecord() - : clock(0.0f) -{ - type = ClockSpeed; -} - -void CClockRecord::read_own(binistream &in) -{ - clock = in.readFloat(binio::Single); -} - -void CClockRecord::write_own(binostream &out) -{ - out.writeFloat(clock, binio::Single); -} - -unsigned long CClockRecord::get_size() -{ - return 4; -} - -bool CClockRecord::user_read_own(std::istream &in, std::ostream &out) -{ - out << "Clockspeed: "; in >> clock; - return true; -} - -bool CClockRecord::user_write_own(std::ostream &out) -{ - out << "Clock speed: " << clock << " Hz" << std::endl; - return true; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/database.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,426 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (c) 1999 - 2006 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 + * + * database.cpp - AdPlug database class + * Copyright (c) 2002 Riven the Mage <riven@ok.ru> + * Copyright (c) 2002, 2003, 2006 Simon Peter <dn.tlp@gmx.net> + */ + +#include <binio.h> +#include <binfile.h> +#include <string.h> + +#include "database.h" + +#define DB_FILEID_V10 "AdPlug Module Information Database 1.0\x10" + +/***** CAdPlugDatabase *****/ + +const unsigned short CAdPlugDatabase::hash_radix = 0xfff1; // should be prime + +CAdPlugDatabase::CAdPlugDatabase() + : linear_index(0), linear_logic_length(0), linear_length(0) +{ + db_linear = new DB_Bucket * [hash_radix]; + db_hashed = new DB_Bucket * [hash_radix]; + memset(db_linear, 0, sizeof(DB_Bucket *) * hash_radix); + memset(db_hashed, 0, sizeof(DB_Bucket *) * hash_radix); +} + +CAdPlugDatabase::~CAdPlugDatabase() +{ + unsigned long i; + + for(i = 0; i < linear_length; i++) + delete db_linear[i]; + + delete [] db_linear; + delete [] db_hashed; +} + +bool CAdPlugDatabase::load(std::string db_name) +{ + binifstream f(db_name); + if(f.error()) return false; + return load(f); +} + +bool CAdPlugDatabase::load(binistream &f) +{ + unsigned int idlen = strlen(DB_FILEID_V10); + char *id = new char [idlen]; + unsigned long length; + + // Open database as little endian with IEEE floats + f.setFlag(binio::BigEndian, false); f.setFlag(binio::FloatIEEE); + + f.readString(id,idlen); + if(memcmp(id,DB_FILEID_V10,idlen)) { + delete [] id; + return false; + } + delete [] id; + length = f.readInt(4); + + // read records + for(unsigned long i = 0; i < length; i++) + insert(CRecord::factory(f)); + + return true; +} + +bool CAdPlugDatabase::save(std::string db_name) +{ + binofstream f(db_name); + if(f.error()) return false; + return save(f); +} + +bool CAdPlugDatabase::save(binostream &f) +{ + unsigned long i; + + // Save database as little endian with IEEE floats + f.setFlag(binio::BigEndian, false); f.setFlag(binio::FloatIEEE); + + f.writeString(DB_FILEID_V10); + f.writeInt(linear_logic_length, 4); + + // write records + for(i = 0; i < linear_length; i++) + if(!db_linear[i]->deleted) + db_linear[i]->record->write(f); + + return true; +} + +CAdPlugDatabase::CRecord *CAdPlugDatabase::search(CKey const &key) +{ + if(lookup(key)) return get_record(); else return 0; +} + +bool CAdPlugDatabase::lookup(CKey const &key) +{ + unsigned long index = make_hash(key); + if(!db_hashed[index]) return false; + + // immediate hit ? + DB_Bucket *bucket = db_hashed[index]; + + if(!bucket->deleted && bucket->record->key == key) { + linear_index = bucket->index; + return true; + } + + // in-chain hit ? + bucket = db_hashed[index]->chain; + + while(bucket) { + if(!bucket->deleted && bucket->record->key == key) { + linear_index = bucket->index; + return true; + } + + bucket = bucket->chain; + } + + return false; +} + +bool CAdPlugDatabase::insert(CRecord *record) +{ + long index; + + // sanity checks + if(!record) return false; // null-pointer given + if(linear_length == hash_radix) return false; // max. db size exceeded + if(lookup(record->key)) return false; // record already in db + + // make bucket + DB_Bucket *bucket = new DB_Bucket(linear_length, record); + if(!bucket) return false; + + // add to linear list + db_linear[linear_length] = bucket; + linear_logic_length++; linear_length++; + + // add to hashed list + index = make_hash(record->key); + + if(!db_hashed[index]) // First entry in hashtable + db_hashed[index] = bucket; + else { // Add entry in chained list + DB_Bucket *chain = db_hashed[index]; + + while(chain->chain) chain = chain->chain; + chain->chain = bucket; + } + + return true; +} + +void CAdPlugDatabase::wipe(CRecord *record) +{ + if(!lookup(record->key)) return; + wipe(); +} + +void CAdPlugDatabase::wipe() +{ + if(!linear_length) return; + + DB_Bucket *bucket = db_linear[linear_index]; + + if(!bucket->deleted) { + delete bucket->record; + linear_logic_length--; + bucket->deleted = true; + } +} + +CAdPlugDatabase::CRecord *CAdPlugDatabase::get_record() +{ + if(!linear_length) return 0; + return db_linear[linear_index]->record; +} + +bool CAdPlugDatabase::go_forward() +{ + if(linear_index + 1 < linear_length) { + linear_index++; + return true; + } else + return false; +} + +bool CAdPlugDatabase::go_backward() +{ + if(!linear_index) return false; + linear_index--; + return true; +} + +void CAdPlugDatabase::goto_begin() +{ + if(linear_length) linear_index = 0; +} + +void CAdPlugDatabase::goto_end() +{ + if(linear_length) linear_index = linear_length - 1; +} + +inline unsigned long CAdPlugDatabase::make_hash(CKey const &key) +{ + return (key.crc32 + key.crc16) % hash_radix; +} + +/***** CAdPlugDatabase::DB_Bucket *****/ + +CAdPlugDatabase::DB_Bucket::DB_Bucket(unsigned long nindex, CRecord *newrecord, DB_Bucket *newchain) + : index(nindex), deleted(false), chain(newchain), record(newrecord) +{ +} + +CAdPlugDatabase::DB_Bucket::~DB_Bucket() +{ + if(!deleted) delete record; +} + +/***** CAdPlugDatabase::CRecord *****/ + +CAdPlugDatabase::CRecord *CAdPlugDatabase::CRecord::factory(RecordType type) +{ + switch(type) { + case Plain: return new CPlainRecord; + case SongInfo: return new CInfoRecord; + case ClockSpeed: return new CClockRecord; + default: return 0; + } +} + +CAdPlugDatabase::CRecord *CAdPlugDatabase::CRecord::factory(binistream &in) +{ + RecordType type; + unsigned long size; + CRecord *rec; + + type = (RecordType)in.readInt(1); size = in.readInt(4); + rec = factory(type); + + if(rec) { + rec->key.crc16 = in.readInt(2); rec->key.crc32 = in.readInt(4); + rec->filetype = in.readString('\0'); rec->comment = in.readString('\0'); + rec->read_own(in); + return rec; + } else { + // skip this record, cause we don't know about it + in.seek(size, binio::Add); + return 0; + } +} + +void CAdPlugDatabase::CRecord::write(binostream &out) +{ + out.writeInt(type, 1); + out.writeInt(get_size() + filetype.length() + comment.length() + 8, 4); + out.writeInt(key.crc16, 2); out.writeInt(key.crc32, 4); + out.writeString(filetype); out.writeInt('\0', 1); + out.writeString(comment); out.writeInt('\0', 1); + + write_own(out); +} + +bool CAdPlugDatabase::CRecord::user_read(std::istream &in, std::ostream &out) +{ + return user_read_own(in, out); +} + +bool CAdPlugDatabase::CRecord::user_write(std::ostream &out) +{ + out << "Record type: "; + switch(type) { + case Plain: out << "Plain"; break; + case SongInfo: out << "SongInfo"; break; + case ClockSpeed: out << "ClockSpeed"; break; + default: out << "*** Unknown ***"; break; + } + out << std::endl; + out << "Key: " << std::hex << key.crc16 << ":" << key.crc32 << std::dec << std::endl; + out << "File type: " << filetype << std::endl; + out << "Comment: " << comment << std::endl; + + return user_write_own(out); +} + +/***** CAdPlugDatabase::CRecord::CKey *****/ + +CAdPlugDatabase::CKey::CKey(binistream &buf) +{ + make(buf); +} + +bool CAdPlugDatabase::CKey::operator==(const CKey &key) +{ + return ((crc16 == key.crc16) && (crc32 == key.crc32)); +} + +void CAdPlugDatabase::CKey::make(binistream &buf) +// Key is CRC16:CRC32 pair. CRC16 and CRC32 calculation routines (c) Zhengxi +{ + static const unsigned short magic16 = 0xa001; + static const unsigned long magic32 = 0xedb88320; + + crc16 = 0; crc32 = ~0; + + while(!buf.eof()) + { + unsigned char byte = buf.readInt(1); + + for (int j=0;j<8;j++) + { + if ((crc16 ^ byte) & 1) + crc16 = (crc16 >> 1) ^ magic16; + else + crc16 >>= 1; + + if ((crc32 ^ byte) & 1) + crc32 = (crc32 >> 1) ^ magic32; + else + crc32 >>= 1; + + byte >>= 1; + } + } + + crc16 &= 0xffff; + crc32 = ~crc32; +} + +/***** CInfoRecord *****/ + +CInfoRecord::CInfoRecord() +{ + type = SongInfo; +} + +void CInfoRecord::read_own(binistream &in) +{ + title = in.readString('\0'); + author = in.readString('\0'); +} + +void CInfoRecord::write_own(binostream &out) +{ + out.writeString(title); out.writeInt('\0', 1); + out.writeString(author); out.writeInt('\0', 1); +} + +unsigned long CInfoRecord::get_size() +{ + return title.length() + author.length() + 2; +} + +bool CInfoRecord::user_read_own(std::istream &in, std::ostream &out) +{ + out << "Title: "; in >> title; + out << "Author: "; in >> author; + return true; +} + +bool CInfoRecord::user_write_own(std::ostream &out) +{ + out << "Title: " << title << std::endl; + out << "Author: " << author << std::endl; + return true; +} + +/***** CClockRecord *****/ + +CClockRecord::CClockRecord() + : clock(0.0f) +{ + type = ClockSpeed; +} + +void CClockRecord::read_own(binistream &in) +{ + clock = in.readFloat(binio::Single); +} + +void CClockRecord::write_own(binostream &out) +{ + out.writeFloat(clock, binio::Single); +} + +unsigned long CClockRecord::get_size() +{ + return 4; +} + +bool CClockRecord::user_read_own(std::istream &in, std::ostream &out) +{ + out << "Clockspeed: "; in >> clock; + return true; +} + +bool CClockRecord::user_write_own(std::ostream &out) +{ + out << "Clock speed: " << clock << " Hz" << std::endl; + return true; +}
--- a/Plugins/Input/adplug/core/dfm.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * 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 - * - * dfm.cpp - Digital-FM Loader by Simon Peter <dn.tlp@gmx.net> - */ - -#include <stdio.h> -#include <string.h> - -#include "dfm.h" -#include "debug.h" - -CPlayer *CdfmLoader::factory(Copl *newopl) -{ - return new CdfmLoader(newopl); -} - -bool CdfmLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - unsigned char npats,n,note,fx,c,r,param; - unsigned int i; - const unsigned char convfx[8] = {255,255,17,19,23,24,255,13}; - - // file validation - f->readString(header.id, 4); - header.hiver = f->readInt(1); header.lover = f->readInt(1); - if(strncmp(header.id,"DFM\x1a",4) || header.hiver > 1) - { fp.close(f); return false; } - - // load - restartpos = 0; flags = Standard; bpm = 0; - init_trackord(); - f->readString(songinfo, 33); - initspeed = f->readInt(1); - for(i = 0; i < 32; i++) - f->readString(instname[i], 12); - for(i = 0; i < 32; i++) { - inst[i].data[1] = f->readInt(1); - inst[i].data[2] = f->readInt(1); - inst[i].data[9] = f->readInt(1); - inst[i].data[10] = f->readInt(1); - inst[i].data[3] = f->readInt(1); - inst[i].data[4] = f->readInt(1); - inst[i].data[5] = f->readInt(1); - inst[i].data[6] = f->readInt(1); - inst[i].data[7] = f->readInt(1); - inst[i].data[8] = f->readInt(1); - inst[i].data[0] = f->readInt(1); - } - for(i = 0; i < 128; i++) order[i] = f->readInt(1); - for(i = 0; i < 128 && order[i] != 128; i++) ; length = i; - npats = f->readInt(1); - for(i = 0; i < npats; i++) { - n = f->readInt(1); - for(r = 0; r < 64; r++) - for(c = 0; c < 9; c++) { - note = f->readInt(1); - if((note & 15) == 15) - tracks[n*9+c][r].note = 127; // key off - else - tracks[n*9+c][r].note = ((note & 127) >> 4) * 12 + (note & 15); - if(note & 128) { // additional effect byte - fx = f->readInt(1); - if(fx >> 5 == 1) - tracks[n*9+c][r].inst = (fx & 31) + 1; - else { - tracks[n*9+c][r].command = convfx[fx >> 5]; - if(tracks[n*9+c][r].command == 17) { // set volume - param = fx & 31; - param = 63 - param * 2; - tracks[n*9+c][r].param1 = param >> 4; - tracks[n*9+c][r].param2 = param & 15; - } else { - tracks[n*9+c][r].param1 = (fx & 31) >> 4; - tracks[n*9+c][r].param2 = fx & 15; - } - } - } - - } - } - - fp.close(f); - rewind(0); - return true; -} - -std::string CdfmLoader::gettype() -{ - char tmpstr[20]; - - sprintf(tmpstr,"Digital-FM %d.%d",header.hiver,header.lover); - return std::string(tmpstr); -} - -float CdfmLoader::getrefresh() -{ - return 125.0f; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/dfm.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,115 @@ +/* + * 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 + * + * dfm.cpp - Digital-FM Loader by Simon Peter <dn.tlp@gmx.net> + */ + +#include <stdio.h> +#include <string.h> + +#include "dfm.h" +#include "debug.h" + +CPlayer *CdfmLoader::factory(Copl *newopl) +{ + return new CdfmLoader(newopl); +} + +bool CdfmLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + unsigned char npats,n,note,fx,c,r,param; + unsigned int i; + const unsigned char convfx[8] = {255,255,17,19,23,24,255,13}; + + // file validation + f->readString(header.id, 4); + header.hiver = f->readInt(1); header.lover = f->readInt(1); + if(strncmp(header.id,"DFM\x1a",4) || header.hiver > 1) + { fp.close(f); return false; } + + // load + restartpos = 0; flags = Standard; bpm = 0; + init_trackord(); + f->readString(songinfo, 33); + initspeed = f->readInt(1); + for(i = 0; i < 32; i++) + f->readString(instname[i], 12); + for(i = 0; i < 32; i++) { + inst[i].data[1] = f->readInt(1); + inst[i].data[2] = f->readInt(1); + inst[i].data[9] = f->readInt(1); + inst[i].data[10] = f->readInt(1); + inst[i].data[3] = f->readInt(1); + inst[i].data[4] = f->readInt(1); + inst[i].data[5] = f->readInt(1); + inst[i].data[6] = f->readInt(1); + inst[i].data[7] = f->readInt(1); + inst[i].data[8] = f->readInt(1); + inst[i].data[0] = f->readInt(1); + } + for(i = 0; i < 128; i++) order[i] = f->readInt(1); + for(i = 0; i < 128 && order[i] != 128; i++) ; length = i; + npats = f->readInt(1); + for(i = 0; i < npats; i++) { + n = f->readInt(1); + for(r = 0; r < 64; r++) + for(c = 0; c < 9; c++) { + note = f->readInt(1); + if((note & 15) == 15) + tracks[n*9+c][r].note = 127; // key off + else + tracks[n*9+c][r].note = ((note & 127) >> 4) * 12 + (note & 15); + if(note & 128) { // additional effect byte + fx = f->readInt(1); + if(fx >> 5 == 1) + tracks[n*9+c][r].inst = (fx & 31) + 1; + else { + tracks[n*9+c][r].command = convfx[fx >> 5]; + if(tracks[n*9+c][r].command == 17) { // set volume + param = fx & 31; + param = 63 - param * 2; + tracks[n*9+c][r].param1 = param >> 4; + tracks[n*9+c][r].param2 = param & 15; + } else { + tracks[n*9+c][r].param1 = (fx & 31) >> 4; + tracks[n*9+c][r].param2 = fx & 15; + } + } + } + + } + } + + fp.close(f); + rewind(0); + return true; +} + +std::string CdfmLoader::gettype() +{ + char tmpstr[20]; + + sprintf(tmpstr,"Digital-FM %d.%d",header.hiver,header.lover); + return std::string(tmpstr); +} + +float CdfmLoader::getrefresh() +{ + return 125.0f; +}
--- a/Plugins/Input/adplug/core/diskopl.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2005 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 - * - * diskopl.cpp - Disk Writer OPL, by Simon Peter <dn.tlp@gmx.net> - */ - -#include "diskopl.h" - -//static const unsigned short note_table[12] = {363,385,408,432,458,485,514,544,577,611,647,686}; -const unsigned char CDiskopl::op_table[9] = {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12}; - -CDiskopl::CDiskopl(std::string filename) - : old_freq(0.0f), del(1), nowrite(false) -{ - unsigned short clock = 0xffff; - - currType = TYPE_OPL3; - f = fopen(filename.c_str(),"wb"); - fwrite("RAWADATA",8,1,f); - fwrite(&clock,sizeof(clock),1,f); -} - -CDiskopl::~CDiskopl() -{ - fclose(f); -} - -void CDiskopl::update(CPlayer *p) -{ - unsigned short clock; - unsigned int wait; - - if(p->getrefresh() != old_freq) { - old_freq = p->getrefresh(); - del = wait = (unsigned int)(18.2f / old_freq); - clock = (unsigned short)(1192737/(old_freq*(wait+1))); - fputc(0,f); fputc(2,f); - fwrite(&clock,2,1,f); - } - if(!nowrite) { - fputc(del+1,f); - fputc(0,f); - } -} - -void CDiskopl::setchip(int n) -{ - Copl::setchip(n); - - if(!nowrite) { - fputc(currChip + 1, f); - fputc(2, f); - } -} - -void CDiskopl::write(int reg, int val) -{ - if(!nowrite) - diskwrite(reg,val); -} - -void CDiskopl::init() -{ - for (int i=0;i<9;i++) { // stop instruments - diskwrite(0xb0 + i,0); // key off - diskwrite(0x80 + op_table[i],0xff); // fastest release - } - diskwrite(0xbd,0); // clear misc. register -} - -void CDiskopl::diskwrite(int reg, int val) -{ - fputc(val,f); - fputc(reg,f); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/diskopl.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,90 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2005 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 + * + * diskopl.cpp - Disk Writer OPL, by Simon Peter <dn.tlp@gmx.net> + */ + +#include "diskopl.h" + +//static const unsigned short note_table[12] = {363,385,408,432,458,485,514,544,577,611,647,686}; +const unsigned char CDiskopl::op_table[9] = {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12}; + +CDiskopl::CDiskopl(std::string filename) + : old_freq(0.0f), del(1), nowrite(false) +{ + unsigned short clock = 0xffff; + + currType = TYPE_OPL3; + f = fopen(filename.c_str(),"wb"); + fwrite("RAWADATA",8,1,f); + fwrite(&clock,sizeof(clock),1,f); +} + +CDiskopl::~CDiskopl() +{ + fclose(f); +} + +void CDiskopl::update(CPlayer *p) +{ + unsigned short clock; + unsigned int wait; + + if(p->getrefresh() != old_freq) { + old_freq = p->getrefresh(); + del = wait = (unsigned int)(18.2f / old_freq); + clock = (unsigned short)(1192737/(old_freq*(wait+1))); + fputc(0,f); fputc(2,f); + fwrite(&clock,2,1,f); + } + if(!nowrite) { + fputc(del+1,f); + fputc(0,f); + } +} + +void CDiskopl::setchip(int n) +{ + Copl::setchip(n); + + if(!nowrite) { + fputc(currChip + 1, f); + fputc(2, f); + } +} + +void CDiskopl::write(int reg, int val) +{ + if(!nowrite) + diskwrite(reg,val); +} + +void CDiskopl::init() +{ + for (int i=0;i<9;i++) { // stop instruments + diskwrite(0xb0 + i,0); // key off + diskwrite(0x80 + op_table[i],0xff); // fastest release + } + diskwrite(0xbd,0); // clear misc. register +} + +void CDiskopl::diskwrite(int reg, int val) +{ + fputc(val,f); + fputc(reg,f); +}
--- a/Plugins/Input/adplug/core/dmo.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,403 +0,0 @@ -/* - Adplug - Replayer for many OPL2/OPL3 audio file formats. - Copyright (C) 1999 - 2004, 2006 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 - - dmo.cpp - TwinTeam loader by Riven the Mage <riven@ok.ru> -*/ -/* - NOTES: - Panning is ignored. - - A WORD ist 16 bits, a DWORD is 32 bits and a BYTE is 8 bits in this context. -*/ - -#include <string.h> -#include <binstr.h> - -#include "dmo.h" -#include "debug.h" - -#define LOWORD(l) ((l) & 0xffff) -#define HIWORD(l) ((l) >> 16) -#define LOBYTE(w) ((w) & 0xff) -#define HIBYTE(w) ((w) >> 8) - -#define ARRAY_AS_DWORD(a, i) \ -((a[i + 3] << 24) + (a[i + 2] << 16) + (a[i + 1] << 8) + a[i]) -#define ARRAY_AS_WORD(a, i) ((a[i + 1] << 8) + a[i]) - -#define CHARP_AS_WORD(p) (((*(p + 1)) << 8) + (*p)) - -/* -------- Public Methods -------------------------------- */ - -CPlayer *CdmoLoader::factory(Copl *newopl) -{ - return new CdmoLoader(newopl); -} - -bool CdmoLoader::load(const std::string &filename, const CFileProvider &fp) -{ - int i,j; - binistream *f; - - // check header - dmo_unpacker *unpacker = new dmo_unpacker; - unsigned char chkhdr[16]; - - if(!fp.extension(filename, ".dmo")) return false; - f = fp.open(filename); if(!f) return false; - - f->readString((char *)chkhdr, 16); - - if (!unpacker->decrypt(chkhdr, 16)) - { - delete unpacker; - fp.close(f); - return false; - } - - // get file size - long packed_length = fp.filesize(f); - f->seek(0); - - unsigned char *packed_module = new unsigned char [packed_length]; - - // load file - f->readString((char *)packed_module, packed_length); - fp.close(f); - - // decrypt - unpacker->decrypt(packed_module,packed_length); - - long unpacked_length = 0x2000 * ARRAY_AS_WORD(packed_module, 12); - unsigned char *module = new unsigned char [unpacked_length]; - - // unpack - if (!unpacker->unpack(packed_module+12,module,unpacked_length)) - { - delete unpacker; - delete [] packed_module; - delete [] module; - return false; - } - - delete unpacker; - delete [] packed_module; - - // "TwinTeam" - signed ? - if (memcmp(module,"TwinTeam Module File""\x0D\x0A",22)) - { - delete module; - return false; - } - - // load header - binisstream uf(module, unpacked_length); - uf.setFlag(binio::BigEndian, false); uf.setFlag(binio::FloatIEEE); - - memset(&header,0,sizeof(s3mheader)); - - uf.ignore(22); // ignore DMO header ID string - uf.readString(header.name, 28); - - uf.ignore(2); // _unk_1 - header.ordnum = uf.readInt(2); - header.insnum = uf.readInt(2); - header.patnum = uf.readInt(2); - uf.ignore(2); // _unk_2 - header.is = uf.readInt(2); - header.it = uf.readInt(2); - - memset(header.chanset,0xFF,32); - - for (i=0;i<9;i++) - header.chanset[i] = 0x10 + i; - - uf.ignore(32); // ignore panning settings for all 32 channels - - // load orders - for(i = 0; i < 256; i++) orders[i] = uf.readInt(1); - - orders[header.ordnum] = 0xFF; - - // load pattern lengths - unsigned short my_patlen[100]; - for(i = 0; i < 100; i++) my_patlen[i] = uf.readInt(2); - - // load instruments - for (i = 0; i < header.insnum; i++) - { - memset(&inst[i],0,sizeof(s3minst)); - - uf.readString(inst[i].name, 28); - - inst[i].volume = uf.readInt(1); - inst[i].dsk = uf.readInt(1); - inst[i].c2spd = uf.readInt(4); - inst[i].type = uf.readInt(1); - inst[i].d00 = uf.readInt(1); - inst[i].d01 = uf.readInt(1); - inst[i].d02 = uf.readInt(1); - inst[i].d03 = uf.readInt(1); - inst[i].d04 = uf.readInt(1); - inst[i].d05 = uf.readInt(1); - inst[i].d06 = uf.readInt(1); - inst[i].d07 = uf.readInt(1); - inst[i].d08 = uf.readInt(1); - inst[i].d09 = uf.readInt(1); - inst[i].d0a = uf.readInt(1); - /* - * Originally, riven sets d0b = d0a and ignores 1 byte in the - * stream, but i guess this was a typo, so i read it here. - */ - inst[i].d0b = uf.readInt(1); - } - - // load patterns - for (i = 0; i < header.patnum; i++) { - long cur_pos = uf.pos(); - - for (j = 0; j < 64; j++) { - while (1) { - unsigned char token = uf.readInt(1); - - if (!token) - break; - - unsigned char chan = token & 31; - - // note + instrument ? - if (token & 32) { - unsigned char bufbyte = uf.readInt(1); - - pattern[i][j][chan].note = bufbyte & 15; - pattern[i][j][chan].oct = bufbyte >> 4; - pattern[i][j][chan].instrument = uf.readInt(1); - } - - // volume ? - if (token & 64) - pattern[i][j][chan].volume = uf.readInt(1); - - // command ? - if (token & 128) { - pattern[i][j][chan].command = uf.readInt(1); - pattern[i][j][chan].info = uf.readInt(1); - } - } - } - - uf.seek(cur_pos + my_patlen[i]); - } - - delete [] module; - rewind(0); - return true; -} - -std::string CdmoLoader::gettype() -{ - return std::string("TwinTeam (packed S3M)"); -} - -std::string CdmoLoader::getauthor() -{ - /* - All available .DMO modules written by one composer. And because all .DMO - stuff was lost due to hd crash (TwinTeam guys said this), there are - never(?) be another. - */ - return std::string("Benjamin GERARDIN"); -} - -/* -------- Private Methods ------------------------------- */ - -unsigned short CdmoLoader::dmo_unpacker::brand(unsigned short range) -{ - unsigned short ax,bx,cx,dx; - - ax = LOWORD(bseed); - bx = HIWORD(bseed); - cx = ax; - ax = LOWORD(cx * 0x8405); - dx = HIWORD(cx * 0x8405); - cx <<= 3; - cx = (((HIBYTE(cx) + LOBYTE(cx)) & 0xFF) << 8) + LOBYTE(cx); - dx += cx; - dx += bx; - bx <<= 2; - dx += bx; - dx = (((HIBYTE(dx) + LOBYTE(bx)) & 0xFF) << 8) + LOBYTE(dx); - bx <<= 5; - dx = (((HIBYTE(dx) + LOBYTE(bx)) & 0xFF) << 8) + LOBYTE(dx); - ax += 1; - if (!ax) dx += 1; - - // leave it that way or amd64 might get it wrong - bseed = dx; - bseed <<= 16; - bseed += ax; - - return HIWORD(HIWORD(LOWORD(bseed) * range) + HIWORD(bseed) * range); -} - -bool CdmoLoader::dmo_unpacker::decrypt(unsigned char *buf, long len) -{ - unsigned long seed = 0; - int i; - - bseed = ARRAY_AS_DWORD(buf, 0); - - for (i=0; i < ARRAY_AS_WORD(buf, 4) + 1; i++) - seed += brand(0xffff); - - bseed = seed ^ ARRAY_AS_DWORD(buf, 6); - - if (ARRAY_AS_WORD(buf, 10) != brand(0xffff)) - return false; - - for (i=0;i<(len-12);i++) - buf[12+i] ^= brand(0x100); - - buf[len - 2] = buf[len - 1] = 0; - - return true; -} - -short CdmoLoader::dmo_unpacker::unpack_block(unsigned char *ibuf, long ilen, unsigned char *obuf) -{ - unsigned char code,par1,par2; - unsigned short ax,bx,cx; - - unsigned char *ipos = ibuf; - unsigned char *opos = obuf; - - // LZ77 child - while (ipos - ibuf < ilen) - { - code = *ipos++; - - // 00xxxxxx: copy (xxxxxx + 1) bytes - if ((code >> 6) == 0) - { - cx = (code & 0x3F) + 1; - - if(opos + cx >= oend) - return -1; - - for (int i=0;i<cx;i++) - *opos++ = *ipos++; - - continue; - } - - // 01xxxxxx xxxyyyyy: copy (Y + 3) bytes from (X + 1) - if ((code >> 6) == 1) - { - par1 = *ipos++; - - ax = ((code & 0x3F) << 3) + ((par1 & 0xE0) >> 5) + 1; - cx = (par1 & 0x1F) + 3; - - if(opos + cx >= oend) - return -1; - - for(int i=0;i<cx;i++) - *opos++ = *(opos - ax); - - continue; - } - - // 10xxxxxx xyyyzzzz: copy (Y + 3) bytes from (X + 1); copy Z bytes - if ((code >> 6) == 2) - { - int i; - - par1 = *ipos++; - - ax = ((code & 0x3F) << 1) + (par1 >> 7) + 1; - cx = ((par1 & 0x70) >> 4) + 3; - bx = par1 & 0x0F; - - if(opos + bx + cx >= oend) - return -1; - - for(i=0;i<cx;i++) - *opos++ = *(opos - ax); - - for (i=0;i<bx;i++) - *opos++ = *ipos++; - - continue; - } - - // 11xxxxxx xxxxxxxy yyyyzzzz: copy (Y + 4) from X; copy Z bytes - if ((code >> 6) == 3) - { - int i; - - par1 = *ipos++; - par2 = *ipos++; - - bx = ((code & 0x3F) << 7) + (par1 >> 1); - cx = ((par1 & 0x01) << 4) + (par2 >> 4) + 4; - ax = par2 & 0x0F; - - if(opos + ax + cx >= oend) - return -1; - - for(i=0;i<cx;i++) - *opos++ = *(opos - bx); - - for (i=0;i<ax;i++) - *opos++ = *ipos++; - - continue; - } - } - - return opos - obuf; -} - -long CdmoLoader::dmo_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf, - unsigned long outputsize) -{ - long olen = 0; - unsigned short block_count = CHARP_AS_WORD(ibuf); - - ibuf += 2; - unsigned char *block_length = ibuf; - ibuf += 2 * block_count; - - oend = obuf + outputsize; - - for (int i=0;i<block_count;i++) - { - unsigned short bul = CHARP_AS_WORD(ibuf); - - if(unpack_block(ibuf + 2,CHARP_AS_WORD(block_length) - 2,obuf) != bul) - return 0; - - obuf += bul; - olen += bul; - - ibuf += CHARP_AS_WORD(block_length); - block_length += 2; - } - - return olen; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/dmo.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,403 @@ +/* + Adplug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2004, 2006 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 + + dmo.cpp - TwinTeam loader by Riven the Mage <riven@ok.ru> +*/ +/* + NOTES: + Panning is ignored. + + A WORD ist 16 bits, a DWORD is 32 bits and a BYTE is 8 bits in this context. +*/ + +#include <string.h> +#include <binstr.h> + +#include "dmo.h" +#include "debug.h" + +#define LOWORD(l) ((l) & 0xffff) +#define HIWORD(l) ((l) >> 16) +#define LOBYTE(w) ((w) & 0xff) +#define HIBYTE(w) ((w) >> 8) + +#define ARRAY_AS_DWORD(a, i) \ +((a[i + 3] << 24) + (a[i + 2] << 16) + (a[i + 1] << 8) + a[i]) +#define ARRAY_AS_WORD(a, i) ((a[i + 1] << 8) + a[i]) + +#define CHARP_AS_WORD(p) (((*(p + 1)) << 8) + (*p)) + +/* -------- Public Methods -------------------------------- */ + +CPlayer *CdmoLoader::factory(Copl *newopl) +{ + return new CdmoLoader(newopl); +} + +bool CdmoLoader::load(const std::string &filename, const CFileProvider &fp) +{ + int i,j; + binistream *f; + + // check header + dmo_unpacker *unpacker = new dmo_unpacker; + unsigned char chkhdr[16]; + + if(!fp.extension(filename, ".dmo")) return false; + f = fp.open(filename); if(!f) return false; + + f->readString((char *)chkhdr, 16); + + if (!unpacker->decrypt(chkhdr, 16)) + { + delete unpacker; + fp.close(f); + return false; + } + + // get file size + long packed_length = fp.filesize(f); + f->seek(0); + + unsigned char *packed_module = new unsigned char [packed_length]; + + // load file + f->readString((char *)packed_module, packed_length); + fp.close(f); + + // decrypt + unpacker->decrypt(packed_module,packed_length); + + long unpacked_length = 0x2000 * ARRAY_AS_WORD(packed_module, 12); + unsigned char *module = new unsigned char [unpacked_length]; + + // unpack + if (!unpacker->unpack(packed_module+12,module,unpacked_length)) + { + delete unpacker; + delete [] packed_module; + delete [] module; + return false; + } + + delete unpacker; + delete [] packed_module; + + // "TwinTeam" - signed ? + if (memcmp(module,"TwinTeam Module File""\x0D\x0A",22)) + { + delete module; + return false; + } + + // load header + binisstream uf(module, unpacked_length); + uf.setFlag(binio::BigEndian, false); uf.setFlag(binio::FloatIEEE); + + memset(&header,0,sizeof(s3mheader)); + + uf.ignore(22); // ignore DMO header ID string + uf.readString(header.name, 28); + + uf.ignore(2); // _unk_1 + header.ordnum = uf.readInt(2); + header.insnum = uf.readInt(2); + header.patnum = uf.readInt(2); + uf.ignore(2); // _unk_2 + header.is = uf.readInt(2); + header.it = uf.readInt(2); + + memset(header.chanset,0xFF,32); + + for (i=0;i<9;i++) + header.chanset[i] = 0x10 + i; + + uf.ignore(32); // ignore panning settings for all 32 channels + + // load orders + for(i = 0; i < 256; i++) orders[i] = uf.readInt(1); + + orders[header.ordnum] = 0xFF; + + // load pattern lengths + unsigned short my_patlen[100]; + for(i = 0; i < 100; i++) my_patlen[i] = uf.readInt(2); + + // load instruments + for (i = 0; i < header.insnum; i++) + { + memset(&inst[i],0,sizeof(s3minst)); + + uf.readString(inst[i].name, 28); + + inst[i].volume = uf.readInt(1); + inst[i].dsk = uf.readInt(1); + inst[i].c2spd = uf.readInt(4); + inst[i].type = uf.readInt(1); + inst[i].d00 = uf.readInt(1); + inst[i].d01 = uf.readInt(1); + inst[i].d02 = uf.readInt(1); + inst[i].d03 = uf.readInt(1); + inst[i].d04 = uf.readInt(1); + inst[i].d05 = uf.readInt(1); + inst[i].d06 = uf.readInt(1); + inst[i].d07 = uf.readInt(1); + inst[i].d08 = uf.readInt(1); + inst[i].d09 = uf.readInt(1); + inst[i].d0a = uf.readInt(1); + /* + * Originally, riven sets d0b = d0a and ignores 1 byte in the + * stream, but i guess this was a typo, so i read it here. + */ + inst[i].d0b = uf.readInt(1); + } + + // load patterns + for (i = 0; i < header.patnum; i++) { + long cur_pos = uf.pos(); + + for (j = 0; j < 64; j++) { + while (1) { + unsigned char token = uf.readInt(1); + + if (!token) + break; + + unsigned char chan = token & 31; + + // note + instrument ? + if (token & 32) { + unsigned char bufbyte = uf.readInt(1); + + pattern[i][j][chan].note = bufbyte & 15; + pattern[i][j][chan].oct = bufbyte >> 4; + pattern[i][j][chan].instrument = uf.readInt(1); + } + + // volume ? + if (token & 64) + pattern[i][j][chan].volume = uf.readInt(1); + + // command ? + if (token & 128) { + pattern[i][j][chan].command = uf.readInt(1); + pattern[i][j][chan].info = uf.readInt(1); + } + } + } + + uf.seek(cur_pos + my_patlen[i]); + } + + delete [] module; + rewind(0); + return true; +} + +std::string CdmoLoader::gettype() +{ + return std::string("TwinTeam (packed S3M)"); +} + +std::string CdmoLoader::getauthor() +{ + /* + All available .DMO modules written by one composer. And because all .DMO + stuff was lost due to hd crash (TwinTeam guys said this), there are + never(?) be another. + */ + return std::string("Benjamin GERARDIN"); +} + +/* -------- Private Methods ------------------------------- */ + +unsigned short CdmoLoader::dmo_unpacker::brand(unsigned short range) +{ + unsigned short ax,bx,cx,dx; + + ax = LOWORD(bseed); + bx = HIWORD(bseed); + cx = ax; + ax = LOWORD(cx * 0x8405); + dx = HIWORD(cx * 0x8405); + cx <<= 3; + cx = (((HIBYTE(cx) + LOBYTE(cx)) & 0xFF) << 8) + LOBYTE(cx); + dx += cx; + dx += bx; + bx <<= 2; + dx += bx; + dx = (((HIBYTE(dx) + LOBYTE(bx)) & 0xFF) << 8) + LOBYTE(dx); + bx <<= 5; + dx = (((HIBYTE(dx) + LOBYTE(bx)) & 0xFF) << 8) + LOBYTE(dx); + ax += 1; + if (!ax) dx += 1; + + // leave it that way or amd64 might get it wrong + bseed = dx; + bseed <<= 16; + bseed += ax; + + return HIWORD(HIWORD(LOWORD(bseed) * range) + HIWORD(bseed) * range); +} + +bool CdmoLoader::dmo_unpacker::decrypt(unsigned char *buf, long len) +{ + unsigned long seed = 0; + int i; + + bseed = ARRAY_AS_DWORD(buf, 0); + + for (i=0; i < ARRAY_AS_WORD(buf, 4) + 1; i++) + seed += brand(0xffff); + + bseed = seed ^ ARRAY_AS_DWORD(buf, 6); + + if (ARRAY_AS_WORD(buf, 10) != brand(0xffff)) + return false; + + for (i=0;i<(len-12);i++) + buf[12+i] ^= brand(0x100); + + buf[len - 2] = buf[len - 1] = 0; + + return true; +} + +short CdmoLoader::dmo_unpacker::unpack_block(unsigned char *ibuf, long ilen, unsigned char *obuf) +{ + unsigned char code,par1,par2; + unsigned short ax,bx,cx; + + unsigned char *ipos = ibuf; + unsigned char *opos = obuf; + + // LZ77 child + while (ipos - ibuf < ilen) + { + code = *ipos++; + + // 00xxxxxx: copy (xxxxxx + 1) bytes + if ((code >> 6) == 0) + { + cx = (code & 0x3F) + 1; + + if(opos + cx >= oend) + return -1; + + for (int i=0;i<cx;i++) + *opos++ = *ipos++; + + continue; + } + + // 01xxxxxx xxxyyyyy: copy (Y + 3) bytes from (X + 1) + if ((code >> 6) == 1) + { + par1 = *ipos++; + + ax = ((code & 0x3F) << 3) + ((par1 & 0xE0) >> 5) + 1; + cx = (par1 & 0x1F) + 3; + + if(opos + cx >= oend) + return -1; + + for(int i=0;i<cx;i++) + *opos++ = *(opos - ax); + + continue; + } + + // 10xxxxxx xyyyzzzz: copy (Y + 3) bytes from (X + 1); copy Z bytes + if ((code >> 6) == 2) + { + int i; + + par1 = *ipos++; + + ax = ((code & 0x3F) << 1) + (par1 >> 7) + 1; + cx = ((par1 & 0x70) >> 4) + 3; + bx = par1 & 0x0F; + + if(opos + bx + cx >= oend) + return -1; + + for(i=0;i<cx;i++) + *opos++ = *(opos - ax); + + for (i=0;i<bx;i++) + *opos++ = *ipos++; + + continue; + } + + // 11xxxxxx xxxxxxxy yyyyzzzz: copy (Y + 4) from X; copy Z bytes + if ((code >> 6) == 3) + { + int i; + + par1 = *ipos++; + par2 = *ipos++; + + bx = ((code & 0x3F) << 7) + (par1 >> 1); + cx = ((par1 & 0x01) << 4) + (par2 >> 4) + 4; + ax = par2 & 0x0F; + + if(opos + ax + cx >= oend) + return -1; + + for(i=0;i<cx;i++) + *opos++ = *(opos - bx); + + for (i=0;i<ax;i++) + *opos++ = *ipos++; + + continue; + } + } + + return opos - obuf; +} + +long CdmoLoader::dmo_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf, + unsigned long outputsize) +{ + long olen = 0; + unsigned short block_count = CHARP_AS_WORD(ibuf); + + ibuf += 2; + unsigned char *block_length = ibuf; + ibuf += 2 * block_count; + + oend = obuf + outputsize; + + for (int i=0;i<block_count;i++) + { + unsigned short bul = CHARP_AS_WORD(ibuf); + + if(unpack_block(ibuf + 2,CHARP_AS_WORD(block_length) - 2,obuf) != bul) + return 0; + + obuf += bul; + olen += bul; + + ibuf += CHARP_AS_WORD(block_length); + block_length += 2; + } + + return olen; +}
--- a/Plugins/Input/adplug/core/dro.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2005 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 - * - * dro.c - DOSBox Raw OPL Player by Sjoerd van der Berg <harekiet@zophar.net> - * - * upgraded by matthew gambrell <zeromus@zeromus.org> - * - * NOTES: 3-oct-04: the DRO format is not yet finalized. beware. - */ - -#include <stdio.h> - -#include "dro.h" - -/*** public methods *************************************/ - -CPlayer *CdroPlayer::factory(Copl *newopl) -{ - return new CdroPlayer(newopl); -} - -CdroPlayer::CdroPlayer(Copl *newopl) - : CPlayer(newopl), data(0) -{ - if(opl->gettype() == Copl::TYPE_OPL2) - opl3_mode = 0; - else - opl3_mode = 1; -} - -bool CdroPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - char id[8]; - unsigned long i; - - // file validation section - f->readString(id, 8); - if(strncmp(id,"DBRAWOPL",8)) { fp.close (f); return false; } - int version = f->readInt(4); // not very useful just yet - if(version != 0x10000) { fp.close(f); return false; } - - // load section - mstotal = f->readInt(4); // Total milliseconds in file - length = f->readInt(4); // Total data bytes in file - f->ignore(1); // Type of opl data this can contain - ignored - data = new unsigned char [length]; - for (i=0;i<length;i++) - data[i]=f->readInt(1); - fp.close(f); - rewind(0); - return true; -} - -bool CdroPlayer::update() -{ - if (delay>500) { - delay-=500; - return true; - } else - delay=0; - - while (pos < length) { - unsigned char cmd = data[pos++]; - switch(cmd) { - case 0: - delay = 1 + data[pos++]; - return true; - case 1: - delay = 1 + data[pos] + (data[pos+1]<<8); - pos+=2; - return true; - case 2: - index = 0; - opl->setchip(0); - break; - case 3: - index = 1; - opl->setchip(1); - break; - default: - if(cmd==4) cmd = data[pos++]; //data override - if(index == 0 || opl3_mode) - opl->write(cmd,data[pos++]); - break; - } - } - - return pos<length; -} - -void CdroPlayer::rewind(int subsong) -{ - delay=1; - pos = index = 0; - opl->init(); - - //dro assumes all registers are initialized to 0 - //registers not initialized to 0 will be corrected - //in the data stream - for(int i=0;i<256;i++) - opl->write(i,0); - - opl->setchip(1); - for(int i=0;i<256;i++) - opl->write(i,0); - opl->setchip(0); -} - -float CdroPlayer::getrefresh() -{ - if (delay > 500) return 1000 / 500; - else return 1000 / (double)delay; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/dro.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,129 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2005 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 + * + * dro.c - DOSBox Raw OPL Player by Sjoerd van der Berg <harekiet@zophar.net> + * + * upgraded by matthew gambrell <zeromus@zeromus.org> + * + * NOTES: 3-oct-04: the DRO format is not yet finalized. beware. + */ + +#include <stdio.h> + +#include "dro.h" + +/*** public methods *************************************/ + +CPlayer *CdroPlayer::factory(Copl *newopl) +{ + return new CdroPlayer(newopl); +} + +CdroPlayer::CdroPlayer(Copl *newopl) + : CPlayer(newopl), data(0) +{ + if(opl->gettype() == Copl::TYPE_OPL2) + opl3_mode = 0; + else + opl3_mode = 1; +} + +bool CdroPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[8]; + unsigned long i; + + // file validation section + f->readString(id, 8); + if(strncmp(id,"DBRAWOPL",8)) { fp.close (f); return false; } + int version = f->readInt(4); // not very useful just yet + if(version != 0x10000) { fp.close(f); return false; } + + // load section + mstotal = f->readInt(4); // Total milliseconds in file + length = f->readInt(4); // Total data bytes in file + f->ignore(1); // Type of opl data this can contain - ignored + data = new unsigned char [length]; + for (i=0;i<length;i++) + data[i]=f->readInt(1); + fp.close(f); + rewind(0); + return true; +} + +bool CdroPlayer::update() +{ + if (delay>500) { + delay-=500; + return true; + } else + delay=0; + + while (pos < length) { + unsigned char cmd = data[pos++]; + switch(cmd) { + case 0: + delay = 1 + data[pos++]; + return true; + case 1: + delay = 1 + data[pos] + (data[pos+1]<<8); + pos+=2; + return true; + case 2: + index = 0; + opl->setchip(0); + break; + case 3: + index = 1; + opl->setchip(1); + break; + default: + if(cmd==4) cmd = data[pos++]; //data override + if(index == 0 || opl3_mode) + opl->write(cmd,data[pos++]); + break; + } + } + + return pos<length; +} + +void CdroPlayer::rewind(int subsong) +{ + delay=1; + pos = index = 0; + opl->init(); + + //dro assumes all registers are initialized to 0 + //registers not initialized to 0 will be corrected + //in the data stream + for(int i=0;i<256;i++) + opl->write(i,0); + + opl->setchip(1); + for(int i=0;i<256;i++) + opl->write(i,0); + opl->setchip(0); +} + +float CdroPlayer::getrefresh() +{ + if (delay > 500) return 1000 / 500; + else return 1000 / (double)delay; +}
--- a/Plugins/Input/adplug/core/dtm.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,317 +0,0 @@ -/* - Adplug - Replayer for many OPL2/OPL3 audio file formats. - Copyright (C) 1999 - 2006 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 - - dtm.cpp - DTM loader by Riven the Mage <riven@ok.ru> -*/ -/* - NOTE: Panning (Ex) effect is ignored. -*/ - -#include "dtm.h" - -/* -------- Public Methods -------------------------------- */ - -CPlayer *CdtmLoader::factory(Copl *newopl) -{ - return new CdtmLoader(newopl); -} - -bool CdtmLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 }; - const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE }; - - int i,j,k,t=0; - - // read header - f->readString(header.id, 12); - header.version = f->readInt(1); - f->readString(header.title, 20); f->readString(header.author, 20); - header.numpat = f->readInt(1); header.numinst = f->readInt(1); - - // signature exists ? good version ? - if(memcmp(header.id,"DeFy DTM ",9) || header.version != 0x10) - { fp.close (f); return false; } - - header.numinst++; - - // load description - memset(desc,0,80*16); - - char bufstr[80]; - - for (i=0;i<16;i++) - { - // get line length - unsigned char bufstr_length = f->readInt(1); - - if(bufstr_length > 80) { - fp.close(f); - return false; - } - - // read line - if (bufstr_length) - { - f->readString(bufstr,bufstr_length); - - for (j=0;j<bufstr_length;j++) - if (!bufstr[j]) - bufstr[j] = 0x20; - - bufstr[bufstr_length] = 0; - - strcat(desc,bufstr); - } - - strcat(desc,"\n"); - } - - // init CmodPlayer - realloc_instruments(header.numinst); - realloc_order(100); - realloc_patterns(header.numpat,64,9); - init_notetable(conv_note); - init_trackord(); - - // load instruments - for (i=0;i<header.numinst;i++) - { - unsigned char name_length = f->readInt(1); - - if (name_length) - f->readString(instruments[i].name, name_length); - - instruments[i].name[name_length] = 0; - - for(j = 0; j < 12; j++) - instruments[i].data[j] = f->readInt(1); - - for (j=0;j<11;j++) - inst[i].data[conv_inst[j]] = instruments[i].data[j]; - } - - // load order - for(i = 0; i < 100; i++) order[i] = f->readInt(1); - - nop = header.numpat; - - unsigned char *pattern = new unsigned char [0x480]; - - // load tracks - for (i=0;i<nop;i++) - { - unsigned short packed_length; - - packed_length = f->readInt(2); - - unsigned char *packed_pattern = new unsigned char [packed_length]; - - for(j = 0; j < packed_length; j++) - packed_pattern[j] = f->readInt(1); - - long unpacked_length = unpack_pattern(packed_pattern,packed_length,pattern,0x480); - - delete [] packed_pattern; - - if (!unpacked_length) - { - delete pattern; - fp.close(f); - return false; - } - - // convert pattern - for (j=0;j<9;j++) - { - for (k=0;k<64;k++) - { - dtm_event *event = (dtm_event *)&pattern[(k*9+j)*2]; - - // instrument - if (event->byte0 == 0x80) - { - if (event->byte1 <= 0x80) - tracks[t][k].inst = event->byte1 + 1; - } - - // note + effect - else - { - tracks[t][k].note = event->byte0; - - if ((event->byte0 != 0) && (event->byte0 != 127)) - tracks[t][k].note++; - - // convert effects - switch (event->byte1 >> 4) - { - case 0x0: // pattern break - if ((event->byte1 & 15) == 1) - tracks[t][k].command = 13; - break; - - case 0x1: // freq. slide up - tracks[t][k].command = 28; - tracks[t][k].param1 = event->byte1 & 15; - break; - - case 0x2: // freq. slide down - tracks[t][k].command = 28; - tracks[t][k].param2 = event->byte1 & 15; - break; - - case 0xA: // set carrier volume - case 0xC: // set instrument volume - tracks[t][k].command = 22; - tracks[t][k].param1 = (0x3F - (event->byte1 & 15)) >> 4; - tracks[t][k].param2 = (0x3F - (event->byte1 & 15)) & 15; - break; - - case 0xB: // set modulator volume - tracks[t][k].command = 21; - tracks[t][k].param1 = (0x3F - (event->byte1 & 15)) >> 4; - tracks[t][k].param2 = (0x3F - (event->byte1 & 15)) & 15; - break; - - case 0xE: // set panning - break; - - case 0xF: // set speed - tracks[t][k].command = 13; - tracks[t][k].param2 = event->byte1 & 15; - break; - } - } - } - - t++; - } - } - - delete [] pattern; - fp.close(f); - - // order length - for (i=0;i<100;i++) - { - if (order[i] >= 0x80) - { - length = i; - - if (order[i] == 0xFF) - restartpos = 0; - else - restartpos = order[i] - 0x80; - - break; - } - } - - // initial speed - initspeed = 2; - - rewind(0); - - return true; -} - -void CdtmLoader::rewind(int subsong) -{ - CmodPlayer::rewind(subsong); - - // default instruments - for (int i=0;i<9;i++) - { - channel[i].inst = i; - - channel[i].vol1 = 63 - (inst[i].data[10] & 63); - channel[i].vol2 = 63 - (inst[i].data[9] & 63); - } -} - -float CdtmLoader::getrefresh() -{ - return 18.2f; -} - -std::string CdtmLoader::gettype() -{ - return std::string("DeFy Adlib Tracker"); -} - -std::string CdtmLoader::gettitle() -{ - return std::string(header.title); -} - -std::string CdtmLoader::getauthor() -{ - return std::string(header.author); -} - -std::string CdtmLoader::getdesc() -{ - return std::string(desc); -} - -std::string CdtmLoader::getinstrument(unsigned int n) -{ - return std::string(instruments[n].name); -} - -unsigned int CdtmLoader::getinstruments() -{ - return header.numinst; -} - -/* -------- Private Methods ------------------------------- */ - -long CdtmLoader::unpack_pattern(unsigned char *ibuf, long ilen, unsigned char *obuf, long olen) -{ - unsigned char *input = ibuf; - unsigned char *output = obuf; - - long input_length = 0; - long output_length = 0; - - unsigned char repeat_byte, repeat_counter; - - // RLE - while (input_length < ilen) - { - repeat_byte = input[input_length++]; - - if ((repeat_byte & 0xF0) == 0xD0) - { - repeat_counter = repeat_byte & 15; - repeat_byte = input[input_length++]; - } - else - repeat_counter = 1; - - for (int i=0;i<repeat_counter;i++) - { - if (output_length < olen) - output[output_length++] = repeat_byte; - } - } - - return output_length; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/dtm.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,317 @@ +/* + Adplug - Replayer for many OPL2/OPL3 audio file formats. + Copyright (C) 1999 - 2006 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 + + dtm.cpp - DTM loader by Riven the Mage <riven@ok.ru> +*/ +/* + NOTE: Panning (Ex) effect is ignored. +*/ + +#include "dtm.h" + +/* -------- Public Methods -------------------------------- */ + +CPlayer *CdtmLoader::factory(Copl *newopl) +{ + return new CdtmLoader(newopl); +} + +bool CdtmLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 }; + const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE }; + + int i,j,k,t=0; + + // read header + f->readString(header.id, 12); + header.version = f->readInt(1); + f->readString(header.title, 20); f->readString(header.author, 20); + header.numpat = f->readInt(1); header.numinst = f->readInt(1); + + // signature exists ? good version ? + if(memcmp(header.id,"DeFy DTM ",9) || header.version != 0x10) + { fp.close (f); return false; } + + header.numinst++; + + // load description + memset(desc,0,80*16); + + char bufstr[80]; + + for (i=0;i<16;i++) + { + // get line length + unsigned char bufstr_length = f->readInt(1); + + if(bufstr_length > 80) { + fp.close(f); + return false; + } + + // read line + if (bufstr_length) + { + f->readString(bufstr,bufstr_length); + + for (j=0;j<bufstr_length;j++) + if (!bufstr[j]) + bufstr[j] = 0x20; + + bufstr[bufstr_length] = 0; + + strcat(desc,bufstr); + } + + strcat(desc,"\n"); + } + + // init CmodPlayer + realloc_instruments(header.numinst); + realloc_order(100); + realloc_patterns(header.numpat,64,9); + init_notetable(conv_note); + init_trackord(); + + // load instruments + for (i=0;i<header.numinst;i++) + { + unsigned char name_length = f->readInt(1); + + if (name_length) + f->readString(instruments[i].name, name_length); + + instruments[i].name[name_length] = 0; + + for(j = 0; j < 12; j++) + instruments[i].data[j] = f->readInt(1); + + for (j=0;j<11;j++) + inst[i].data[conv_inst[j]] = instruments[i].data[j]; + } + + // load order + for(i = 0; i < 100; i++) order[i] = f->readInt(1); + + nop = header.numpat; + + unsigned char *pattern = new unsigned char [0x480]; + + // load tracks + for (i=0;i<nop;i++) + { + unsigned short packed_length; + + packed_length = f->readInt(2); + + unsigned char *packed_pattern = new unsigned char [packed_length]; + + for(j = 0; j < packed_length; j++) + packed_pattern[j] = f->readInt(1); + + long unpacked_length = unpack_pattern(packed_pattern,packed_length,pattern,0x480); + + delete [] packed_pattern; + + if (!unpacked_length) + { + delete pattern; + fp.close(f); + return false; + } + + // convert pattern + for (j=0;j<9;j++) + { + for (k=0;k<64;k++) + { + dtm_event *event = (dtm_event *)&pattern[(k*9+j)*2]; + + // instrument + if (event->byte0 == 0x80) + { + if (event->byte1 <= 0x80) + tracks[t][k].inst = event->byte1 + 1; + } + + // note + effect + else + { + tracks[t][k].note = event->byte0; + + if ((event->byte0 != 0) && (event->byte0 != 127)) + tracks[t][k].note++; + + // convert effects + switch (event->byte1 >> 4) + { + case 0x0: // pattern break + if ((event->byte1 & 15) == 1) + tracks[t][k].command = 13; + break; + + case 0x1: // freq. slide up + tracks[t][k].command = 28; + tracks[t][k].param1 = event->byte1 & 15; + break; + + case 0x2: // freq. slide down + tracks[t][k].command = 28; + tracks[t][k].param2 = event->byte1 & 15; + break; + + case 0xA: // set carrier volume + case 0xC: // set instrument volume + tracks[t][k].command = 22; + tracks[t][k].param1 = (0x3F - (event->byte1 & 15)) >> 4; + tracks[t][k].param2 = (0x3F - (event->byte1 & 15)) & 15; + break; + + case 0xB: // set modulator volume + tracks[t][k].command = 21; + tracks[t][k].param1 = (0x3F - (event->byte1 & 15)) >> 4; + tracks[t][k].param2 = (0x3F - (event->byte1 & 15)) & 15; + break; + + case 0xE: // set panning + break; + + case 0xF: // set speed + tracks[t][k].command = 13; + tracks[t][k].param2 = event->byte1 & 15; + break; + } + } + } + + t++; + } + } + + delete [] pattern; + fp.close(f); + + // order length + for (i=0;i<100;i++) + { + if (order[i] >= 0x80) + { + length = i; + + if (order[i] == 0xFF) + restartpos = 0; + else + restartpos = order[i] - 0x80; + + break; + } + } + + // initial speed + initspeed = 2; + + rewind(0); + + return true; +} + +void CdtmLoader::rewind(int subsong) +{ + CmodPlayer::rewind(subsong); + + // default instruments + for (int i=0;i<9;i++) + { + channel[i].inst = i; + + channel[i].vol1 = 63 - (inst[i].data[10] & 63); + channel[i].vol2 = 63 - (inst[i].data[9] & 63); + } +} + +float CdtmLoader::getrefresh() +{ + return 18.2f; +} + +std::string CdtmLoader::gettype() +{ + return std::string("DeFy Adlib Tracker"); +} + +std::string CdtmLoader::gettitle() +{ + return std::string(header.title); +} + +std::string CdtmLoader::getauthor() +{ + return std::string(header.author); +} + +std::string CdtmLoader::getdesc() +{ + return std::string(desc); +} + +std::string CdtmLoader::getinstrument(unsigned int n) +{ + return std::string(instruments[n].name); +} + +unsigned int CdtmLoader::getinstruments() +{ + return header.numinst; +} + +/* -------- Private Methods ------------------------------- */ + +long CdtmLoader::unpack_pattern(unsigned char *ibuf, long ilen, unsigned char *obuf, long olen) +{ + unsigned char *input = ibuf; + unsigned char *output = obuf; + + long input_length = 0; + long output_length = 0; + + unsigned char repeat_byte, repeat_counter; + + // RLE + while (input_length < ilen) + { + repeat_byte = input[input_length++]; + + if ((repeat_byte & 0xF0) == 0xD0) + { + repeat_counter = repeat_byte & 15; + repeat_byte = input[input_length++]; + } + else + repeat_counter = 1; + + for (int i=0;i<repeat_counter;i++) + { + if (output_length < olen) + output[output_length++] = repeat_byte; + } + } + + return output_length; +}
--- a/Plugins/Input/adplug/core/emuopl.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +0,0 @@ -/* - * AdPlug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2005 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 - * - * emuopl.cpp - Emulated OPL, by Simon Peter <dn.tlp@gmx.net> - */ - -#include "emuopl.h" - -CEmuopl::CEmuopl(int rate, bool bit16, bool usestereo) - : use16bit(bit16), stereo(usestereo), mixbufSamples(0) -{ - opl[0] = OPLCreate(OPL_TYPE_YM3812, 3579545, rate); - opl[1] = OPLCreate(OPL_TYPE_YM3812, 3579545, rate); - - currType = TYPE_DUAL_OPL2; - - init(); -} - -CEmuopl::~CEmuopl() -{ - OPLDestroy(opl[0]); OPLDestroy(opl[1]); - - if(mixbufSamples) { - delete [] mixbuf0; - delete [] mixbuf1; - } -} - -void CEmuopl::update(short *buf, int samples) -{ - int i; - - //ensure that our mix buffers are adequately sized - if(mixbufSamples < samples) { - if(mixbufSamples) { delete[] mixbuf0; delete[] mixbuf1; } - mixbufSamples = samples; - - //*2 = make room for stereo, if we need it - mixbuf0 = new short[samples*2]; - mixbuf1 = new short[samples*2]; - } - - //data should be rendered to outbuf - //tempbuf should be used as a temporary buffer - //if we are supposed to generate 16bit output, - //then outbuf may point directly to the actual waveform output "buf" - //if we are supposed to generate 8bit output, - //then outbuf cannot point to "buf" (because there will not be enough room) - //and so it must point to a mixbuf instead-- - //it will be reduced to 8bit and put in "buf" later - short *outbuf; - short *tempbuf=mixbuf0; - short *tempbuf2=mixbuf1; - if(use16bit) outbuf = buf; - else outbuf = mixbuf1; - //...there is a potentially confusing situation where mixbuf1 can be aliased. - //beware. it is a little loony. - - //all of the following rendering code produces 16bit output - - switch(currType) { - case TYPE_OPL2: - //for opl2 mode: - //render chip0 to the output buffer - YM3812UpdateOne(opl[0],outbuf,samples); - - //if we are supposed to output stereo, - //then we need to dup the mono channel - if(stereo) - for(i=samples-1;i>=0;i--) { - outbuf[i*2] = outbuf[i]; - outbuf[i*2+1] = outbuf[i]; - } - break; - - case TYPE_OPL3: // unsupported - break; - - case TYPE_DUAL_OPL2: - //for dual opl2 mode: - //render each chip to a different tempbuffer - YM3812UpdateOne(opl[0],tempbuf2,samples); - YM3812UpdateOne(opl[1],tempbuf,samples); - - //output stereo: - //then we need to interleave the two buffers - if(stereo){ - //first, spread tempbuf's samples across left channel - //left channel - for(i=0;i<samples;i++) - outbuf[i*2] = tempbuf2[i]; - //next, insert the samples from tempbuf2 into right channel - for(i=0;i<samples;i++) - outbuf[i*2+1] = tempbuf[i]; - } else - //output mono: - //then we need to mix the two buffers into buf - for(i=0;i<samples;i++) - outbuf[i] = (tempbuf[i]>>1) + (tempbuf2[i]>>1); - break; - } - - //now reduce to 8bit if we need to - if(!use16bit) - for(i=0;i<(stereo ? samples*2 : samples);i++) - ((char *)buf)[i] = (outbuf[i] >> 8) ^ 0x80; -} - -void CEmuopl::write(int reg, int val) -{ - switch(currType){ - case TYPE_OPL2: - case TYPE_DUAL_OPL2: - OPLWrite(opl[currChip], 0, reg); - OPLWrite(opl[currChip], 1, val); - break; - case TYPE_OPL3: // unsupported - break; - } -} - -void CEmuopl::init() -{ - OPLResetChip(opl[0]); OPLResetChip(opl[1]); - currChip = 0; -} - -void CEmuopl::settype(ChipType type) -{ - currType = type; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/emuopl.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,147 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2005 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 + * + * emuopl.cpp - Emulated OPL, by Simon Peter <dn.tlp@gmx.net> + */ + +#include "emuopl.h" + +CEmuopl::CEmuopl(int rate, bool bit16, bool usestereo) + : use16bit(bit16), stereo(usestereo), mixbufSamples(0) +{ + opl[0] = OPLCreate(OPL_TYPE_YM3812, 3579545, rate); + opl[1] = OPLCreate(OPL_TYPE_YM3812, 3579545, rate); + + currType = TYPE_DUAL_OPL2; + + init(); +} + +CEmuopl::~CEmuopl() +{ + OPLDestroy(opl[0]); OPLDestroy(opl[1]); + + if(mixbufSamples) { + delete [] mixbuf0; + delete [] mixbuf1; + } +} + +void CEmuopl::update(short *buf, int samples) +{ + int i; + + //ensure that our mix buffers are adequately sized + if(mixbufSamples < samples) { + if(mixbufSamples) { delete[] mixbuf0; delete[] mixbuf1; } + mixbufSamples = samples; + + //*2 = make room for stereo, if we need it + mixbuf0 = new short[samples*2]; + mixbuf1 = new short[samples*2]; + } + + //data should be rendered to outbuf + //tempbuf should be used as a temporary buffer + //if we are supposed to generate 16bit output, + //then outbuf may point directly to the actual waveform output "buf" + //if we are supposed to generate 8bit output, + //then outbuf cannot point to "buf" (because there will not be enough room) + //and so it must point to a mixbuf instead-- + //it will be reduced to 8bit and put in "buf" later + short *outbuf; + short *tempbuf=mixbuf0; + short *tempbuf2=mixbuf1; + if(use16bit) outbuf = buf; + else outbuf = mixbuf1; + //...there is a potentially confusing situation where mixbuf1 can be aliased. + //beware. it is a little loony. + + //all of the following rendering code produces 16bit output + + switch(currType) { + case TYPE_OPL2: + //for opl2 mode: + //render chip0 to the output buffer + YM3812UpdateOne(opl[0],outbuf,samples); + + //if we are supposed to output stereo, + //then we need to dup the mono channel + if(stereo) + for(i=samples-1;i>=0;i--) { + outbuf[i*2] = outbuf[i]; + outbuf[i*2+1] = outbuf[i]; + } + break; + + case TYPE_OPL3: // unsupported + break; + + case TYPE_DUAL_OPL2: + //for dual opl2 mode: + //render each chip to a different tempbuffer + YM3812UpdateOne(opl[0],tempbuf2,samples); + YM3812UpdateOne(opl[1],tempbuf,samples); + + //output stereo: + //then we need to interleave the two buffers + if(stereo){ + //first, spread tempbuf's samples across left channel + //left channel + for(i=0;i<samples;i++) + outbuf[i*2] = tempbuf2[i]; + //next, insert the samples from tempbuf2 into right channel + for(i=0;i<samples;i++) + outbuf[i*2+1] = tempbuf[i]; + } else + //output mono: + //then we need to mix the two buffers into buf + for(i=0;i<samples;i++) + outbuf[i] = (tempbuf[i]>>1) + (tempbuf2[i]>>1); + break; + } + + //now reduce to 8bit if we need to + if(!use16bit) + for(i=0;i<(stereo ? samples*2 : samples);i++) + ((char *)buf)[i] = (outbuf[i] >> 8) ^ 0x80; +} + +void CEmuopl::write(int reg, int val) +{ + switch(currType){ + case TYPE_OPL2: + case TYPE_DUAL_OPL2: + OPLWrite(opl[currChip], 0, reg); + OPLWrite(opl[currChip], 1, val); + break; + case TYPE_OPL3: // unsupported + break; + } +} + +void CEmuopl::init() +{ + OPLResetChip(opl[0]); OPLResetChip(opl[1]); + currChip = 0; +} + +void CEmuopl::settype(ChipType type) +{ + currType = type; +}
--- a/Plugins/Input/adplug/core/flash.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,230 +0,0 @@ -/* - * 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] FLASH player, by Riven the Mage <riven@ok.ru> - */ - -/* - - discovery - - - file(s) : LA-INTRO.EXE - type : Lunatic Asylum BBStro - tune : by Rogue [Logic Design] - player : by Flash [Logic Design] -*/ - -#include "flash.h" -#include "debug.h" - -const unsigned char CxadflashPlayer::flash_adlib_registers[99] = -{ - 0x23, 0x20, 0x43, 0x40, 0x63, 0x60, 0x83, 0x80, 0xC0, 0xE3, 0xE0, - 0x24, 0x21, 0x44, 0x41, 0x64, 0x61, 0x84, 0x81, 0xC1, 0xE4, 0xE1, - 0x25, 0x22, 0x45, 0x42, 0x65, 0x62, 0x85, 0x82, 0xC2, 0xE5, 0xE2, - 0x2B, 0x28, 0x4B, 0x48, 0x6B, 0x68, 0x8B, 0x88, 0xC3, 0xEB, 0xE8, - 0x2C, 0x29, 0x4C, 0x49, 0x6C, 0x69, 0x8C, 0x89, 0xC4, 0xEC, 0xE9, - 0x2D, 0x2A, 0x4D, 0x4A, 0x6D, 0x6A, 0x8D, 0x8A, 0xC5, 0xED, 0xEA, - 0x33, 0x30, 0x53, 0x50, 0x73, 0x70, 0x93, 0x90, 0xC6, 0xF3, 0xF0, - 0x34, 0x31, 0x54, 0x51, 0x74, 0x71, 0x94, 0x91, 0xC7, 0xF4, 0xF1, - 0x35, 0x32, 0x55, 0x52, 0x75, 0x72, 0x95, 0x92, 0xC8, 0xF5, 0xF2 -}; - -const unsigned short CxadflashPlayer::flash_notes_encoded[268] = -{ - 0x000, - 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800, 0x900, 0xA00, 0xB00, 0xC00, - 0x101, 0x201, 0x301, 0x401, 0x501, 0x601, 0x701, 0x801, 0x901, 0xA01, 0xB01, 0xC01, - 0x102, 0x202, 0x302, 0x402, 0x502, 0x602, 0x702, 0x802, 0x902, 0xA02, 0xB02, 0xC02, - 0x103, 0x203, 0x303, 0x403, 0x503, 0x603, 0x703, 0x803, 0x903, 0xA03, 0xB03, 0xC03, - 0x104, 0x204, 0x304, 0x404, 0x504, 0x604, 0x704, 0x804, 0x904, 0xA04, 0xB04, 0xC04, - 0x105, 0x205, 0x305, 0x405, 0x505, 0x605, 0x705, 0x805, 0x905, 0xA05, 0xB05, 0xC05, - 0x106, 0x206, 0x306, 0x406, 0x506, 0x606, 0x706, 0x806, 0x906, 0xA06, 0xB06, 0xC06, - 0x107, 0x207, 0x307, 0x407, 0x507, 0x607, 0x707, 0x807, 0x907, 0xA07, 0xB07, 0xC07, - 0x108, 0x208, 0x308, 0x408, 0x508, 0x608, 0x708, 0x808, 0x908, 0xA08, 0xB08, 0xC08, - 0x109, 0x209, 0x309, 0x409, 0x509, 0x609, 0x709, 0x809, 0x909, 0xA09, 0xB09, 0xC09, - 0x10A, 0x20A, 0x30A, 0x40A, 0x50A, 0x60A, 0x70A, 0x80A, 0x90A, 0xA0A, 0xB0A, 0xC0A, - 0x10B, 0x20B, 0x30B, 0x40B, 0x50B, 0x60B, 0x70B, 0x80B, 0x90B, 0xA0B, 0xB0B, 0xC0B, - 0x10C, 0x20C, 0x30C, 0x40C, 0x50C, 0x60C, 0x70C, 0x80C, 0x90C, 0xA0C, 0xB0C, 0xC0C, - 0x10D, 0x20D, 0x30D, 0x40D, 0x50D, 0x60D, 0x70D, 0x80D, 0x90D, 0xA0D, 0xB0D, 0xC0D, - 0x10E, 0x20E, 0x30E, 0x40E, 0x50E, 0x60E, 0x70E, 0x80E, 0x90E, 0xA0E, 0xB0E, 0xC0E, - 0x10F, 0x20F, 0x30F, 0x40F, 0x50F, 0x60F, 0x70F, 0x80F, 0x90F, 0xA0F, 0xB0F, 0xC0F, - 0x110, 0x210, 0x310, 0x410, 0x510, 0x610, 0x710, 0x810, 0x910, 0xA10, 0xB10, 0xC10, - 0x111, 0x211, 0x311, 0x411, 0x511, 0x611, 0x711, 0x811, 0x911, 0xA11, 0xB11, 0xC11, - 0x112, 0x212, 0x312, 0x412, 0x512, 0x612, 0x712, 0x812, 0x912, 0xA12, 0xB12, 0xC12, - 0x113, 0x213, 0x313, 0x413, 0x513, 0x613, 0x713, 0x813, 0x913, 0xA13, 0xB13, 0xC13, - 0x114, 0x214, 0x314, 0x414, 0x514, 0x614, 0x714, 0x814, 0x914, 0xA14, 0xB14, 0xC14, - 0x115, 0x215, 0x315 -}; - -const unsigned short CxadflashPlayer::flash_notes[12] = -{ - 0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287 -}; - -const unsigned char CxadflashPlayer::flash_default_instrument[8] = -{ - 0x00, 0x00, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF -}; - -CPlayer *CxadflashPlayer::factory(Copl *newopl) -{ - return new CxadflashPlayer(newopl); -} - -void CxadflashPlayer::xadplayer_rewind(int subsong) -{ - int i; - - plr.speed = xad.speed; - - flash.order_pos = 0; - flash.pattern_pos = 0; - - opl_write(0x08, 0x00); - opl_write(0xBD, 0x00); - - // assign default instrument - for(i=0; i<9; i++) - { - opl_write(0xA0+i, 0x00); - opl_write(0xB0+i, 0x00); - } - - // assign instruments - for(i=0; i<9; i++) - for(int j=0; j<11; j++) - opl_write(flash_adlib_registers[i*11+j], tune[i*12+j]); -} - -void CxadflashPlayer::xadplayer_update() -{ - unsigned short event_pos = (tune[0x600+flash.order_pos]*1152) + \ - (flash.pattern_pos*18) + \ - 0x633; - - for (int i=0; i<9; i++) - { - unsigned short flash_channel_freq = (adlib[0xB0+i] << 8) + adlib[0xA0+i]; - - unsigned char event_b0 = tune[event_pos++]; - unsigned char event_b1 = tune[event_pos++]; -#ifdef DEBUG - AdPlug_LogWrite("channel %02X, event %02X %02X:\n",i+1,event_b0,event_b1); -#endif - - if (event_b0 == 0x80) // 0.0x80: Set Instrument - { - for(int j=0; j<11; j++) - opl_write(flash_adlib_registers[i*11+j], tune[event_b1*12+j]); - } - else - { - if (event_b1 == 0x01) - flash.pattern_pos = 0x3F; // 1.0x01: Pattern Break - - unsigned char fx = (event_b1 >> 4); - unsigned char fx_p = (event_b1 & 0x0F); - - switch(fx) - { - case 0x0A: // 1.0xAy: Set Carrier volume - opl_write(flash_adlib_registers[11*i+2], fx_p << 2); - break; - case 0x0B: // 1.0xBy: Set Modulator volume - opl_write(flash_adlib_registers[11*i+3], fx_p << 2); - break; - case 0x0C: // 1.0xCy: Set both operators volume - opl_write(flash_adlib_registers[11*i+2], fx_p << 2); - opl_write(flash_adlib_registers[11*i+3], fx_p << 2); - break; -// case 0x0E: // 1.0xEy: ? (increase some value) - case 0x0F: // 1.0xFy: Set Speed - plr.speed = (fx_p + 1); - break; - } - - if (event_b0) - { - // mute channel - opl_write(0xA0+i, adlib[0xA0+i]); - opl_write(0xB0+i, adlib[0xB0+i] & 0xDF); - - // is note ? - if (event_b0 != 0x7F) - { - unsigned short note_encoded = flash_notes_encoded[event_b0]; - unsigned short freq = flash_notes[(note_encoded >> 8) - 1]; - - flash_channel_freq = freq | ((note_encoded & 0xFF) << 10) | 0x2000; - - opl_write(0xA0+i, flash_channel_freq & 0xFF); - opl_write(0xB0+i, flash_channel_freq >> 8); - } - } - - if (fx == 0x01) // 1.0x1y: Fine Frequency Slide Up - { - flash_channel_freq += (fx_p << 1); - - opl_write(0xA0+i, flash_channel_freq & 0xFF); - opl_write(0xB0+i, flash_channel_freq >> 8); - } - else if (fx == 0x02) // 1.0x2y: Fine Frequency Slide Down - { - flash_channel_freq -= (fx_p << 1); - - opl_write(0xA0+i, flash_channel_freq & 0xFF); - opl_write(0xB0+i, flash_channel_freq >> 8); - } - } - } - - // next row - flash.pattern_pos++; - - // end of pattern ? - if (flash.pattern_pos >= 0x40) - { - flash.pattern_pos = 0; - - flash.order_pos++; - - // end of module ? - if (tune[0x600+flash.order_pos] == 0xFF) - { - flash.order_pos = 0; - - plr.looping = 1; - } - } -} - -float CxadflashPlayer::xadplayer_getrefresh() -{ - return 17.5f; -} - -std::string CxadflashPlayer::xadplayer_gettype() -{ - return std::string("xad: flash player"); -} - -unsigned int CxadflashPlayer::xadplayer_getinstruments() -{ - return 32; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/flash.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,230 @@ +/* + * 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] FLASH player, by Riven the Mage <riven@ok.ru> + */ + +/* + - discovery - + + file(s) : LA-INTRO.EXE + type : Lunatic Asylum BBStro + tune : by Rogue [Logic Design] + player : by Flash [Logic Design] +*/ + +#include "flash.h" +#include "debug.h" + +const unsigned char CxadflashPlayer::flash_adlib_registers[99] = +{ + 0x23, 0x20, 0x43, 0x40, 0x63, 0x60, 0x83, 0x80, 0xC0, 0xE3, 0xE0, + 0x24, 0x21, 0x44, 0x41, 0x64, 0x61, 0x84, 0x81, 0xC1, 0xE4, 0xE1, + 0x25, 0x22, 0x45, 0x42, 0x65, 0x62, 0x85, 0x82, 0xC2, 0xE5, 0xE2, + 0x2B, 0x28, 0x4B, 0x48, 0x6B, 0x68, 0x8B, 0x88, 0xC3, 0xEB, 0xE8, + 0x2C, 0x29, 0x4C, 0x49, 0x6C, 0x69, 0x8C, 0x89, 0xC4, 0xEC, 0xE9, + 0x2D, 0x2A, 0x4D, 0x4A, 0x6D, 0x6A, 0x8D, 0x8A, 0xC5, 0xED, 0xEA, + 0x33, 0x30, 0x53, 0x50, 0x73, 0x70, 0x93, 0x90, 0xC6, 0xF3, 0xF0, + 0x34, 0x31, 0x54, 0x51, 0x74, 0x71, 0x94, 0x91, 0xC7, 0xF4, 0xF1, + 0x35, 0x32, 0x55, 0x52, 0x75, 0x72, 0x95, 0x92, 0xC8, 0xF5, 0xF2 +}; + +const unsigned short CxadflashPlayer::flash_notes_encoded[268] = +{ + 0x000, + 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800, 0x900, 0xA00, 0xB00, 0xC00, + 0x101, 0x201, 0x301, 0x401, 0x501, 0x601, 0x701, 0x801, 0x901, 0xA01, 0xB01, 0xC01, + 0x102, 0x202, 0x302, 0x402, 0x502, 0x602, 0x702, 0x802, 0x902, 0xA02, 0xB02, 0xC02, + 0x103, 0x203, 0x303, 0x403, 0x503, 0x603, 0x703, 0x803, 0x903, 0xA03, 0xB03, 0xC03, + 0x104, 0x204, 0x304, 0x404, 0x504, 0x604, 0x704, 0x804, 0x904, 0xA04, 0xB04, 0xC04, + 0x105, 0x205, 0x305, 0x405, 0x505, 0x605, 0x705, 0x805, 0x905, 0xA05, 0xB05, 0xC05, + 0x106, 0x206, 0x306, 0x406, 0x506, 0x606, 0x706, 0x806, 0x906, 0xA06, 0xB06, 0xC06, + 0x107, 0x207, 0x307, 0x407, 0x507, 0x607, 0x707, 0x807, 0x907, 0xA07, 0xB07, 0xC07, + 0x108, 0x208, 0x308, 0x408, 0x508, 0x608, 0x708, 0x808, 0x908, 0xA08, 0xB08, 0xC08, + 0x109, 0x209, 0x309, 0x409, 0x509, 0x609, 0x709, 0x809, 0x909, 0xA09, 0xB09, 0xC09, + 0x10A, 0x20A, 0x30A, 0x40A, 0x50A, 0x60A, 0x70A, 0x80A, 0x90A, 0xA0A, 0xB0A, 0xC0A, + 0x10B, 0x20B, 0x30B, 0x40B, 0x50B, 0x60B, 0x70B, 0x80B, 0x90B, 0xA0B, 0xB0B, 0xC0B, + 0x10C, 0x20C, 0x30C, 0x40C, 0x50C, 0x60C, 0x70C, 0x80C, 0x90C, 0xA0C, 0xB0C, 0xC0C, + 0x10D, 0x20D, 0x30D, 0x40D, 0x50D, 0x60D, 0x70D, 0x80D, 0x90D, 0xA0D, 0xB0D, 0xC0D, + 0x10E, 0x20E, 0x30E, 0x40E, 0x50E, 0x60E, 0x70E, 0x80E, 0x90E, 0xA0E, 0xB0E, 0xC0E, + 0x10F, 0x20F, 0x30F, 0x40F, 0x50F, 0x60F, 0x70F, 0x80F, 0x90F, 0xA0F, 0xB0F, 0xC0F, + 0x110, 0x210, 0x310, 0x410, 0x510, 0x610, 0x710, 0x810, 0x910, 0xA10, 0xB10, 0xC10, + 0x111, 0x211, 0x311, 0x411, 0x511, 0x611, 0x711, 0x811, 0x911, 0xA11, 0xB11, 0xC11, + 0x112, 0x212, 0x312, 0x412, 0x512, 0x612, 0x712, 0x812, 0x912, 0xA12, 0xB12, 0xC12, + 0x113, 0x213, 0x313, 0x413, 0x513, 0x613, 0x713, 0x813, 0x913, 0xA13, 0xB13, 0xC13, + 0x114, 0x214, 0x314, 0x414, 0x514, 0x614, 0x714, 0x814, 0x914, 0xA14, 0xB14, 0xC14, + 0x115, 0x215, 0x315 +}; + +const unsigned short CxadflashPlayer::flash_notes[12] = +{ + 0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287 +}; + +const unsigned char CxadflashPlayer::flash_default_instrument[8] = +{ + 0x00, 0x00, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF +}; + +CPlayer *CxadflashPlayer::factory(Copl *newopl) +{ + return new CxadflashPlayer(newopl); +} + +void CxadflashPlayer::xadplayer_rewind(int subsong) +{ + int i; + + plr.speed = xad.speed; + + flash.order_pos = 0; + flash.pattern_pos = 0; + + opl_write(0x08, 0x00); + opl_write(0xBD, 0x00); + + // assign default instrument + for(i=0; i<9; i++) + { + opl_write(0xA0+i, 0x00); + opl_write(0xB0+i, 0x00); + } + + // assign instruments + for(i=0; i<9; i++) + for(int j=0; j<11; j++) + opl_write(flash_adlib_registers[i*11+j], tune[i*12+j]); +} + +void CxadflashPlayer::xadplayer_update() +{ + unsigned short event_pos = (tune[0x600+flash.order_pos]*1152) + \ + (flash.pattern_pos*18) + \ + 0x633; + + for (int i=0; i<9; i++) + { + unsigned short flash_channel_freq = (adlib[0xB0+i] << 8) + adlib[0xA0+i]; + + unsigned char event_b0 = tune[event_pos++]; + unsigned char event_b1 = tune[event_pos++]; +#ifdef DEBUG + AdPlug_LogWrite("channel %02X, event %02X %02X:\n",i+1,event_b0,event_b1); +#endif + + if (event_b0 == 0x80) // 0.0x80: Set Instrument + { + for(int j=0; j<11; j++) + opl_write(flash_adlib_registers[i*11+j], tune[event_b1*12+j]); + } + else + { + if (event_b1 == 0x01) + flash.pattern_pos = 0x3F; // 1.0x01: Pattern Break + + unsigned char fx = (event_b1 >> 4); + unsigned char fx_p = (event_b1 & 0x0F); + + switch(fx) + { + case 0x0A: // 1.0xAy: Set Carrier volume + opl_write(flash_adlib_registers[11*i+2], fx_p << 2); + break; + case 0x0B: // 1.0xBy: Set Modulator volume + opl_write(flash_adlib_registers[11*i+3], fx_p << 2); + break; + case 0x0C: // 1.0xCy: Set both operators volume + opl_write(flash_adlib_registers[11*i+2], fx_p << 2); + opl_write(flash_adlib_registers[11*i+3], fx_p << 2); + break; +// case 0x0E: // 1.0xEy: ? (increase some value) + case 0x0F: // 1.0xFy: Set Speed + plr.speed = (fx_p + 1); + break; + } + + if (event_b0) + { + // mute channel + opl_write(0xA0+i, adlib[0xA0+i]); + opl_write(0xB0+i, adlib[0xB0+i] & 0xDF); + + // is note ? + if (event_b0 != 0x7F) + { + unsigned short note_encoded = flash_notes_encoded[event_b0]; + unsigned short freq = flash_notes[(note_encoded >> 8) - 1]; + + flash_channel_freq = freq | ((note_encoded & 0xFF) << 10) | 0x2000; + + opl_write(0xA0+i, flash_channel_freq & 0xFF); + opl_write(0xB0+i, flash_channel_freq >> 8); + } + } + + if (fx == 0x01) // 1.0x1y: Fine Frequency Slide Up + { + flash_channel_freq += (fx_p << 1); + + opl_write(0xA0+i, flash_channel_freq & 0xFF); + opl_write(0xB0+i, flash_channel_freq >> 8); + } + else if (fx == 0x02) // 1.0x2y: Fine Frequency Slide Down + { + flash_channel_freq -= (fx_p << 1); + + opl_write(0xA0+i, flash_channel_freq & 0xFF); + opl_write(0xB0+i, flash_channel_freq >> 8); + } + } + } + + // next row + flash.pattern_pos++; + + // end of pattern ? + if (flash.pattern_pos >= 0x40) + { + flash.pattern_pos = 0; + + flash.order_pos++; + + // end of module ? + if (tune[0x600+flash.order_pos] == 0xFF) + { + flash.order_pos = 0; + + plr.looping = 1; + } + } +} + +float CxadflashPlayer::xadplayer_getrefresh() +{ + return 17.5f; +} + +std::string CxadflashPlayer::xadplayer_gettype() +{ + return std::string("xad: flash player"); +} + +unsigned int CxadflashPlayer::xadplayer_getinstruments() +{ + return 32; +}
--- a/Plugins/Input/adplug/core/fmc.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,223 +0,0 @@ -/* - 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 - - fmc.cpp - FMC Loader by Riven the Mage <riven@ok.ru> -*/ - -#include "fmc.h" - -/* -------- Public Methods -------------------------------- */ - -CPlayer *CfmcLoader::factory(Copl *newopl) -{ - return new CfmcLoader(newopl); -} - -bool CfmcLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - const unsigned char conv_fx[16] = {0,1,2,3,4,8,255,255,255,255,26,11,12,13,14,15}; - - int i,j,k,t=0; - - // read header - f->readString(header.id, 4); - f->readString(header.title, 21); - header.numchan = f->readInt(1); - - // 'FMC!' - signed ? - if (strncmp(header.id,"FMC!",4)) { fp.close(f); return false; } - - // init CmodPlayer - realloc_instruments(32); - realloc_order(256); - realloc_patterns(64,64,header.numchan); - init_trackord(); - - // load order - for(i = 0; i < 256; i++) order[i] = f->readInt(1); - - f->ignore(2); - - // load instruments - for(i = 0; i < 32; i++) { - instruments[i].synthesis = f->readInt(1); - instruments[i].feedback = f->readInt(1); - - instruments[i].mod_attack = f->readInt(1); - instruments[i].mod_decay = f->readInt(1); - instruments[i].mod_sustain = f->readInt(1); - instruments[i].mod_release = f->readInt(1); - instruments[i].mod_volume = f->readInt(1); - instruments[i].mod_ksl = f->readInt(1); - instruments[i].mod_freq_multi = f->readInt(1); - instruments[i].mod_waveform = f->readInt(1); - instruments[i].mod_sustain_sound = f->readInt(1); - instruments[i].mod_ksr = f->readInt(1); - instruments[i].mod_vibrato = f->readInt(1); - instruments[i].mod_tremolo = f->readInt(1); - - instruments[i].car_attack = f->readInt(1); - instruments[i].car_decay = f->readInt(1); - instruments[i].car_sustain = f->readInt(1); - instruments[i].car_release = f->readInt(1); - instruments[i].car_volume = f->readInt(1); - instruments[i].car_ksl = f->readInt(1); - instruments[i].car_freq_multi = f->readInt(1); - instruments[i].car_waveform = f->readInt(1); - instruments[i].car_sustain_sound = f->readInt(1); - instruments[i].car_ksr = f->readInt(1); - instruments[i].car_vibrato = f->readInt(1); - instruments[i].car_tremolo = f->readInt(1); - - instruments[i].pitch_shift = f->readInt(1); - - f->readString(instruments[i].name, 21); - } - - // load tracks - for (i=0;i<64;i++) - { - if(f->ateof()) break; - - for (j=0;j<header.numchan;j++) - { - for (k=0;k<64;k++) - { - fmc_event event; - - // read event - event.byte0 = f->readInt(1); - event.byte1 = f->readInt(1); - event.byte2 = f->readInt(1); - - // convert event - tracks[t][k].note = event.byte0 & 0x7F; - tracks[t][k].inst = ((event.byte0 & 0x80) >> 3) + (event.byte1 >> 4) + 1; - tracks[t][k].command = conv_fx[event.byte1 & 0x0F]; - tracks[t][k].param1 = event.byte2 >> 4; - tracks[t][k].param2 = event.byte2 & 0x0F; - - // fix effects - if (tracks[t][k].command == 0x0E) // 0x0E (14): Retrig - tracks[t][k].param1 = 3; - if (tracks[t][k].command == 0x1A) // 0x1A (26): Volume Slide - if (tracks[t][k].param1 > tracks[t][k].param2) - { - tracks[t][k].param1 -= tracks[t][k].param2; - tracks[t][k].param2 = 0; - } - else - { - tracks[t][k].param2 -= tracks[t][k].param1; - tracks[t][k].param1 = 0; - } - } - - t++; - } - } - fp.close(f); - - // convert instruments - for (i=0;i<31;i++) - buildinst(i); - - // order length - for (i=0;i<256;i++) - { - if (order[i] >= 0xFE) - { - length = i; - break; - } - } - - // data for Protracker - activechan = (0xffff >> (16 - header.numchan)) << (16 - header.numchan); - nop = t / header.numchan; - restartpos = 0; - - // flags - flags = Faust; - - rewind(0); - - return true; -} - -float CfmcLoader::getrefresh() -{ - return 50.0f; -} - -std::string CfmcLoader::gettype() -{ - return std::string("Faust Music Creator"); -} - -std::string CfmcLoader::gettitle() -{ - return std::string(header.title); -} - -std::string CfmcLoader::getinstrument(unsigned int n) -{ - return std::string(instruments[n].name); -} - -unsigned int CfmcLoader::getinstruments() -{ - return 32; -} - -/* -------- Private Methods ------------------------------- */ - -void CfmcLoader::buildinst(unsigned char i) -{ - inst[i].data[0] = ((instruments[i].synthesis & 1) ^ 1); - inst[i].data[0] |= ((instruments[i].feedback & 7) << 1); - - inst[i].data[3] = ((instruments[i].mod_attack & 15) << 4); - inst[i].data[3] |= (instruments[i].mod_decay & 15); - inst[i].data[5] = ((15 - (instruments[i].mod_sustain & 15)) << 4); - inst[i].data[5] |= (instruments[i].mod_release & 15); - inst[i].data[9] = (63 - (instruments[i].mod_volume & 63)); - inst[i].data[9] |= ((instruments[i].mod_ksl & 3) << 6); - inst[i].data[1] = (instruments[i].mod_freq_multi & 15); - inst[i].data[7] = (instruments[i].mod_waveform & 3); - inst[i].data[1] |= ((instruments[i].mod_sustain_sound & 1) << 5); - inst[i].data[1] |= ((instruments[i].mod_ksr & 1) << 4); - inst[i].data[1] |= ((instruments[i].mod_vibrato & 1) << 6); - inst[i].data[1] |= ((instruments[i].mod_tremolo & 1) << 7); - - inst[i].data[4] = ((instruments[i].car_attack & 15) << 4); - inst[i].data[4] |= (instruments[i].car_decay & 15); - inst[i].data[6] = ((15 - (instruments[i].car_sustain & 15)) << 4); - inst[i].data[6] |= (instruments[i].car_release & 15); - inst[i].data[10] = (63 - (instruments[i].car_volume & 63)); - inst[i].data[10] |= ((instruments[i].car_ksl & 3) << 6); - inst[i].data[2] = (instruments[i].car_freq_multi & 15); - inst[i].data[8] = (instruments[i].car_waveform & 3); - inst[i].data[2] |= ((instruments[i].car_sustain_sound & 1) << 5); - inst[i].data[2] |= ((instruments[i].car_ksr & 1) << 4); - inst[i].data[2] |= ((instruments[i].car_vibrato & 1) << 6); - inst[i].data[2] |= ((instruments[i].car_tremolo & 1) << 7); - - inst[i].slide = instruments[i].pitch_shift; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/fmc.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,223 @@ +/* + 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 + + fmc.cpp - FMC Loader by Riven the Mage <riven@ok.ru> +*/ + +#include "fmc.h" + +/* -------- Public Methods -------------------------------- */ + +CPlayer *CfmcLoader::factory(Copl *newopl) +{ + return new CfmcLoader(newopl); +} + +bool CfmcLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + const unsigned char conv_fx[16] = {0,1,2,3,4,8,255,255,255,255,26,11,12,13,14,15}; + + int i,j,k,t=0; + + // read header + f->readString(header.id, 4); + f->readString(header.title, 21); + header.numchan = f->readInt(1); + + // 'FMC!' - signed ? + if (strncmp(header.id,"FMC!",4)) { fp.close(f); return false; } + + // init CmodPlayer + realloc_instruments(32); + realloc_order(256); + realloc_patterns(64,64,header.numchan); + init_trackord(); + + // load order + for(i = 0; i < 256; i++) order[i] = f->readInt(1); + + f->ignore(2); + + // load instruments + for(i = 0; i < 32; i++) { + instruments[i].synthesis = f->readInt(1); + instruments[i].feedback = f->readInt(1); + + instruments[i].mod_attack = f->readInt(1); + instruments[i].mod_decay = f->readInt(1); + instruments[i].mod_sustain = f->readInt(1); + instruments[i].mod_release = f->readInt(1); + instruments[i].mod_volume = f->readInt(1); + instruments[i].mod_ksl = f->readInt(1); + instruments[i].mod_freq_multi = f->readInt(1); + instruments[i].mod_waveform = f->readInt(1); + instruments[i].mod_sustain_sound = f->readInt(1); + instruments[i].mod_ksr = f->readInt(1); + instruments[i].mod_vibrato = f->readInt(1); + instruments[i].mod_tremolo = f->readInt(1); + + instruments[i].car_attack = f->readInt(1); + instruments[i].car_decay = f->readInt(1); + instruments[i].car_sustain = f->readInt(1); + instruments[i].car_release = f->readInt(1); + instruments[i].car_volume = f->readInt(1); + instruments[i].car_ksl = f->readInt(1); + instruments[i].car_freq_multi = f->readInt(1); + instruments[i].car_waveform = f->readInt(1); + instruments[i].car_sustain_sound = f->readInt(1); + instruments[i].car_ksr = f->readInt(1); + instruments[i].car_vibrato = f->readInt(1); + instruments[i].car_tremolo = f->readInt(1); + + instruments[i].pitch_shift = f->readInt(1); + + f->readString(instruments[i].name, 21); + } + + // load tracks + for (i=0;i<64;i++) + { + if(f->ateof()) break; + + for (j=0;j<header.numchan;j++) + { + for (k=0;k<64;k++) + { + fmc_event event; + + // read event + event.byte0 = f->readInt(1); + event.byte1 = f->readInt(1); + event.byte2 = f->readInt(1); + + // convert event + tracks[t][k].note = event.byte0 & 0x7F; + tracks[t][k].inst = ((event.byte0 & 0x80) >> 3) + (event.byte1 >> 4) + 1; + tracks[t][k].command = conv_fx[event.byte1 & 0x0F]; + tracks[t][k].param1 = event.byte2 >> 4; + tracks[t][k].param2 = event.byte2 & 0x0F; + + // fix effects + if (tracks[t][k].command == 0x0E) // 0x0E (14): Retrig + tracks[t][k].param1 = 3; + if (tracks[t][k].command == 0x1A) // 0x1A (26): Volume Slide + if (tracks[t][k].param1 > tracks[t][k].param2) + { + tracks[t][k].param1 -= tracks[t][k].param2; + tracks[t][k].param2 = 0; + } + else + { + tracks[t][k].param2 -= tracks[t][k].param1; + tracks[t][k].param1 = 0; + } + } + + t++; + } + } + fp.close(f); + + // convert instruments + for (i=0;i<31;i++) + buildinst(i); + + // order length + for (i=0;i<256;i++) + { + if (order[i] >= 0xFE) + { + length = i; + break; + } + } + + // data for Protracker + activechan = (0xffff >> (16 - header.numchan)) << (16 - header.numchan); + nop = t / header.numchan; + restartpos = 0; + + // flags + flags = Faust; + + rewind(0); + + return true; +} + +float CfmcLoader::getrefresh() +{ + return 50.0f; +} + +std::string CfmcLoader::gettype() +{ + return std::string("Faust Music Creator"); +} + +std::string CfmcLoader::gettitle() +{ + return std::string(header.title); +} + +std::string CfmcLoader::getinstrument(unsigned int n) +{ + return std::string(instruments[n].name); +} + +unsigned int CfmcLoader::getinstruments() +{ + return 32; +} + +/* -------- Private Methods ------------------------------- */ + +void CfmcLoader::buildinst(unsigned char i) +{ + inst[i].data[0] = ((instruments[i].synthesis & 1) ^ 1); + inst[i].data[0] |= ((instruments[i].feedback & 7) << 1); + + inst[i].data[3] = ((instruments[i].mod_attack & 15) << 4); + inst[i].data[3] |= (instruments[i].mod_decay & 15); + inst[i].data[5] = ((15 - (instruments[i].mod_sustain & 15)) << 4); + inst[i].data[5] |= (instruments[i].mod_release & 15); + inst[i].data[9] = (63 - (instruments[i].mod_volume & 63)); + inst[i].data[9] |= ((instruments[i].mod_ksl & 3) << 6); + inst[i].data[1] = (instruments[i].mod_freq_multi & 15); + inst[i].data[7] = (instruments[i].mod_waveform & 3); + inst[i].data[1] |= ((instruments[i].mod_sustain_sound & 1) << 5); + inst[i].data[1] |= ((instruments[i].mod_ksr & 1) << 4); + inst[i].data[1] |= ((instruments[i].mod_vibrato & 1) << 6); + inst[i].data[1] |= ((instruments[i].mod_tremolo & 1) << 7); + + inst[i].data[4] = ((instruments[i].car_attack & 15) << 4); + inst[i].data[4] |= (instruments[i].car_decay & 15); + inst[i].data[6] = ((15 - (instruments[i].car_sustain & 15)) << 4); + inst[i].data[6] |= (instruments[i].car_release & 15); + inst[i].data[10] = (63 - (instruments[i].car_volume & 63)); + inst[i].data[10] |= ((instruments[i].car_ksl & 3) << 6); + inst[i].data[2] = (instruments[i].car_freq_multi & 15); + inst[i].data[8] = (instruments[i].car_waveform & 3); + inst[i].data[2] |= ((instruments[i].car_sustain_sound & 1) << 5); + inst[i].data[2] |= ((instruments[i].car_ksr & 1) << 4); + inst[i].data[2] |= ((instruments[i].car_vibrato & 1) << 6); + inst[i].data[2] |= ((instruments[i].car_tremolo & 1) << 7); + + inst[i].slide = instruments[i].pitch_shift; +}
--- a/Plugins/Input/adplug/core/fprovide.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2002 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 - * - * fprovide.cpp - File provider class framework, by Simon Peter <dn.tlp@gmx.net> - */ - -#include <string.h> -#include <binio.h> -#include <binfile.h> - -#include "fprovide.h" - -/***** CFileProvider *****/ - -bool CFileProvider::extension(const std::string &filename, - const std::string &extension) -{ - const char *fname = filename.c_str(), *ext = extension.c_str(); - - if(strlen(fname) < strlen(ext) || - stricmp(fname + strlen(fname) - strlen(ext), ext)) - return false; - else - return true; -} - -unsigned long CFileProvider::filesize(binistream *f) -{ - unsigned long oldpos = f->pos(), size; - - f->seek(0, binio::End); - size = f->pos(); - f->seek(oldpos, binio::Set); - - return size; -} - -/***** CProvider_Filesystem *****/ - -binistream *CProvider_Filesystem::open(std::string filename) const -{ - binifstream *f = new binifstream(filename); - - if(!f) return 0; - if(f->error()) { delete f; return 0; } - - // Open all files as little endian with IEEE floats by default - f->setFlag(binio::BigEndian, false); f->setFlag(binio::FloatIEEE); - - return f; -} - -void CProvider_Filesystem::close(binistream *f) const -{ - binifstream *ff = (binifstream *)f; - - if(f) { - ff->close(); - delete ff; - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/fprovide.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,76 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 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 + * + * fprovide.cpp - File provider class framework, by Simon Peter <dn.tlp@gmx.net> + */ + +#include <string.h> +#include <binio.h> +#include <binfile.h> + +#include "fprovide.h" + +/***** CFileProvider *****/ + +bool CFileProvider::extension(const std::string &filename, + const std::string &extension) +{ + const char *fname = filename.c_str(), *ext = extension.c_str(); + + if(strlen(fname) < strlen(ext) || + stricmp(fname + strlen(fname) - strlen(ext), ext)) + return false; + else + return true; +} + +unsigned long CFileProvider::filesize(binistream *f) +{ + unsigned long oldpos = f->pos(), size; + + f->seek(0, binio::End); + size = f->pos(); + f->seek(oldpos, binio::Set); + + return size; +} + +/***** CProvider_Filesystem *****/ + +binistream *CProvider_Filesystem::open(std::string filename) const +{ + binifstream *f = new binifstream(filename); + + if(!f) return 0; + if(f->error()) { delete f; return 0; } + + // Open all files as little endian with IEEE floats by default + f->setFlag(binio::BigEndian, false); f->setFlag(binio::FloatIEEE); + + return f; +} + +void CProvider_Filesystem::close(binistream *f) const +{ + binifstream *ff = (binifstream *)f; + + if(f) { + ff->close(); + delete ff; + } +}
--- a/Plugins/Input/adplug/core/hsc.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,317 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2004 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 - * - * hsc.cpp - HSC Player by Simon Peter <dn.tlp@gmx.net> - */ - -#include <string.h> - -#include "hsc.h" -#include "debug.h" - -/*** public methods **************************************/ - -CPlayer *ChscPlayer::factory(Copl *newopl) -{ - return new ChscPlayer(newopl); -} - -bool ChscPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); - int i; - - // file validation section - if(!f || !fp.extension(filename, ".hsc") || fp.filesize(f) > 59187) { - AdPlug_LogWrite("ChscPlayer::load(\"%s\"): Not a HSC file!\n", filename.c_str()); - fp.close(f); - return false; - } - - // load section - for(i=0;i<128*12;i++) // load instruments - *((unsigned char *)instr + i) = f->readInt(1); - for (i=0;i<128;i++) { // correct instruments - instr[i][2] ^= (instr[i][2] & 0x40) << 1; - instr[i][3] ^= (instr[i][3] & 0x40) << 1; - instr[i][11] >>= 4; // slide - } - for(i=0;i<51;i++) song[i] = f->readInt(1); // load tracklist - for(i=0;i<50*64*9;i++) // load patterns - *((char *)patterns + i) = f->readInt(1); - - fp.close(f); - rewind(0); // rewind module - return true; -} - -bool ChscPlayer::update() -{ - // general vars - unsigned char chan,pattnr,note,effect,eff_op,inst,vol,Okt,db; - unsigned short Fnr; - unsigned long pattoff; - - del--; // player speed handling - if(del) - return !songend; // nothing done - - if(fadein) // fade-in handling - fadein--; - - pattnr = song[songpos]; - if(pattnr == 0xff) { // arrangement handling - songend = 1; // set end-flag - songpos = 0; - pattnr = song[songpos]; - } else - if ((pattnr & 128) && (pattnr <= 0xb1)) { // goto pattern "nr" - songpos = song[songpos] & 127; - pattpos = 0; - pattnr = song[songpos]; - songend = 1; - } - - pattoff = pattpos*9; - for (chan=0;chan<9;chan++) { // handle all channels - note = patterns[pattnr][pattoff].note; - effect = patterns[pattnr][pattoff].effect; - pattoff++; - - if(note & 128) { // set instrument - setinstr(chan,effect); - continue; - } - eff_op = effect & 0x0f; - inst = channel[chan].inst; - if(note) - channel[chan].slide = 0; - - switch (effect & 0xf0) { // effect handling - case 0: // global effect - /* The following fx are unimplemented on purpose: - * 02 - Slide Mainvolume up - * 03 - Slide Mainvolume down (here: fade in) - * 04 - Set Mainvolume to 0 - * - * This is because i've never seen any HSC modules using the fx this way. - * All modules use the fx the way, i've implemented it. - */ - switch(eff_op) { - case 1: pattbreak++; break; // jump to next pattern - case 3: fadein = 31; break; // fade in (divided by 2) - case 5: mode6 = 1; break; // 6 voice mode on - case 6: mode6 = 0; break; // 6 voice mode off - } - break; - case 0x20: - case 0x10: // manual slides - if (effect & 0x10) { - channel[chan].freq += eff_op; - channel[chan].slide += eff_op; - } else { - channel[chan].freq -= eff_op; - channel[chan].slide -= eff_op; - } - if(!note) - setfreq(chan,channel[chan].freq); - break; - case 0x50: // set percussion instrument (unimplemented) - break; - case 0x60: // set feedback - opl->write(0xc0 + chan, (instr[channel[chan].inst][8] & 1) + (eff_op << 1)); - break; - case 0xa0: // set carrier volume - vol = eff_op << 2; - opl->write(0x43 + op_table[chan], vol | (instr[channel[chan].inst][2] & ~63)); - break; - case 0xb0: // set modulator volume - vol = eff_op << 2; - if (instr[inst][8] & 1) - opl->write(0x40 + op_table[chan], vol | (instr[channel[chan].inst][3] & ~63)); - else - opl->write(0x40 + op_table[chan],vol | (instr[inst][3] & ~63)); - break; - case 0xc0: // set instrument volume - db = eff_op << 2; - opl->write(0x43 + op_table[chan], db | (instr[channel[chan].inst][2] & ~63)); - if (instr[inst][8] & 1) - opl->write(0x40 + op_table[chan], db | (instr[channel[chan].inst][3] & ~63)); - break; - case 0xd0: pattbreak++; songpos = eff_op; songend = 1; break; // position jump - case 0xf0: // set speed - speed = eff_op; - del = ++speed; - break; - } - - if(fadein) // fade-in volume setting - setvolume(chan,fadein*2,fadein*2); - - if(!note) // note handling - continue; - note--; - - if ((note == 0x7f-1) || ((note/12) & ~7)) { // pause (7fh) - adl_freq[chan] &= ~32; - opl->write(0xb0 + chan,adl_freq[chan]); - continue; - } - - // play the note - if(mtkmode) // imitate MPU-401 Trakker bug - note--; - Okt = ((note/12) & 7) << 2; - Fnr = note_table[(note % 12)] + instr[inst][11] + channel[chan].slide; - channel[chan].freq = Fnr; - if(!mode6 || chan < 6) - adl_freq[chan] = Okt | 32; - else - adl_freq[chan] = Okt; // never set key for drums - opl->write(0xb0 + chan, 0); - setfreq(chan,Fnr); - if(mode6) { - switch(chan) { // play drums - case 6: opl->write(0xbd,bd & ~16); bd |= 48; break; // bass drum - case 7: opl->write(0xbd,bd & ~1); bd |= 33; break; // hihat - case 8: opl->write(0xbd,bd & ~2); bd |= 34; break; // cymbal - } - opl->write(0xbd,bd); - } - } - - del = speed; // player speed-timing - if(pattbreak) { // do post-effect handling - pattpos=0; // pattern break! - pattbreak=0; - songpos++; - songpos %= 50; - if(!songpos) - songend = 1; - } else { - pattpos++; - pattpos &= 63; // advance in pattern data - if (!pattpos) { - songpos++; - songpos %= 50; - if(!songpos) - songend = 1; - } - } - return !songend; // still playing -} - -void ChscPlayer::rewind(int subsong) -{ - int i; // counter - - // rewind HSC player - pattpos = 0; songpos = 0; pattbreak = 0; speed = 2; - del = 1; songend = 0; mode6 = 0; bd = 0; fadein = 0; - - opl->init(); // reset OPL chip - opl->write(1,32); opl->write(8,128); opl->write(0xbd,0); - - for(i=0;i<9;i++) - setinstr((char) i,(char) i); // init channels -} - -unsigned int ChscPlayer::getpatterns() -{ - unsigned char poscnt,pattcnt=0; - - // count patterns - for(poscnt=0;poscnt<51 && song[poscnt] != 0xff;poscnt++) - if(song[poscnt] > pattcnt) - pattcnt = song[poscnt]; - - return (pattcnt+1); -} - -unsigned int ChscPlayer::getorders() -{ - unsigned char poscnt; - - // count positions - for(poscnt=0;poscnt<51;poscnt++) - if(song[poscnt] == 0xff) - break; - - return poscnt; -} - -unsigned int ChscPlayer::getinstruments() -{ - unsigned char instcnt,instnum=0,i; - bool isinst; - - // count instruments - for(instcnt=0;instcnt<128;instcnt++) { - isinst = false; - for(i=0;i<12;i++) - if(instr[instcnt][i]) - isinst = true; - if(isinst) - instnum++; - } - - return instnum; -} - -/*** private methods *************************************/ - -void ChscPlayer::setfreq(unsigned char chan, unsigned short freq) -{ - adl_freq[chan] = (adl_freq[chan] & ~3) | (freq >> 8); - - opl->write(0xa0 + chan, freq & 0xff); - opl->write(0xb0 + chan, adl_freq[chan]); -} - -void ChscPlayer::setvolume(unsigned char chan, int volc, int volm) -{ - unsigned char *ins = instr[channel[chan].inst]; - char op = op_table[chan]; - - opl->write(0x43 + op,volc | (ins[2] & ~63)); - if (ins[8] & 1) // carrier - opl->write(0x40 + op,volm | (ins[3] & ~63)); - else - opl->write(0x40 + op, ins[3]); // modulator -} - -void ChscPlayer::setinstr(unsigned char chan, unsigned char insnr) -{ - unsigned char *ins = instr[insnr]; - char op = op_table[chan]; - - channel[chan].inst = insnr; // set internal instrument - opl->write(0xb0 + chan,0); // stop old note - - // set instrument - opl->write(0xc0 + chan, ins[8]); - opl->write(0x23 + op, ins[0]); // carrier - opl->write(0x20 + op, ins[1]); // modulator - opl->write(0x63 + op, ins[4]); // bits 0..3 = decay; 4..7 = attack - opl->write(0x60 + op, ins[5]); - opl->write(0x83 + op, ins[6]); // 0..3 = release; 4..7 = sustain - opl->write(0x80 + op, ins[7]); - opl->write(0xe3 + op, ins[9]); // bits 0..1 = Wellenform - opl->write(0xe0 + op, ins[10]); - setvolume(chan, ins[2] & 63, ins[3] & 63); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hsc.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,317 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 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 + * + * hsc.cpp - HSC Player by Simon Peter <dn.tlp@gmx.net> + */ + +#include <string.h> + +#include "hsc.h" +#include "debug.h" + +/*** public methods **************************************/ + +CPlayer *ChscPlayer::factory(Copl *newopl) +{ + return new ChscPlayer(newopl); +} + +bool ChscPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); + int i; + + // file validation section + if(!f || !fp.extension(filename, ".hsc") || fp.filesize(f) > 59187) { + AdPlug_LogWrite("ChscPlayer::load(\"%s\"): Not a HSC file!\n", filename.c_str()); + fp.close(f); + return false; + } + + // load section + for(i=0;i<128*12;i++) // load instruments + *((unsigned char *)instr + i) = f->readInt(1); + for (i=0;i<128;i++) { // correct instruments + instr[i][2] ^= (instr[i][2] & 0x40) << 1; + instr[i][3] ^= (instr[i][3] & 0x40) << 1; + instr[i][11] >>= 4; // slide + } + for(i=0;i<51;i++) song[i] = f->readInt(1); // load tracklist + for(i=0;i<50*64*9;i++) // load patterns + *((char *)patterns + i) = f->readInt(1); + + fp.close(f); + rewind(0); // rewind module + return true; +} + +bool ChscPlayer::update() +{ + // general vars + unsigned char chan,pattnr,note,effect,eff_op,inst,vol,Okt,db; + unsigned short Fnr; + unsigned long pattoff; + + del--; // player speed handling + if(del) + return !songend; // nothing done + + if(fadein) // fade-in handling + fadein--; + + pattnr = song[songpos]; + if(pattnr == 0xff) { // arrangement handling + songend = 1; // set end-flag + songpos = 0; + pattnr = song[songpos]; + } else + if ((pattnr & 128) && (pattnr <= 0xb1)) { // goto pattern "nr" + songpos = song[songpos] & 127; + pattpos = 0; + pattnr = song[songpos]; + songend = 1; + } + + pattoff = pattpos*9; + for (chan=0;chan<9;chan++) { // handle all channels + note = patterns[pattnr][pattoff].note; + effect = patterns[pattnr][pattoff].effect; + pattoff++; + + if(note & 128) { // set instrument + setinstr(chan,effect); + continue; + } + eff_op = effect & 0x0f; + inst = channel[chan].inst; + if(note) + channel[chan].slide = 0; + + switch (effect & 0xf0) { // effect handling + case 0: // global effect + /* The following fx are unimplemented on purpose: + * 02 - Slide Mainvolume up + * 03 - Slide Mainvolume down (here: fade in) + * 04 - Set Mainvolume to 0 + * + * This is because i've never seen any HSC modules using the fx this way. + * All modules use the fx the way, i've implemented it. + */ + switch(eff_op) { + case 1: pattbreak++; break; // jump to next pattern + case 3: fadein = 31; break; // fade in (divided by 2) + case 5: mode6 = 1; break; // 6 voice mode on + case 6: mode6 = 0; break; // 6 voice mode off + } + break; + case 0x20: + case 0x10: // manual slides + if (effect & 0x10) { + channel[chan].freq += eff_op; + channel[chan].slide += eff_op; + } else { + channel[chan].freq -= eff_op; + channel[chan].slide -= eff_op; + } + if(!note) + setfreq(chan,channel[chan].freq); + break; + case 0x50: // set percussion instrument (unimplemented) + break; + case 0x60: // set feedback + opl->write(0xc0 + chan, (instr[channel[chan].inst][8] & 1) + (eff_op << 1)); + break; + case 0xa0: // set carrier volume + vol = eff_op << 2; + opl->write(0x43 + op_table[chan], vol | (instr[channel[chan].inst][2] & ~63)); + break; + case 0xb0: // set modulator volume + vol = eff_op << 2; + if (instr[inst][8] & 1) + opl->write(0x40 + op_table[chan], vol | (instr[channel[chan].inst][3] & ~63)); + else + opl->write(0x40 + op_table[chan],vol | (instr[inst][3] & ~63)); + break; + case 0xc0: // set instrument volume + db = eff_op << 2; + opl->write(0x43 + op_table[chan], db | (instr[channel[chan].inst][2] & ~63)); + if (instr[inst][8] & 1) + opl->write(0x40 + op_table[chan], db | (instr[channel[chan].inst][3] & ~63)); + break; + case 0xd0: pattbreak++; songpos = eff_op; songend = 1; break; // position jump + case 0xf0: // set speed + speed = eff_op; + del = ++speed; + break; + } + + if(fadein) // fade-in volume setting + setvolume(chan,fadein*2,fadein*2); + + if(!note) // note handling + continue; + note--; + + if ((note == 0x7f-1) || ((note/12) & ~7)) { // pause (7fh) + adl_freq[chan] &= ~32; + opl->write(0xb0 + chan,adl_freq[chan]); + continue; + } + + // play the note + if(mtkmode) // imitate MPU-401 Trakker bug + note--; + Okt = ((note/12) & 7) << 2; + Fnr = note_table[(note % 12)] + instr[inst][11] + channel[chan].slide; + channel[chan].freq = Fnr; + if(!mode6 || chan < 6) + adl_freq[chan] = Okt | 32; + else + adl_freq[chan] = Okt; // never set key for drums + opl->write(0xb0 + chan, 0); + setfreq(chan,Fnr); + if(mode6) { + switch(chan) { // play drums + case 6: opl->write(0xbd,bd & ~16); bd |= 48; break; // bass drum + case 7: opl->write(0xbd,bd & ~1); bd |= 33; break; // hihat + case 8: opl->write(0xbd,bd & ~2); bd |= 34; break; // cymbal + } + opl->write(0xbd,bd); + } + } + + del = speed; // player speed-timing + if(pattbreak) { // do post-effect handling + pattpos=0; // pattern break! + pattbreak=0; + songpos++; + songpos %= 50; + if(!songpos) + songend = 1; + } else { + pattpos++; + pattpos &= 63; // advance in pattern data + if (!pattpos) { + songpos++; + songpos %= 50; + if(!songpos) + songend = 1; + } + } + return !songend; // still playing +} + +void ChscPlayer::rewind(int subsong) +{ + int i; // counter + + // rewind HSC player + pattpos = 0; songpos = 0; pattbreak = 0; speed = 2; + del = 1; songend = 0; mode6 = 0; bd = 0; fadein = 0; + + opl->init(); // reset OPL chip + opl->write(1,32); opl->write(8,128); opl->write(0xbd,0); + + for(i=0;i<9;i++) + setinstr((char) i,(char) i); // init channels +} + +unsigned int ChscPlayer::getpatterns() +{ + unsigned char poscnt,pattcnt=0; + + // count patterns + for(poscnt=0;poscnt<51 && song[poscnt] != 0xff;poscnt++) + if(song[poscnt] > pattcnt) + pattcnt = song[poscnt]; + + return (pattcnt+1); +} + +unsigned int ChscPlayer::getorders() +{ + unsigned char poscnt; + + // count positions + for(poscnt=0;poscnt<51;poscnt++) + if(song[poscnt] == 0xff) + break; + + return poscnt; +} + +unsigned int ChscPlayer::getinstruments() +{ + unsigned char instcnt,instnum=0,i; + bool isinst; + + // count instruments + for(instcnt=0;instcnt<128;instcnt++) { + isinst = false; + for(i=0;i<12;i++) + if(instr[instcnt][i]) + isinst = true; + if(isinst) + instnum++; + } + + return instnum; +} + +/*** private methods *************************************/ + +void ChscPlayer::setfreq(unsigned char chan, unsigned short freq) +{ + adl_freq[chan] = (adl_freq[chan] & ~3) | (freq >> 8); + + opl->write(0xa0 + chan, freq & 0xff); + opl->write(0xb0 + chan, adl_freq[chan]); +} + +void ChscPlayer::setvolume(unsigned char chan, int volc, int volm) +{ + unsigned char *ins = instr[channel[chan].inst]; + char op = op_table[chan]; + + opl->write(0x43 + op,volc | (ins[2] & ~63)); + if (ins[8] & 1) // carrier + opl->write(0x40 + op,volm | (ins[3] & ~63)); + else + opl->write(0x40 + op, ins[3]); // modulator +} + +void ChscPlayer::setinstr(unsigned char chan, unsigned char insnr) +{ + unsigned char *ins = instr[insnr]; + char op = op_table[chan]; + + channel[chan].inst = insnr; // set internal instrument + opl->write(0xb0 + chan,0); // stop old note + + // set instrument + opl->write(0xc0 + chan, ins[8]); + opl->write(0x23 + op, ins[0]); // carrier + opl->write(0x20 + op, ins[1]); // modulator + opl->write(0x63 + op, ins[4]); // bits 0..3 = decay; 4..7 = attack + opl->write(0x60 + op, ins[5]); + opl->write(0x83 + op, ins[6]); // 0..3 = release; 4..7 = sustain + opl->write(0x80 + op, ins[7]); + opl->write(0xe3 + op, ins[9]); // bits 0..1 = Wellenform + opl->write(0xe0 + op, ins[10]); + setvolume(chan, ins[2] & 63, ins[3] & 63); +}
--- a/Plugins/Input/adplug/core/hsp.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2004 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 - * - * hsp.cpp - HSP Loader by Simon Peter <dn.tlp@gmx.net> - */ - -#include <string.h> - -#include "hsp.h" - -CPlayer *ChspLoader::factory(Copl *newopl) -{ - return new ChspLoader(newopl); -} - -bool ChspLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - unsigned long i, j, orgsize, filesize; - unsigned char *cmp, *org; - - // file validation section - if(!fp.extension(filename, ".hsp")) { fp.close(f); return false; } - - filesize = fp.filesize(f); - orgsize = f->readInt(2); - if(orgsize > 59187) { fp.close(f); return false; } - - // load section - cmp = new unsigned char[filesize]; - for(i = 0; i < filesize; i++) cmp[i] = f->readInt(1); - fp.close(f); - - org = new unsigned char[orgsize]; - for(i = 0, j = 0; i < filesize; j += cmp[i], i += 2) { // RLE decompress - if(j >= orgsize) break; // memory boundary check - memset(org + j, cmp[i + 1], j + cmp[i] < orgsize ? cmp[i] : orgsize - j - 1); - } - delete [] cmp; - - memcpy(instr, org, 128 * 12); // instruments - for(i = 0; i < 128; i++) { // correct instruments - instr[i][2] ^= (instr[i][2] & 0x40) << 1; - instr[i][3] ^= (instr[i][3] & 0x40) << 1; - instr[i][11] >>= 4; // slide - } - memcpy(song, org + 128 * 12, 51); // tracklist - memcpy(patterns, org + 128 * 12 + 51, orgsize - 128 * 12 - 51); // patterns - delete [] org; - - rewind(0); - return true; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hsp.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,68 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 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 + * + * hsp.cpp - HSP Loader by Simon Peter <dn.tlp@gmx.net> + */ + +#include <string.h> + +#include "hsp.h" + +CPlayer *ChspLoader::factory(Copl *newopl) +{ + return new ChspLoader(newopl); +} + +bool ChspLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + unsigned long i, j, orgsize, filesize; + unsigned char *cmp, *org; + + // file validation section + if(!fp.extension(filename, ".hsp")) { fp.close(f); return false; } + + filesize = fp.filesize(f); + orgsize = f->readInt(2); + if(orgsize > 59187) { fp.close(f); return false; } + + // load section + cmp = new unsigned char[filesize]; + for(i = 0; i < filesize; i++) cmp[i] = f->readInt(1); + fp.close(f); + + org = new unsigned char[orgsize]; + for(i = 0, j = 0; i < filesize; j += cmp[i], i += 2) { // RLE decompress + if(j >= orgsize) break; // memory boundary check + memset(org + j, cmp[i + 1], j + cmp[i] < orgsize ? cmp[i] : orgsize - j - 1); + } + delete [] cmp; + + memcpy(instr, org, 128 * 12); // instruments + for(i = 0; i < 128; i++) { // correct instruments + instr[i][2] ^= (instr[i][2] & 0x40) << 1; + instr[i][3] ^= (instr[i][3] & 0x40) << 1; + instr[i][11] >>= 4; // slide + } + memcpy(song, org + 128 * 12, 51); // tracklist + memcpy(patterns, org + 128 * 12 + 51, orgsize - 128 * 12 - 51); // patterns + delete [] org; + + rewind(0); + return true; +}
--- a/Plugins/Input/adplug/core/hybrid.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,248 +0,0 @@ -/* - * 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] HYBRID player, by Riven the Mage <riven@ok.ru> - */ - -/* - - discovery - - - file(s) : HYBRID.EXE - type : Hybrid cracktro for Apache Longbow CD-RIP - tune : from 'Mig-29 Super Fulcrum' game by Domark - player : from 'Mig-29 Super Fulcrum' game by Domark -*/ - -#include "hybrid.h" -#include "debug.h" - -const unsigned char CxadhybridPlayer::hyb_adlib_registers[99] = -{ - 0xE0, 0x60, 0x80, 0x20, 0x40, 0xE3, 0x63, 0x83, 0x23, 0x43, 0xC0, - 0xE1, 0x61, 0x81, 0x21, 0x41, 0xE4, 0x64, 0x84, 0x24, 0x44, 0xC1, - 0xE2, 0x62, 0x82, 0x22, 0x42, 0xE5, 0x65, 0x85, 0x25, 0x45, 0xC2, - 0xE8, 0x68, 0x88, 0x28, 0x48, 0xEB, 0x6B, 0x8B, 0x2B, 0x4B, 0xC3, - 0xE9, 0x69, 0x89, 0x29, 0x49, 0xEC, 0x6C, 0x8C, 0x2C, 0x4C, 0xC4, - 0xEA, 0x6A, 0x8A, 0x2A, 0x4A, 0xED, 0x6D, 0x8D, 0x2D, 0x4D, 0xC5, - 0xF0, 0x70, 0x90, 0x30, 0x50, 0xF3, 0x73, 0x93, 0x33, 0x53, 0xC6, - 0xF1, 0x71, 0x91, 0x31, 0x51, 0xF4, 0x74, 0x94, 0x34, 0x54, 0xC7, - 0xF2, 0x72, 0x92, 0x32, 0x52, 0xF5, 0x75, 0x95, 0x35, 0x55, 0xC8 -}; - -const unsigned short CxadhybridPlayer::hyb_notes[98] = -{ - 0x0000, 0x0000, - 0x016B, 0x0181, 0x0198, 0x01B0, 0x01CA, 0x01E5, 0x0202, 0x0220, 0x0241, 0x0263, 0x0287, 0x02AE, - 0x056B, 0x0581, 0x0598, 0x05B0, 0x05CA, 0x05E5, 0x0602, 0x0620, 0x0641, 0x0663, 0x0687, 0x06AE, - 0x096B, 0x0981, 0x0998, 0x09B0, 0x09CA, 0x09E5, 0x0A02, 0x0A20, 0x0A41, 0x0A63, 0x0A87, 0x0AAE, - 0x0D6B, 0x0D81, 0x0D98, 0x0DB0, 0x0DCA, 0x0DE5, 0x0E02, 0x0E20, 0x0E41, 0x0E63, 0x0E87, 0x0EAE, - 0x116B, 0x1181, 0x1198, 0x11B0, 0x11CA, 0x11E5, 0x1202, 0x1220, 0x1241, 0x1263, 0x1287, 0x12AE, - 0x156B, 0x1581, 0x1598, 0x15B0, 0x15CA, 0x15E5, 0x1602, 0x1620, 0x1641, 0x1663, 0x1687, 0x16AE, - 0x196B, 0x1981, 0x1998, 0x19B0, 0x19CA, 0x19E5, 0x1A02, 0x1A20, 0x1A41, 0x1A63, 0x1A87, 0x1AAE, - 0x1D6B, 0x1D81, 0x1D98, 0x1DB0, 0x1DCA, 0x1DE5, 0x1E02, 0x1E20, 0x1E41, 0x1E63, 0x1E87, 0x1EAE -}; - -const unsigned char CxadhybridPlayer::hyb_default_instrument[11] = -{ - 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00 -}; - -CPlayer *CxadhybridPlayer::factory(Copl *newopl) -{ - return new CxadhybridPlayer(newopl); -} - -bool CxadhybridPlayer::xadplayer_load() -{ - if(xad.fmt != HYBRID) - return false; - - // load instruments - hyb.inst = (hyb_instrument *)&tune[0]; - - // load order - hyb.order = &tune[0x1D4]; - - return true; -} - -void CxadhybridPlayer::xadplayer_rewind(int subsong) -{ - int i; - - hyb.order_pos = 0; - hyb.pattern_pos = 0; - - hyb.speed = 6; - hyb.speed_counter = 1; - - plr.speed = 1; - - // init channel data - for(i=0;i<9;i++) - { - hyb.channel[i].freq = 0x2000; - hyb.channel[i].freq_slide = 0x0000; - } - - // basic OPL init - opl_write(0x01, 0x20); - opl_write(0xBD, 0x40); - opl_write(0x08, 0x00); - - // init OPL channels - for(i=0;i<9;i++) - { - for(int j=0;j<11;j++) - opl_write(hyb_adlib_registers[i*11+j], 0x00 /* hyb_default_instrument[j] */ ); - - opl_write(0xA0+i, 0x00); - opl_write(0xB0+i, 0x20); - } -} - -void CxadhybridPlayer::xadplayer_update() -{ - int i,j; - unsigned char patpos,ordpos; - - if (--hyb.speed_counter) - goto update_slides; - - hyb.speed_counter = hyb.speed; - - patpos = hyb.pattern_pos; - ordpos = hyb.order_pos; - - // process channels - for(i=0;i<9;i++) - { - unsigned char *pos = &tune[0xADE + (hyb.order[hyb.order_pos*9 + i] * 64 * 2) + (patpos * 2)]; - // read event - unsigned short event = (pos[1] << 8) + pos[0]; - -#ifdef DEBUG - AdPlug_LogWrite("track %02X, channel %02X, event %04X:\n", hyb.order[hyb.order_pos*9 + i], i, event ); -#endif - - // calculate variables - unsigned char note = event >> 9; - unsigned char ins = ((event & 0x01F0) >> 4); - unsigned char slide = event & 0x000F; - - // play event - switch(note) - { - case 0x7D: // 0x7D: Set Speed - hyb.speed = event & 0xFF; - break; - case 0x7E: // 0x7E: Jump Position - hyb.order_pos = event & 0xFF; - hyb.pattern_pos = 0x3F; - - // jumpback ? - if (hyb.order_pos <= ordpos) - plr.looping = 1; - - break; - case 0x7F: // 0x7F: Pattern Break - hyb.pattern_pos = 0x3F; - break; - default: - - // is instrument ? - if (ins) - for(j=0;j<11;j++) - opl_write(hyb_adlib_registers[i*11+j], *((unsigned char *)&hyb.inst[ins-1] + 7 + j)); // +7 = skip name... - - // is note ? - if (note) - { - hyb.channel[i].freq = hyb_notes[note]; - hyb.channel[i].freq_slide = 0; - } - - // is slide ? - if (slide) - { - hyb.channel[i].freq_slide = (((slide >> 3) * -1) * (slide & 7)) << 1; - - if (slide & 0x80) - slide = -(slide & 7); - } - - // set frequency - if (!(hyb.channel[i].freq & 0x2000)) - { - opl_write(0xA0+i, hyb.channel[i].freq & 0xFF); - opl_write(0xB0+i, hyb.channel[i].freq >> 8); - - hyb.channel[i].freq |= 0x2000; - - opl_write(0xA0+i, hyb.channel[i].freq & 0xFF); - opl_write(0xB0+i, hyb.channel[i].freq >> 8); - } - - break; - } - } - - hyb.pattern_pos++; - - // end of pattern ? - if (hyb.pattern_pos >= 0x40) - { - hyb.pattern_pos = 0; - - hyb.order_pos++; - } - -update_slides: -#ifdef DEBUG - AdPlug_LogWrite("slides:\n"); -#endif - // update fine frequency slides - for(i=0;i<9;i++) - if (hyb.channel[i].freq_slide) - { - hyb.channel[i].freq = (((hyb.channel[i].freq & 0x1FFF) + hyb.channel[i].freq_slide) & 0x1FFF) | 0x2000; - - opl_write(0xA0+i, hyb.channel[i].freq & 0xFF); - opl_write(0xB0+i, hyb.channel[i].freq >> 8); - } -} - -float CxadhybridPlayer::xadplayer_getrefresh() -{ - return 50.0f; -} - -std::string CxadhybridPlayer::xadplayer_gettype() -{ - return (std::string("xad: hybrid player")); -} - -std::string CxadhybridPlayer::xadplayer_getinstrument(unsigned int i) -{ - return (std::string(hyb.inst[i].name,7)); -} - -unsigned int CxadhybridPlayer::xadplayer_getinstruments() -{ - return 26; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hybrid.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,248 @@ +/* + * 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] HYBRID player, by Riven the Mage <riven@ok.ru> + */ + +/* + - discovery - + + file(s) : HYBRID.EXE + type : Hybrid cracktro for Apache Longbow CD-RIP + tune : from 'Mig-29 Super Fulcrum' game by Domark + player : from 'Mig-29 Super Fulcrum' game by Domark +*/ + +#include "hybrid.h" +#include "debug.h" + +const unsigned char CxadhybridPlayer::hyb_adlib_registers[99] = +{ + 0xE0, 0x60, 0x80, 0x20, 0x40, 0xE3, 0x63, 0x83, 0x23, 0x43, 0xC0, + 0xE1, 0x61, 0x81, 0x21, 0x41, 0xE4, 0x64, 0x84, 0x24, 0x44, 0xC1, + 0xE2, 0x62, 0x82, 0x22, 0x42, 0xE5, 0x65, 0x85, 0x25, 0x45, 0xC2, + 0xE8, 0x68, 0x88, 0x28, 0x48, 0xEB, 0x6B, 0x8B, 0x2B, 0x4B, 0xC3, + 0xE9, 0x69, 0x89, 0x29, 0x49, 0xEC, 0x6C, 0x8C, 0x2C, 0x4C, 0xC4, + 0xEA, 0x6A, 0x8A, 0x2A, 0x4A, 0xED, 0x6D, 0x8D, 0x2D, 0x4D, 0xC5, + 0xF0, 0x70, 0x90, 0x30, 0x50, 0xF3, 0x73, 0x93, 0x33, 0x53, 0xC6, + 0xF1, 0x71, 0x91, 0x31, 0x51, 0xF4, 0x74, 0x94, 0x34, 0x54, 0xC7, + 0xF2, 0x72, 0x92, 0x32, 0x52, 0xF5, 0x75, 0x95, 0x35, 0x55, 0xC8 +}; + +const unsigned short CxadhybridPlayer::hyb_notes[98] = +{ + 0x0000, 0x0000, + 0x016B, 0x0181, 0x0198, 0x01B0, 0x01CA, 0x01E5, 0x0202, 0x0220, 0x0241, 0x0263, 0x0287, 0x02AE, + 0x056B, 0x0581, 0x0598, 0x05B0, 0x05CA, 0x05E5, 0x0602, 0x0620, 0x0641, 0x0663, 0x0687, 0x06AE, + 0x096B, 0x0981, 0x0998, 0x09B0, 0x09CA, 0x09E5, 0x0A02, 0x0A20, 0x0A41, 0x0A63, 0x0A87, 0x0AAE, + 0x0D6B, 0x0D81, 0x0D98, 0x0DB0, 0x0DCA, 0x0DE5, 0x0E02, 0x0E20, 0x0E41, 0x0E63, 0x0E87, 0x0EAE, + 0x116B, 0x1181, 0x1198, 0x11B0, 0x11CA, 0x11E5, 0x1202, 0x1220, 0x1241, 0x1263, 0x1287, 0x12AE, + 0x156B, 0x1581, 0x1598, 0x15B0, 0x15CA, 0x15E5, 0x1602, 0x1620, 0x1641, 0x1663, 0x1687, 0x16AE, + 0x196B, 0x1981, 0x1998, 0x19B0, 0x19CA, 0x19E5, 0x1A02, 0x1A20, 0x1A41, 0x1A63, 0x1A87, 0x1AAE, + 0x1D6B, 0x1D81, 0x1D98, 0x1DB0, 0x1DCA, 0x1DE5, 0x1E02, 0x1E20, 0x1E41, 0x1E63, 0x1E87, 0x1EAE +}; + +const unsigned char CxadhybridPlayer::hyb_default_instrument[11] = +{ + 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00 +}; + +CPlayer *CxadhybridPlayer::factory(Copl *newopl) +{ + return new CxadhybridPlayer(newopl); +} + +bool CxadhybridPlayer::xadplayer_load() +{ + if(xad.fmt != HYBRID) + return false; + + // load instruments + hyb.inst = (hyb_instrument *)&tune[0]; + + // load order + hyb.order = &tune[0x1D4]; + + return true; +} + +void CxadhybridPlayer::xadplayer_rewind(int subsong) +{ + int i; + + hyb.order_pos = 0; + hyb.pattern_pos = 0; + + hyb.speed = 6; + hyb.speed_counter = 1; + + plr.speed = 1; + + // init channel data + for(i=0;i<9;i++) + { + hyb.channel[i].freq = 0x2000; + hyb.channel[i].freq_slide = 0x0000; + } + + // basic OPL init + opl_write(0x01, 0x20); + opl_write(0xBD, 0x40); + opl_write(0x08, 0x00); + + // init OPL channels + for(i=0;i<9;i++) + { + for(int j=0;j<11;j++) + opl_write(hyb_adlib_registers[i*11+j], 0x00 /* hyb_default_instrument[j] */ ); + + opl_write(0xA0+i, 0x00); + opl_write(0xB0+i, 0x20); + } +} + +void CxadhybridPlayer::xadplayer_update() +{ + int i,j; + unsigned char patpos,ordpos; + + if (--hyb.speed_counter) + goto update_slides; + + hyb.speed_counter = hyb.speed; + + patpos = hyb.pattern_pos; + ordpos = hyb.order_pos; + + // process channels + for(i=0;i<9;i++) + { + unsigned char *pos = &tune[0xADE + (hyb.order[hyb.order_pos*9 + i] * 64 * 2) + (patpos * 2)]; + // read event + unsigned short event = (pos[1] << 8) + pos[0]; + +#ifdef DEBUG + AdPlug_LogWrite("track %02X, channel %02X, event %04X:\n", hyb.order[hyb.order_pos*9 + i], i, event ); +#endif + + // calculate variables + unsigned char note = event >> 9; + unsigned char ins = ((event & 0x01F0) >> 4); + unsigned char slide = event & 0x000F; + + // play event + switch(note) + { + case 0x7D: // 0x7D: Set Speed + hyb.speed = event & 0xFF; + break; + case 0x7E: // 0x7E: Jump Position + hyb.order_pos = event & 0xFF; + hyb.pattern_pos = 0x3F; + + // jumpback ? + if (hyb.order_pos <= ordpos) + plr.looping = 1; + + break; + case 0x7F: // 0x7F: Pattern Break + hyb.pattern_pos = 0x3F; + break; + default: + + // is instrument ? + if (ins) + for(j=0;j<11;j++) + opl_write(hyb_adlib_registers[i*11+j], *((unsigned char *)&hyb.inst[ins-1] + 7 + j)); // +7 = skip name... + + // is note ? + if (note) + { + hyb.channel[i].freq = hyb_notes[note]; + hyb.channel[i].freq_slide = 0; + } + + // is slide ? + if (slide) + { + hyb.channel[i].freq_slide = (((slide >> 3) * -1) * (slide & 7)) << 1; + + if (slide & 0x80) + slide = -(slide & 7); + } + + // set frequency + if (!(hyb.channel[i].freq & 0x2000)) + { + opl_write(0xA0+i, hyb.channel[i].freq & 0xFF); + opl_write(0xB0+i, hyb.channel[i].freq >> 8); + + hyb.channel[i].freq |= 0x2000; + + opl_write(0xA0+i, hyb.channel[i].freq & 0xFF); + opl_write(0xB0+i, hyb.channel[i].freq >> 8); + } + + break; + } + } + + hyb.pattern_pos++; + + // end of pattern ? + if (hyb.pattern_pos >= 0x40) + { + hyb.pattern_pos = 0; + + hyb.order_pos++; + } + +update_slides: +#ifdef DEBUG + AdPlug_LogWrite("slides:\n"); +#endif + // update fine frequency slides + for(i=0;i<9;i++) + if (hyb.channel[i].freq_slide) + { + hyb.channel[i].freq = (((hyb.channel[i].freq & 0x1FFF) + hyb.channel[i].freq_slide) & 0x1FFF) | 0x2000; + + opl_write(0xA0+i, hyb.channel[i].freq & 0xFF); + opl_write(0xB0+i, hyb.channel[i].freq >> 8); + } +} + +float CxadhybridPlayer::xadplayer_getrefresh() +{ + return 50.0f; +} + +std::string CxadhybridPlayer::xadplayer_gettype() +{ + return (std::string("xad: hybrid player")); +} + +std::string CxadhybridPlayer::xadplayer_getinstrument(unsigned int i) +{ + return (std::string(hyb.inst[i].name,7)); +} + +unsigned int CxadhybridPlayer::xadplayer_getinstruments() +{ + return 26; +}
--- a/Plugins/Input/adplug/core/hyp.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * 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] HYP player, by Riven the Mage <riven@ok.ru> - */ - -/* - - discovery - - - file(s) : HT-EF2.COM, HT-EF3.COM - type : Eiserne Front BBStro - tune : by Shadowdancer [Hypnosis] - player : by (?)Hetero [LKCC/SAC] -*/ - -#include "hyp.h" -#include "debug.h" - -const unsigned char CxadhypPlayer::hyp_adlib_registers[99] = -{ - 0x20, 0x23, 0x40, 0x43, 0x60, 0x63, 0x80, 0x83, 0xA0, 0xB0, 0xC0, - 0x21, 0x24, 0x41, 0x44, 0x61, 0x64, 0x81, 0x84, 0xA1, 0xB1, 0xC1, - 0x22, 0x25, 0x42, 0x45, 0x62, 0x65, 0x82, 0x85, 0xA2, 0xB2, 0xC2, - 0x28, 0x2B, 0x48, 0x4B, 0x68, 0x6B, 0x88, 0x8B, 0xA3, 0xB3, 0xC3, - 0x29, 0x2C, 0x49, 0x4C, 0x69, 0x6C, 0x89, 0x8C, 0xA4, 0xB4, 0xC4, - 0x2A, 0x2D, 0x4A, 0x4D, 0x6A, 0x6D, 0x8A, 0x8D, 0xA5, 0xB5, 0xC5, - 0x30, 0x33, 0x50, 0x53, 0x70, 0x73, 0x90, 0x93, 0xA6, 0xB6, 0xC6, - 0x31, 0x34, 0x51, 0x54, 0x71, 0x74, 0x91, 0x94, 0xA7, 0xB7, 0xC7, - 0x32, 0x35, 0x52, 0x55, 0x72, 0x75, 0x92, 0x95, 0xA8, 0xB8, 0xC8 -}; - -const unsigned short CxadhypPlayer::hyp_notes[73] = -{ - 0x0000, // by riven - 0x0956, 0x096B, 0x0980, 0x0998, 0x09B1, 0x09C9, 0x09E5, 0x0A03, 0x0A21, - 0x0A41, 0x0A63, 0x0A86, 0x0D56, 0x0D6B, 0x0D80, 0x0D98, 0x0DB1, 0x0DC9, - 0x0DE5, 0x0E03, 0x0E21, 0x0E41, 0x0E63, 0x0E86, 0x1156, 0x116B, 0x1180, - 0x1198, 0x11B1, 0x11C9, 0x11E5, 0x1203, 0x1221, 0x1241, 0x1263, 0x1286, - 0x1556, 0x156B, 0x1580, 0x1598, 0x15B1, 0x15C9, 0x15E5, 0x1603, 0x1621, - 0x1641, 0x1663, 0x1686, 0x1956, 0x196B, 0x1980, 0x1998, 0x19B1, 0x19C9, - 0x19E5, 0x1A03, 0x1A21, 0x1A41, 0x1A63, 0x1A86, 0x1D56, 0x1D6B, 0x1D80, - 0x1D98, 0x1DB1, 0x1DC9, 0x1DE5, 0x1E03, 0x1E21, 0x1E41, 0x1E63, 0x1E86 -}; - -CPlayer *CxadhypPlayer::factory(Copl *newopl) -{ - return new CxadhypPlayer(newopl); -} - -void CxadhypPlayer::xadplayer_rewind(int subsong) -{ - int i; - - plr.speed = tune[5]; - - opl_write(0xBD,0xC0); - - for(i=0; i<9; i++) - adlib[0xB0+i] = 0; - - // define instruments - for(i=0; i<99; i++) - opl_write(hyp_adlib_registers[i], tune[6+i]); - - hyp.pointer = 0x69; -} - -void CxadhypPlayer::xadplayer_update() -{ - for(int i=0; i<9; i++) - { - unsigned char event = tune[hyp.pointer++]; - - if (event) - { - unsigned short freq = hyp_notes[event & 0x3F]; - - unsigned char lofreq = (freq & 0xFF); - unsigned char hifreq = (freq >> 8); - - opl_write(0xB0+i, adlib[0xB0+i]); - - if (!(event & 0x40)) - { - opl_write(0xA0+i, lofreq); - opl_write(0xB0+i, hifreq | 0x20); - } - - adlib[0xB0+i] &= 0xDF; - } - } - - hyp.pointer += 3; - - if (hyp.pointer >= tune_size) - { - hyp.pointer = 0x69; - plr.looping = 1; - } -} - -float CxadhypPlayer::xadplayer_getrefresh() -{ - return 60.0f; -} - -std::string CxadhypPlayer::xadplayer_gettype() -{ - return std::string("xad: hypnosis player"); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/hyp.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,125 @@ +/* + * 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] HYP player, by Riven the Mage <riven@ok.ru> + */ + +/* + - discovery - + + file(s) : HT-EF2.COM, HT-EF3.COM + type : Eiserne Front BBStro + tune : by Shadowdancer [Hypnosis] + player : by (?)Hetero [LKCC/SAC] +*/ + +#include "hyp.h" +#include "debug.h" + +const unsigned char CxadhypPlayer::hyp_adlib_registers[99] = +{ + 0x20, 0x23, 0x40, 0x43, 0x60, 0x63, 0x80, 0x83, 0xA0, 0xB0, 0xC0, + 0x21, 0x24, 0x41, 0x44, 0x61, 0x64, 0x81, 0x84, 0xA1, 0xB1, 0xC1, + 0x22, 0x25, 0x42, 0x45, 0x62, 0x65, 0x82, 0x85, 0xA2, 0xB2, 0xC2, + 0x28, 0x2B, 0x48, 0x4B, 0x68, 0x6B, 0x88, 0x8B, 0xA3, 0xB3, 0xC3, + 0x29, 0x2C, 0x49, 0x4C, 0x69, 0x6C, 0x89, 0x8C, 0xA4, 0xB4, 0xC4, + 0x2A, 0x2D, 0x4A, 0x4D, 0x6A, 0x6D, 0x8A, 0x8D, 0xA5, 0xB5, 0xC5, + 0x30, 0x33, 0x50, 0x53, 0x70, 0x73, 0x90, 0x93, 0xA6, 0xB6, 0xC6, + 0x31, 0x34, 0x51, 0x54, 0x71, 0x74, 0x91, 0x94, 0xA7, 0xB7, 0xC7, + 0x32, 0x35, 0x52, 0x55, 0x72, 0x75, 0x92, 0x95, 0xA8, 0xB8, 0xC8 +}; + +const unsigned short CxadhypPlayer::hyp_notes[73] = +{ + 0x0000, // by riven + 0x0956, 0x096B, 0x0980, 0x0998, 0x09B1, 0x09C9, 0x09E5, 0x0A03, 0x0A21, + 0x0A41, 0x0A63, 0x0A86, 0x0D56, 0x0D6B, 0x0D80, 0x0D98, 0x0DB1, 0x0DC9, + 0x0DE5, 0x0E03, 0x0E21, 0x0E41, 0x0E63, 0x0E86, 0x1156, 0x116B, 0x1180, + 0x1198, 0x11B1, 0x11C9, 0x11E5, 0x1203, 0x1221, 0x1241, 0x1263, 0x1286, + 0x1556, 0x156B, 0x1580, 0x1598, 0x15B1, 0x15C9, 0x15E5, 0x1603, 0x1621, + 0x1641, 0x1663, 0x1686, 0x1956, 0x196B, 0x1980, 0x1998, 0x19B1, 0x19C9, + 0x19E5, 0x1A03, 0x1A21, 0x1A41, 0x1A63, 0x1A86, 0x1D56, 0x1D6B, 0x1D80, + 0x1D98, 0x1DB1, 0x1DC9, 0x1DE5, 0x1E03, 0x1E21, 0x1E41, 0x1E63, 0x1E86 +}; + +CPlayer *CxadhypPlayer::factory(Copl *newopl) +{ + return new CxadhypPlayer(newopl); +} + +void CxadhypPlayer::xadplayer_rewind(int subsong) +{ + int i; + + plr.speed = tune[5]; + + opl_write(0xBD,0xC0); + + for(i=0; i<9; i++) + adlib[0xB0+i] = 0; + + // define instruments + for(i=0; i<99; i++) + opl_write(hyp_adlib_registers[i], tune[6+i]); + + hyp.pointer = 0x69; +} + +void CxadhypPlayer::xadplayer_update() +{ + for(int i=0; i<9; i++) + { + unsigned char event = tune[hyp.pointer++]; + + if (event) + { + unsigned short freq = hyp_notes[event & 0x3F]; + + unsigned char lofreq = (freq & 0xFF); + unsigned char hifreq = (freq >> 8); + + opl_write(0xB0+i, adlib[0xB0+i]); + + if (!(event & 0x40)) + { + opl_write(0xA0+i, lofreq); + opl_write(0xB0+i, hifreq | 0x20); + } + + adlib[0xB0+i] &= 0xDF; + } + } + + hyp.pointer += 3; + + if (hyp.pointer >= tune_size) + { + hyp.pointer = 0x69; + plr.looping = 1; + } +} + +float CxadhypPlayer::xadplayer_getrefresh() +{ + return 60.0f; +} + +std::string CxadhypPlayer::xadplayer_gettype() +{ + return std::string("xad: hypnosis player"); +}
--- a/Plugins/Input/adplug/core/imf.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 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 - * - * imf.cpp - IMF Player by Simon Peter <dn.tlp@gmx.net> - * - * FILE FORMAT: - * There seem to be 2 different flavors of IMF formats out there. One version - * contains just the raw IMF music data. In this case, the first word of the - * file is always 0 (because the music data starts this way). This is already - * the music data! So read in the entire file and play it. - * - * If this word is greater than 0, it specifies the size of the following - * song data in bytes. In this case, the file has a footer that contains - * arbitrary infos about it. Mostly, this is plain ASCII text with some words - * of the author. Read and play the specified amount of song data and display - * the remaining data as ASCII text. - * - * NOTES: - * This player handles the two above mentioned formats, as well as a third - * type, invented by Martin Fernandez <mfernan@cnba.uba.ar>, that's got a - * proper header to add title/game name information. After the header starts - * the normal IMF file in one of the two above mentioned formats. - * - * This player also handles a special footer format by Adam Nielsen, - * which has defined fields of information about the song, the author - * and more. - */ - -#include <string.h> - -#include "imf.h" -#include "database.h" - -/*** public methods *************************************/ - -CPlayer *CimfPlayer::factory(Copl *newopl) -{ - return new CimfPlayer(newopl); -} - -bool CimfPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - unsigned long fsize, flsize, mfsize = 0; - unsigned int i; - - // file validation section - { - char header[5]; - int version; - - f->readString(header, 5); - version = f->readInt(1); - - if(strncmp(header, "ADLIB", 5) || version != 1) { - if(!fp.extension(filename, ".imf") && !fp.extension(filename, ".wlf")) { - // It's no IMF file at all - fp.close(f); - return false; - } else - f->seek(0); // It's a normal IMF file - } else { - // It's a IMF file with header - track_name = f->readString('\0'); - game_name = f->readString('\0'); - f->ignore(1); - mfsize = f->pos() + 2; - } - } - - // load section - if(mfsize) - fsize = f->readInt(4); - else - fsize = f->readInt(2); - flsize = fp.filesize(f); - if(!fsize) { // footerless file (raw music data) - if(mfsize) - f->seek(-4, binio::Add); - else - f->seek(-2, binio::Add); - size = (flsize - mfsize) / 4; - } else // file has got a footer - size = fsize / 4; - - data = new Sdata[size]; - for(i = 0; i < size; i++) { - data[i].reg = f->readInt(1); data[i].val = f->readInt(1); - data[i].time = f->readInt(2); - } - - // read footer, if any - if(fsize && (fsize < flsize - 2 - mfsize)) - if(f->readInt(1) == 0x1a) { - // Adam Nielsen's footer format - track_name = f->readString(); - author_name = f->readString(); - remarks = f->readString(); - } else { - // Generic footer - unsigned long footerlen = flsize - fsize - 2 - mfsize; - - footer = new char[footerlen + 1]; - f->readString(footer, footerlen); - footer[footerlen] = '\0'; // Make ASCIIZ string - } - - rate = getrate(filename, fp, f); - fp.close(f); - rewind(0); - return true; -} - -bool CimfPlayer::update() -{ - do { - opl->write(data[pos].reg,data[pos].val); - del = data[pos].time; - pos++; - } while(!del && pos < size); - - if(pos >= size) { - pos = 0; - songend = true; - } - else timer = rate / (float)del; - - return !songend; -} - -void CimfPlayer::rewind(int subsong) -{ - pos = 0; del = 0; timer = rate; songend = false; - opl->init(); opl->write(1,32); // go to OPL2 mode -} - -std::string CimfPlayer::gettitle() -{ - std::string title; - - title = track_name; - - if(!track_name.empty() && !game_name.empty()) - title += " - "; - - title += game_name; - - return title; -} - -std::string CimfPlayer::getdesc() -{ - std::string desc; - - if(footer) - desc = std::string(footer); - - if(!remarks.empty() && footer) - desc += "\n\n"; - - desc += remarks; - - return desc; -} - -/*** private methods *************************************/ - -float CimfPlayer::getrate(const std::string &filename, const CFileProvider &fp, binistream *f) -{ - if(db) { // Database available - f->seek(0, binio::Set); - CClockRecord *record = (CClockRecord *)db->search(CAdPlugDatabase::CKey(*f)); - if (record && record->type == CAdPlugDatabase::CRecord::ClockSpeed) - return record->clock; - } - - // Otherwise the database is either unavailable, or there's no entry for this file - if (fp.extension(filename, ".imf")) return 560.0f; - if (fp.extension(filename, ".wlf")) return 700.0f; - return 700.0f; // default speed for unknown files that aren't .IMF or .WLF -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/imf.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,196 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2006 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 + * + * imf.cpp - IMF Player by Simon Peter <dn.tlp@gmx.net> + * + * FILE FORMAT: + * There seem to be 2 different flavors of IMF formats out there. One version + * contains just the raw IMF music data. In this case, the first word of the + * file is always 0 (because the music data starts this way). This is already + * the music data! So read in the entire file and play it. + * + * If this word is greater than 0, it specifies the size of the following + * song data in bytes. In this case, the file has a footer that contains + * arbitrary infos about it. Mostly, this is plain ASCII text with some words + * of the author. Read and play the specified amount of song data and display + * the remaining data as ASCII text. + * + * NOTES: + * This player handles the two above mentioned formats, as well as a third + * type, invented by Martin Fernandez <mfernan@cnba.uba.ar>, that's got a + * proper header to add title/game name information. After the header starts + * the normal IMF file in one of the two above mentioned formats. + * + * This player also handles a special footer format by Adam Nielsen, + * which has defined fields of information about the song, the author + * and more. + */ + +#include <string.h> + +#include "imf.h" +#include "database.h" + +/*** public methods *************************************/ + +CPlayer *CimfPlayer::factory(Copl *newopl) +{ + return new CimfPlayer(newopl); +} + +bool CimfPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + unsigned long fsize, flsize, mfsize = 0; + unsigned int i; + + // file validation section + { + char header[5]; + int version; + + f->readString(header, 5); + version = f->readInt(1); + + if(strncmp(header, "ADLIB", 5) || version != 1) { + if(!fp.extension(filename, ".imf") && !fp.extension(filename, ".wlf")) { + // It's no IMF file at all + fp.close(f); + return false; + } else + f->seek(0); // It's a normal IMF file + } else { + // It's a IMF file with header + track_name = f->readString('\0'); + game_name = f->readString('\0'); + f->ignore(1); + mfsize = f->pos() + 2; + } + } + + // load section + if(mfsize) + fsize = f->readInt(4); + else + fsize = f->readInt(2); + flsize = fp.filesize(f); + if(!fsize) { // footerless file (raw music data) + if(mfsize) + f->seek(-4, binio::Add); + else + f->seek(-2, binio::Add); + size = (flsize - mfsize) / 4; + } else // file has got a footer + size = fsize / 4; + + data = new Sdata[size]; + for(i = 0; i < size; i++) { + data[i].reg = f->readInt(1); data[i].val = f->readInt(1); + data[i].time = f->readInt(2); + } + + // read footer, if any + if(fsize && (fsize < flsize - 2 - mfsize)) + if(f->readInt(1) == 0x1a) { + // Adam Nielsen's footer format + track_name = f->readString(); + author_name = f->readString(); + remarks = f->readString(); + } else { + // Generic footer + unsigned long footerlen = flsize - fsize - 2 - mfsize; + + footer = new char[footerlen + 1]; + f->readString(footer, footerlen); + footer[footerlen] = '\0'; // Make ASCIIZ string + } + + rate = getrate(filename, fp, f); + fp.close(f); + rewind(0); + return true; +} + +bool CimfPlayer::update() +{ + do { + opl->write(data[pos].reg,data[pos].val); + del = data[pos].time; + pos++; + } while(!del && pos < size); + + if(pos >= size) { + pos = 0; + songend = true; + } + else timer = rate / (float)del; + + return !songend; +} + +void CimfPlayer::rewind(int subsong) +{ + pos = 0; del = 0; timer = rate; songend = false; + opl->init(); opl->write(1,32); // go to OPL2 mode +} + +std::string CimfPlayer::gettitle() +{ + std::string title; + + title = track_name; + + if(!track_name.empty() && !game_name.empty()) + title += " - "; + + title += game_name; + + return title; +} + +std::string CimfPlayer::getdesc() +{ + std::string desc; + + if(footer) + desc = std::string(footer); + + if(!remarks.empty() && footer) + desc += "\n\n"; + + desc += remarks; + + return desc; +} + +/*** private methods *************************************/ + +float CimfPlayer::getrate(const std::string &filename, const CFileProvider &fp, binistream *f) +{ + if(db) { // Database available + f->seek(0, binio::Set); + CClockRecord *record = (CClockRecord *)db->search(CAdPlugDatabase::CKey(*f)); + if (record && record->type == CAdPlugDatabase::CRecord::ClockSpeed) + return record->clock; + } + + // Otherwise the database is either unavailable, or there's no entry for this file + if (fp.extension(filename, ".imf")) return 560.0f; + if (fp.extension(filename, ".wlf")) return 700.0f; + return 700.0f; // default speed for unknown files that aren't .IMF or .WLF +}
--- a/Plugins/Input/adplug/core/ksm.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,336 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 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 - * - * ksm.cpp - KSM Player for AdPlug by Simon Peter <dn.tlp@gmx.net> - */ - -#include <string.h> - -#include "ksm.h" -#include "debug.h" - -const unsigned int CksmPlayer::adlibfreq[63] = { - 0, - 2390,2411,2434,2456,2480,2506,2533,2562,2592,2625,2659,2695, - 3414,3435,3458,3480,3504,3530,3557,3586,3616,3649,3683,3719, - 4438,4459,4482,4504,4528,4554,4581,4610,4640,4673,4707,4743, - 5462,5483,5506,5528,5552,5578,5605,5634,5664,5697,5731,5767, - 6486,6507,6530,6552,6576,6602,6629,6658,6688,6721,6755,6791, - 7510}; - -/*** public methods **************************************/ - -CPlayer *CksmPlayer::factory(Copl *newopl) -{ - return new CksmPlayer(newopl); -} - -bool CksmPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f; - int i; - char *fn = new char[filename.length() + 9]; - - // file validation section - if(!fp.extension(filename, ".ksm")) { - AdPlug_LogWrite("CksmPlayer::load(,\"%s\"): File doesn't have '.ksm' " - "extension! Rejected!\n", filename.c_str()); - return false; - } - AdPlug_LogWrite("*** CksmPlayer::load(,\"%s\") ***\n", filename.c_str()); - - // Load instruments from 'insts.dat' - strcpy(fn, filename.c_str()); - for(i = strlen(fn) - 1; i >= 0; i--) - if(fn[i] == '/' || fn[i] == '\\') - break; - strcpy(fn + i + 1, "insts.dat"); - AdPlug_LogWrite("Instruments file: \"%s\"\n", fn); - f = fp.open(fn); - delete [] fn; - if(!f) { - AdPlug_LogWrite("Couldn't open instruments file! Aborting!\n"); - AdPlug_LogWrite("--- CksmPlayer::load ---\n"); - return false; - } - loadinsts(f); - fp.close(f); - - f = fp.open(filename); if(!f) return false; - for(i = 0; i < 16; i++) trinst[i] = f->readInt(1); - for(i = 0; i < 16; i++) trquant[i] = f->readInt(1); - for(i = 0; i < 16; i++) trchan[i] = f->readInt(1); - f->ignore(16); - for(i = 0; i < 16; i++) trvol[i] = f->readInt(1); - numnotes = f->readInt(2); - note = new unsigned long [numnotes]; - for(i = 0; i < numnotes; i++) note[i] = f->readInt(4); - fp.close(f); - - if(!trchan[11]) { - drumstat = 0; - numchans = 9; - } else { - drumstat = 32; - numchans = 6; - } - - rewind(0); - AdPlug_LogWrite("--- CksmPlayer::load ---\n"); - return true; -} - -bool CksmPlayer::update() -{ - int quanter,chan,drumnum,freq,track,volevel,volval; - unsigned int i,j,bufnum; - unsigned long temp,templong; - - count++; - if (count >= countstop) - { - bufnum = 0; - while (count >= countstop) - { - templong = note[nownote]; - track = (int)((templong>>8)&15); - if ((templong&192) == 0) - { - i = 0; - - while ((i < numchans) && - ((chanfreq[i] != (templong&63)) || - (chantrack[i] != ((templong>>8)&15)))) - i++; - if (i < numchans) - { - databuf[bufnum] = (char)0; bufnum++; - databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++; - databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)&223); bufnum++; - chanfreq[i] = 0; - chanage[i] = 0; - } - } - else - { - volevel = trvol[track]; - if ((templong&192) == 128) - { - volevel -= 4; - if (volevel < 0) - volevel = 0; - } - if ((templong&192) == 192) - { - volevel += 4; - if (volevel > 63) - volevel = 63; - } - if (track < 11) - { - temp = 0; - i = numchans; - for(j=0;j<numchans;j++) - if ((countstop - chanage[j] >= temp) && (chantrack[j] == track)) - { - temp = countstop - chanage[j]; - i = j; - } - if (i < numchans) - { - databuf[bufnum] = (char)0, bufnum++; - databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++; - databuf[bufnum] = (unsigned char)0; bufnum++; - volval = (inst[trinst[track]][1]&192)+(volevel^63); - databuf[bufnum] = (char)0, bufnum++; - databuf[bufnum] = (unsigned char)(0x40+op_table[i]+3); bufnum++; - databuf[bufnum] = (unsigned char)volval; bufnum++; - databuf[bufnum] = (char)0, bufnum++; - databuf[bufnum] = (unsigned char)(0xa0+i); bufnum++; - databuf[bufnum] = (unsigned char)(adlibfreq[templong&63]&255); bufnum++; - databuf[bufnum] = (char)0, bufnum++; - databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++; - databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)|32); bufnum++; - chanfreq[i] = templong&63; - chanage[i] = countstop; - } - } - else if ((drumstat&32) > 0) - { - freq = adlibfreq[templong&63]; - switch(track) - { - case 11: drumnum = 16; chan = 6; freq -= 2048; break; - case 12: drumnum = 8; chan = 7; freq -= 2048; break; - case 13: drumnum = 4; chan = 8; break; - case 14: drumnum = 2; chan = 8; break; - case 15: drumnum = 1; chan = 7; freq -= 2048; break; - } - databuf[bufnum] = (char)0, bufnum++; - databuf[bufnum] = (unsigned char)(0xa0+chan); bufnum++; - databuf[bufnum] = (unsigned char)(freq&255); bufnum++; - databuf[bufnum] = (char)0, bufnum++; - databuf[bufnum] = (unsigned char)(0xb0+chan); bufnum++; - databuf[bufnum] = (unsigned char)((freq>>8)&223); bufnum++; - databuf[bufnum] = (char)0, bufnum++; - databuf[bufnum] = (unsigned char)(0xbd); bufnum++; - databuf[bufnum] = (unsigned char)(drumstat&(255-drumnum)); bufnum++; - drumstat |= drumnum; - if ((track == 11) || (track == 12) || (track == 14)) - { - volval = (inst[trinst[track]][1]&192)+(volevel^63); - databuf[bufnum] = (char)0, bufnum++; - databuf[bufnum] = (unsigned char)(0x40+op_table[chan]+3); bufnum++; - databuf[bufnum] = (unsigned char)(volval); bufnum++; - } - else - { - volval = (inst[trinst[track]][6]&192)+(volevel^63); - databuf[bufnum] = (char)0, bufnum++; - databuf[bufnum] = (unsigned char)(0x40+op_table[chan]); bufnum++; - databuf[bufnum] = (unsigned char)(volval); bufnum++; - } - databuf[bufnum] = (char)0, bufnum++; - databuf[bufnum] = (unsigned char)(0xbd); bufnum++; - databuf[bufnum] = (unsigned char)(drumstat); bufnum++; - } - } - nownote++; - if (nownote >= numnotes) { - nownote = 0; - songend = true; - } - templong = note[nownote]; - if (nownote == 0) - count = (templong>>12)-1; - quanter = (240/trquant[(templong>>8)&15]); - countstop = (((templong>>12)+(quanter>>1)) / quanter) * quanter; - } - for(i=0;i<bufnum;i+=3) - opl->write(databuf[i+1],databuf[i+2]); - } - return !songend; -} - -void CksmPlayer::rewind(int subsong) -{ - unsigned int i,j,k; - unsigned char instbuf[11]; - unsigned long templong; - - songend = false; - opl->init(); opl->write(1,32); opl->write(4,0); opl->write(8,0); opl->write(0xbd,drumstat); - - if (trchan[11] == 1) { - for(i=0;i<11;i++) - instbuf[i] = inst[trinst[11]][i]; - instbuf[1] = ((instbuf[1]&192)|(trvol[11])^63); - setinst(6,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); - for(i=0;i<5;i++) - instbuf[i] = inst[trinst[12]][i]; - for(i=5;i<11;i++) - instbuf[i] = inst[trinst[15]][i]; - instbuf[1] = ((instbuf[1]&192)|(trvol[12])^63); - instbuf[6] = ((instbuf[6]&192)|(trvol[15])^63); - setinst(7,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); - for(i=0;i<5;i++) - instbuf[i] = inst[trinst[14]][i]; - for(i=5;i<11;i++) - instbuf[i] = inst[trinst[13]][i]; - instbuf[1] = ((instbuf[1]&192)|(trvol[14])^63); - instbuf[6] = ((instbuf[6]&192)|(trvol[13])^63); - setinst(8,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); - } - - for(i=0;i<numchans;i++) - { - chantrack[i] = 0; - chanage[i] = 0; - } - j = 0; - for(i=0;i<16;i++) - if ((trchan[i] > 0) && (j < numchans)) - { - k = trchan[i]; - while ((j < numchans) && (k > 0)) - { - chantrack[j] = i; - k--; - j++; - } - } - for(i=0;i<numchans;i++) - { - for(j=0;j<11;j++) - instbuf[j] = inst[trinst[chantrack[i]]][j]; - instbuf[1] = ((instbuf[1]&192)|(63-trvol[chantrack[i]])); - setinst(i,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); - chanfreq[i] = 0; - } - k = 0; - templong = *note; - count = (templong>>12)-1; - countstop = (templong>>12)-1; - nownote = 0; -} - -std::string CksmPlayer::getinstrument(unsigned int n) -{ - if(trchan[n]) - return std::string(instname[trinst[n]]); - else - return std::string(); -} - -/*** private methods *************************************/ - -void CksmPlayer::loadinsts(binistream *f) -{ - int i, j; - - for(i = 0; i < 256; i++) { - f->readString(instname[i], 20); - for(j = 0; j < 11; j++) inst[i][j] = f->readInt(1); - f->ignore(2); - } -} - -void CksmPlayer::setinst(int chan, - unsigned char v0,unsigned char v1,unsigned char v2, - unsigned char v3,unsigned char v4,unsigned char v5, - unsigned char v6,unsigned char v7,unsigned char v8, - unsigned char v9,unsigned char v10) -{ - int offs; - - opl->write(0xa0+chan,0); - opl->write(0xb0+chan,0); - opl->write(0xc0+chan,v10); - offs = op_table[chan]; - opl->write(0x20+offs,v5); - opl->write(0x40+offs,v6); - opl->write(0x60+offs,v7); - opl->write(0x80+offs,v8); - opl->write(0xe0+offs,v9); - offs+=3; - opl->write(0x20+offs,v0); - opl->write(0x40+offs,v1); - opl->write(0x60+offs,v2); - opl->write(0x80+offs,v3); - opl->write(0xe0+offs,v4); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/ksm.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,336 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2006 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 + * + * ksm.cpp - KSM Player for AdPlug by Simon Peter <dn.tlp@gmx.net> + */ + +#include <string.h> + +#include "ksm.h" +#include "debug.h" + +const unsigned int CksmPlayer::adlibfreq[63] = { + 0, + 2390,2411,2434,2456,2480,2506,2533,2562,2592,2625,2659,2695, + 3414,3435,3458,3480,3504,3530,3557,3586,3616,3649,3683,3719, + 4438,4459,4482,4504,4528,4554,4581,4610,4640,4673,4707,4743, + 5462,5483,5506,5528,5552,5578,5605,5634,5664,5697,5731,5767, + 6486,6507,6530,6552,6576,6602,6629,6658,6688,6721,6755,6791, + 7510}; + +/*** public methods **************************************/ + +CPlayer *CksmPlayer::factory(Copl *newopl) +{ + return new CksmPlayer(newopl); +} + +bool CksmPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f; + int i; + char *fn = new char[filename.length() + 9]; + + // file validation section + if(!fp.extension(filename, ".ksm")) { + AdPlug_LogWrite("CksmPlayer::load(,\"%s\"): File doesn't have '.ksm' " + "extension! Rejected!\n", filename.c_str()); + return false; + } + AdPlug_LogWrite("*** CksmPlayer::load(,\"%s\") ***\n", filename.c_str()); + + // Load instruments from 'insts.dat' + strcpy(fn, filename.c_str()); + for(i = strlen(fn) - 1; i >= 0; i--) + if(fn[i] == '/' || fn[i] == '\\') + break; + strcpy(fn + i + 1, "insts.dat"); + AdPlug_LogWrite("Instruments file: \"%s\"\n", fn); + f = fp.open(fn); + delete [] fn; + if(!f) { + AdPlug_LogWrite("Couldn't open instruments file! Aborting!\n"); + AdPlug_LogWrite("--- CksmPlayer::load ---\n"); + return false; + } + loadinsts(f); + fp.close(f); + + f = fp.open(filename); if(!f) return false; + for(i = 0; i < 16; i++) trinst[i] = f->readInt(1); + for(i = 0; i < 16; i++) trquant[i] = f->readInt(1); + for(i = 0; i < 16; i++) trchan[i] = f->readInt(1); + f->ignore(16); + for(i = 0; i < 16; i++) trvol[i] = f->readInt(1); + numnotes = f->readInt(2); + note = new unsigned long [numnotes]; + for(i = 0; i < numnotes; i++) note[i] = f->readInt(4); + fp.close(f); + + if(!trchan[11]) { + drumstat = 0; + numchans = 9; + } else { + drumstat = 32; + numchans = 6; + } + + rewind(0); + AdPlug_LogWrite("--- CksmPlayer::load ---\n"); + return true; +} + +bool CksmPlayer::update() +{ + int quanter,chan,drumnum,freq,track,volevel,volval; + unsigned int i,j,bufnum; + unsigned long temp,templong; + + count++; + if (count >= countstop) + { + bufnum = 0; + while (count >= countstop) + { + templong = note[nownote]; + track = (int)((templong>>8)&15); + if ((templong&192) == 0) + { + i = 0; + + while ((i < numchans) && + ((chanfreq[i] != (templong&63)) || + (chantrack[i] != ((templong>>8)&15)))) + i++; + if (i < numchans) + { + databuf[bufnum] = (char)0; bufnum++; + databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++; + databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)&223); bufnum++; + chanfreq[i] = 0; + chanage[i] = 0; + } + } + else + { + volevel = trvol[track]; + if ((templong&192) == 128) + { + volevel -= 4; + if (volevel < 0) + volevel = 0; + } + if ((templong&192) == 192) + { + volevel += 4; + if (volevel > 63) + volevel = 63; + } + if (track < 11) + { + temp = 0; + i = numchans; + for(j=0;j<numchans;j++) + if ((countstop - chanage[j] >= temp) && (chantrack[j] == track)) + { + temp = countstop - chanage[j]; + i = j; + } + if (i < numchans) + { + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++; + databuf[bufnum] = (unsigned char)0; bufnum++; + volval = (inst[trinst[track]][1]&192)+(volevel^63); + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0x40+op_table[i]+3); bufnum++; + databuf[bufnum] = (unsigned char)volval; bufnum++; + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xa0+i); bufnum++; + databuf[bufnum] = (unsigned char)(adlibfreq[templong&63]&255); bufnum++; + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++; + databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)|32); bufnum++; + chanfreq[i] = templong&63; + chanage[i] = countstop; + } + } + else if ((drumstat&32) > 0) + { + freq = adlibfreq[templong&63]; + switch(track) + { + case 11: drumnum = 16; chan = 6; freq -= 2048; break; + case 12: drumnum = 8; chan = 7; freq -= 2048; break; + case 13: drumnum = 4; chan = 8; break; + case 14: drumnum = 2; chan = 8; break; + case 15: drumnum = 1; chan = 7; freq -= 2048; break; + } + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xa0+chan); bufnum++; + databuf[bufnum] = (unsigned char)(freq&255); bufnum++; + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xb0+chan); bufnum++; + databuf[bufnum] = (unsigned char)((freq>>8)&223); bufnum++; + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xbd); bufnum++; + databuf[bufnum] = (unsigned char)(drumstat&(255-drumnum)); bufnum++; + drumstat |= drumnum; + if ((track == 11) || (track == 12) || (track == 14)) + { + volval = (inst[trinst[track]][1]&192)+(volevel^63); + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0x40+op_table[chan]+3); bufnum++; + databuf[bufnum] = (unsigned char)(volval); bufnum++; + } + else + { + volval = (inst[trinst[track]][6]&192)+(volevel^63); + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0x40+op_table[chan]); bufnum++; + databuf[bufnum] = (unsigned char)(volval); bufnum++; + } + databuf[bufnum] = (char)0, bufnum++; + databuf[bufnum] = (unsigned char)(0xbd); bufnum++; + databuf[bufnum] = (unsigned char)(drumstat); bufnum++; + } + } + nownote++; + if (nownote >= numnotes) { + nownote = 0; + songend = true; + } + templong = note[nownote]; + if (nownote == 0) + count = (templong>>12)-1; + quanter = (240/trquant[(templong>>8)&15]); + countstop = (((templong>>12)+(quanter>>1)) / quanter) * quanter; + } + for(i=0;i<bufnum;i+=3) + opl->write(databuf[i+1],databuf[i+2]); + } + return !songend; +} + +void CksmPlayer::rewind(int subsong) +{ + unsigned int i,j,k; + unsigned char instbuf[11]; + unsigned long templong; + + songend = false; + opl->init(); opl->write(1,32); opl->write(4,0); opl->write(8,0); opl->write(0xbd,drumstat); + + if (trchan[11] == 1) { + for(i=0;i<11;i++) + instbuf[i] = inst[trinst[11]][i]; + instbuf[1] = ((instbuf[1]&192)|(trvol[11])^63); + setinst(6,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); + for(i=0;i<5;i++) + instbuf[i] = inst[trinst[12]][i]; + for(i=5;i<11;i++) + instbuf[i] = inst[trinst[15]][i]; + instbuf[1] = ((instbuf[1]&192)|(trvol[12])^63); + instbuf[6] = ((instbuf[6]&192)|(trvol[15])^63); + setinst(7,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); + for(i=0;i<5;i++) + instbuf[i] = inst[trinst[14]][i]; + for(i=5;i<11;i++) + instbuf[i] = inst[trinst[13]][i]; + instbuf[1] = ((instbuf[1]&192)|(trvol[14])^63); + instbuf[6] = ((instbuf[6]&192)|(trvol[13])^63); + setinst(8,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); + } + + for(i=0;i<numchans;i++) + { + chantrack[i] = 0; + chanage[i] = 0; + } + j = 0; + for(i=0;i<16;i++) + if ((trchan[i] > 0) && (j < numchans)) + { + k = trchan[i]; + while ((j < numchans) && (k > 0)) + { + chantrack[j] = i; + k--; + j++; + } + } + for(i=0;i<numchans;i++) + { + for(j=0;j<11;j++) + instbuf[j] = inst[trinst[chantrack[i]]][j]; + instbuf[1] = ((instbuf[1]&192)|(63-trvol[chantrack[i]])); + setinst(i,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]); + chanfreq[i] = 0; + } + k = 0; + templong = *note; + count = (templong>>12)-1; + countstop = (templong>>12)-1; + nownote = 0; +} + +std::string CksmPlayer::getinstrument(unsigned int n) +{ + if(trchan[n]) + return std::string(instname[trinst[n]]); + else + return std::string(); +} + +/*** private methods *************************************/ + +void CksmPlayer::loadinsts(binistream *f) +{ + int i, j; + + for(i = 0; i < 256; i++) { + f->readString(instname[i], 20); + for(j = 0; j < 11; j++) inst[i][j] = f->readInt(1); + f->ignore(2); + } +} + +void CksmPlayer::setinst(int chan, + unsigned char v0,unsigned char v1,unsigned char v2, + unsigned char v3,unsigned char v4,unsigned char v5, + unsigned char v6,unsigned char v7,unsigned char v8, + unsigned char v9,unsigned char v10) +{ + int offs; + + opl->write(0xa0+chan,0); + opl->write(0xb0+chan,0); + opl->write(0xc0+chan,v10); + offs = op_table[chan]; + opl->write(0x20+offs,v5); + opl->write(0x40+offs,v6); + opl->write(0x60+offs,v7); + opl->write(0x80+offs,v8); + opl->write(0xe0+offs,v9); + offs+=3; + opl->write(0x20+offs,v0); + opl->write(0x40+offs,v1); + opl->write(0x60+offs,v2); + opl->write(0x80+offs,v3); + opl->write(0xe0+offs,v4); +}
--- a/Plugins/Input/adplug/core/lds.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,676 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2004 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 - * - * lds.cpp - LOUDNESS Player by Simon Peter <dn.tlp@gmx.net> - */ - -#include <string.h> - -#include "lds.h" -#include "debug.h" - -// Note frequency table (16 notes / octave) -const unsigned short CldsPlayer::frequency[] = { - 343, 344, 345, 347, 348, 349, 350, 352, 353, 354, 356, 357, 358, - 359, 361, 362, 363, 365, 366, 367, 369, 370, 371, 373, 374, 375, - 377, 378, 379, 381, 382, 384, 385, 386, 388, 389, 391, 392, 393, - 395, 396, 398, 399, 401, 402, 403, 405, 406, 408, 409, 411, 412, - 414, 415, 417, 418, 420, 421, 423, 424, 426, 427, 429, 430, 432, - 434, 435, 437, 438, 440, 442, 443, 445, 446, 448, 450, 451, 453, - 454, 456, 458, 459, 461, 463, 464, 466, 468, 469, 471, 473, 475, - 476, 478, 480, 481, 483, 485, 487, 488, 490, 492, 494, 496, 497, - 499, 501, 503, 505, 506, 508, 510, 512, 514, 516, 518, 519, 521, - 523, 525, 527, 529, 531, 533, 535, 537, 538, 540, 542, 544, 546, - 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 568, 571, 573, - 575, 577, 579, 581, 583, 585, 587, 589, 591, 594, 596, 598, 600, - 602, 604, 607, 609, 611, 613, 615, 618, 620, 622, 624, 627, 629, - 631, 633, 636, 638, 640, 643, 645, 647, 650, 652, 654, 657, 659, - 662, 664, 666, 669, 671, 674, 676, 678, 681, 683 -}; - -// Vibrato (sine) table -const unsigned char CldsPlayer::vibtab[] = { - 0, 13, 25, 37, 50, 62, 74, 86, 98, 109, 120, 131, 142, 152, 162, - 171, 180, 189, 197, 205, 212, 219, 225, 231, 236, 240, 244, 247, - 250, 252, 254, 255, 255, 255, 254, 252, 250, 247, 244, 240, 236, - 231, 225, 219, 212, 205, 197, 189, 180, 171, 162, 152, 142, 131, - 120, 109, 98, 86, 74, 62, 50, 37, 25, 13 -}; - -// Tremolo (sine * sine) table -const unsigned char CldsPlayer::tremtab[] = { - 0, 0, 1, 1, 2, 4, 5, 7, 10, 12, 15, 18, 21, 25, 29, 33, 37, 42, 47, - 52, 57, 62, 67, 73, 79, 85, 90, 97, 103, 109, 115, 121, 128, 134, - 140, 146, 152, 158, 165, 170, 176, 182, 188, 193, 198, 203, 208, - 213, 218, 222, 226, 230, 234, 237, 240, 243, 245, 248, 250, 251, - 253, 254, 254, 255, 255, 255, 254, 254, 253, 251, 250, 248, 245, - 243, 240, 237, 234, 230, 226, 222, 218, 213, 208, 203, 198, 193, - 188, 182, 176, 170, 165, 158, 152, 146, 140, 134, 127, 121, 115, - 109, 103, 97, 90, 85, 79, 73, 67, 62, 57, 52, 47, 42, 37, 33, 29, - 25, 21, 18, 15, 12, 10, 7, 5, 4, 2, 1, 1, 0 -}; - -// 'maxsound' is maximum number of patches (instruments) -// 'maxpos' is maximum number of entries in position list (orderlist) -const unsigned short CldsPlayer::maxsound = 0x3f, CldsPlayer::maxpos = 0xff; - -/*** public methods *************************************/ - -CldsPlayer::CldsPlayer(Copl *newopl) - : CPlayer(newopl), soundbank(0), positions(0), patterns(0) -{ -} - -CldsPlayer::~CldsPlayer() -{ - if(soundbank) delete [] soundbank; - if(positions) delete [] positions; - if(patterns) delete [] patterns; -} - -bool CldsPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f; - unsigned int i, j; - SoundBank *sb; - - // file validation section (actually just an extension check) - if(!fp.extension(filename, ".lds")) return false; - f = fp.open(filename); if(!f) return false; - - // file load section (header) - mode = f->readInt(1); - if(mode > 2) { fp.close(f); return false; } - speed = f->readInt(2); - tempo = f->readInt(1); - pattlen = f->readInt(1); - for(i = 0; i < 9; i++) chandelay[i] = f->readInt(1); - regbd = f->readInt(1); - - // load patches - numpatch = f->readInt(2); - soundbank = new SoundBank[numpatch]; - for(i = 0; i < numpatch; i++) { - sb = &soundbank[i]; - sb->mod_misc = f->readInt(1); sb->mod_vol = f->readInt(1); - sb->mod_ad = f->readInt(1); sb->mod_sr = f->readInt(1); - sb->mod_wave = f->readInt(1); sb->car_misc = f->readInt(1); - sb->car_vol = f->readInt(1); sb->car_ad = f->readInt(1); - sb->car_sr = f->readInt(1); sb->car_wave = f->readInt(1); - sb->feedback = f->readInt(1); sb->keyoff = f->readInt(1); - sb->portamento = f->readInt(1); sb->glide = f->readInt(1); - sb->finetune = f->readInt(1); sb->vibrato = f->readInt(1); - sb->vibdelay = f->readInt(1); sb->mod_trem = f->readInt(1); - sb->car_trem = f->readInt(1); sb->tremwait = f->readInt(1); - sb->arpeggio = f->readInt(1); - for(j = 0; j < 12; j++) sb->arp_tab[j] = f->readInt(1); - sb->start = f->readInt(2); sb->size = f->readInt(2); - sb->fms = f->readInt(1); sb->transp = f->readInt(2); - sb->midinst = f->readInt(1); sb->midvelo = f->readInt(1); - sb->midkey = f->readInt(1); sb->midtrans = f->readInt(1); - sb->middum1 = f->readInt(1); sb->middum2 = f->readInt(1); - } - - // load positions - numposi = f->readInt(2); - positions = new Position[9 * numposi]; - for(i = 0; i < numposi; i++) - for(j = 0; j < 9; j++) { - /* - * patnum is a pointer inside the pattern space, but patterns are 16bit - * word fields anyway, so it ought to be an even number (hopefully) and - * we can just divide it by 2 to get our array index of 16bit words. - */ - positions[i * 9 + j].patnum = f->readInt(2) / 2; - positions[i * 9 + j].transpose = f->readInt(1); - } - - AdPlug_LogWrite("CldsPlayer::load(\"%s\",fp): loading LOUDNESS file: mode = " - "%d, pattlen = %d, numpatch = %d, numposi = %d\n", - filename.c_str(), mode, pattlen, numpatch, numposi); - - // load patterns - f->ignore(2); // ignore # of digital sounds (not played by this player) - patterns = new unsigned short[(fp.filesize(f) - f->pos()) / 2 + 1]; - for(i = 0; !f->eof(); i++) - patterns[i] = f->readInt(2); - - fp.close(f); - rewind(0); - return true; -} - -bool CldsPlayer::update() -{ - unsigned short comword, freq, octave, chan, tune, wibc, tremc, arpreg; - bool vbreak; - unsigned char level, regnum, comhi, comlo; - int i; - Channel *c; - - if(!playing) return false; - - // handle fading - if(fadeonoff) - if(fadeonoff <= 128) { - if(allvolume > fadeonoff || allvolume == 0) - allvolume -= fadeonoff; - else { - allvolume = 1; - fadeonoff = 0; - if(hardfade != 0) { - playing = false; - hardfade = 0; - for(i = 0; i < 9; i++) - channel[i].keycount = 1; - } - } - } else - if((unsigned int)((allvolume + (0x100 - fadeonoff)) & 0xff) <= mainvolume) - allvolume += 0x100 - fadeonoff; - else { - allvolume = mainvolume; - fadeonoff = 0; - } - - // handle channel delay - for(chan = 0; chan < 9; chan++) { - c = &channel[chan]; - if(c->chancheat.chandelay) - if(!(--c->chancheat.chandelay)) - playsound(c->chancheat.sound, chan, c->chancheat.high); - } - - // handle notes - if(!tempo_now) { - vbreak = false; - for(chan = 0; chan < 9; chan++) { - c = &channel[chan]; - if(!c->packwait) { - unsigned short patnum = positions[posplay * 9 + chan].patnum; - unsigned char transpose = positions[posplay * 9 + chan].transpose; - - comword = patterns[patnum + c->packpos]; - comhi = comword >> 8; comlo = comword & 0xff; - if(comword) - if(comhi == 0x80) - c->packwait = comlo; - else - if(comhi >= 0x80) { - switch(comhi) { - case 0xff: - c->volcar = (((c->volcar & 0x3f) * comlo) >> 6) & 0x3f; - if(fmchip[0xc0 + chan] & 1) - c->volmod = (((c->volmod & 0x3f) * comlo) >> 6) & 0x3f; - break; - case 0xfe: - tempo = comword & 0x3f; - break; - case 0xfd: - c->nextvol = comlo; - break; - case 0xfc: - playing = false; - // in real player there's also full keyoff here, but we don't need it - break; - case 0xfb: - c->keycount = 1; - break; - case 0xfa: - vbreak = true; - jumppos = (posplay + 1) & maxpos; - break; - case 0xf9: - vbreak = true; - jumppos = comlo & maxpos; - jumping = 1; - if(jumppos < posplay) songlooped = true; - break; - case 0xf8: - c->lasttune = 0; - break; - case 0xf7: - c->vibwait = 0; - // PASCAL: c->vibspeed = ((comlo >> 4) & 15) + 2; - c->vibspeed = (comlo >> 4) + 2; - c->vibrate = (comlo & 15) + 1; - break; - case 0xf6: - c->glideto = comlo; - break; - case 0xf5: - c->finetune = comlo; - break; - case 0xf4: - if(!hardfade) { - allvolume = mainvolume = comlo; - fadeonoff = 0; - } - break; - case 0xf3: - if(!hardfade) fadeonoff = comlo; - break; - case 0xf2: - c->trmstay = comlo; - break; - case 0xf1: // panorama - case 0xf0: // progch - // MIDI commands (unhandled) - AdPlug_LogWrite("CldsPlayer(): not handling MIDI command 0x%x, " - "value = 0x%x\n", comhi); - break; - default: - if(comhi < 0xa0) - c->glideto = comhi & 0x1f; - else - AdPlug_LogWrite("CldsPlayer(): unknown command 0x%x encountered!" - " value = 0x%x\n", comhi, comlo); - break; - } - } else { - unsigned char sound; - unsigned short high; - signed char transp = transpose & 127; - - /* - * Originally, in assembler code, the player first shifted - * logically left the transpose byte by 1 and then shifted - * arithmetically right the same byte to achieve the final, - * signed transpose value. Since we can't do arithmetic shifts - * in C, we just duplicate the 7th bit into the 8th one and - * discard the 8th one completely. - */ - - if(transpose & 64) transp |= 128; - - if(transpose & 128) { - sound = (comlo + transp) & maxsound; - high = comhi << 4; - } else { - sound = comlo & maxsound; - high = (comhi + transp) << 4; - } - - /* - PASCAL: - sound = comlo & maxsound; - high = (comhi + (((transpose + 0x24) & 0xff) - 0x24)) << 4; - */ - - if(!chandelay[chan]) - playsound(sound, chan, high); - else { - c->chancheat.chandelay = chandelay[chan]; - c->chancheat.sound = sound; - c->chancheat.high = high; - } - } - - c->packpos++; - } else - c->packwait--; - } - - tempo_now = tempo; - /* - The continue table is updated here, but this is only used in the - original player, which can be paused in the middle of a song and then - unpaused. Since AdPlug does all this for us automatically, we don't - have a continue table here. The continue table update code is noted - here for reference only. - - if(!pattplay) { - conttab[speed & maxcont].position = posplay & 0xff; - conttab[speed & maxcont].tempo = tempo; - } - */ - pattplay++; - if(vbreak) { - pattplay = 0; - for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; - posplay = jumppos; - } else - if(pattplay >= pattlen) { - pattplay = 0; - for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; - posplay = (posplay + 1) & maxpos; - } - } else - tempo_now--; - - // make effects - for(chan = 0; chan < 9; chan++) { - c = &channel[chan]; - regnum = op_table[chan]; - if(c->keycount > 0) { - if(c->keycount == 1) - setregs_adv(0xb0 + chan, 0xdf, 0); - c->keycount--; - } - - // arpeggio - if(c->arp_size == 0) - arpreg = 0; - else { - arpreg = c->arp_tab[c->arp_pos] << 4; - if(arpreg == 0x800) { - if(c->arp_pos > 0) c->arp_tab[0] = c->arp_tab[c->arp_pos - 1]; - c->arp_size = 1; c->arp_pos = 0; - arpreg = c->arp_tab[0] << 4; - } - - if(c->arp_count == c->arp_speed) { - c->arp_pos++; - if(c->arp_pos >= c->arp_size) c->arp_pos = 0; - c->arp_count = 0; - } else - c->arp_count++; - } - - // glide & portamento - if(c->lasttune && (c->lasttune != c->gototune)) { - if(c->lasttune > c->gototune) { - if(c->lasttune - c->gototune < c->portspeed) - c->lasttune = c->gototune; - else - c->lasttune -= c->portspeed; - } else { - if(c->gototune - c->lasttune < c->portspeed) - c->lasttune = c->gototune; - else - c->lasttune += c->portspeed; - } - - if(arpreg >= 0x800) - arpreg = c->lasttune - (arpreg ^ 0xff0) - 16; - else - arpreg += c->lasttune; - - freq = frequency[arpreg % (12 * 16)]; - octave = arpreg / (12 * 16) - 1; - setregs(0xa0 + chan, freq & 0xff); - setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); - } else { - // vibrato - if(!c->vibwait) { - if(c->vibrate) { - wibc = vibtab[c->vibcount & 0x3f] * c->vibrate; - - if((c->vibcount & 0x40) == 0) - tune = c->lasttune + (wibc >> 8); - else - tune = c->lasttune - (wibc >> 8); - - if(arpreg >= 0x800) - tune = tune - (arpreg ^ 0xff0) - 16; - else - tune += arpreg; - - freq = frequency[tune % (12 * 16)]; - octave = tune / (12 * 16) - 1; - setregs(0xa0 + chan, freq & 0xff); - setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); - c->vibcount += c->vibspeed; - } else - if(c->arp_size != 0) { // no vibrato, just arpeggio - if(arpreg >= 0x800) - tune = c->lasttune - (arpreg ^ 0xff0) - 16; - else - tune = c->lasttune + arpreg; - - freq = frequency[tune % (12 * 16)]; - octave = tune / (12 * 16) - 1; - setregs(0xa0 + chan, freq & 0xff); - setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); - } - } else { // no vibrato, just arpeggio - c->vibwait--; - - if(c->arp_size != 0) { - if(arpreg >= 0x800) - tune = c->lasttune - (arpreg ^ 0xff0) - 16; - else - tune = c->lasttune + arpreg; - - freq = frequency[tune % (12 * 16)]; - octave = tune / (12 * 16) - 1; - setregs(0xa0 + chan, freq & 0xff); - setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); - } - } - } - - // tremolo (modulator) - if(!c->trmwait) { - if(c->trmrate) { - tremc = tremtab[c->trmcount & 0x7f] * c->trmrate; - if((tremc >> 8) <= (c->volmod & 0x3f)) - level = (c->volmod & 0x3f) - (tremc >> 8); - else - level = 0; - - if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) - setregs_adv(0x40 + regnum, 0xc0, ((level * allvolume) >> 8) ^ 0x3f); - else - setregs_adv(0x40 + regnum, 0xc0, level ^ 0x3f); - - c->trmcount += c->trmspeed; - } else - if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) - setregs_adv(0x40 + regnum, 0xc0, ((((c->volmod & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); - else - setregs_adv(0x40 + regnum, 0xc0, (c->volmod ^ 0x3f) & 0x3f); - } else { - c->trmwait--; - if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) - setregs_adv(0x40 + regnum, 0xc0, ((((c->volmod & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); - } - - // tremolo (carrier) - if(!c->trcwait) { - if(c->trcrate) { - tremc = tremtab[c->trccount & 0x7f] * c->trcrate; - if((tremc >> 8) <= (c->volcar & 0x3f)) - level = (c->volcar & 0x3f) - (tremc >> 8); - else - level = 0; - - if(allvolume != 0) - setregs_adv(0x43 + regnum, 0xc0, ((level * allvolume) >> 8) ^ 0x3f); - else - setregs_adv(0x43 + regnum, 0xc0, level ^ 0x3f); - c->trccount += c->trcspeed; - } else - if(allvolume != 0) - setregs_adv(0x43 + regnum, 0xc0, ((((c->volcar & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); - else - setregs_adv(0x43 + regnum, 0xc0, (c->volcar ^ 0x3f) & 0x3f); - } else { - c->trcwait--; - if(allvolume != 0) - setregs_adv(0x43 + regnum, 0xc0, ((((c->volcar & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); - } - } - - return (!playing || songlooped) ? false : true; -} - -void CldsPlayer::rewind(int subsong) -{ - int i; - - // init all with 0 - tempo_now = 3; playing = true; songlooped = false; - jumping = fadeonoff = allvolume = hardfade = pattplay = posplay = jumppos = - mainvolume = 0; - memset(channel, 0, sizeof(channel)); - memset(fmchip, 0, sizeof(fmchip)); - - // OPL2 init - opl->init(); // Reset OPL chip - opl->write(1, 0x20); - opl->write(8, 0); - opl->write(0xbd, regbd); - - for(i = 0; i < 9; i++) { - opl->write(0x20 + op_table[i], 0); - opl->write(0x23 + op_table[i], 0); - opl->write(0x40 + op_table[i], 0x3f); - opl->write(0x43 + op_table[i], 0x3f); - opl->write(0x60 + op_table[i], 0xff); - opl->write(0x63 + op_table[i], 0xff); - opl->write(0x80 + op_table[i], 0xff); - opl->write(0x83 + op_table[i], 0xff); - opl->write(0xe0 + op_table[i], 0); - opl->write(0xe3 + op_table[i], 0); - opl->write(0xa0 + i, 0); - opl->write(0xb0 + i, 0); - opl->write(0xc0 + i, 0); - } -} - -/*** private methods *************************************/ - -void CldsPlayer::playsound(int inst_number, int channel_number, int tunehigh) -{ - Channel *c = &channel[channel_number]; // current channel - SoundBank *i = &soundbank[inst_number]; // current instrument - unsigned int regnum = op_table[channel_number]; // channel's OPL2 register - unsigned char volcalc, octave; - unsigned short freq; - - // set fine tune - tunehigh += ((i->finetune + c->finetune + 0x80) & 0xff) - 0x80; - - // arpeggio handling - if(!i->arpeggio) { - unsigned short arpcalc = i->arp_tab[0] << 4; - - if(arpcalc > 0x800) - tunehigh = tunehigh - (arpcalc ^ 0xff0) - 16; - else - tunehigh += arpcalc; - } - - // glide handling - if(c->glideto != 0) { - c->gototune = tunehigh; - c->portspeed = c->glideto; - c->glideto = c->finetune = 0; - return; - } - - // set modulator registers - setregs(0x20 + regnum, i->mod_misc); - volcalc = i->mod_vol; - if(!c->nextvol || !(i->feedback & 1)) - c->volmod = volcalc; - else - c->volmod = (volcalc & 0xc0) | ((((volcalc & 0x3f) * c->nextvol) >> 6)); - - if((i->feedback & 1) == 1 && allvolume != 0) - setregs(0x40 + regnum, ((c->volmod & 0xc0) | (((c->volmod & 0x3f) * allvolume) >> 8)) ^ 0x3f); - else - setregs(0x40 + regnum, c->volmod ^ 0x3f); - setregs(0x60 + regnum, i->mod_ad); - setregs(0x80 + regnum, i->mod_sr); - setregs(0xe0 + regnum, i->mod_wave); - - // Set carrier registers - setregs(0x23 + regnum, i->car_misc); - volcalc = i->car_vol; - if(!c->nextvol) - c->volcar = volcalc; - else - c->volcar = (volcalc & 0xc0) | ((((volcalc & 0x3f) * c->nextvol) >> 6)); - - if(allvolume) - setregs(0x43 + regnum, ((c->volcar & 0xc0) | (((c->volcar & 0x3f) * allvolume) >> 8)) ^ 0x3f); - else - setregs(0x43 + regnum, c->volcar ^ 0x3f); - setregs(0x63 + regnum, i->car_ad); - setregs(0x83 + regnum, i->car_sr); - setregs(0xe3 + regnum, i->car_wave); - setregs(0xc0 + channel_number, i->feedback); - setregs_adv(0xb0 + channel_number, 0xdf, 0); // key off - - freq = frequency[tunehigh % (12 * 16)]; - octave = tunehigh / (12 * 16) - 1; - if(!i->glide) { - if(!i->portamento || !c->lasttune) { - setregs(0xa0 + channel_number, freq & 0xff); - setregs(0xb0 + channel_number, (octave << 2) + 0x20 + (freq >> 8)); - c->lasttune = c->gototune = tunehigh; - } else { - c->gototune = tunehigh; - c->portspeed = i->portamento; - setregs_adv(0xb0 + channel_number, 0xdf, 0x20); // key on - } - } else { - setregs(0xa0 + channel_number, freq & 0xff); - setregs(0xb0 + channel_number, (octave << 2) + 0x20 + (freq >> 8)); - c->lasttune = tunehigh; - c->gototune = tunehigh + ((i->glide + 0x80) & 0xff) - 0x80; // set destination - c->portspeed = i->portamento; - } - - if(!i->vibrato) - c->vibwait = c->vibspeed = c->vibrate = 0; - else { - c->vibwait = i->vibdelay; - // PASCAL: c->vibspeed = ((i->vibrato >> 4) & 15) + 1; - c->vibspeed = (i->vibrato >> 4) + 2; - c->vibrate = (i->vibrato & 15) + 1; - } - - if(!(c->trmstay & 0xf0)) { - c->trmwait = (i->tremwait & 0xf0) >> 3; - // PASCAL: c->trmspeed = (i->mod_trem >> 4) & 15; - c->trmspeed = i->mod_trem >> 4; - c->trmrate = i->mod_trem & 15; - c->trmcount = 0; - } - - if(!(c->trmstay & 0x0f)) { - c->trcwait = (i->tremwait & 15) << 1; - // PASCAL: c->trcspeed = (i->car_trem >> 4) & 15; - c->trcspeed = i->car_trem >> 4; - c->trcrate = i->car_trem & 15; - c->trccount = 0; - } - - c->arp_size = i->arpeggio & 15; - c->arp_speed = i->arpeggio >> 4; - memcpy(c->arp_tab, i->arp_tab, 12); - c->keycount = i->keyoff; - c->nextvol = c->glideto = c->finetune = c->vibcount = c->arp_pos = c->arp_count = 0; -} - -inline void CldsPlayer::setregs(unsigned char reg, unsigned char val) -{ - if(fmchip[reg] == val) return; - - fmchip[reg] = val; - opl->write(reg, val); -} - -inline void CldsPlayer::setregs_adv(unsigned char reg, unsigned char mask, - unsigned char val) -{ - setregs(reg, (fmchip[reg] & mask) | val); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/lds.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,676 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 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 + * + * lds.cpp - LOUDNESS Player by Simon Peter <dn.tlp@gmx.net> + */ + +#include <string.h> + +#include "lds.h" +#include "debug.h" + +// Note frequency table (16 notes / octave) +const unsigned short CldsPlayer::frequency[] = { + 343, 344, 345, 347, 348, 349, 350, 352, 353, 354, 356, 357, 358, + 359, 361, 362, 363, 365, 366, 367, 369, 370, 371, 373, 374, 375, + 377, 378, 379, 381, 382, 384, 385, 386, 388, 389, 391, 392, 393, + 395, 396, 398, 399, 401, 402, 403, 405, 406, 408, 409, 411, 412, + 414, 415, 417, 418, 420, 421, 423, 424, 426, 427, 429, 430, 432, + 434, 435, 437, 438, 440, 442, 443, 445, 446, 448, 450, 451, 453, + 454, 456, 458, 459, 461, 463, 464, 466, 468, 469, 471, 473, 475, + 476, 478, 480, 481, 483, 485, 487, 488, 490, 492, 494, 496, 497, + 499, 501, 503, 505, 506, 508, 510, 512, 514, 516, 518, 519, 521, + 523, 525, 527, 529, 531, 533, 535, 537, 538, 540, 542, 544, 546, + 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 568, 571, 573, + 575, 577, 579, 581, 583, 585, 587, 589, 591, 594, 596, 598, 600, + 602, 604, 607, 609, 611, 613, 615, 618, 620, 622, 624, 627, 629, + 631, 633, 636, 638, 640, 643, 645, 647, 650, 652, 654, 657, 659, + 662, 664, 666, 669, 671, 674, 676, 678, 681, 683 +}; + +// Vibrato (sine) table +const unsigned char CldsPlayer::vibtab[] = { + 0, 13, 25, 37, 50, 62, 74, 86, 98, 109, 120, 131, 142, 152, 162, + 171, 180, 189, 197, 205, 212, 219, 225, 231, 236, 240, 244, 247, + 250, 252, 254, 255, 255, 255, 254, 252, 250, 247, 244, 240, 236, + 231, 225, 219, 212, 205, 197, 189, 180, 171, 162, 152, 142, 131, + 120, 109, 98, 86, 74, 62, 50, 37, 25, 13 +}; + +// Tremolo (sine * sine) table +const unsigned char CldsPlayer::tremtab[] = { + 0, 0, 1, 1, 2, 4, 5, 7, 10, 12, 15, 18, 21, 25, 29, 33, 37, 42, 47, + 52, 57, 62, 67, 73, 79, 85, 90, 97, 103, 109, 115, 121, 128, 134, + 140, 146, 152, 158, 165, 170, 176, 182, 188, 193, 198, 203, 208, + 213, 218, 222, 226, 230, 234, 237, 240, 243, 245, 248, 250, 251, + 253, 254, 254, 255, 255, 255, 254, 254, 253, 251, 250, 248, 245, + 243, 240, 237, 234, 230, 226, 222, 218, 213, 208, 203, 198, 193, + 188, 182, 176, 170, 165, 158, 152, 146, 140, 134, 127, 121, 115, + 109, 103, 97, 90, 85, 79, 73, 67, 62, 57, 52, 47, 42, 37, 33, 29, + 25, 21, 18, 15, 12, 10, 7, 5, 4, 2, 1, 1, 0 +}; + +// 'maxsound' is maximum number of patches (instruments) +// 'maxpos' is maximum number of entries in position list (orderlist) +const unsigned short CldsPlayer::maxsound = 0x3f, CldsPlayer::maxpos = 0xff; + +/*** public methods *************************************/ + +CldsPlayer::CldsPlayer(Copl *newopl) + : CPlayer(newopl), soundbank(0), positions(0), patterns(0) +{ +} + +CldsPlayer::~CldsPlayer() +{ + if(soundbank) delete [] soundbank; + if(positions) delete [] positions; + if(patterns) delete [] patterns; +} + +bool CldsPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f; + unsigned int i, j; + SoundBank *sb; + + // file validation section (actually just an extension check) + if(!fp.extension(filename, ".lds")) return false; + f = fp.open(filename); if(!f) return false; + + // file load section (header) + mode = f->readInt(1); + if(mode > 2) { fp.close(f); return false; } + speed = f->readInt(2); + tempo = f->readInt(1); + pattlen = f->readInt(1); + for(i = 0; i < 9; i++) chandelay[i] = f->readInt(1); + regbd = f->readInt(1); + + // load patches + numpatch = f->readInt(2); + soundbank = new SoundBank[numpatch]; + for(i = 0; i < numpatch; i++) { + sb = &soundbank[i]; + sb->mod_misc = f->readInt(1); sb->mod_vol = f->readInt(1); + sb->mod_ad = f->readInt(1); sb->mod_sr = f->readInt(1); + sb->mod_wave = f->readInt(1); sb->car_misc = f->readInt(1); + sb->car_vol = f->readInt(1); sb->car_ad = f->readInt(1); + sb->car_sr = f->readInt(1); sb->car_wave = f->readInt(1); + sb->feedback = f->readInt(1); sb->keyoff = f->readInt(1); + sb->portamento = f->readInt(1); sb->glide = f->readInt(1); + sb->finetune = f->readInt(1); sb->vibrato = f->readInt(1); + sb->vibdelay = f->readInt(1); sb->mod_trem = f->readInt(1); + sb->car_trem = f->readInt(1); sb->tremwait = f->readInt(1); + sb->arpeggio = f->readInt(1); + for(j = 0; j < 12; j++) sb->arp_tab[j] = f->readInt(1); + sb->start = f->readInt(2); sb->size = f->readInt(2); + sb->fms = f->readInt(1); sb->transp = f->readInt(2); + sb->midinst = f->readInt(1); sb->midvelo = f->readInt(1); + sb->midkey = f->readInt(1); sb->midtrans = f->readInt(1); + sb->middum1 = f->readInt(1); sb->middum2 = f->readInt(1); + } + + // load positions + numposi = f->readInt(2); + positions = new Position[9 * numposi]; + for(i = 0; i < numposi; i++) + for(j = 0; j < 9; j++) { + /* + * patnum is a pointer inside the pattern space, but patterns are 16bit + * word fields anyway, so it ought to be an even number (hopefully) and + * we can just divide it by 2 to get our array index of 16bit words. + */ + positions[i * 9 + j].patnum = f->readInt(2) / 2; + positions[i * 9 + j].transpose = f->readInt(1); + } + + AdPlug_LogWrite("CldsPlayer::load(\"%s\",fp): loading LOUDNESS file: mode = " + "%d, pattlen = %d, numpatch = %d, numposi = %d\n", + filename.c_str(), mode, pattlen, numpatch, numposi); + + // load patterns + f->ignore(2); // ignore # of digital sounds (not played by this player) + patterns = new unsigned short[(fp.filesize(f) - f->pos()) / 2 + 1]; + for(i = 0; !f->eof(); i++) + patterns[i] = f->readInt(2); + + fp.close(f); + rewind(0); + return true; +} + +bool CldsPlayer::update() +{ + unsigned short comword, freq, octave, chan, tune, wibc, tremc, arpreg; + bool vbreak; + unsigned char level, regnum, comhi, comlo; + int i; + Channel *c; + + if(!playing) return false; + + // handle fading + if(fadeonoff) + if(fadeonoff <= 128) { + if(allvolume > fadeonoff || allvolume == 0) + allvolume -= fadeonoff; + else { + allvolume = 1; + fadeonoff = 0; + if(hardfade != 0) { + playing = false; + hardfade = 0; + for(i = 0; i < 9; i++) + channel[i].keycount = 1; + } + } + } else + if((unsigned int)((allvolume + (0x100 - fadeonoff)) & 0xff) <= mainvolume) + allvolume += 0x100 - fadeonoff; + else { + allvolume = mainvolume; + fadeonoff = 0; + } + + // handle channel delay + for(chan = 0; chan < 9; chan++) { + c = &channel[chan]; + if(c->chancheat.chandelay) + if(!(--c->chancheat.chandelay)) + playsound(c->chancheat.sound, chan, c->chancheat.high); + } + + // handle notes + if(!tempo_now) { + vbreak = false; + for(chan = 0; chan < 9; chan++) { + c = &channel[chan]; + if(!c->packwait) { + unsigned short patnum = positions[posplay * 9 + chan].patnum; + unsigned char transpose = positions[posplay * 9 + chan].transpose; + + comword = patterns[patnum + c->packpos]; + comhi = comword >> 8; comlo = comword & 0xff; + if(comword) + if(comhi == 0x80) + c->packwait = comlo; + else + if(comhi >= 0x80) { + switch(comhi) { + case 0xff: + c->volcar = (((c->volcar & 0x3f) * comlo) >> 6) & 0x3f; + if(fmchip[0xc0 + chan] & 1) + c->volmod = (((c->volmod & 0x3f) * comlo) >> 6) & 0x3f; + break; + case 0xfe: + tempo = comword & 0x3f; + break; + case 0xfd: + c->nextvol = comlo; + break; + case 0xfc: + playing = false; + // in real player there's also full keyoff here, but we don't need it + break; + case 0xfb: + c->keycount = 1; + break; + case 0xfa: + vbreak = true; + jumppos = (posplay + 1) & maxpos; + break; + case 0xf9: + vbreak = true; + jumppos = comlo & maxpos; + jumping = 1; + if(jumppos < posplay) songlooped = true; + break; + case 0xf8: + c->lasttune = 0; + break; + case 0xf7: + c->vibwait = 0; + // PASCAL: c->vibspeed = ((comlo >> 4) & 15) + 2; + c->vibspeed = (comlo >> 4) + 2; + c->vibrate = (comlo & 15) + 1; + break; + case 0xf6: + c->glideto = comlo; + break; + case 0xf5: + c->finetune = comlo; + break; + case 0xf4: + if(!hardfade) { + allvolume = mainvolume = comlo; + fadeonoff = 0; + } + break; + case 0xf3: + if(!hardfade) fadeonoff = comlo; + break; + case 0xf2: + c->trmstay = comlo; + break; + case 0xf1: // panorama + case 0xf0: // progch + // MIDI commands (unhandled) + AdPlug_LogWrite("CldsPlayer(): not handling MIDI command 0x%x, " + "value = 0x%x\n", comhi); + break; + default: + if(comhi < 0xa0) + c->glideto = comhi & 0x1f; + else + AdPlug_LogWrite("CldsPlayer(): unknown command 0x%x encountered!" + " value = 0x%x\n", comhi, comlo); + break; + } + } else { + unsigned char sound; + unsigned short high; + signed char transp = transpose & 127; + + /* + * Originally, in assembler code, the player first shifted + * logically left the transpose byte by 1 and then shifted + * arithmetically right the same byte to achieve the final, + * signed transpose value. Since we can't do arithmetic shifts + * in C, we just duplicate the 7th bit into the 8th one and + * discard the 8th one completely. + */ + + if(transpose & 64) transp |= 128; + + if(transpose & 128) { + sound = (comlo + transp) & maxsound; + high = comhi << 4; + } else { + sound = comlo & maxsound; + high = (comhi + transp) << 4; + } + + /* + PASCAL: + sound = comlo & maxsound; + high = (comhi + (((transpose + 0x24) & 0xff) - 0x24)) << 4; + */ + + if(!chandelay[chan]) + playsound(sound, chan, high); + else { + c->chancheat.chandelay = chandelay[chan]; + c->chancheat.sound = sound; + c->chancheat.high = high; + } + } + + c->packpos++; + } else + c->packwait--; + } + + tempo_now = tempo; + /* + The continue table is updated here, but this is only used in the + original player, which can be paused in the middle of a song and then + unpaused. Since AdPlug does all this for us automatically, we don't + have a continue table here. The continue table update code is noted + here for reference only. + + if(!pattplay) { + conttab[speed & maxcont].position = posplay & 0xff; + conttab[speed & maxcont].tempo = tempo; + } + */ + pattplay++; + if(vbreak) { + pattplay = 0; + for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; + posplay = jumppos; + } else + if(pattplay >= pattlen) { + pattplay = 0; + for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; + posplay = (posplay + 1) & maxpos; + } + } else + tempo_now--; + + // make effects + for(chan = 0; chan < 9; chan++) { + c = &channel[chan]; + regnum = op_table[chan]; + if(c->keycount > 0) { + if(c->keycount == 1) + setregs_adv(0xb0 + chan, 0xdf, 0); + c->keycount--; + } + + // arpeggio + if(c->arp_size == 0) + arpreg = 0; + else { + arpreg = c->arp_tab[c->arp_pos] << 4; + if(arpreg == 0x800) { + if(c->arp_pos > 0) c->arp_tab[0] = c->arp_tab[c->arp_pos - 1]; + c->arp_size = 1; c->arp_pos = 0; + arpreg = c->arp_tab[0] << 4; + } + + if(c->arp_count == c->arp_speed) { + c->arp_pos++; + if(c->arp_pos >= c->arp_size) c->arp_pos = 0; + c->arp_count = 0; + } else + c->arp_count++; + } + + // glide & portamento + if(c->lasttune && (c->lasttune != c->gototune)) { + if(c->lasttune > c->gototune) { + if(c->lasttune - c->gototune < c->portspeed) + c->lasttune = c->gototune; + else + c->lasttune -= c->portspeed; + } else { + if(c->gototune - c->lasttune < c->portspeed) + c->lasttune = c->gototune; + else + c->lasttune += c->portspeed; + } + + if(arpreg >= 0x800) + arpreg = c->lasttune - (arpreg ^ 0xff0) - 16; + else + arpreg += c->lasttune; + + freq = frequency[arpreg % (12 * 16)]; + octave = arpreg / (12 * 16) - 1; + setregs(0xa0 + chan, freq & 0xff); + setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + } else { + // vibrato + if(!c->vibwait) { + if(c->vibrate) { + wibc = vibtab[c->vibcount & 0x3f] * c->vibrate; + + if((c->vibcount & 0x40) == 0) + tune = c->lasttune + (wibc >> 8); + else + tune = c->lasttune - (wibc >> 8); + + if(arpreg >= 0x800) + tune = tune - (arpreg ^ 0xff0) - 16; + else + tune += arpreg; + + freq = frequency[tune % (12 * 16)]; + octave = tune / (12 * 16) - 1; + setregs(0xa0 + chan, freq & 0xff); + setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + c->vibcount += c->vibspeed; + } else + if(c->arp_size != 0) { // no vibrato, just arpeggio + if(arpreg >= 0x800) + tune = c->lasttune - (arpreg ^ 0xff0) - 16; + else + tune = c->lasttune + arpreg; + + freq = frequency[tune % (12 * 16)]; + octave = tune / (12 * 16) - 1; + setregs(0xa0 + chan, freq & 0xff); + setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + } + } else { // no vibrato, just arpeggio + c->vibwait--; + + if(c->arp_size != 0) { + if(arpreg >= 0x800) + tune = c->lasttune - (arpreg ^ 0xff0) - 16; + else + tune = c->lasttune + arpreg; + + freq = frequency[tune % (12 * 16)]; + octave = tune / (12 * 16) - 1; + setregs(0xa0 + chan, freq & 0xff); + setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + } + } + } + + // tremolo (modulator) + if(!c->trmwait) { + if(c->trmrate) { + tremc = tremtab[c->trmcount & 0x7f] * c->trmrate; + if((tremc >> 8) <= (c->volmod & 0x3f)) + level = (c->volmod & 0x3f) - (tremc >> 8); + else + level = 0; + + if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) + setregs_adv(0x40 + regnum, 0xc0, ((level * allvolume) >> 8) ^ 0x3f); + else + setregs_adv(0x40 + regnum, 0xc0, level ^ 0x3f); + + c->trmcount += c->trmspeed; + } else + if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) + setregs_adv(0x40 + regnum, 0xc0, ((((c->volmod & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + else + setregs_adv(0x40 + regnum, 0xc0, (c->volmod ^ 0x3f) & 0x3f); + } else { + c->trmwait--; + if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) + setregs_adv(0x40 + regnum, 0xc0, ((((c->volmod & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + } + + // tremolo (carrier) + if(!c->trcwait) { + if(c->trcrate) { + tremc = tremtab[c->trccount & 0x7f] * c->trcrate; + if((tremc >> 8) <= (c->volcar & 0x3f)) + level = (c->volcar & 0x3f) - (tremc >> 8); + else + level = 0; + + if(allvolume != 0) + setregs_adv(0x43 + regnum, 0xc0, ((level * allvolume) >> 8) ^ 0x3f); + else + setregs_adv(0x43 + regnum, 0xc0, level ^ 0x3f); + c->trccount += c->trcspeed; + } else + if(allvolume != 0) + setregs_adv(0x43 + regnum, 0xc0, ((((c->volcar & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + else + setregs_adv(0x43 + regnum, 0xc0, (c->volcar ^ 0x3f) & 0x3f); + } else { + c->trcwait--; + if(allvolume != 0) + setregs_adv(0x43 + regnum, 0xc0, ((((c->volcar & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + } + } + + return (!playing || songlooped) ? false : true; +} + +void CldsPlayer::rewind(int subsong) +{ + int i; + + // init all with 0 + tempo_now = 3; playing = true; songlooped = false; + jumping = fadeonoff = allvolume = hardfade = pattplay = posplay = jumppos = + mainvolume = 0; + memset(channel, 0, sizeof(channel)); + memset(fmchip, 0, sizeof(fmchip)); + + // OPL2 init + opl->init(); // Reset OPL chip + opl->write(1, 0x20); + opl->write(8, 0); + opl->write(0xbd, regbd); + + for(i = 0; i < 9; i++) { + opl->write(0x20 + op_table[i], 0); + opl->write(0x23 + op_table[i], 0); + opl->write(0x40 + op_table[i], 0x3f); + opl->write(0x43 + op_table[i], 0x3f); + opl->write(0x60 + op_table[i], 0xff); + opl->write(0x63 + op_table[i], 0xff); + opl->write(0x80 + op_table[i], 0xff); + opl->write(0x83 + op_table[i], 0xff); + opl->write(0xe0 + op_table[i], 0); + opl->write(0xe3 + op_table[i], 0); + opl->write(0xa0 + i, 0); + opl->write(0xb0 + i, 0); + opl->write(0xc0 + i, 0); + } +} + +/*** private methods *************************************/ + +void CldsPlayer::playsound(int inst_number, int channel_number, int tunehigh) +{ + Channel *c = &channel[channel_number]; // current channel + SoundBank *i = &soundbank[inst_number]; // current instrument + unsigned int regnum = op_table[channel_number]; // channel's OPL2 register + unsigned char volcalc, octave; + unsigned short freq; + + // set fine tune + tunehigh += ((i->finetune + c->finetune + 0x80) & 0xff) - 0x80; + + // arpeggio handling + if(!i->arpeggio) { + unsigned short arpcalc = i->arp_tab[0] << 4; + + if(arpcalc > 0x800) + tunehigh = tunehigh - (arpcalc ^ 0xff0) - 16; + else + tunehigh += arpcalc; + } + + // glide handling + if(c->glideto != 0) { + c->gototune = tunehigh; + c->portspeed = c->glideto; + c->glideto = c->finetune = 0; + return; + } + + // set modulator registers + setregs(0x20 + regnum, i->mod_misc); + volcalc = i->mod_vol; + if(!c->nextvol || !(i->feedback & 1)) + c->volmod = volcalc; + else + c->volmod = (volcalc & 0xc0) | ((((volcalc & 0x3f) * c->nextvol) >> 6)); + + if((i->feedback & 1) == 1 && allvolume != 0) + setregs(0x40 + regnum, ((c->volmod & 0xc0) | (((c->volmod & 0x3f) * allvolume) >> 8)) ^ 0x3f); + else + setregs(0x40 + regnum, c->volmod ^ 0x3f); + setregs(0x60 + regnum, i->mod_ad); + setregs(0x80 + regnum, i->mod_sr); + setregs(0xe0 + regnum, i->mod_wave); + + // Set carrier registers + setregs(0x23 + regnum, i->car_misc); + volcalc = i->car_vol; + if(!c->nextvol) + c->volcar = volcalc; + else + c->volcar = (volcalc & 0xc0) | ((((volcalc & 0x3f) * c->nextvol) >> 6)); + + if(allvolume) + setregs(0x43 + regnum, ((c->volcar & 0xc0) | (((c->volcar & 0x3f) * allvolume) >> 8)) ^ 0x3f); + else + setregs(0x43 + regnum, c->volcar ^ 0x3f); + setregs(0x63 + regnum, i->car_ad); + setregs(0x83 + regnum, i->car_sr); + setregs(0xe3 + regnum, i->car_wave); + setregs(0xc0 + channel_number, i->feedback); + setregs_adv(0xb0 + channel_number, 0xdf, 0); // key off + + freq = frequency[tunehigh % (12 * 16)]; + octave = tunehigh / (12 * 16) - 1; + if(!i->glide) { + if(!i->portamento || !c->lasttune) { + setregs(0xa0 + channel_number, freq & 0xff); + setregs(0xb0 + channel_number, (octave << 2) + 0x20 + (freq >> 8)); + c->lasttune = c->gototune = tunehigh; + } else { + c->gototune = tunehigh; + c->portspeed = i->portamento; + setregs_adv(0xb0 + channel_number, 0xdf, 0x20); // key on + } + } else { + setregs(0xa0 + channel_number, freq & 0xff); + setregs(0xb0 + channel_number, (octave << 2) + 0x20 + (freq >> 8)); + c->lasttune = tunehigh; + c->gototune = tunehigh + ((i->glide + 0x80) & 0xff) - 0x80; // set destination + c->portspeed = i->portamento; + } + + if(!i->vibrato) + c->vibwait = c->vibspeed = c->vibrate = 0; + else { + c->vibwait = i->vibdelay; + // PASCAL: c->vibspeed = ((i->vibrato >> 4) & 15) + 1; + c->vibspeed = (i->vibrato >> 4) + 2; + c->vibrate = (i->vibrato & 15) + 1; + } + + if(!(c->trmstay & 0xf0)) { + c->trmwait = (i->tremwait & 0xf0) >> 3; + // PASCAL: c->trmspeed = (i->mod_trem >> 4) & 15; + c->trmspeed = i->mod_trem >> 4; + c->trmrate = i->mod_trem & 15; + c->trmcount = 0; + } + + if(!(c->trmstay & 0x0f)) { + c->trcwait = (i->tremwait & 15) << 1; + // PASCAL: c->trcspeed = (i->car_trem >> 4) & 15; + c->trcspeed = i->car_trem >> 4; + c->trcrate = i->car_trem & 15; + c->trccount = 0; + } + + c->arp_size = i->arpeggio & 15; + c->arp_speed = i->arpeggio >> 4; + memcpy(c->arp_tab, i->arp_tab, 12); + c->keycount = i->keyoff; + c->nextvol = c->glideto = c->finetune = c->vibcount = c->arp_pos = c->arp_count = 0; +} + +inline void CldsPlayer::setregs(unsigned char reg, unsigned char val) +{ + if(fmchip[reg] == val) return; + + fmchip[reg] = val; + opl->write(reg, val); +} + +inline void CldsPlayer::setregs_adv(unsigned char reg, unsigned char mask, + unsigned char val) +{ + setregs(reg, (fmchip[reg] & mask) | val); +}
--- a/Plugins/Input/adplug/core/mad.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -/* - 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 - - mad.cpp - MAD loader by Riven the Mage <riven@ok.ru> -*/ - -#include "mad.h" - -/* -------- Public Methods -------------------------------- */ - -CPlayer *CmadLoader::factory(Copl *newopl) -{ - return new CmadLoader(newopl); -} - -bool CmadLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - const unsigned char conv_inst[10] = { 2,1,10,9,4,3,6,5,8,7 }; - unsigned int i, j, k, t = 0; - - // 'MAD+' - signed ? - char id[4]; f->readString(id, 4); - if (strncmp(id,"MAD+",4)) { fp.close(f); return false; } - - // load instruments - for(i = 0; i < 9; i++) { - f->readString(instruments[i].name, 8); - for(j = 0; j < 12; j++) instruments[i].data[j] = f->readInt(1); - } - - f->ignore(1); - - // data for Protracker - length = f->readInt(1); nop = f->readInt(1); timer = f->readInt(1); - - // init CmodPlayer - realloc_instruments(9); - realloc_order(length); - realloc_patterns(nop,32,9); - init_trackord(); - - // load tracks - for(i = 0; i < nop; i++) - for(k = 0; k < 32; k++) - for(j = 0; j < 9; j++) { - t = i * 9 + j; - - // read event - unsigned char event = f->readInt(1); - - // convert event - if (event < 0x61) - tracks[t][k].note = event; - if (event == 0xFF) // 0xFF: Release note - tracks[t][k].command = 8; - if (event == 0xFE) // 0xFE: Pattern Break - tracks[t][k].command = 13; - } - - // load order - for(i = 0; i < length; i++) order[i] = f->readInt(1) - 1; - - fp.close(f); - - // convert instruments - for(i = 0; i < 9; i++) - for(j = 0; j < 10; j++) - inst[i].data[conv_inst[j]] = instruments[i].data[j]; - - // data for Protracker - restartpos = 0; - initspeed = 1; - - rewind(0); - return true; -} - -void CmadLoader::rewind(int subsong) -{ - CmodPlayer::rewind(subsong); - - // default instruments - for (int i=0;i<9;i++) - { - channel[i].inst = i; - - channel[i].vol1 = 63 - (inst[i].data[10] & 63); - channel[i].vol2 = 63 - (inst[i].data[9] & 63); - } -} - -float CmadLoader::getrefresh() -{ - return (float)timer; -} - -std::string CmadLoader::gettype() -{ - return std::string("Mlat Adlib Tracker"); -} - -std::string CmadLoader::getinstrument(unsigned int n) -{ - return std::string(instruments[n].name,8); -} - -unsigned int CmadLoader::getinstruments() -{ - return 9; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mad.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,126 @@ +/* + 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 + + mad.cpp - MAD loader by Riven the Mage <riven@ok.ru> +*/ + +#include "mad.h" + +/* -------- Public Methods -------------------------------- */ + +CPlayer *CmadLoader::factory(Copl *newopl) +{ + return new CmadLoader(newopl); +} + +bool CmadLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + const unsigned char conv_inst[10] = { 2,1,10,9,4,3,6,5,8,7 }; + unsigned int i, j, k, t = 0; + + // 'MAD+' - signed ? + char id[4]; f->readString(id, 4); + if (strncmp(id,"MAD+",4)) { fp.close(f); return false; } + + // load instruments + for(i = 0; i < 9; i++) { + f->readString(instruments[i].name, 8); + for(j = 0; j < 12; j++) instruments[i].data[j] = f->readInt(1); + } + + f->ignore(1); + + // data for Protracker + length = f->readInt(1); nop = f->readInt(1); timer = f->readInt(1); + + // init CmodPlayer + realloc_instruments(9); + realloc_order(length); + realloc_patterns(nop,32,9); + init_trackord(); + + // load tracks + for(i = 0; i < nop; i++) + for(k = 0; k < 32; k++) + for(j = 0; j < 9; j++) { + t = i * 9 + j; + + // read event + unsigned char event = f->readInt(1); + + // convert event + if (event < 0x61) + tracks[t][k].note = event; + if (event == 0xFF) // 0xFF: Release note + tracks[t][k].command = 8; + if (event == 0xFE) // 0xFE: Pattern Break + tracks[t][k].command = 13; + } + + // load order + for(i = 0; i < length; i++) order[i] = f->readInt(1) - 1; + + fp.close(f); + + // convert instruments + for(i = 0; i < 9; i++) + for(j = 0; j < 10; j++) + inst[i].data[conv_inst[j]] = instruments[i].data[j]; + + // data for Protracker + restartpos = 0; + initspeed = 1; + + rewind(0); + return true; +} + +void CmadLoader::rewind(int subsong) +{ + CmodPlayer::rewind(subsong); + + // default instruments + for (int i=0;i<9;i++) + { + channel[i].inst = i; + + channel[i].vol1 = 63 - (inst[i].data[10] & 63); + channel[i].vol2 = 63 - (inst[i].data[9] & 63); + } +} + +float CmadLoader::getrefresh() +{ + return (float)timer; +} + +std::string CmadLoader::gettype() +{ + return std::string("Mlat Adlib Tracker"); +} + +std::string CmadLoader::getinstrument(unsigned int n) +{ + return std::string(instruments[n].name,8); +} + +unsigned int CmadLoader::getinstruments() +{ + return 9; +}
--- a/Plugins/Input/adplug/core/mid.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1088 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2005 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 - * - * - * MIDI & MIDI-like file player - Last Update: 10/15/2005 - * by Phil Hassey - www.imitationpickles.org - * philhassey@hotmail.com - * - * Can play the following - * .LAA - a raw save of a Lucas Arts Adlib music - * or - * a raw save of a LucasFilm Adlib music - * .CMF - Creative Music Format - * .SCI - the sierra "midi" format. - * Files must be in the form - * xxxNAME.sci - * So that the loader can load the right patch file: - * xxxPATCH.003 (patch.003 must be saved from the - * sierra resource from each game.) - * - * 1/9/2006: audacious libadplug - * Status: MID not as fine as originally thought. Removing general MIDI detector so timidity handles these files instead. - * - * 6/2/2000: v1.0 relased by phil hassey - * Status: LAA is almost perfect - * - some volumes are a bit off (intrument too quiet) - * MID is fine (who wants to listen to MIDI vid adlib anyway) - * CMF is okay (still needs the adlib rythm mode implemented - * for real) - * 6/6/2000: - * Status: SCI: there are two SCI formats, orginal and advanced. - * original: (Found in SCI/EGA Sierra Adventures) - * played almost perfectly, I believe - * there is one mistake in the instrument - * loader that causes some sounds to - * not be quite right. Most sounds are fine. - * advanced: (Found in SCI/VGA Sierra Adventures) - * These are multi-track files. (Thus the - * player had to be modified to work with - * them.) This works fine. - * There are also multiple tunes in each file. - * I think some of them are supposed to be - * played at the same time, but I'm not sure - * when. - * 8/16/2000: - * Status: LAA: now EGA and VGA lucas games work pretty well - * - * 10/15/2005: Changes by Simon Peter - * Added rhythm mode support for CMF format. - * - * Other acknowledgements: - * Allegro - for the midi instruments and the midi volume table - * SCUMM Revisited - for getting the .LAA / .MIDs out of those - * LucasArts files. - * FreeSCI - for some information on the sci music files - * SD - the SCI Decoder (to get all .sci out of the Sierra files) - */ - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <string.h> -#include "mid.h" -#include "mididata.h" - -/*#define TESTING*/ -#ifdef TESTING -#define midiprintf printf -#else -void CmidPlayer::midiprintf(char *format, ...) - { - } -#endif - -#define LUCAS_STYLE 1 -#define CMF_STYLE 2 -#define MIDI_STYLE 4 -#define SIERRA_STYLE 8 - -// AdLib melodic and rhythm mode defines -#define ADLIB_MELODIC 0 -#define ADLIB_RYTHM 1 - -// File types -#define FILE_LUCAS 1 -#define FILE_MIDI 2 -#define FILE_CMF 3 -#define FILE_SIERRA 4 -#define FILE_ADVSIERRA 5 -#define FILE_OLDLUCAS 6 - -// AdLib standard operator table -const unsigned char CmidPlayer::adlib_opadd[] = {0x00 ,0x01 ,0x02 ,0x08 ,0x09 ,0x0A ,0x10 ,0x11 ,0x12}; - -// dunno -const int CmidPlayer::ops[] = {0x20,0x20,0x40,0x40,0x60,0x60,0x80,0x80,0xe0,0xe0,0xc0}; - -// map CMF drum channels 12 - 15 to corresponding AdLib drum operators -// bass drum (channel 11) not mapped, cause it's handled like a normal instrument -const int CmidPlayer::map_chan[] = { 0x14, 0x12, 0x15, 0x11 }; - -// Standard AdLib frequency table -const int CmidPlayer::fnums[] = { 0x16b,0x181,0x198,0x1b0,0x1ca,0x1e5,0x202,0x220,0x241,0x263,0x287,0x2ae }; - -// Map CMF drum channels 11 - 15 to corresponding AdLib drum channels -const int CmidPlayer::percussion_map[] = { 6, 7, 8, 8, 7 }; - -CPlayer *CmidPlayer::factory(Copl *newopl) -{ - return new CmidPlayer(newopl); -} - -CmidPlayer::CmidPlayer(Copl *newopl) - : CPlayer(newopl), author(&emptystr), title(&emptystr), remarks(&emptystr), - emptystr('\0'), flen(0), data(0) -{ -} - -unsigned char CmidPlayer::datalook(long pos) -{ - if (pos<0 || pos >= flen) return(0); - return(data[pos]); -} - -unsigned long CmidPlayer::getnexti(unsigned long num) -{ - unsigned long v=0; - unsigned long i; - - for (i=0; i<num; i++) - { - v+=(datalook(pos)<<(8*i)); pos++; - } - return(v); -} - -unsigned long CmidPlayer::getnext(unsigned long num) -{ - unsigned long v=0; - unsigned long i; - - for (i=0; i<num; i++) - { - v<<=8; - v+=datalook(pos); pos++; - } - return(v); -} - -unsigned long CmidPlayer::getval() -{ - int v=0; - unsigned char b; - - b=(unsigned char)getnext(1); - v=b&0x7f; - while ((b&0x80) !=0) - { - b=(unsigned char)getnext(1); - v = (v << 7) + (b & 0x7F); - } - return(v); -} - -bool CmidPlayer::load_sierra_ins(const std::string &fname, const CFileProvider &fp) -{ - long i,j,k,l; - unsigned char ins[28]; - char *pfilename; - binistream *f; - - pfilename = (char *)malloc(fname.length()+9); - strcpy(pfilename,fname.c_str()); - j=0; - for(i=strlen(pfilename)-1; i >= 0; i--) - if(pfilename[i] == '/' || pfilename[i] == '\\') { - j = i+1; - break; - } - sprintf(pfilename+j+3,"patch.003"); - - f = fp.open(pfilename); - free(pfilename); - if(!f) return false; - - f->ignore(2); - stins = 0; - for (i=0; i<2; i++) - { - for (k=0; k<48; k++) - { - l=i*48+k; - midiprintf ("\n%2d: ",l); - for (j=0; j<28; j++) - ins[j] = f->readInt(1); - - myinsbank[l][0]= - (ins[9]*0x80) + (ins[10]*0x40) + - (ins[5]*0x20) + (ins[11]*0x10) + - ins[1]; //1=ins5 - myinsbank[l][1]= - (ins[22]*0x80) + (ins[23]*0x40) + - (ins[18]*0x20) + (ins[24]*0x10) + - ins[14]; //1=ins18 - - myinsbank[l][2]=(ins[0]<<6)+ins[8]; - myinsbank[l][3]=(ins[13]<<6)+ins[21]; - - myinsbank[l][4]=(ins[3]<<4)+ins[6]; - myinsbank[l][5]=(ins[16]<<4)+ins[19]; - myinsbank[l][6]=(ins[4]<<4)+ins[7]; - myinsbank[l][7]=(ins[17]<<4)+ins[20]; - - myinsbank[l][8]=ins[26]; - myinsbank[l][9]=ins[27]; - - myinsbank[l][10]=((ins[2]<<1))+(1-(ins[12]&1)); - //(ins[12] ? 0:1)+((ins[2]<<1)); - - for (j=0; j<11; j++) - midiprintf ("%02X ",myinsbank[l][j]); - stins++; - } - f->ignore(2); - } - - fp.close(f); - memcpy(smyinsbank, myinsbank, 128 * 16); - return true; -} - -void CmidPlayer::sierra_next_section() -{ - int i,j; - - for (i=0; i<16; i++) - track[i].on=0; - - midiprintf("\n\nnext adv sierra section:\n"); - - pos=sierra_pos; - i=0;j=0; - while (i!=0xff) - { - getnext(1); - curtrack=j; j++; - track[curtrack].on=1; - track[curtrack].spos = getnext(1); - track[curtrack].spos += (getnext(1) << 8) + 4; //4 best usually +3? not 0,1,2 or 5 -// track[curtrack].spos=getnext(1)+(getnext(1)<<8)+4; // dynamite!: doesn't optimize correctly!! - track[curtrack].tend=flen; //0xFC will kill it - track[curtrack].iwait=0; - track[curtrack].pv=0; - midiprintf ("track %d starts at %lx\n",curtrack,track[curtrack].spos); - - getnext(2); - i=getnext(1); - } - getnext(2); - deltas=0x20; - sierra_pos=pos; - //getch(); - - fwait=0; - doing=1; -} - -bool CmidPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - int good; - unsigned char s[6]; - - f->readString((char *)s, 6); - good=0; - subsongs=0; - switch(s[0]) - { - case 'A': - if (s[1]=='D' && s[2]=='L') good=FILE_LUCAS; - break; - case 'C': - if (s[1]=='T' && s[2]=='M' && s[3]=='F') good=FILE_CMF; - break; - case 0x84: - if (s[1]==0x00 && load_sierra_ins(filename, fp)) - if (s[2]==0xf0) - good=FILE_ADVSIERRA; - else - good=FILE_SIERRA; - break; - default: - if (s[4]=='A' && s[5]=='D') good=FILE_OLDLUCAS; - break; - } - - if (good!=0) - subsongs=1; - else { - fp.close(f); - return false; - } - - type=good; - f->seek(0); - flen = fp.filesize(f); - data = new unsigned char [flen]; - f->readString((char *)data, flen); - - fp.close(f); - rewind(0); - return true; -} - -void CmidPlayer::midi_write_adlib(unsigned int r, unsigned char v) -{ - opl->write(r,v); - adlib_data[r]=v; -} - -void CmidPlayer::midi_fm_instrument(int voice, unsigned char *inst) -{ - if ((adlib_style&SIERRA_STYLE)!=0) - midi_write_adlib(0xbd,0); //just gotta make sure this happens.. - //'cause who knows when it'll be - //reset otherwise. - - - midi_write_adlib(0x20+adlib_opadd[voice],inst[0]); - midi_write_adlib(0x23+adlib_opadd[voice],inst[1]); - - if ((adlib_style&LUCAS_STYLE)!=0) - { - midi_write_adlib(0x43+adlib_opadd[voice],0x3f); - if ((inst[10] & 1)==0) - midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); - else - midi_write_adlib(0x40+adlib_opadd[voice],0x3f); - } - else - { - if ((adlib_style&SIERRA_STYLE)!=0) - { - midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); - midi_write_adlib(0x43+adlib_opadd[voice],inst[3]); - } - else - { - midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); - if ((inst[10] & 1)==0) - midi_write_adlib(0x43+adlib_opadd[voice],inst[3]); - else - midi_write_adlib(0x43+adlib_opadd[voice],0); - } - } - - midi_write_adlib(0x60+adlib_opadd[voice],inst[4]); - midi_write_adlib(0x63+adlib_opadd[voice],inst[5]); - midi_write_adlib(0x80+adlib_opadd[voice],inst[6]); - midi_write_adlib(0x83+adlib_opadd[voice],inst[7]); - midi_write_adlib(0xe0+adlib_opadd[voice],inst[8]); - midi_write_adlib(0xe3+adlib_opadd[voice],inst[9]); - - midi_write_adlib(0xc0+voice,inst[10]); -} - -void CmidPlayer::midi_fm_percussion(int ch, unsigned char *inst) -{ - int opadd = map_chan[ch - 12]; - - midi_write_adlib(0x20 + opadd, inst[0]); - midi_write_adlib(0x40 + opadd, inst[2]); - midi_write_adlib(0x60 + opadd, inst[4]); - midi_write_adlib(0x80 + opadd, inst[6]); - midi_write_adlib(0xe0 + opadd, inst[8]); - midi_write_adlib(0xc0 + opadd, inst[10]); -} - -void CmidPlayer::midi_fm_volume(int voice, int volume) -{ - int vol; - - if ((adlib_style&SIERRA_STYLE)==0) //sierra likes it loud! - { - vol=volume>>2; - - if ((adlib_style&LUCAS_STYLE)!=0) - { - if ((adlib_data[0xc0+voice]&1)==1) - midi_write_adlib(0x40+adlib_opadd[voice], (unsigned char)((63-vol) | - (adlib_data[0x40+adlib_opadd[voice]]&0xc0))); - midi_write_adlib(0x43+adlib_opadd[voice], (unsigned char)((63-vol) | - (adlib_data[0x43+adlib_opadd[voice]]&0xc0))); - } - else - { - if ((adlib_data[0xc0+voice]&1)==1) - midi_write_adlib(0x40+adlib_opadd[voice], (unsigned char)((63-vol) | - (adlib_data[0x40+adlib_opadd[voice]]&0xc0))); - midi_write_adlib(0x43+adlib_opadd[voice], (unsigned char)((63-vol) | - (adlib_data[0x43+adlib_opadd[voice]]&0xc0))); - } - } -} - -void CmidPlayer::midi_fm_playnote(int voice, int note, int volume) -{ - int freq=fnums[note%12]; - int oct=note/12; - int c; - - midi_fm_volume(voice,volume); - midi_write_adlib(0xa0+voice,(unsigned char)(freq&0xff)); - - c=((freq&0x300) >> 8)+(oct<<2) + (adlib_mode == ADLIB_MELODIC || voice < 6 ? (1<<5) : 0); - midi_write_adlib(0xb0+voice,(unsigned char)c); -} - -void CmidPlayer::midi_fm_endnote(int voice) -{ - //midi_fm_volume(voice,0); - //midi_write_adlib(0xb0+voice,0); - - midi_write_adlib(0xb0+voice,(unsigned char)(adlib_data[0xb0+voice]&(255-32))); -} - -void CmidPlayer::midi_fm_reset() -{ - int i; - - opl->init(); - - for (i=0; i<256; i++) - midi_write_adlib(i,0); - - midi_write_adlib(0x01, 0x20); - midi_write_adlib(0xBD,0xc0); -} - -bool CmidPlayer::update() -{ - long w,v,note,vel,ctrl,nv,x,l,lnum; - int i=0,j,c; - int on,onl,numchan; - int ret; - - if (doing == 1) - { - // just get the first wait and ignore it :> - for (curtrack=0; curtrack<16; curtrack++) - if (track[curtrack].on) - { - pos=track[curtrack].pos; - if (type != FILE_SIERRA && type !=FILE_ADVSIERRA) - track[curtrack].iwait+=getval(); - else - track[curtrack].iwait+=getnext(1); - track[curtrack].pos=pos; - } - doing=0; - } - - iwait=0; - ret=1; - - while (iwait==0 && ret==1) - { - for (curtrack=0; curtrack<16; curtrack++) - if (track[curtrack].on && track[curtrack].iwait==0 && - track[curtrack].pos < track[curtrack].tend) - { - pos=track[curtrack].pos; - - v=getnext(1); - - // This is to do implied MIDI events. - if (v<0x80) {v=track[curtrack].pv; pos--;} - track[curtrack].pv=(unsigned char)v; - - c=v&0x0f; - midiprintf ("[%2X]",v); - switch(v&0xf0) - { - case 0x80: /*note off*/ - note=getnext(1); vel=getnext(1); - for (i=0; i<9; i++) - if (chp[i][0]==c && chp[i][1]==note) - { - midi_fm_endnote(i); - chp[i][0]=-1; - } - break; - case 0x90: /*note on*/ - // doing=0; - note=getnext(1); vel=getnext(1); - - if(adlib_mode == ADLIB_RYTHM) - numchan = 6; - else - numchan = 9; - - if (ch[c].on!=0) - { - for (i=0; i<18; i++) - chp[i][2]++; - - if(c < 11 || adlib_mode == ADLIB_MELODIC) { - j=0; - on=-1;onl=0; - for (i=0; i<numchan; i++) - if (chp[i][0]==-1 && chp[i][2]>onl) - { onl=chp[i][2]; on=i; j=1; } - - if (on==-1) - { - onl=0; - for (i=0; i<numchan; i++) - if (chp[i][2]>onl) - { onl=chp[i][2]; on=i; } - } - - if (j==0) - midi_fm_endnote(on); - } else - on = percussion_map[c - 11]; - - if (vel!=0 && ch[c].inum>=0 && ch[c].inum<128) - { - if (adlib_mode == ADLIB_MELODIC || c < 12) - midi_fm_instrument(on,ch[c].ins); - else - midi_fm_percussion(c, ch[c].ins); - - if ((adlib_style&MIDI_STYLE)!=0) - { - nv=((ch[c].vol*vel)/128); - if ((adlib_style&LUCAS_STYLE)!=0) - nv*=2; - if (nv>127) nv=127; - nv=my_midi_fm_vol_table[nv]; - if ((adlib_style&LUCAS_STYLE)!=0) - nv=(int)((float)sqrt((float)nv)*11); - } - else - { - nv=vel; - } - - midi_fm_playnote(on,note+ch[c].nshift,nv*2); - chp[on][0]=c; - chp[on][1]=note; - chp[on][2]=0; - - if(adlib_mode == ADLIB_RYTHM && c >= 11) { - midi_write_adlib(0xbd, adlib_data[0xbd] & ~(0x10 >> (c - 11))); - midi_write_adlib(0xbd, adlib_data[0xbd] | (0x10 >> (c - 11))); - } - - } - else - { - if (vel==0) //same code as end note - { - for (i=0; i<9; i++) - if (chp[i][0]==c && chp[i][1]==note) - { - // midi_fm_volume(i,0); // really end the note - midi_fm_endnote(i); - chp[i][0]=-1; - } - } - else - { // i forget what this is for. - chp[on][0]=-1; - chp[on][2]=0; - } - } - midiprintf(" [%d:%d:%d:%d]\n",c,ch[c].inum,note,vel); - } - else - midiprintf ("off"); - break; - case 0xa0: /*key after touch */ - note=getnext(1); vel=getnext(1); - /* //this might all be good - for (i=0; i<9; i++) - if (chp[i][0]==c & chp[i][1]==note) - -midi_fm_playnote(i,note+cnote[c],my_midi_fm_vol_table[(cvols[c]*vel)/128]*2); - */ - break; - case 0xb0: /*control change .. pitch bend? */ - ctrl=getnext(1); vel=getnext(1); - - switch(ctrl) - { - case 0x07: - midiprintf ("(pb:%d: %d %d)",c,ctrl,vel); - ch[c].vol=vel; - midiprintf("vol"); - break; - case 0x67: - midiprintf ("\n\nhere:%d\n\n",vel); - if ((adlib_style&CMF_STYLE)!=0) { - adlib_mode=vel; - if(adlib_mode == ADLIB_RYTHM) - midi_write_adlib(0xbd, adlib_data[0xbd] | (1 << 5)); - else - midi_write_adlib(0xbd, adlib_data[0xbd] & ~(1 << 5)); - } - break; - } - break; - case 0xc0: /*patch change*/ - x=getnext(1); - ch[c].inum=x; - for (j=0; j<11; j++) - ch[c].ins[j]=myinsbank[ch[c].inum][j]; - break; - case 0xd0: /*chanel touch*/ - x=getnext(1); - break; - case 0xe0: /*pitch wheel*/ - x=getnext(1); - x=getnext(1); - break; - case 0xf0: - switch(v) - { - case 0xf0: - case 0xf7: /*sysex*/ - l=getval(); - if (datalook(pos+l)==0xf7) - i=1; - midiprintf("{%d}",l); - midiprintf("\n"); - - if (datalook(pos)==0x7d && - datalook(pos+1)==0x10 && - datalook(pos+2)<16) - { - adlib_style=LUCAS_STYLE|MIDI_STYLE; - for (i=0; i<l; i++) - { - midiprintf ("%x ",datalook(pos+i)); - if ((i-3)%10 == 0) midiprintf("\n"); - } - midiprintf ("\n"); - getnext(1); - getnext(1); - c=getnext(1); - getnext(1); - - // getnext(22); //temp - ch[c].ins[0]=(unsigned char)((getnext(1)<<4)+getnext(1)); - ch[c].ins[2]=(unsigned char)(0xff-(((getnext(1)<<4)+getnext(1))&0x3f)); - ch[c].ins[4]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1))); - ch[c].ins[6]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1))); - ch[c].ins[8]=(unsigned char)((getnext(1)<<4)+getnext(1)); - - ch[c].ins[1]=(unsigned char)((getnext(1)<<4)+getnext(1)); - ch[c].ins[3]=(unsigned char)(0xff-(((getnext(1)<<4)+getnext(1))&0x3f)); - ch[c].ins[5]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1))); - ch[c].ins[7]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1))); - ch[c].ins[9]=(unsigned char)((getnext(1)<<4)+getnext(1)); - - i=(getnext(1)<<4)+getnext(1); - ch[c].ins[10]=i; - - //if ((i&1)==1) ch[c].ins[10]=1; - - midiprintf ("\n%d: ",c); - for (i=0; i<11; i++) - midiprintf ("%2X ",ch[c].ins[i]); - getnext(l-26); - } - else - { - midiprintf("\n"); - for (j=0; j<l; j++) - midiprintf ("%2X ",getnext(1)); - } - - midiprintf("\n"); - if(i==1) - getnext(1); - break; - case 0xf1: - break; - case 0xf2: - getnext(2); - break; - case 0xf3: - getnext(1); - break; - case 0xf4: - break; - case 0xf5: - break; - case 0xf6: /*something*/ - case 0xf8: - case 0xfa: - case 0xfb: - case 0xfc: - //this ends the track for sierra. - if (type == FILE_SIERRA || - type == FILE_ADVSIERRA) - { - track[curtrack].tend=pos; - midiprintf ("endmark: %ld -- %lx\n",pos,pos); - } - break; - case 0xfe: - break; - case 0xfd: - break; - case 0xff: - v=getnext(1); - l=getval(); - midiprintf ("\n"); - midiprintf("{%X_%X}",v,l); - if (v==0x51) - { - lnum=getnext(l); - msqtr=lnum; /*set tempo*/ - midiprintf ("(qtr=%ld)",msqtr); - } - else - { - for (i=0; i<l; i++) - midiprintf ("%2X ",getnext(1)); - } - break; - } - break; - default: midiprintf("!",v); /* if we get down here, a error occurred */ - break; - } - - if (pos < track[curtrack].tend) - { - if (type != FILE_SIERRA && type !=FILE_ADVSIERRA) - w=getval(); - else - w=getnext(1); - track[curtrack].iwait=w; - /* - if (w!=0) - { - midiprintf("\n<%d>",w); - f = -((float)w/(float)deltas)*((float)msqtr/(float)1000000); - if (doing==1) f=0; //not playing yet. don't wait yet - } - */ - } - else - track[curtrack].iwait=0; - - track[curtrack].pos=pos; - } - - - ret=0; //end of song. - iwait=0; - for (curtrack=0; curtrack<16; curtrack++) - if (track[curtrack].on == 1 && - track[curtrack].pos < track[curtrack].tend) - ret=1; //not yet.. - - if (ret==1) - { - iwait=0xffffff; // bigger than any wait can be! - for (curtrack=0; curtrack<16; curtrack++) - if (track[curtrack].on == 1 && - track[curtrack].pos < track[curtrack].tend && - track[curtrack].iwait < iwait) - iwait=track[curtrack].iwait; - } - } - - - if (iwait !=0 && ret==1) - { - for (curtrack=0; curtrack<16; curtrack++) - if (track[curtrack].on) - track[curtrack].iwait-=iwait; - - -fwait=1.0f/(((float)iwait/(float)deltas)*((float)msqtr/(float)1000000)); - } - else - fwait=50; // 1/50th of a second - - midiprintf ("\n"); - for (i=0; i<16; i++) - if (track[i].on) - if (track[i].pos < track[i].tend) - midiprintf ("<%d>",track[i].iwait); - else - midiprintf("stop"); - - /* - if (ret==0 && type==FILE_ADVSIERRA) - if (datalook(sierra_pos-2)!=0xff) - { - midiprintf ("next sectoin!"); - sierra_next_section(p); - fwait=50; - ret=1; - } - */ - - if(ret) - return true; - else - return false; -} - -float CmidPlayer::getrefresh() -{ - return (fwait > 0.01f ? fwait : 0.01f); -} - -void CmidPlayer::rewind(int subsong) -{ - long i,j,n,m,l; - long o_sierra_pos; - unsigned char ins[16]; - - pos=0; tins=0; - adlib_style=MIDI_STYLE|CMF_STYLE; - adlib_mode=ADLIB_MELODIC; - for (i=0; i<128; i++) - for (j=0; j<16; j++) - myinsbank[i][j]=midi_fm_instruments[i][j]; - for (i=0; i<16; i++) - { - ch[i].inum=0; - for (j=0; j<11; j++) - ch[i].ins[j]=myinsbank[ch[i].inum][j]; - ch[i].vol=127; - ch[i].nshift=-25; - ch[i].on=1; - } - - /* General init */ - for (i=0; i<9; i++) - { - chp[i][0]=-1; - chp[i][2]=0; - } - - deltas=250; // just a number, not a standard - msqtr=500000; - fwait=123; // gotta be a small thing.. sorta like nothing - iwait=0; - - subsongs=1; - - for (i=0; i<16; i++) - { - track[i].tend=0; - track[i].spos=0; - track[i].pos=0; - track[i].iwait=0; - track[i].on=0; - track[i].pv=0; - } - curtrack=0; - - /* specific to file-type init */ - - pos=0; - i=getnext(1); - switch(type) - { - case FILE_LUCAS: - getnext(24); //skip junk and get to the midi. - adlib_style=LUCAS_STYLE|MIDI_STYLE; - //note: no break, we go right into midi headers... - case FILE_MIDI: - if (type != FILE_LUCAS) - tins=128; - getnext(11); /*skip header*/ - deltas=getnext(2); - midiprintf ("deltas:%ld\n",deltas); - getnext(4); - - curtrack=0; - track[curtrack].on=1; - track[curtrack].tend=getnext(4); - track[curtrack].spos=pos; - midiprintf ("tracklen:%ld\n",track[curtrack].tend); - break; - case FILE_CMF: - getnext(3); // ctmf - getnexti(2); //version - n=getnexti(2); // instrument offset - m=getnexti(2); // music offset - deltas=getnexti(2); //ticks/qtr note - msqtr=1000000/getnexti(2)*deltas; - //the stuff in the cmf is click ticks per second.. - - i=getnexti(2); - if(i) title = (char *)data+i; - i=getnexti(2); - if(i) author = (char *)data+i; - i=getnexti(2); - if(i) remarks = (char *)data+i; - - getnext(16); // channel in use table .. - i=getnexti(2); // num instr - if (i>128) i=128; // to ward of bad numbers... - getnexti(2); //basic tempo - - midiprintf("\nioff:%d\nmoff%d\ndeltas:%ld\nmsqtr:%ld\nnumi:%d\n", - n,m,deltas,msqtr,i); - pos=n; // jump to instruments - tins=i; - for (j=0; j<i; j++) - { - midiprintf ("\n%d: ",j); - for (l=0; l<16; l++) - { - myinsbank[j][l]=(unsigned char)getnext(1); - midiprintf ("%2X ",myinsbank[j][l]); - } - } - - for (i=0; i<16; i++) - ch[i].nshift=-13; - - adlib_style=CMF_STYLE; - - curtrack=0; - track[curtrack].on=1; - track[curtrack].tend=flen; // music until the end of the file - track[curtrack].spos=m; //jump to midi music - break; - case FILE_OLDLUCAS: - msqtr=250000; - pos=9; - deltas=getnext(1); - - i=8; - pos=0x19; // jump to instruments - tins=i; - for (j=0; j<i; j++) - { - midiprintf ("\n%d: ",j); - for (l=0; l<16; l++) - ins[l]=(unsigned char)getnext(1); - - myinsbank[j][10]=ins[2]; - myinsbank[j][0]=ins[3]; - myinsbank[j][2]=ins[4]; - myinsbank[j][4]=ins[5]; - myinsbank[j][6]=ins[6]; - myinsbank[j][8]=ins[7]; - myinsbank[j][1]=ins[8]; - myinsbank[j][3]=ins[9]; - myinsbank[j][5]=ins[10]; - myinsbank[j][7]=ins[11]; - myinsbank[j][9]=ins[12]; - - for (l=0; l<11; l++) - midiprintf ("%2X ",myinsbank[j][l]); - } - - for (i=0; i<16; i++) - { - if (i<tins) - { - ch[i].inum=i; - for (j=0; j<11; j++) - ch[i].ins[j]=myinsbank[ch[i].inum][j]; - } - } - - adlib_style=LUCAS_STYLE|MIDI_STYLE; - - curtrack=0; - track[curtrack].on=1; - track[curtrack].tend=flen; // music until the end of the file - track[curtrack].spos=0x98; //jump to midi music - break; - case FILE_ADVSIERRA: - memcpy(myinsbank, smyinsbank, 128 * 16); - tins = stins; - deltas=0x20; - getnext(11); //worthless empty space and "stuff" :) - - o_sierra_pos=sierra_pos=pos; - sierra_next_section(); - while (datalook(sierra_pos-2)!=0xff) - { - sierra_next_section(); - subsongs++; - } - - if (subsong < 0 || subsong >= subsongs) subsong=0; - - sierra_pos=o_sierra_pos; - sierra_next_section(); - i=0; - while (i != subsong) - { - sierra_next_section(); - i++; - } - - adlib_style=SIERRA_STYLE|MIDI_STYLE; //advanced sierra tunes use volume - break; - case FILE_SIERRA: - memcpy(myinsbank, smyinsbank, 128 * 16); - tins = stins; - getnext(2); - deltas=0x20; - - curtrack=0; - track[curtrack].on=1; - track[curtrack].tend=flen; // music until the end of the file - - for (i=0; i<16; i++) - { - ch[i].nshift=-13; - ch[i].on=getnext(1); - ch[i].inum=getnext(1); - for (j=0; j<11; j++) - ch[i].ins[j]=myinsbank[ch[i].inum][j]; - } - - track[curtrack].spos=pos; - adlib_style=SIERRA_STYLE|MIDI_STYLE; - break; - } - - -/* sprintf(info,"%s\r\nTicks/Quarter Note: %ld\r\n",info,deltas); - sprintf(info,"%sms/Quarter Note: %ld",info,msqtr); */ - - for (i=0; i<16; i++) - if (track[i].on) - { - track[i].pos=track[i].spos; - track[i].pv=0; - track[i].iwait=0; - } - - doing=1; - midi_fm_reset(); -} - -std::string CmidPlayer::gettype() -{ - switch(type) { - case FILE_LUCAS: - return std::string("LucasArts AdLib MIDI"); - case FILE_MIDI: - return std::string("General MIDI"); - case FILE_CMF: - return std::string("Creative Music Format (CMF MIDI)"); - case FILE_OLDLUCAS: - return std::string("Lucasfilm Adlib MIDI"); - case FILE_ADVSIERRA: - return std::string("Sierra On-Line VGA MIDI"); - case FILE_SIERRA: - return std::string("Sierra On-Line EGA MIDI"); - default: - return std::string("MIDI unknown"); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mid.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,1088 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2005 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 + * + * + * MIDI & MIDI-like file player - Last Update: 10/15/2005 + * by Phil Hassey - www.imitationpickles.org + * philhassey@hotmail.com + * + * Can play the following + * .LAA - a raw save of a Lucas Arts Adlib music + * or + * a raw save of a LucasFilm Adlib music + * .CMF - Creative Music Format + * .SCI - the sierra "midi" format. + * Files must be in the form + * xxxNAME.sci + * So that the loader can load the right patch file: + * xxxPATCH.003 (patch.003 must be saved from the + * sierra resource from each game.) + * + * 1/9/2006: audacious libadplug + * Status: MID not as fine as originally thought. Removing general MIDI detector so timidity handles these files instead. + * + * 6/2/2000: v1.0 relased by phil hassey + * Status: LAA is almost perfect + * - some volumes are a bit off (intrument too quiet) + * MID is fine (who wants to listen to MIDI vid adlib anyway) + * CMF is okay (still needs the adlib rythm mode implemented + * for real) + * 6/6/2000: + * Status: SCI: there are two SCI formats, orginal and advanced. + * original: (Found in SCI/EGA Sierra Adventures) + * played almost perfectly, I believe + * there is one mistake in the instrument + * loader that causes some sounds to + * not be quite right. Most sounds are fine. + * advanced: (Found in SCI/VGA Sierra Adventures) + * These are multi-track files. (Thus the + * player had to be modified to work with + * them.) This works fine. + * There are also multiple tunes in each file. + * I think some of them are supposed to be + * played at the same time, but I'm not sure + * when. + * 8/16/2000: + * Status: LAA: now EGA and VGA lucas games work pretty well + * + * 10/15/2005: Changes by Simon Peter + * Added rhythm mode support for CMF format. + * + * Other acknowledgements: + * Allegro - for the midi instruments and the midi volume table + * SCUMM Revisited - for getting the .LAA / .MIDs out of those + * LucasArts files. + * FreeSCI - for some information on the sci music files + * SD - the SCI Decoder (to get all .sci out of the Sierra files) + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> +#include "mid.h" +#include "mididata.h" + +/*#define TESTING*/ +#ifdef TESTING +#define midiprintf printf +#else +void CmidPlayer::midiprintf(char *format, ...) + { + } +#endif + +#define LUCAS_STYLE 1 +#define CMF_STYLE 2 +#define MIDI_STYLE 4 +#define SIERRA_STYLE 8 + +// AdLib melodic and rhythm mode defines +#define ADLIB_MELODIC 0 +#define ADLIB_RYTHM 1 + +// File types +#define FILE_LUCAS 1 +#define FILE_MIDI 2 +#define FILE_CMF 3 +#define FILE_SIERRA 4 +#define FILE_ADVSIERRA 5 +#define FILE_OLDLUCAS 6 + +// AdLib standard operator table +const unsigned char CmidPlayer::adlib_opadd[] = {0x00 ,0x01 ,0x02 ,0x08 ,0x09 ,0x0A ,0x10 ,0x11 ,0x12}; + +// dunno +const int CmidPlayer::ops[] = {0x20,0x20,0x40,0x40,0x60,0x60,0x80,0x80,0xe0,0xe0,0xc0}; + +// map CMF drum channels 12 - 15 to corresponding AdLib drum operators +// bass drum (channel 11) not mapped, cause it's handled like a normal instrument +const int CmidPlayer::map_chan[] = { 0x14, 0x12, 0x15, 0x11 }; + +// Standard AdLib frequency table +const int CmidPlayer::fnums[] = { 0x16b,0x181,0x198,0x1b0,0x1ca,0x1e5,0x202,0x220,0x241,0x263,0x287,0x2ae }; + +// Map CMF drum channels 11 - 15 to corresponding AdLib drum channels +const int CmidPlayer::percussion_map[] = { 6, 7, 8, 8, 7 }; + +CPlayer *CmidPlayer::factory(Copl *newopl) +{ + return new CmidPlayer(newopl); +} + +CmidPlayer::CmidPlayer(Copl *newopl) + : CPlayer(newopl), author(&emptystr), title(&emptystr), remarks(&emptystr), + emptystr('\0'), flen(0), data(0) +{ +} + +unsigned char CmidPlayer::datalook(long pos) +{ + if (pos<0 || pos >= flen) return(0); + return(data[pos]); +} + +unsigned long CmidPlayer::getnexti(unsigned long num) +{ + unsigned long v=0; + unsigned long i; + + for (i=0; i<num; i++) + { + v+=(datalook(pos)<<(8*i)); pos++; + } + return(v); +} + +unsigned long CmidPlayer::getnext(unsigned long num) +{ + unsigned long v=0; + unsigned long i; + + for (i=0; i<num; i++) + { + v<<=8; + v+=datalook(pos); pos++; + } + return(v); +} + +unsigned long CmidPlayer::getval() +{ + int v=0; + unsigned char b; + + b=(unsigned char)getnext(1); + v=b&0x7f; + while ((b&0x80) !=0) + { + b=(unsigned char)getnext(1); + v = (v << 7) + (b & 0x7F); + } + return(v); +} + +bool CmidPlayer::load_sierra_ins(const std::string &fname, const CFileProvider &fp) +{ + long i,j,k,l; + unsigned char ins[28]; + char *pfilename; + binistream *f; + + pfilename = (char *)malloc(fname.length()+9); + strcpy(pfilename,fname.c_str()); + j=0; + for(i=strlen(pfilename)-1; i >= 0; i--) + if(pfilename[i] == '/' || pfilename[i] == '\\') { + j = i+1; + break; + } + sprintf(pfilename+j+3,"patch.003"); + + f = fp.open(pfilename); + free(pfilename); + if(!f) return false; + + f->ignore(2); + stins = 0; + for (i=0; i<2; i++) + { + for (k=0; k<48; k++) + { + l=i*48+k; + midiprintf ("\n%2d: ",l); + for (j=0; j<28; j++) + ins[j] = f->readInt(1); + + myinsbank[l][0]= + (ins[9]*0x80) + (ins[10]*0x40) + + (ins[5]*0x20) + (ins[11]*0x10) + + ins[1]; //1=ins5 + myinsbank[l][1]= + (ins[22]*0x80) + (ins[23]*0x40) + + (ins[18]*0x20) + (ins[24]*0x10) + + ins[14]; //1=ins18 + + myinsbank[l][2]=(ins[0]<<6)+ins[8]; + myinsbank[l][3]=(ins[13]<<6)+ins[21]; + + myinsbank[l][4]=(ins[3]<<4)+ins[6]; + myinsbank[l][5]=(ins[16]<<4)+ins[19]; + myinsbank[l][6]=(ins[4]<<4)+ins[7]; + myinsbank[l][7]=(ins[17]<<4)+ins[20]; + + myinsbank[l][8]=ins[26]; + myinsbank[l][9]=ins[27]; + + myinsbank[l][10]=((ins[2]<<1))+(1-(ins[12]&1)); + //(ins[12] ? 0:1)+((ins[2]<<1)); + + for (j=0; j<11; j++) + midiprintf ("%02X ",myinsbank[l][j]); + stins++; + } + f->ignore(2); + } + + fp.close(f); + memcpy(smyinsbank, myinsbank, 128 * 16); + return true; +} + +void CmidPlayer::sierra_next_section() +{ + int i,j; + + for (i=0; i<16; i++) + track[i].on=0; + + midiprintf("\n\nnext adv sierra section:\n"); + + pos=sierra_pos; + i=0;j=0; + while (i!=0xff) + { + getnext(1); + curtrack=j; j++; + track[curtrack].on=1; + track[curtrack].spos = getnext(1); + track[curtrack].spos += (getnext(1) << 8) + 4; //4 best usually +3? not 0,1,2 or 5 +// track[curtrack].spos=getnext(1)+(getnext(1)<<8)+4; // dynamite!: doesn't optimize correctly!! + track[curtrack].tend=flen; //0xFC will kill it + track[curtrack].iwait=0; + track[curtrack].pv=0; + midiprintf ("track %d starts at %lx\n",curtrack,track[curtrack].spos); + + getnext(2); + i=getnext(1); + } + getnext(2); + deltas=0x20; + sierra_pos=pos; + //getch(); + + fwait=0; + doing=1; +} + +bool CmidPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + int good; + unsigned char s[6]; + + f->readString((char *)s, 6); + good=0; + subsongs=0; + switch(s[0]) + { + case 'A': + if (s[1]=='D' && s[2]=='L') good=FILE_LUCAS; + break; + case 'C': + if (s[1]=='T' && s[2]=='M' && s[3]=='F') good=FILE_CMF; + break; + case 0x84: + if (s[1]==0x00 && load_sierra_ins(filename, fp)) + if (s[2]==0xf0) + good=FILE_ADVSIERRA; + else + good=FILE_SIERRA; + break; + default: + if (s[4]=='A' && s[5]=='D') good=FILE_OLDLUCAS; + break; + } + + if (good!=0) + subsongs=1; + else { + fp.close(f); + return false; + } + + type=good; + f->seek(0); + flen = fp.filesize(f); + data = new unsigned char [flen]; + f->readString((char *)data, flen); + + fp.close(f); + rewind(0); + return true; +} + +void CmidPlayer::midi_write_adlib(unsigned int r, unsigned char v) +{ + opl->write(r,v); + adlib_data[r]=v; +} + +void CmidPlayer::midi_fm_instrument(int voice, unsigned char *inst) +{ + if ((adlib_style&SIERRA_STYLE)!=0) + midi_write_adlib(0xbd,0); //just gotta make sure this happens.. + //'cause who knows when it'll be + //reset otherwise. + + + midi_write_adlib(0x20+adlib_opadd[voice],inst[0]); + midi_write_adlib(0x23+adlib_opadd[voice],inst[1]); + + if ((adlib_style&LUCAS_STYLE)!=0) + { + midi_write_adlib(0x43+adlib_opadd[voice],0x3f); + if ((inst[10] & 1)==0) + midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); + else + midi_write_adlib(0x40+adlib_opadd[voice],0x3f); + } + else + { + if ((adlib_style&SIERRA_STYLE)!=0) + { + midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); + midi_write_adlib(0x43+adlib_opadd[voice],inst[3]); + } + else + { + midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); + if ((inst[10] & 1)==0) + midi_write_adlib(0x43+adlib_opadd[voice],inst[3]); + else + midi_write_adlib(0x43+adlib_opadd[voice],0); + } + } + + midi_write_adlib(0x60+adlib_opadd[voice],inst[4]); + midi_write_adlib(0x63+adlib_opadd[voice],inst[5]); + midi_write_adlib(0x80+adlib_opadd[voice],inst[6]); + midi_write_adlib(0x83+adlib_opadd[voice],inst[7]); + midi_write_adlib(0xe0+adlib_opadd[voice],inst[8]); + midi_write_adlib(0xe3+adlib_opadd[voice],inst[9]); + + midi_write_adlib(0xc0+voice,inst[10]); +} + +void CmidPlayer::midi_fm_percussion(int ch, unsigned char *inst) +{ + int opadd = map_chan[ch - 12]; + + midi_write_adlib(0x20 + opadd, inst[0]); + midi_write_adlib(0x40 + opadd, inst[2]); + midi_write_adlib(0x60 + opadd, inst[4]); + midi_write_adlib(0x80 + opadd, inst[6]); + midi_write_adlib(0xe0 + opadd, inst[8]); + midi_write_adlib(0xc0 + opadd, inst[10]); +} + +void CmidPlayer::midi_fm_volume(int voice, int volume) +{ + int vol; + + if ((adlib_style&SIERRA_STYLE)==0) //sierra likes it loud! + { + vol=volume>>2; + + if ((adlib_style&LUCAS_STYLE)!=0) + { + if ((adlib_data[0xc0+voice]&1)==1) + midi_write_adlib(0x40+adlib_opadd[voice], (unsigned char)((63-vol) | + (adlib_data[0x40+adlib_opadd[voice]]&0xc0))); + midi_write_adlib(0x43+adlib_opadd[voice], (unsigned char)((63-vol) | + (adlib_data[0x43+adlib_opadd[voice]]&0xc0))); + } + else + { + if ((adlib_data[0xc0+voice]&1)==1) + midi_write_adlib(0x40+adlib_opadd[voice], (unsigned char)((63-vol) | + (adlib_data[0x40+adlib_opadd[voice]]&0xc0))); + midi_write_adlib(0x43+adlib_opadd[voice], (unsigned char)((63-vol) | + (adlib_data[0x43+adlib_opadd[voice]]&0xc0))); + } + } +} + +void CmidPlayer::midi_fm_playnote(int voice, int note, int volume) +{ + int freq=fnums[note%12]; + int oct=note/12; + int c; + + midi_fm_volume(voice,volume); + midi_write_adlib(0xa0+voice,(unsigned char)(freq&0xff)); + + c=((freq&0x300) >> 8)+(oct<<2) + (adlib_mode == ADLIB_MELODIC || voice < 6 ? (1<<5) : 0); + midi_write_adlib(0xb0+voice,(unsigned char)c); +} + +void CmidPlayer::midi_fm_endnote(int voice) +{ + //midi_fm_volume(voice,0); + //midi_write_adlib(0xb0+voice,0); + + midi_write_adlib(0xb0+voice,(unsigned char)(adlib_data[0xb0+voice]&(255-32))); +} + +void CmidPlayer::midi_fm_reset() +{ + int i; + + opl->init(); + + for (i=0; i<256; i++) + midi_write_adlib(i,0); + + midi_write_adlib(0x01, 0x20); + midi_write_adlib(0xBD,0xc0); +} + +bool CmidPlayer::update() +{ + long w,v,note,vel,ctrl,nv,x,l,lnum; + int i=0,j,c; + int on,onl,numchan; + int ret; + + if (doing == 1) + { + // just get the first wait and ignore it :> + for (curtrack=0; curtrack<16; curtrack++) + if (track[curtrack].on) + { + pos=track[curtrack].pos; + if (type != FILE_SIERRA && type !=FILE_ADVSIERRA) + track[curtrack].iwait+=getval(); + else + track[curtrack].iwait+=getnext(1); + track[curtrack].pos=pos; + } + doing=0; + } + + iwait=0; + ret=1; + + while (iwait==0 && ret==1) + { + for (curtrack=0; curtrack<16; curtrack++) + if (track[curtrack].on && track[curtrack].iwait==0 && + track[curtrack].pos < track[curtrack].tend) + { + pos=track[curtrack].pos; + + v=getnext(1); + + // This is to do implied MIDI events. + if (v<0x80) {v=track[curtrack].pv; pos--;} + track[curtrack].pv=(unsigned char)v; + + c=v&0x0f; + midiprintf ("[%2X]",v); + switch(v&0xf0) + { + case 0x80: /*note off*/ + note=getnext(1); vel=getnext(1); + for (i=0; i<9; i++) + if (chp[i][0]==c && chp[i][1]==note) + { + midi_fm_endnote(i); + chp[i][0]=-1; + } + break; + case 0x90: /*note on*/ + // doing=0; + note=getnext(1); vel=getnext(1); + + if(adlib_mode == ADLIB_RYTHM) + numchan = 6; + else + numchan = 9; + + if (ch[c].on!=0) + { + for (i=0; i<18; i++) + chp[i][2]++; + + if(c < 11 || adlib_mode == ADLIB_MELODIC) { + j=0; + on=-1;onl=0; + for (i=0; i<numchan; i++) + if (chp[i][0]==-1 && chp[i][2]>onl) + { onl=chp[i][2]; on=i; j=1; } + + if (on==-1) + { + onl=0; + for (i=0; i<numchan; i++) + if (chp[i][2]>onl) + { onl=chp[i][2]; on=i; } + } + + if (j==0) + midi_fm_endnote(on); + } else + on = percussion_map[c - 11]; + + if (vel!=0 && ch[c].inum>=0 && ch[c].inum<128) + { + if (adlib_mode == ADLIB_MELODIC || c < 12) + midi_fm_instrument(on,ch[c].ins); + else + midi_fm_percussion(c, ch[c].ins); + + if ((adlib_style&MIDI_STYLE)!=0) + { + nv=((ch[c].vol*vel)/128); + if ((adlib_style&LUCAS_STYLE)!=0) + nv*=2; + if (nv>127) nv=127; + nv=my_midi_fm_vol_table[nv]; + if ((adlib_style&LUCAS_STYLE)!=0) + nv=(int)((float)sqrt((float)nv)*11); + } + else + { + nv=vel; + } + + midi_fm_playnote(on,note+ch[c].nshift,nv*2); + chp[on][0]=c; + chp[on][1]=note; + chp[on][2]=0; + + if(adlib_mode == ADLIB_RYTHM && c >= 11) { + midi_write_adlib(0xbd, adlib_data[0xbd] & ~(0x10 >> (c - 11))); + midi_write_adlib(0xbd, adlib_data[0xbd] | (0x10 >> (c - 11))); + } + + } + else + { + if (vel==0) //same code as end note + { + for (i=0; i<9; i++) + if (chp[i][0]==c && chp[i][1]==note) + { + // midi_fm_volume(i,0); // really end the note + midi_fm_endnote(i); + chp[i][0]=-1; + } + } + else + { // i forget what this is for. + chp[on][0]=-1; + chp[on][2]=0; + } + } + midiprintf(" [%d:%d:%d:%d]\n",c,ch[c].inum,note,vel); + } + else + midiprintf ("off"); + break; + case 0xa0: /*key after touch */ + note=getnext(1); vel=getnext(1); + /* //this might all be good + for (i=0; i<9; i++) + if (chp[i][0]==c & chp[i][1]==note) + +midi_fm_playnote(i,note+cnote[c],my_midi_fm_vol_table[(cvols[c]*vel)/128]*2); + */ + break; + case 0xb0: /*control change .. pitch bend? */ + ctrl=getnext(1); vel=getnext(1); + + switch(ctrl) + { + case 0x07: + midiprintf ("(pb:%d: %d %d)",c,ctrl,vel); + ch[c].vol=vel; + midiprintf("vol"); + break; + case 0x67: + midiprintf ("\n\nhere:%d\n\n",vel); + if ((adlib_style&CMF_STYLE)!=0) { + adlib_mode=vel; + if(adlib_mode == ADLIB_RYTHM) + midi_write_adlib(0xbd, adlib_data[0xbd] | (1 << 5)); + else + midi_write_adlib(0xbd, adlib_data[0xbd] & ~(1 << 5)); + } + break; + } + break; + case 0xc0: /*patch change*/ + x=getnext(1); + ch[c].inum=x; + for (j=0; j<11; j++) + ch[c].ins[j]=myinsbank[ch[c].inum][j]; + break; + case 0xd0: /*chanel touch*/ + x=getnext(1); + break; + case 0xe0: /*pitch wheel*/ + x=getnext(1); + x=getnext(1); + break; + case 0xf0: + switch(v) + { + case 0xf0: + case 0xf7: /*sysex*/ + l=getval(); + if (datalook(pos+l)==0xf7) + i=1; + midiprintf("{%d}",l); + midiprintf("\n"); + + if (datalook(pos)==0x7d && + datalook(pos+1)==0x10 && + datalook(pos+2)<16) + { + adlib_style=LUCAS_STYLE|MIDI_STYLE; + for (i=0; i<l; i++) + { + midiprintf ("%x ",datalook(pos+i)); + if ((i-3)%10 == 0) midiprintf("\n"); + } + midiprintf ("\n"); + getnext(1); + getnext(1); + c=getnext(1); + getnext(1); + + // getnext(22); //temp + ch[c].ins[0]=(unsigned char)((getnext(1)<<4)+getnext(1)); + ch[c].ins[2]=(unsigned char)(0xff-(((getnext(1)<<4)+getnext(1))&0x3f)); + ch[c].ins[4]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1))); + ch[c].ins[6]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1))); + ch[c].ins[8]=(unsigned char)((getnext(1)<<4)+getnext(1)); + + ch[c].ins[1]=(unsigned char)((getnext(1)<<4)+getnext(1)); + ch[c].ins[3]=(unsigned char)(0xff-(((getnext(1)<<4)+getnext(1))&0x3f)); + ch[c].ins[5]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1))); + ch[c].ins[7]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1))); + ch[c].ins[9]=(unsigned char)((getnext(1)<<4)+getnext(1)); + + i=(getnext(1)<<4)+getnext(1); + ch[c].ins[10]=i; + + //if ((i&1)==1) ch[c].ins[10]=1; + + midiprintf ("\n%d: ",c); + for (i=0; i<11; i++) + midiprintf ("%2X ",ch[c].ins[i]); + getnext(l-26); + } + else + { + midiprintf("\n"); + for (j=0; j<l; j++) + midiprintf ("%2X ",getnext(1)); + } + + midiprintf("\n"); + if(i==1) + getnext(1); + break; + case 0xf1: + break; + case 0xf2: + getnext(2); + break; + case 0xf3: + getnext(1); + break; + case 0xf4: + break; + case 0xf5: + break; + case 0xf6: /*something*/ + case 0xf8: + case 0xfa: + case 0xfb: + case 0xfc: + //this ends the track for sierra. + if (type == FILE_SIERRA || + type == FILE_ADVSIERRA) + { + track[curtrack].tend=pos; + midiprintf ("endmark: %ld -- %lx\n",pos,pos); + } + break; + case 0xfe: + break; + case 0xfd: + break; + case 0xff: + v=getnext(1); + l=getval(); + midiprintf ("\n"); + midiprintf("{%X_%X}",v,l); + if (v==0x51) + { + lnum=getnext(l); + msqtr=lnum; /*set tempo*/ + midiprintf ("(qtr=%ld)",msqtr); + } + else + { + for (i=0; i<l; i++) + midiprintf ("%2X ",getnext(1)); + } + break; + } + break; + default: midiprintf("!",v); /* if we get down here, a error occurred */ + break; + } + + if (pos < track[curtrack].tend) + { + if (type != FILE_SIERRA && type !=FILE_ADVSIERRA) + w=getval(); + else + w=getnext(1); + track[curtrack].iwait=w; + /* + if (w!=0) + { + midiprintf("\n<%d>",w); + f = +((float)w/(float)deltas)*((float)msqtr/(float)1000000); + if (doing==1) f=0; //not playing yet. don't wait yet + } + */ + } + else + track[curtrack].iwait=0; + + track[curtrack].pos=pos; + } + + + ret=0; //end of song. + iwait=0; + for (curtrack=0; curtrack<16; curtrack++) + if (track[curtrack].on == 1 && + track[curtrack].pos < track[curtrack].tend) + ret=1; //not yet.. + + if (ret==1) + { + iwait=0xffffff; // bigger than any wait can be! + for (curtrack=0; curtrack<16; curtrack++) + if (track[curtrack].on == 1 && + track[curtrack].pos < track[curtrack].tend && + track[curtrack].iwait < iwait) + iwait=track[curtrack].iwait; + } + } + + + if (iwait !=0 && ret==1) + { + for (curtrack=0; curtrack<16; curtrack++) + if (track[curtrack].on) + track[curtrack].iwait-=iwait; + + +fwait=1.0f/(((float)iwait/(float)deltas)*((float)msqtr/(float)1000000)); + } + else + fwait=50; // 1/50th of a second + + midiprintf ("\n"); + for (i=0; i<16; i++) + if (track[i].on) + if (track[i].pos < track[i].tend) + midiprintf ("<%d>",track[i].iwait); + else + midiprintf("stop"); + + /* + if (ret==0 && type==FILE_ADVSIERRA) + if (datalook(sierra_pos-2)!=0xff) + { + midiprintf ("next sectoin!"); + sierra_next_section(p); + fwait=50; + ret=1; + } + */ + + if(ret) + return true; + else + return false; +} + +float CmidPlayer::getrefresh() +{ + return (fwait > 0.01f ? fwait : 0.01f); +} + +void CmidPlayer::rewind(int subsong) +{ + long i,j,n,m,l; + long o_sierra_pos; + unsigned char ins[16]; + + pos=0; tins=0; + adlib_style=MIDI_STYLE|CMF_STYLE; + adlib_mode=ADLIB_MELODIC; + for (i=0; i<128; i++) + for (j=0; j<16; j++) + myinsbank[i][j]=midi_fm_instruments[i][j]; + for (i=0; i<16; i++) + { + ch[i].inum=0; + for (j=0; j<11; j++) + ch[i].ins[j]=myinsbank[ch[i].inum][j]; + ch[i].vol=127; + ch[i].nshift=-25; + ch[i].on=1; + } + + /* General init */ + for (i=0; i<9; i++) + { + chp[i][0]=-1; + chp[i][2]=0; + } + + deltas=250; // just a number, not a standard + msqtr=500000; + fwait=123; // gotta be a small thing.. sorta like nothing + iwait=0; + + subsongs=1; + + for (i=0; i<16; i++) + { + track[i].tend=0; + track[i].spos=0; + track[i].pos=0; + track[i].iwait=0; + track[i].on=0; + track[i].pv=0; + } + curtrack=0; + + /* specific to file-type init */ + + pos=0; + i=getnext(1); + switch(type) + { + case FILE_LUCAS: + getnext(24); //skip junk and get to the midi. + adlib_style=LUCAS_STYLE|MIDI_STYLE; + //note: no break, we go right into midi headers... + case FILE_MIDI: + if (type != FILE_LUCAS) + tins=128; + getnext(11); /*skip header*/ + deltas=getnext(2); + midiprintf ("deltas:%ld\n",deltas); + getnext(4); + + curtrack=0; + track[curtrack].on=1; + track[curtrack].tend=getnext(4); + track[curtrack].spos=pos; + midiprintf ("tracklen:%ld\n",track[curtrack].tend); + break; + case FILE_CMF: + getnext(3); // ctmf + getnexti(2); //version + n=getnexti(2); // instrument offset + m=getnexti(2); // music offset + deltas=getnexti(2); //ticks/qtr note + msqtr=1000000/getnexti(2)*deltas; + //the stuff in the cmf is click ticks per second.. + + i=getnexti(2); + if(i) title = (char *)data+i; + i=getnexti(2); + if(i) author = (char *)data+i; + i=getnexti(2); + if(i) remarks = (char *)data+i; + + getnext(16); // channel in use table .. + i=getnexti(2); // num instr + if (i>128) i=128; // to ward of bad numbers... + getnexti(2); //basic tempo + + midiprintf("\nioff:%d\nmoff%d\ndeltas:%ld\nmsqtr:%ld\nnumi:%d\n", + n,m,deltas,msqtr,i); + pos=n; // jump to instruments + tins=i; + for (j=0; j<i; j++) + { + midiprintf ("\n%d: ",j); + for (l=0; l<16; l++) + { + myinsbank[j][l]=(unsigned char)getnext(1); + midiprintf ("%2X ",myinsbank[j][l]); + } + } + + for (i=0; i<16; i++) + ch[i].nshift=-13; + + adlib_style=CMF_STYLE; + + curtrack=0; + track[curtrack].on=1; + track[curtrack].tend=flen; // music until the end of the file + track[curtrack].spos=m; //jump to midi music + break; + case FILE_OLDLUCAS: + msqtr=250000; + pos=9; + deltas=getnext(1); + + i=8; + pos=0x19; // jump to instruments + tins=i; + for (j=0; j<i; j++) + { + midiprintf ("\n%d: ",j); + for (l=0; l<16; l++) + ins[l]=(unsigned char)getnext(1); + + myinsbank[j][10]=ins[2]; + myinsbank[j][0]=ins[3]; + myinsbank[j][2]=ins[4]; + myinsbank[j][4]=ins[5]; + myinsbank[j][6]=ins[6]; + myinsbank[j][8]=ins[7]; + myinsbank[j][1]=ins[8]; + myinsbank[j][3]=ins[9]; + myinsbank[j][5]=ins[10]; + myinsbank[j][7]=ins[11]; + myinsbank[j][9]=ins[12]; + + for (l=0; l<11; l++) + midiprintf ("%2X ",myinsbank[j][l]); + } + + for (i=0; i<16; i++) + { + if (i<tins) + { + ch[i].inum=i; + for (j=0; j<11; j++) + ch[i].ins[j]=myinsbank[ch[i].inum][j]; + } + } + + adlib_style=LUCAS_STYLE|MIDI_STYLE; + + curtrack=0; + track[curtrack].on=1; + track[curtrack].tend=flen; // music until the end of the file + track[curtrack].spos=0x98; //jump to midi music + break; + case FILE_ADVSIERRA: + memcpy(myinsbank, smyinsbank, 128 * 16); + tins = stins; + deltas=0x20; + getnext(11); //worthless empty space and "stuff" :) + + o_sierra_pos=sierra_pos=pos; + sierra_next_section(); + while (datalook(sierra_pos-2)!=0xff) + { + sierra_next_section(); + subsongs++; + } + + if (subsong < 0 || subsong >= subsongs) subsong=0; + + sierra_pos=o_sierra_pos; + sierra_next_section(); + i=0; + while (i != subsong) + { + sierra_next_section(); + i++; + } + + adlib_style=SIERRA_STYLE|MIDI_STYLE; //advanced sierra tunes use volume + break; + case FILE_SIERRA: + memcpy(myinsbank, smyinsbank, 128 * 16); + tins = stins; + getnext(2); + deltas=0x20; + + curtrack=0; + track[curtrack].on=1; + track[curtrack].tend=flen; // music until the end of the file + + for (i=0; i<16; i++) + { + ch[i].nshift=-13; + ch[i].on=getnext(1); + ch[i].inum=getnext(1); + for (j=0; j<11; j++) + ch[i].ins[j]=myinsbank[ch[i].inum][j]; + } + + track[curtrack].spos=pos; + adlib_style=SIERRA_STYLE|MIDI_STYLE; + break; + } + + +/* sprintf(info,"%s\r\nTicks/Quarter Note: %ld\r\n",info,deltas); + sprintf(info,"%sms/Quarter Note: %ld",info,msqtr); */ + + for (i=0; i<16; i++) + if (track[i].on) + { + track[i].pos=track[i].spos; + track[i].pv=0; + track[i].iwait=0; + } + + doing=1; + midi_fm_reset(); +} + +std::string CmidPlayer::gettype() +{ + switch(type) { + case FILE_LUCAS: + return std::string("LucasArts AdLib MIDI"); + case FILE_MIDI: + return std::string("General MIDI"); + case FILE_CMF: + return std::string("Creative Music Format (CMF MIDI)"); + case FILE_OLDLUCAS: + return std::string("Lucasfilm Adlib MIDI"); + case FILE_ADVSIERRA: + return std::string("Sierra On-Line VGA MIDI"); + case FILE_SIERRA: + return std::string("Sierra On-Line EGA MIDI"); + default: + return std::string("MIDI unknown"); + } +}
--- a/Plugins/Input/adplug/core/mkj.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2004 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 - * - * mkj.cpp - MKJamz Player, by Simon Peter <dn.tlp@gmx.net> - */ - -#include <assert.h> - -#include "mkj.h" -#include "debug.h" - -CPlayer *CmkjPlayer::factory(Copl *newopl) -{ - return new CmkjPlayer(newopl); -} - -bool CmkjPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - char id[6]; - float ver; - int i, j; - short inst[8]; - - // file validation - f->readString(id, 6); - if(strncmp(id,"MKJamz",6)) { fp.close(f); return false; } - ver = f->readFloat(binio::Single); - if(ver > 1.12) { fp.close(f); return false; } - - // load - maxchannel = f->readInt(2); - opl->init(); opl->write(1, 32); - for(i = 0; i < maxchannel; i++) { - for(j = 0; j < 8; j++) inst[j] = f->readInt(2); - opl->write(0x20+op_table[i],inst[4]); - opl->write(0x23+op_table[i],inst[0]); - opl->write(0x40+op_table[i],inst[5]); - opl->write(0x43+op_table[i],inst[1]); - opl->write(0x60+op_table[i],inst[6]); - opl->write(0x63+op_table[i],inst[2]); - opl->write(0x80+op_table[i],inst[7]); - opl->write(0x83+op_table[i],inst[3]); - } - maxnotes = f->readInt(2); - songbuf = new short [(maxchannel+1)*maxnotes]; - for(i = 0; i < maxchannel; i++) channel[i].defined = f->readInt(2); - for(i = 0; i < (maxchannel + 1) * maxnotes; i++) - songbuf[i] = f->readInt(2); - - AdPlug_LogWrite("CmkjPlayer::load(\"%s\"): loaded file ver %.2f, %d channels," - " %d notes/channel.\n", filename.c_str(), ver, maxchannel, - maxnotes); - fp.close(f); - rewind(0); - return true; -} - -bool CmkjPlayer::update() -{ - int c, i; - short note; - - for(c = 0; c < maxchannel; c++) { - if(!channel[c].defined) // skip if channel is disabled - continue; - - if(channel[c].pstat) { - channel[c].pstat--; - continue; - } - - opl->write(0xb0 + c, 0); // key off - do { - assert(channel[c].songptr < (maxchannel + 1) * maxnotes); - note = songbuf[channel[c].songptr]; - if(channel[c].songptr - c > maxchannel) - if(note && note < 250) - channel[c].pstat = channel[c].speed; - switch(note) { - // normal notes - case 68: opl->write(0xa0 + c,0x81); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; - case 69: opl->write(0xa0 + c,0xb0); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; - case 70: opl->write(0xa0 + c,0xca); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; - case 71: opl->write(0xa0 + c,0x2); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; - case 65: opl->write(0xa0 + c,0x41); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; - case 66: opl->write(0xa0 + c,0x87); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; - case 67: opl->write(0xa0 + c,0xae); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; - case 17: opl->write(0xa0 + c,0x6b); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; - case 18: opl->write(0xa0 + c,0x98); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; - case 20: opl->write(0xa0 + c,0xe5); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; - case 21: opl->write(0xa0 + c,0x20); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; - case 15: opl->write(0xa0 + c,0x63); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; - case 255: // delay - channel[c].songptr += maxchannel; - channel[c].pstat = songbuf[channel[c].songptr]; - break; - case 254: // set octave - channel[c].songptr += maxchannel; - channel[c].octave = songbuf[channel[c].songptr]; - break; - case 253: // set speed - channel[c].songptr += maxchannel; - channel[c].speed = songbuf[channel[c].songptr]; - break; - case 252: // set waveform - channel[c].songptr += maxchannel; - channel[c].waveform = songbuf[channel[c].songptr] - 300; - if(c > 2) - opl->write(0xe0 + c + (c+6),channel[c].waveform); - else - opl->write(0xe0 + c,channel[c].waveform); - break; - case 251: // song end - for(i = 0; i < maxchannel; i++) channel[i].songptr = i; - songend = true; - return false; - } - - if(channel[c].songptr - c < maxnotes) - channel[c].songptr += maxchannel; - else - channel[c].songptr = c; - } while(!channel[c].pstat); - } - - return !songend; -} - -void CmkjPlayer::rewind(int subsong) -{ - int i; - - for(i = 0; i < maxchannel; i++) { - channel[i].pstat = 0; - channel[i].speed = 0; - channel[i].waveform = 0; - channel[i].songptr = i; - channel[i].octave = 4; - } - - songend = false; -} - -float CmkjPlayer::getrefresh() -{ - return 100.0f; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mkj.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,163 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 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 + * + * mkj.cpp - MKJamz Player, by Simon Peter <dn.tlp@gmx.net> + */ + +#include <assert.h> + +#include "mkj.h" +#include "debug.h" + +CPlayer *CmkjPlayer::factory(Copl *newopl) +{ + return new CmkjPlayer(newopl); +} + +bool CmkjPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[6]; + float ver; + int i, j; + short inst[8]; + + // file validation + f->readString(id, 6); + if(strncmp(id,"MKJamz",6)) { fp.close(f); return false; } + ver = f->readFloat(binio::Single); + if(ver > 1.12) { fp.close(f); return false; } + + // load + maxchannel = f->readInt(2); + opl->init(); opl->write(1, 32); + for(i = 0; i < maxchannel; i++) { + for(j = 0; j < 8; j++) inst[j] = f->readInt(2); + opl->write(0x20+op_table[i],inst[4]); + opl->write(0x23+op_table[i],inst[0]); + opl->write(0x40+op_table[i],inst[5]); + opl->write(0x43+op_table[i],inst[1]); + opl->write(0x60+op_table[i],inst[6]); + opl->write(0x63+op_table[i],inst[2]); + opl->write(0x80+op_table[i],inst[7]); + opl->write(0x83+op_table[i],inst[3]); + } + maxnotes = f->readInt(2); + songbuf = new short [(maxchannel+1)*maxnotes]; + for(i = 0; i < maxchannel; i++) channel[i].defined = f->readInt(2); + for(i = 0; i < (maxchannel + 1) * maxnotes; i++) + songbuf[i] = f->readInt(2); + + AdPlug_LogWrite("CmkjPlayer::load(\"%s\"): loaded file ver %.2f, %d channels," + " %d notes/channel.\n", filename.c_str(), ver, maxchannel, + maxnotes); + fp.close(f); + rewind(0); + return true; +} + +bool CmkjPlayer::update() +{ + int c, i; + short note; + + for(c = 0; c < maxchannel; c++) { + if(!channel[c].defined) // skip if channel is disabled + continue; + + if(channel[c].pstat) { + channel[c].pstat--; + continue; + } + + opl->write(0xb0 + c, 0); // key off + do { + assert(channel[c].songptr < (maxchannel + 1) * maxnotes); + note = songbuf[channel[c].songptr]; + if(channel[c].songptr - c > maxchannel) + if(note && note < 250) + channel[c].pstat = channel[c].speed; + switch(note) { + // normal notes + case 68: opl->write(0xa0 + c,0x81); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 69: opl->write(0xa0 + c,0xb0); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 70: opl->write(0xa0 + c,0xca); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 71: opl->write(0xa0 + c,0x2); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 65: opl->write(0xa0 + c,0x41); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 66: opl->write(0xa0 + c,0x87); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 67: opl->write(0xa0 + c,0xae); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 17: opl->write(0xa0 + c,0x6b); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 18: opl->write(0xa0 + c,0x98); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 20: opl->write(0xa0 + c,0xe5); opl->write(0xb0 + c,0x21 + 4 * channel[c].octave); break; + case 21: opl->write(0xa0 + c,0x20); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 15: opl->write(0xa0 + c,0x63); opl->write(0xb0 + c,0x22 + 4 * channel[c].octave); break; + case 255: // delay + channel[c].songptr += maxchannel; + channel[c].pstat = songbuf[channel[c].songptr]; + break; + case 254: // set octave + channel[c].songptr += maxchannel; + channel[c].octave = songbuf[channel[c].songptr]; + break; + case 253: // set speed + channel[c].songptr += maxchannel; + channel[c].speed = songbuf[channel[c].songptr]; + break; + case 252: // set waveform + channel[c].songptr += maxchannel; + channel[c].waveform = songbuf[channel[c].songptr] - 300; + if(c > 2) + opl->write(0xe0 + c + (c+6),channel[c].waveform); + else + opl->write(0xe0 + c,channel[c].waveform); + break; + case 251: // song end + for(i = 0; i < maxchannel; i++) channel[i].songptr = i; + songend = true; + return false; + } + + if(channel[c].songptr - c < maxnotes) + channel[c].songptr += maxchannel; + else + channel[c].songptr = c; + } while(!channel[c].pstat); + } + + return !songend; +} + +void CmkjPlayer::rewind(int subsong) +{ + int i; + + for(i = 0; i < maxchannel; i++) { + channel[i].pstat = 0; + channel[i].speed = 0; + channel[i].waveform = 0; + channel[i].songptr = i; + channel[i].octave = 4; + } + + songend = false; +} + +float CmkjPlayer::getrefresh() +{ + return 100.0f; +}
--- a/Plugins/Input/adplug/core/msc.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,312 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 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 - * - * msc.c - MSC Player by Lubomir Bulej (pallas@kadan.cz) - */ - -#include <stdio.h> - -#include "msc.h" -#include "debug.h" - -const unsigned char CmscPlayer::msc_signature [MSC_SIGN_LEN] = { - 'C', 'e', 'r', 'e', 's', ' ', '\x13', ' ', - 'M', 'S', 'C', 'p', 'l', 'a', 'y', ' ' }; - -/*** public methods *************************************/ - -CPlayer *CmscPlayer::factory (Copl * newopl) -{ - return new CmscPlayer (newopl); -} - -CmscPlayer::CmscPlayer(Copl * newopl) : CPlayer (newopl) -{ - desc = NULL; - msc_data = NULL; - raw_data = NULL; - nr_blocks = 0; -} - -CmscPlayer::~CmscPlayer() -{ - if (raw_data != NULL) - delete [] raw_data; - - if (msc_data != NULL) { - // free compressed blocks - for (int blk_num = 0; blk_num < nr_blocks; blk_num++) { - if (msc_data [blk_num].mb_data != NULL) - delete [] msc_data [blk_num].mb_data; - } - - delete [] msc_data; - } - - if (desc != NULL) - delete [] desc; -} - -bool CmscPlayer::load(const std::string & filename, const CFileProvider & fp) -{ - binistream * bf; - msc_header hdr; - - // open and validate the file - bf = fp.open (filename); - if (! bf) - return false; - - if (! load_header (bf, & hdr)) { - fp.close (bf); - return false; - } - - // get stuff from the header - version = hdr.mh_ver; - timer_div = hdr.mh_timer; - nr_blocks = hdr.mh_nr_blocks; - block_len = hdr.mh_block_len; - - if (! nr_blocks) { - fp.close (bf); - return false; - } - - // load compressed data blocks - msc_data = new msc_block [nr_blocks]; - raw_data = new u8 [block_len]; - - for (int blk_num = 0; blk_num < nr_blocks; blk_num++) { - msc_block blk; - - blk.mb_length = bf->readInt (2); - blk.mb_data = new u8 [blk.mb_length]; - for (int oct_num = 0; oct_num < blk.mb_length; oct_num++) { - blk.mb_data [oct_num] = bf->readInt (1); - } - - msc_data [blk_num] = blk; - } - - // clean up & initialize - fp.close (bf); - rewind (0); - - return true; -} - -bool CmscPlayer::update() -{ - // output data - while (! delay) { - u8 cmnd; - u8 data; - - // decode data - if (! decode_octet (& cmnd)) - return false; - - if (! decode_octet (& data)) - return false; - - // check for special commands - switch (cmnd) { - - // delay - case 0xff: - delay = 1 + (u8) (data - 1); - break; - - // play command & data - default: - opl->write (cmnd, data); - - } // command switch - } // play pass - - - // count delays - if (delay) - delay--; - - // advance player position - play_pos++; - return true; -} - -void CmscPlayer::rewind(int subsong) -{ - // reset state - dec_prefix = 0; - block_num = 0; - block_pos = 0; - play_pos = 0; - raw_pos = 0; - delay = 0; - - // init the OPL chip and go to OPL2 mode - opl->init(); - opl->write(1, 32); -} - -float CmscPlayer::getrefresh() -{ - // PC timer oscillator frequency / wait register - return 1193180 / (float) (timer_div ? timer_div : 0xffff); -} - -std::string CmscPlayer::gettype() -{ - char vstr [40]; - - sprintf(vstr, "AdLib MSCplay (version %d)", version); - return std::string (vstr); -} - -/*** private methods *************************************/ - -bool CmscPlayer::load_header(binistream * bf, msc_header * hdr) -{ - // check signature - bf->readString ((char *) hdr->mh_sign, sizeof (hdr->mh_sign)); - if (memcmp (msc_signature, hdr->mh_sign, MSC_SIGN_LEN) != 0) - return false; - - // check version - hdr->mh_ver = bf->readInt (2); - if (hdr->mh_ver != 0) - return false; - - bf->readString ((char *) hdr->mh_desc, sizeof (hdr->mh_desc)); - hdr->mh_timer = bf->readInt (2); - hdr->mh_nr_blocks = bf->readInt (2); - hdr->mh_block_len = bf->readInt (2); - return true; -} - -bool CmscPlayer::decode_octet(u8 * output) -{ - msc_block blk; // compressed data block - - if (block_num >= nr_blocks) - return false; - - blk = msc_data [block_num]; - while (1) { - u8 octet; // decoded octet - u8 len_corr; // length correction - - // advance to next block if necessary - if (block_pos >= blk.mb_length && dec_len == 0) { - block_num++; - if (block_num >= nr_blocks) - return false; - - blk = msc_data [block_num]; - block_pos = 0; - raw_pos = 0; - } - - // decode the compressed music data - switch (dec_prefix) { - - // decode prefix - case 155: - case 175: - octet = blk.mb_data [block_pos++]; - if (octet == 0) { - // invalid prefix, output original - octet = dec_prefix; - dec_prefix = 0; - break; - } - - // isolate length and distance - dec_len = (octet & 0x0F); - len_corr = 2; - - dec_dist = (octet & 0xF0) >> 4; - if (dec_prefix == 155) - dec_dist++; - - // next decode step for respective prefix type - dec_prefix++; - continue; - - - // check for extended length - case 156: - if (dec_len == 15) - dec_len += blk.mb_data [block_pos++]; - - // add length correction and go for copy mode - dec_len += len_corr; - dec_prefix = 255; - continue; - - - // get extended distance - case 176: - dec_dist += 17 + 16 * blk.mb_data [block_pos++]; - len_corr = 3; - - // check for extended length - dec_prefix = 156; - continue; - - - // prefix copy mode - case 255: - if((int)raw_pos >= dec_dist) - octet = raw_data [raw_pos - dec_dist]; - else { - AdPlug_LogWrite("error! read before raw_data buffer.\n"); - octet = 0; - } - - dec_len--; - if (dec_len == 0) { - // back to normal mode - dec_prefix = 0; - } - - break; - - - // normal mode - default: - octet = blk.mb_data [block_pos++]; - if (octet == 155 || octet == 175) { - // it's a prefix, restart - dec_prefix = octet; - continue; - } - } // prefix switch - - - // output the octet - if (output != NULL) - *output = octet; - - raw_data [raw_pos++] = octet; - break; - }; // decode pass - - return true; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/msc.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,312 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2006 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 + * + * msc.c - MSC Player by Lubomir Bulej (pallas@kadan.cz) + */ + +#include <stdio.h> + +#include "msc.h" +#include "debug.h" + +const unsigned char CmscPlayer::msc_signature [MSC_SIGN_LEN] = { + 'C', 'e', 'r', 'e', 's', ' ', '\x13', ' ', + 'M', 'S', 'C', 'p', 'l', 'a', 'y', ' ' }; + +/*** public methods *************************************/ + +CPlayer *CmscPlayer::factory (Copl * newopl) +{ + return new CmscPlayer (newopl); +} + +CmscPlayer::CmscPlayer(Copl * newopl) : CPlayer (newopl) +{ + desc = NULL; + msc_data = NULL; + raw_data = NULL; + nr_blocks = 0; +} + +CmscPlayer::~CmscPlayer() +{ + if (raw_data != NULL) + delete [] raw_data; + + if (msc_data != NULL) { + // free compressed blocks + for (int blk_num = 0; blk_num < nr_blocks; blk_num++) { + if (msc_data [blk_num].mb_data != NULL) + delete [] msc_data [blk_num].mb_data; + } + + delete [] msc_data; + } + + if (desc != NULL) + delete [] desc; +} + +bool CmscPlayer::load(const std::string & filename, const CFileProvider & fp) +{ + binistream * bf; + msc_header hdr; + + // open and validate the file + bf = fp.open (filename); + if (! bf) + return false; + + if (! load_header (bf, & hdr)) { + fp.close (bf); + return false; + } + + // get stuff from the header + version = hdr.mh_ver; + timer_div = hdr.mh_timer; + nr_blocks = hdr.mh_nr_blocks; + block_len = hdr.mh_block_len; + + if (! nr_blocks) { + fp.close (bf); + return false; + } + + // load compressed data blocks + msc_data = new msc_block [nr_blocks]; + raw_data = new u8 [block_len]; + + for (int blk_num = 0; blk_num < nr_blocks; blk_num++) { + msc_block blk; + + blk.mb_length = bf->readInt (2); + blk.mb_data = new u8 [blk.mb_length]; + for (int oct_num = 0; oct_num < blk.mb_length; oct_num++) { + blk.mb_data [oct_num] = bf->readInt (1); + } + + msc_data [blk_num] = blk; + } + + // clean up & initialize + fp.close (bf); + rewind (0); + + return true; +} + +bool CmscPlayer::update() +{ + // output data + while (! delay) { + u8 cmnd; + u8 data; + + // decode data + if (! decode_octet (& cmnd)) + return false; + + if (! decode_octet (& data)) + return false; + + // check for special commands + switch (cmnd) { + + // delay + case 0xff: + delay = 1 + (u8) (data - 1); + break; + + // play command & data + default: + opl->write (cmnd, data); + + } // command switch + } // play pass + + + // count delays + if (delay) + delay--; + + // advance player position + play_pos++; + return true; +} + +void CmscPlayer::rewind(int subsong) +{ + // reset state + dec_prefix = 0; + block_num = 0; + block_pos = 0; + play_pos = 0; + raw_pos = 0; + delay = 0; + + // init the OPL chip and go to OPL2 mode + opl->init(); + opl->write(1, 32); +} + +float CmscPlayer::getrefresh() +{ + // PC timer oscillator frequency / wait register + return 1193180 / (float) (timer_div ? timer_div : 0xffff); +} + +std::string CmscPlayer::gettype() +{ + char vstr [40]; + + sprintf(vstr, "AdLib MSCplay (version %d)", version); + return std::string (vstr); +} + +/*** private methods *************************************/ + +bool CmscPlayer::load_header(binistream * bf, msc_header * hdr) +{ + // check signature + bf->readString ((char *) hdr->mh_sign, sizeof (hdr->mh_sign)); + if (memcmp (msc_signature, hdr->mh_sign, MSC_SIGN_LEN) != 0) + return false; + + // check version + hdr->mh_ver = bf->readInt (2); + if (hdr->mh_ver != 0) + return false; + + bf->readString ((char *) hdr->mh_desc, sizeof (hdr->mh_desc)); + hdr->mh_timer = bf->readInt (2); + hdr->mh_nr_blocks = bf->readInt (2); + hdr->mh_block_len = bf->readInt (2); + return true; +} + +bool CmscPlayer::decode_octet(u8 * output) +{ + msc_block blk; // compressed data block + + if (block_num >= nr_blocks) + return false; + + blk = msc_data [block_num]; + while (1) { + u8 octet; // decoded octet + u8 len_corr; // length correction + + // advance to next block if necessary + if (block_pos >= blk.mb_length && dec_len == 0) { + block_num++; + if (block_num >= nr_blocks) + return false; + + blk = msc_data [block_num]; + block_pos = 0; + raw_pos = 0; + } + + // decode the compressed music data + switch (dec_prefix) { + + // decode prefix + case 155: + case 175: + octet = blk.mb_data [block_pos++]; + if (octet == 0) { + // invalid prefix, output original + octet = dec_prefix; + dec_prefix = 0; + break; + } + + // isolate length and distance + dec_len = (octet & 0x0F); + len_corr = 2; + + dec_dist = (octet & 0xF0) >> 4; + if (dec_prefix == 155) + dec_dist++; + + // next decode step for respective prefix type + dec_prefix++; + continue; + + + // check for extended length + case 156: + if (dec_len == 15) + dec_len += blk.mb_data [block_pos++]; + + // add length correction and go for copy mode + dec_len += len_corr; + dec_prefix = 255; + continue; + + + // get extended distance + case 176: + dec_dist += 17 + 16 * blk.mb_data [block_pos++]; + len_corr = 3; + + // check for extended length + dec_prefix = 156; + continue; + + + // prefix copy mode + case 255: + if((int)raw_pos >= dec_dist) + octet = raw_data [raw_pos - dec_dist]; + else { + AdPlug_LogWrite("error! read before raw_data buffer.\n"); + octet = 0; + } + + dec_len--; + if (dec_len == 0) { + // back to normal mode + dec_prefix = 0; + } + + break; + + + // normal mode + default: + octet = blk.mb_data [block_pos++]; + if (octet == 155 || octet == 175) { + // it's a prefix, restart + dec_prefix = octet; + continue; + } + } // prefix switch + + + // output the octet + if (output != NULL) + *output = octet; + + raw_data [raw_pos++] = octet; + break; + }; // decode pass + + return true; +}
--- a/Plugins/Input/adplug/core/mtk.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 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 - * - * mtk.cpp - MPU-401 Trakker Loader by Simon Peter (dn.tlp@gmx.net) - */ - -#include "mtk.h" - -/*** public methods **************************************/ - -CPlayer *CmtkLoader::factory(Copl *newopl) -{ - return new CmtkLoader(newopl); -} - -bool CmtkLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - struct { - char id[18]; - unsigned short crc,size; - } header; - struct mtkdata { - char songname[34],composername[34],instname[0x80][34]; - unsigned char insts[0x80][12],order[0x80],dummy,patterns[0x32][0x40][9]; - } *data; - unsigned char *cmp,*org; - unsigned int i; - unsigned long cmpsize,cmpptr=0,orgptr=0; - unsigned short ctrlbits=0,ctrlmask=0,cmd,cnt,offs; - - // read header - f->readString(header.id, 18); - header.crc = f->readInt(2); - header.size = f->readInt(2); - - // file validation section - if(strncmp(header.id,"mpu401tr\x92kk\xeer@data",18)) - { fp.close(f); return false; } - - // load section - cmpsize = fp.filesize(f) - 22; - cmp = new unsigned char[cmpsize]; - org = new unsigned char[header.size]; - for(i = 0; i < cmpsize; i++) cmp[i] = f->readInt(1); - fp.close(f); - - while(cmpptr < cmpsize) { // decompress - ctrlmask >>= 1; - if(!ctrlmask) { - ctrlbits = cmp[cmpptr] + (cmp[cmpptr + 1] << 8); - cmpptr += 2; - ctrlmask = 0x8000; - } - if(!(ctrlbits & ctrlmask)) { // uncompressed data - if(orgptr >= header.size) - goto err; - - org[orgptr] = cmp[cmpptr]; - orgptr++; cmpptr++; - continue; - } - - // compressed data - cmd = (cmp[cmpptr] >> 4) & 0x0f; - cnt = cmp[cmpptr] & 0x0f; - cmpptr++; - switch(cmd) { - case 0: - if(orgptr + cnt > header.size) goto err; - cnt += 3; - memset(&org[orgptr],cmp[cmpptr],cnt); - cmpptr++; orgptr += cnt; - break; - - case 1: - if(orgptr + cnt > header.size) goto err; - cnt += (cmp[cmpptr] << 4) + 19; - memset(&org[orgptr],cmp[++cmpptr],cnt); - cmpptr++; orgptr += cnt; - break; - - case 2: - if(orgptr + cnt > header.size) goto err; - offs = (cnt+3) + (cmp[cmpptr] << 4); - cnt = cmp[++cmpptr] + 16; cmpptr++; - memcpy(&org[orgptr],&org[orgptr - offs],cnt); - orgptr += cnt; - break; - - default: - if(orgptr + cmd > header.size) goto err; - offs = (cnt+3) + (cmp[cmpptr++] << 4); - memcpy(&org[orgptr],&org[orgptr-offs],cmd); - orgptr += cmd; - break; - } - } - delete [] cmp; - data = (struct mtkdata *) org; - - // convert to HSC replay data - memset(title,0,34); strncpy(title,data->songname+1,33); - memset(composer,0,34); strncpy(composer,data->composername+1,33); - memset(instname,0,0x80*34); - for(i=0;i<0x80;i++) - strncpy(instname[i],data->instname[i]+1,33); - memcpy(instr,data->insts,0x80 * 12); - memcpy(song,data->order,0x80); - memcpy(patterns,data->patterns,header.size-6084); - for (i=0;i<128;i++) { // correct instruments - instr[i][2] ^= (instr[i][2] & 0x40) << 1; - instr[i][3] ^= (instr[i][3] & 0x40) << 1; - instr[i][11] >>= 4; // make unsigned - } - - delete [] org; - rewind(0); - return true; - - err: - delete [] cmp; - delete [] org; - return false; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/mtk.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,140 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2006 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 + * + * mtk.cpp - MPU-401 Trakker Loader by Simon Peter (dn.tlp@gmx.net) + */ + +#include "mtk.h" + +/*** public methods **************************************/ + +CPlayer *CmtkLoader::factory(Copl *newopl) +{ + return new CmtkLoader(newopl); +} + +bool CmtkLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + struct { + char id[18]; + unsigned short crc,size; + } header; + struct mtkdata { + char songname[34],composername[34],instname[0x80][34]; + unsigned char insts[0x80][12],order[0x80],dummy,patterns[0x32][0x40][9]; + } *data; + unsigned char *cmp,*org; + unsigned int i; + unsigned long cmpsize,cmpptr=0,orgptr=0; + unsigned short ctrlbits=0,ctrlmask=0,cmd,cnt,offs; + + // read header + f->readString(header.id, 18); + header.crc = f->readInt(2); + header.size = f->readInt(2); + + // file validation section + if(strncmp(header.id,"mpu401tr\x92kk\xeer@data",18)) + { fp.close(f); return false; } + + // load section + cmpsize = fp.filesize(f) - 22; + cmp = new unsigned char[cmpsize]; + org = new unsigned char[header.size]; + for(i = 0; i < cmpsize; i++) cmp[i] = f->readInt(1); + fp.close(f); + + while(cmpptr < cmpsize) { // decompress + ctrlmask >>= 1; + if(!ctrlmask) { + ctrlbits = cmp[cmpptr] + (cmp[cmpptr + 1] << 8); + cmpptr += 2; + ctrlmask = 0x8000; + } + if(!(ctrlbits & ctrlmask)) { // uncompressed data + if(orgptr >= header.size) + goto err; + + org[orgptr] = cmp[cmpptr]; + orgptr++; cmpptr++; + continue; + } + + // compressed data + cmd = (cmp[cmpptr] >> 4) & 0x0f; + cnt = cmp[cmpptr] & 0x0f; + cmpptr++; + switch(cmd) { + case 0: + if(orgptr + cnt > header.size) goto err; + cnt += 3; + memset(&org[orgptr],cmp[cmpptr],cnt); + cmpptr++; orgptr += cnt; + break; + + case 1: + if(orgptr + cnt > header.size) goto err; + cnt += (cmp[cmpptr] << 4) + 19; + memset(&org[orgptr],cmp[++cmpptr],cnt); + cmpptr++; orgptr += cnt; + break; + + case 2: + if(orgptr + cnt > header.size) goto err; + offs = (cnt+3) + (cmp[cmpptr] << 4); + cnt = cmp[++cmpptr] + 16; cmpptr++; + memcpy(&org[orgptr],&org[orgptr - offs],cnt); + orgptr += cnt; + break; + + default: + if(orgptr + cmd > header.size) goto err; + offs = (cnt+3) + (cmp[cmpptr++] << 4); + memcpy(&org[orgptr],&org[orgptr-offs],cmd); + orgptr += cmd; + break; + } + } + delete [] cmp; + data = (struct mtkdata *) org; + + // convert to HSC replay data + memset(title,0,34); strncpy(title,data->songname+1,33); + memset(composer,0,34); strncpy(composer,data->composername+1,33); + memset(instname,0,0x80*34); + for(i=0;i<0x80;i++) + strncpy(instname[i],data->instname[i]+1,33); + memcpy(instr,data->insts,0x80 * 12); + memcpy(song,data->order,0x80); + memcpy(patterns,data->patterns,header.size-6084); + for (i=0;i<128;i++) { // correct instruments + instr[i][2] ^= (instr[i][2] & 0x40) << 1; + instr[i][3] ^= (instr[i][3] & 0x40) << 1; + instr[i][11] >>= 4; // make unsigned + } + + delete [] org; + rewind(0); + return true; + + err: + delete [] cmp; + delete [] org; + return false; +}
--- a/Plugins/Input/adplug/core/player.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * 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 - * - * player.cpp - Replayer base class, by Simon Peter <dn.tlp@gmx.net> - */ - -#include "player.h" -#include "adplug.h" -#include "silentopl.h" - -/***** CPlayer *****/ - -const unsigned short CPlayer::note_table[12] = - {363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647, 686}; - -const unsigned char CPlayer::op_table[9] = - {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12}; - -CPlayer::CPlayer(Copl *newopl) - : opl(newopl), db(CAdPlug::database) -{ -} - -CPlayer::~CPlayer() -{ -} - -unsigned long CPlayer::songlength(int subsong) -{ - CSilentopl tempopl; - Copl *saveopl = opl; - float slength = 0.0f; - - // save original OPL from being overwritten - opl = &tempopl; - - // get song length - rewind(subsong); - while(update() && slength < 600000) // song length limit: 10 minutes - slength += 1000.0f / getrefresh(); - rewind(subsong); - - // restore original OPL and return - opl = saveopl; - return (unsigned long)slength; -} - -void CPlayer::seek(unsigned long ms) -{ - float pos = 0.0f; - - rewind(); - while(pos < ms && update()) // seek to new position - pos += 1000/getrefresh(); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/player.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,70 @@ +/* + * 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 + * + * player.cpp - Replayer base class, by Simon Peter <dn.tlp@gmx.net> + */ + +#include "player.h" +#include "adplug.h" +#include "silentopl.h" + +/***** CPlayer *****/ + +const unsigned short CPlayer::note_table[12] = + {363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647, 686}; + +const unsigned char CPlayer::op_table[9] = + {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12}; + +CPlayer::CPlayer(Copl *newopl) + : opl(newopl), db(CAdPlug::database) +{ +} + +CPlayer::~CPlayer() +{ +} + +unsigned long CPlayer::songlength(int subsong) +{ + CSilentopl tempopl; + Copl *saveopl = opl; + float slength = 0.0f; + + // save original OPL from being overwritten + opl = &tempopl; + + // get song length + rewind(subsong); + while(update() && slength < 600000) // song length limit: 10 minutes + slength += 1000.0f / getrefresh(); + rewind(subsong); + + // restore original OPL and return + opl = saveopl; + return (unsigned long)slength; +} + +void CPlayer::seek(unsigned long ms) +{ + float pos = 0.0f; + + rewind(); + while(pos < ms && update()) // seek to new position + pos += 1000/getrefresh(); +}
--- a/Plugins/Input/adplug/core/players.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* - * 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 - * - * players.h - Players enumeration, by Simon Peter <dn.tlp@gmx.net> - */ - -#include <stdlib.h> -#include <string.h> - -#include "players.h" - -/***** CPlayerDesc *****/ - -CPlayerDesc::CPlayerDesc() - : factory(0), extensions(0), extlength(0) -{ -} - -CPlayerDesc::CPlayerDesc(const CPlayerDesc &pd) - : factory(pd.factory), filetype(pd.filetype), extlength(pd.extlength) -{ - if(pd.extensions) { - extensions = (char *)malloc(extlength); - memcpy(extensions, pd.extensions, extlength); - } else - extensions = 0; -} - -CPlayerDesc::CPlayerDesc(Factory f, const std::string &type, const char *ext) - : factory(f), filetype(type), extensions(0) -{ - const char *i = ext; - - // Determine length of passed extensions list - while(*i) i += strlen(i) + 1; - extlength = i - ext + 1; // length = difference between last and first char + 1 - - extensions = (char *)malloc(extlength); - memcpy(extensions, ext, extlength); -} - -CPlayerDesc::~CPlayerDesc() -{ - if(extensions) free(extensions); -} - -void CPlayerDesc::add_extension(const char *ext) -{ - unsigned long newlength = extlength + strlen(ext) + 1; - - extensions = (char *)realloc(extensions, newlength); - strcpy(extensions + extlength - 1, ext); - extensions[newlength - 1] = '\0'; - extlength = newlength; -} - -const char *CPlayerDesc::get_extension(unsigned int n) const -{ - const char *i = extensions; - unsigned int j; - - for(j = 0; j < n && (*i); j++, i += strlen(i) + 1) ; - return (*i != '\0' ? i : 0); -} - -/***** CPlayers *****/ - -const CPlayerDesc *CPlayers::lookup_filetype(const std::string &ftype) const -{ - const_iterator i; - - for(i = begin(); i != end(); i++) - if((*i)->filetype == ftype) - return *i; - - return 0; -} - -const CPlayerDesc *CPlayers::lookup_extension(const std::string &extension) const -{ - const_iterator i; - unsigned int j; - - for(i = begin(); i != end(); i++) - for(j = 0; (*i)->get_extension(j); j++) - if(!stricmp(extension.c_str(), (*i)->get_extension(j))) - return *i; - - return 0; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/players.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,105 @@ +/* + * 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 + * + * players.h - Players enumeration, by Simon Peter <dn.tlp@gmx.net> + */ + +#include <stdlib.h> +#include <string.h> + +#include "players.h" + +/***** CPlayerDesc *****/ + +CPlayerDesc::CPlayerDesc() + : factory(0), extensions(0), extlength(0) +{ +} + +CPlayerDesc::CPlayerDesc(const CPlayerDesc &pd) + : factory(pd.factory), filetype(pd.filetype), extlength(pd.extlength) +{ + if(pd.extensions) { + extensions = (char *)malloc(extlength); + memcpy(extensions, pd.extensions, extlength); + } else + extensions = 0; +} + +CPlayerDesc::CPlayerDesc(Factory f, const std::string &type, const char *ext) + : factory(f), filetype(type), extensions(0) +{ + const char *i = ext; + + // Determine length of passed extensions list + while(*i) i += strlen(i) + 1; + extlength = i - ext + 1; // length = difference between last and first char + 1 + + extensions = (char *)malloc(extlength); + memcpy(extensions, ext, extlength); +} + +CPlayerDesc::~CPlayerDesc() +{ + if(extensions) free(extensions); +} + +void CPlayerDesc::add_extension(const char *ext) +{ + unsigned long newlength = extlength + strlen(ext) + 1; + + extensions = (char *)realloc(extensions, newlength); + strcpy(extensions + extlength - 1, ext); + extensions[newlength - 1] = '\0'; + extlength = newlength; +} + +const char *CPlayerDesc::get_extension(unsigned int n) const +{ + const char *i = extensions; + unsigned int j; + + for(j = 0; j < n && (*i); j++, i += strlen(i) + 1) ; + return (*i != '\0' ? i : 0); +} + +/***** CPlayers *****/ + +const CPlayerDesc *CPlayers::lookup_filetype(const std::string &ftype) const +{ + const_iterator i; + + for(i = begin(); i != end(); i++) + if((*i)->filetype == ftype) + return *i; + + return 0; +} + +const CPlayerDesc *CPlayers::lookup_extension(const std::string &extension) const +{ + const_iterator i; + unsigned int j; + + for(i = begin(); i != end(); i++) + for(j = 0; (*i)->get_extension(j); j++) + if(!stricmp(extension.c_str(), (*i)->get_extension(j))) + return *i; + + return 0; +}
--- a/Plugins/Input/adplug/core/protrack.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,719 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 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 - * - * protrack.cpp - Generic Protracker Player - * - * 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 - * Protracker-like format, this is most certainly the player you want to use. - */ - -#include "protrack.h" -#include "debug.h" - -#define SPECIALARPLEN 256 // Standard length of special arpeggio lists -#define JUMPMARKER 0x80 // Orderlist jump marker - -// SA2 compatible adlib note table -const unsigned short CmodPlayer::sa2_notetable[12] = - {340,363,385,408,432,458,485,514,544,577,611,647}; - -// SA2 compatible vibrato rate table -const unsigned char CmodPlayer::vibratotab[32] = - {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}; - -/*** public methods *************************************/ - -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) -{ - realloc_order(128); - realloc_patterns(64, 64, 9); - realloc_instruments(250); - init_notetable(sa2_notetable); -} - -CmodPlayer::~CmodPlayer() -{ - dealloc(); -} - -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; - - if(!speed) // song full stop - return !songend; - - // effect handling (timer dependant) - for(chan=0;chan<nchans;chan++) { - if(arplist && arpcmd && inst[channel[chan].inst].arpstart) // special arpeggio - if(channel[chan].arpspdcnt) - channel[chan].arpspdcnt--; - else - if(arpcmd[channel[chan].arppos] != 255) { - switch(arpcmd[channel[chan].arppos]) { - case 252: channel[chan].vol1 = arplist[channel[chan].arppos]; // set volume - if(channel[chan].vol1 > 63) // ????? - channel[chan].vol1 = 63; - channel[chan].vol2 = channel[chan].vol1; - setvolume(chan); - break; - case 253: channel[chan].key = 0; setfreq(chan); break; // release sustaining note - 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); - if(arpcmd[channel[chan].arppos] % 10) - opl->write(0xe0 + op_table[chan], (arpcmd[channel[chan].arppos] % 10) - 1); - if(arpcmd[channel[chan].arppos] < 10) // ????? - opl->write(0xe0 + op_table[chan], arpcmd[channel[chan].arppos] - 1); - } - } - if(arpcmd[channel[chan].arppos] != 252) { - if(arplist[channel[chan].arppos] <= 96) - setnote(chan,channel[chan].note + arplist[channel[chan].arppos]); - if(arplist[channel[chan].arppos] >= 100) - setnote(chan,arplist[channel[chan].arppos] - 100); - } else - setnote(chan,channel[chan].note); - setfreq(chan); - if(arpcmd[channel[chan].arppos] != 255) - channel[chan].arppos++; - channel[chan].arpspdcnt = inst[channel[chan].inst].arpspeed - 1; - } - - info1 = channel[chan].info1; - info2 = channel[chan].info2; - if(flags & Decimal) - info = channel[chan].info1 * 10 + channel[chan].info2; - else - info = (channel[chan].info1 << 4) + channel[chan].info2; - switch(channel[chan].fx) { - case 0: if(info) { // arpeggio - if(channel[chan].trigger < 2) - channel[chan].trigger++; - else - channel[chan].trigger = 0; - switch(channel[chan].trigger) { - case 0: setnote(chan,channel[chan].note); break; - case 1: setnote(chan,channel[chan].note + info1); break; - case 2: setnote(chan,channel[chan].note + info2); - } - setfreq(chan); - } - break; - case 1: slide_up(chan,info); setfreq(chan); break; // slide up - case 2: slide_down(chan,info); setfreq(chan); break; // slide down - case 3: tone_portamento(chan,channel[chan].portainfo); break; // tone portamento - case 4: vibrato(chan,channel[chan].vibinfo1,channel[chan].vibinfo2); break; // vibrato - case 5: // tone portamento & volume slide - case 6: if(channel[chan].fx == 5) // vibrato & volume slide - tone_portamento(chan,channel[chan].portainfo); - else - vibrato(chan,channel[chan].vibinfo1,channel[chan].vibinfo2); - case 10: if(del % 4) // SA2 volume slide - break; - if(info1) - vol_up(chan,info1); - else - vol_down(chan,info2); - setvolume(chan); - break; - case 14: if(info1 == 3) // retrig note - if(!(del % (info2+1))) - playnote(chan); - break; - case 16: if(del % 4) // AMD volume slide - break; - if(info1) - vol_up_alt(chan,info1); - else - vol_down_alt(chan,info2); - setvolume(chan); - break; - case 20: // RAD volume slide - if(info < 50) - vol_down_alt(chan,info); - else - vol_up_alt(chan,info - 50); - setvolume(chan); - break; - case 26: // volume slide - if(info1) - vol_up(chan,info1); - else - vol_down(chan,info2); - setvolume(chan); - break; - case 28: - if (info1) { - slide_up(chan,1); channel[chan].info1--; - } - if (info2) { - slide_down(chan,1); channel[chan].info2--; - } - setfreq(chan); - break; - } - } - - if(del) { // speed compensation - del--; - return !songend; - } - - // arrangement handling - if(ord >= length) { - songend = 1; // set end-flag - ord = restartpos; - } - pattnr = order[ord]; - - if(!rw) AdPlug_LogWrite("\nCmodPlayer::update(): Pattern: %d, Order: %d\n", pattnr, ord); - AdPlug_LogWrite("CmodPlayer::update():%3d|", rw); - - // play row - row = rw; - for(chan=0;chan<nchans;chan++) { - if(!(activechan >> (15 - chan)) & 1) { // channel active? - AdPlug_LogWrite("N/A|"); - continue; - } - if(!(track = trackord[pattnr][chan])) { // resolve track - AdPlug_LogWrite("------------|"); - continue; - } else - track--; - - AdPlug_LogWrite("%3d%3d%2X%2X%2X|", tracks[track][row].note, - tracks[track][row].inst, tracks[track][row].command, - tracks[track][row].param1, tracks[track][row].param2); - - donote = 0; - if(tracks[track][row].inst) { - channel[chan].inst = tracks[track][row].inst - 1; - if (!(flags & Faust)) { - channel[chan].vol1 = 63 - (inst[channel[chan].inst].data[10] & 63); - channel[chan].vol2 = 63 - (inst[channel[chan].inst].data[9] & 63); - setvolume(chan); - } - } - - if(tracks[track][row].note && tracks[track][row].command != 3) { // no tone portamento - channel[chan].note = tracks[track][row].note; - setnote(chan,tracks[track][row].note); - channel[chan].nextfreq = channel[chan].freq; - channel[chan].nextoct = channel[chan].oct; - channel[chan].arppos = inst[channel[chan].inst].arpstart; - channel[chan].arpspdcnt = 0; - if(tracks[track][row].note != 127) // handle key off - donote = 1; - } - channel[chan].fx = tracks[track][row].command; - channel[chan].info1 = tracks[track][row].param1; - channel[chan].info2 = tracks[track][row].param2; - - if(donote) - playnote(chan); - - // command handling (row dependant) - info1 = channel[chan].info1; - info2 = channel[chan].info2; - if(flags & Decimal) - info = channel[chan].info1 * 10 + channel[chan].info2; - 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]; - 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; - } - 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; - else - 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 12: // set volume - channel[chan].vol1 = info; - channel[chan].vol2 = info; - if(channel[chan].vol1 > 63) - channel[chan].vol1 = 63; - if(channel[chan].vol2 > 63) - channel[chan].vol2 = 63; - setvolume(chan); - break; - case 13: if(!pattbreak) { pattbreak = 1; rw = info; ord++; } break; // pattern break - case 14: // extended command - switch(info1) { - case 0: if(info2) // define cell-tremolo - regbd |= 128; - else - regbd &= 127; - opl->write(0xbd,regbd); - break; - case 1: if(info2) // define cell-vibrato - regbd |= 64; - else - regbd &= 191; - opl->write(0xbd,regbd); - break; - case 4: vol_up_alt(chan,info2); // increase volume fine - setvolume(chan); - break; - case 5: vol_down_alt(chan,info2); // decrease volume fine - setvolume(chan); - break; - case 6: slide_up(chan,info2); // manual slide up - setfreq(chan); - break; - case 7: slide_down(chan,info2); // manual slide down - setfreq(chan); - break; - } - break; - case 15: // SA2 set speed - if(info <= 0x1f) - speed = info; - if(info >= 0x32) - tempo = info; - if(!info) - songend = 1; - break; - case 17: // alternate set volume - channel[chan].vol1 = info; - if(channel[chan].vol1 > 63) - channel[chan].vol1 = 63; - if(inst[channel[chan].inst].data[0] & 1) { - channel[chan].vol2 = info; - if(channel[chan].vol2 > 63) - channel[chan].vol2 = 63; - } - - 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; - else - channel[chan].vol2 = 63; - setvolume(chan); - break; - case 22: // set carrier volume - if(info <= 63) - channel[chan].vol1 = info; - else - 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); - if(info2 != 0x0f) - opl->write(0xe0 + op_table[chan],info2); - break; - case 27: // set chip tremolo/vibrato - if (info1) - regbd |= 128; - else - regbd &= 127; - if (info2) - regbd |= 64; - else - regbd &= 191; - opl->write(0xbd,regbd); - break; - } - } - - del = speed - 1; // speed compensation - if(!pattbreak) { // next row (only if no manual advance) - rw++; - if(rw >= nrows) { - rw = 0; - ord++; - } - } - if(ord < length) { - if(order[ord] >= JUMPMARKER) { // jump to order - ord = order[ord] - JUMPMARKER; - songend = 1; - } - } else - songend = 1; - - AdPlug_LogWrite("\n"); - return !songend; -} - -void CmodPlayer::rewind(int subsong) -{ - unsigned long i; - - // Reset playing variables - songend = del = ord = rw = regbd = 0; - tempo = bpm; speed = initspeed; - - // Reset channel data - memset(channel,0,sizeof(Channel)*nchans); - - // Compute number of patterns, if needed - if(!nop) - for(i=0;i<length;i++) - nop = (order[i] > nop ? order[i] : nop); - - opl->init(); // Reset OPL chip - opl->write(1,32); // Go to ym3812 mode -} - -float CmodPlayer::getrefresh() -{ - return (float) (tempo / 2.5); -} - -void CmodPlayer::init_trackord() -{ - unsigned long i; - - for(i=0;i<npats*nchans;i++) - trackord[i / nchans][i % nchans] = i + 1; -} - -bool CmodPlayer::init_specialarp() -{ - arplist = new unsigned char[SPECIALARPLEN]; - arpcmd = new unsigned char[SPECIALARPLEN]; - - return true; -} - -void CmodPlayer::init_notetable(const unsigned short *newnotetable) -{ - memcpy(notetable, newnotetable, 12 * 2); -} - -bool CmodPlayer::realloc_order(unsigned long len) -{ - if(order) delete [] order; - order = new unsigned char[len]; - return true; -} - -bool CmodPlayer::realloc_patterns(unsigned long pats, unsigned long rows, unsigned long chans) -{ - unsigned long i; - - dealloc_patterns(); - - // set new number of tracks, rows and channels - npats = pats; nrows = rows; nchans = chans; - - // alloc new patterns - tracks = new Tracks *[pats * chans]; - for(i=0;i<pats*chans;i++) tracks[i] = new Tracks[rows]; - trackord = new unsigned short *[pats]; - for(i=0;i<pats;i++) trackord[i] = new unsigned short[chans]; - channel = new Channel[chans]; - - // initialize new patterns - for(i=0;i<pats*chans;i++) memset(tracks[i],0,sizeof(Tracks)*rows); - for(i=0;i<pats;i++) memset(trackord[i],0,chans*2); - - return true; -} - -void CmodPlayer::dealloc_patterns() -{ - unsigned long i; - - // dealloc everything previously allocated - if(npats && nrows && nchans) { - for(i=0;i<npats*nchans;i++) delete [] tracks[i]; - delete [] tracks; - for(i=0;i<npats;i++) delete [] trackord[i]; - delete [] trackord; - delete [] channel; - } -} - -bool CmodPlayer::realloc_instruments(unsigned long len) -{ - // dealloc previous instance, if any - if(inst) delete [] inst; - - inst = new Instrument[len]; - memset(inst,0,sizeof(Instrument)*len); // reset instruments - return true; -} - -void CmodPlayer::dealloc() -{ - if(inst) delete [] inst; - if(order) delete [] order; - if(arplist) delete [] arplist; - if(arpcmd) delete [] arpcmd; - dealloc_patterns(); -} - -/*** private methods *************************************/ - -void CmodPlayer::setvolume(unsigned char 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)); - } -} - -void CmodPlayer::setvolume_alt(unsigned char 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)); -} - -void CmodPlayer::setfreq(unsigned char chan) -{ - opl->write(0xa0 + chan, channel[chan].freq & 255); - if(channel[chan].key) - opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2) | 32); - else - opl->write(0xb0 + chan, ((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; - - if(!(flags & NoKeyOn)) - opl->write(0xb0 + chan, 0); // stop old note - - // set instrument data - opl->write(0x20 + op, inst[insnr].data[1]); - opl->write(0x23 + op, inst[insnr].data[2]); - opl->write(0x60 + op, inst[insnr].data[3]); - opl->write(0x63 + op, inst[insnr].data[4]); - opl->write(0x80 + op, inst[insnr].data[5]); - 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(0xbd, inst[insnr].misc); // set misc. register - - // set frequency, volume & play - channel[chan].key = 1; - setfreq(chan); - - if (flags & Faust) { - channel[chan].vol2 = 63; - channel[chan].vol1 = 63; - } - setvolume(chan); -} - -void CmodPlayer::setnote(unsigned char chan, int note) -{ - if(note > 96) - if(note == 127) { // key off - channel[chan].key = 0; - setfreq(chan); - return; - } else - note = 96; - - if(note < 13) - channel[chan].freq = notetable[note - 1]; - else - if(note % 12 > 0) - channel[chan].freq = notetable[(note % 12) - 1]; - else - channel[chan].freq = notetable[11]; - channel[chan].oct = (note - 1) / 12; - channel[chan].freq += inst[channel[chan].inst].slide; // apply pre-slide -} - -void CmodPlayer::slide_down(unsigned char chan, int amount) -{ - channel[chan].freq -= amount; - if(channel[chan].freq <= 342) - if(channel[chan].oct) { - channel[chan].oct--; - channel[chan].freq <<= 1; - } else - channel[chan].freq = 342; -} - -void CmodPlayer::slide_up(unsigned char chan, int amount) -{ - channel[chan].freq += amount; - if(channel[chan].freq >= 686) - if(channel[chan].oct < 7) { - channel[chan].oct++; - channel[chan].freq >>= 1; - } else - channel[chan].freq = 686; -} - -void CmodPlayer::tone_portamento(unsigned char chan, unsigned char info) -{ - if(channel[chan].freq + (channel[chan].oct << 10) < channel[chan].nextfreq + - (channel[chan].nextoct << 10)) { - slide_up(chan,info); - if(channel[chan].freq + (channel[chan].oct << 10) > channel[chan].nextfreq + - (channel[chan].nextoct << 10)) { - channel[chan].freq = channel[chan].nextfreq; - channel[chan].oct = channel[chan].nextoct; - } - } - if(channel[chan].freq + (channel[chan].oct << 10) > channel[chan].nextfreq + - (channel[chan].nextoct << 10)) { - slide_down(chan,info); - if(channel[chan].freq + (channel[chan].oct << 10) < channel[chan].nextfreq + - (channel[chan].nextoct << 10)) { - channel[chan].freq = channel[chan].nextfreq; - channel[chan].oct = channel[chan].nextoct; - } - } - setfreq(chan); -} - -void CmodPlayer::vibrato(unsigned char chan, unsigned char speed, unsigned char depth) -{ - int i; - - if(!speed || !depth) - return; - - if(depth > 14) - depth = 14; - - for(i=0;i<speed;i++) { - channel[chan].trigger++; - while(channel[chan].trigger >= 64) - channel[chan].trigger -= 64; - if(channel[chan].trigger >= 16 && channel[chan].trigger < 48) - slide_down(chan,vibratotab[channel[chan].trigger - 16] / (16-depth)); - if(channel[chan].trigger < 16) - slide_up(chan,vibratotab[channel[chan].trigger + 16] / (16-depth)); - if(channel[chan].trigger >= 48) - slide_up(chan,vibratotab[channel[chan].trigger - 48] / (16-depth)); - } - setfreq(chan); -} - -void CmodPlayer::vol_up(unsigned char chan, int amount) -{ - if(channel[chan].vol1 + amount < 63) - channel[chan].vol1 += amount; - else - channel[chan].vol1 = 63; - - if(channel[chan].vol2 + amount < 63) - channel[chan].vol2 += amount; - else - channel[chan].vol2 = 63; -} - -void CmodPlayer::vol_down(unsigned char chan, int amount) -{ - if(channel[chan].vol1 - amount > 0) - channel[chan].vol1 -= amount; - else - channel[chan].vol1 = 0; - - if(channel[chan].vol2 - amount > 0) - channel[chan].vol2 -= amount; - else - channel[chan].vol2 = 0; -} - -void CmodPlayer::vol_up_alt(unsigned char chan, int amount) -{ - if(channel[chan].vol1 + amount < 63) - channel[chan].vol1 += amount; - else - channel[chan].vol1 = 63; - if(inst[channel[chan].inst].data[0] & 1) - if(channel[chan].vol2 + amount < 63) - channel[chan].vol2 += amount; - else - channel[chan].vol2 = 63; -} - -void CmodPlayer::vol_down_alt(unsigned char chan, int amount) -{ - if(channel[chan].vol1 - amount > 0) - channel[chan].vol1 -= amount; - else - channel[chan].vol1 = 0; - if(inst[channel[chan].inst].data[0] & 1) - if(channel[chan].vol2 - amount > 0) - channel[chan].vol2 -= amount; - else - channel[chan].vol2 = 0; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/protrack.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,719 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2006 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 + * + * protrack.cpp - Generic Protracker Player + * + * 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 + * Protracker-like format, this is most certainly the player you want to use. + */ + +#include "protrack.h" +#include "debug.h" + +#define SPECIALARPLEN 256 // Standard length of special arpeggio lists +#define JUMPMARKER 0x80 // Orderlist jump marker + +// SA2 compatible adlib note table +const unsigned short CmodPlayer::sa2_notetable[12] = + {340,363,385,408,432,458,485,514,544,577,611,647}; + +// SA2 compatible vibrato rate table +const unsigned char CmodPlayer::vibratotab[32] = + {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}; + +/*** public methods *************************************/ + +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) +{ + realloc_order(128); + realloc_patterns(64, 64, 9); + realloc_instruments(250); + init_notetable(sa2_notetable); +} + +CmodPlayer::~CmodPlayer() +{ + dealloc(); +} + +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; + + if(!speed) // song full stop + return !songend; + + // effect handling (timer dependant) + for(chan=0;chan<nchans;chan++) { + if(arplist && arpcmd && inst[channel[chan].inst].arpstart) // special arpeggio + if(channel[chan].arpspdcnt) + channel[chan].arpspdcnt--; + else + if(arpcmd[channel[chan].arppos] != 255) { + switch(arpcmd[channel[chan].arppos]) { + case 252: channel[chan].vol1 = arplist[channel[chan].arppos]; // set volume + if(channel[chan].vol1 > 63) // ????? + channel[chan].vol1 = 63; + channel[chan].vol2 = channel[chan].vol1; + setvolume(chan); + break; + case 253: channel[chan].key = 0; setfreq(chan); break; // release sustaining note + 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); + if(arpcmd[channel[chan].arppos] % 10) + opl->write(0xe0 + op_table[chan], (arpcmd[channel[chan].arppos] % 10) - 1); + if(arpcmd[channel[chan].arppos] < 10) // ????? + opl->write(0xe0 + op_table[chan], arpcmd[channel[chan].arppos] - 1); + } + } + if(arpcmd[channel[chan].arppos] != 252) { + if(arplist[channel[chan].arppos] <= 96) + setnote(chan,channel[chan].note + arplist[channel[chan].arppos]); + if(arplist[channel[chan].arppos] >= 100) + setnote(chan,arplist[channel[chan].arppos] - 100); + } else + setnote(chan,channel[chan].note); + setfreq(chan); + if(arpcmd[channel[chan].arppos] != 255) + channel[chan].arppos++; + channel[chan].arpspdcnt = inst[channel[chan].inst].arpspeed - 1; + } + + info1 = channel[chan].info1; + info2 = channel[chan].info2; + if(flags & Decimal) + info = channel[chan].info1 * 10 + channel[chan].info2; + else + info = (channel[chan].info1 << 4) + channel[chan].info2; + switch(channel[chan].fx) { + case 0: if(info) { // arpeggio + if(channel[chan].trigger < 2) + channel[chan].trigger++; + else + channel[chan].trigger = 0; + switch(channel[chan].trigger) { + case 0: setnote(chan,channel[chan].note); break; + case 1: setnote(chan,channel[chan].note + info1); break; + case 2: setnote(chan,channel[chan].note + info2); + } + setfreq(chan); + } + break; + case 1: slide_up(chan,info); setfreq(chan); break; // slide up + case 2: slide_down(chan,info); setfreq(chan); break; // slide down + case 3: tone_portamento(chan,channel[chan].portainfo); break; // tone portamento + case 4: vibrato(chan,channel[chan].vibinfo1,channel[chan].vibinfo2); break; // vibrato + case 5: // tone portamento & volume slide + case 6: if(channel[chan].fx == 5) // vibrato & volume slide + tone_portamento(chan,channel[chan].portainfo); + else + vibrato(chan,channel[chan].vibinfo1,channel[chan].vibinfo2); + case 10: if(del % 4) // SA2 volume slide + break; + if(info1) + vol_up(chan,info1); + else + vol_down(chan,info2); + setvolume(chan); + break; + case 14: if(info1 == 3) // retrig note + if(!(del % (info2+1))) + playnote(chan); + break; + case 16: if(del % 4) // AMD volume slide + break; + if(info1) + vol_up_alt(chan,info1); + else + vol_down_alt(chan,info2); + setvolume(chan); + break; + case 20: // RAD volume slide + if(info < 50) + vol_down_alt(chan,info); + else + vol_up_alt(chan,info - 50); + setvolume(chan); + break; + case 26: // volume slide + if(info1) + vol_up(chan,info1); + else + vol_down(chan,info2); + setvolume(chan); + break; + case 28: + if (info1) { + slide_up(chan,1); channel[chan].info1--; + } + if (info2) { + slide_down(chan,1); channel[chan].info2--; + } + setfreq(chan); + break; + } + } + + if(del) { // speed compensation + del--; + return !songend; + } + + // arrangement handling + if(ord >= length) { + songend = 1; // set end-flag + ord = restartpos; + } + pattnr = order[ord]; + + if(!rw) AdPlug_LogWrite("\nCmodPlayer::update(): Pattern: %d, Order: %d\n", pattnr, ord); + AdPlug_LogWrite("CmodPlayer::update():%3d|", rw); + + // play row + row = rw; + for(chan=0;chan<nchans;chan++) { + if(!(activechan >> (15 - chan)) & 1) { // channel active? + AdPlug_LogWrite("N/A|"); + continue; + } + if(!(track = trackord[pattnr][chan])) { // resolve track + AdPlug_LogWrite("------------|"); + continue; + } else + track--; + + AdPlug_LogWrite("%3d%3d%2X%2X%2X|", tracks[track][row].note, + tracks[track][row].inst, tracks[track][row].command, + tracks[track][row].param1, tracks[track][row].param2); + + donote = 0; + if(tracks[track][row].inst) { + channel[chan].inst = tracks[track][row].inst - 1; + if (!(flags & Faust)) { + channel[chan].vol1 = 63 - (inst[channel[chan].inst].data[10] & 63); + channel[chan].vol2 = 63 - (inst[channel[chan].inst].data[9] & 63); + setvolume(chan); + } + } + + if(tracks[track][row].note && tracks[track][row].command != 3) { // no tone portamento + channel[chan].note = tracks[track][row].note; + setnote(chan,tracks[track][row].note); + channel[chan].nextfreq = channel[chan].freq; + channel[chan].nextoct = channel[chan].oct; + channel[chan].arppos = inst[channel[chan].inst].arpstart; + channel[chan].arpspdcnt = 0; + if(tracks[track][row].note != 127) // handle key off + donote = 1; + } + channel[chan].fx = tracks[track][row].command; + channel[chan].info1 = tracks[track][row].param1; + channel[chan].info2 = tracks[track][row].param2; + + if(donote) + playnote(chan); + + // command handling (row dependant) + info1 = channel[chan].info1; + info2 = channel[chan].info2; + if(flags & Decimal) + info = channel[chan].info1 * 10 + channel[chan].info2; + 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]; + 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; + } + 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; + else + 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 12: // set volume + channel[chan].vol1 = info; + channel[chan].vol2 = info; + if(channel[chan].vol1 > 63) + channel[chan].vol1 = 63; + if(channel[chan].vol2 > 63) + channel[chan].vol2 = 63; + setvolume(chan); + break; + case 13: if(!pattbreak) { pattbreak = 1; rw = info; ord++; } break; // pattern break + case 14: // extended command + switch(info1) { + case 0: if(info2) // define cell-tremolo + regbd |= 128; + else + regbd &= 127; + opl->write(0xbd,regbd); + break; + case 1: if(info2) // define cell-vibrato + regbd |= 64; + else + regbd &= 191; + opl->write(0xbd,regbd); + break; + case 4: vol_up_alt(chan,info2); // increase volume fine + setvolume(chan); + break; + case 5: vol_down_alt(chan,info2); // decrease volume fine + setvolume(chan); + break; + case 6: slide_up(chan,info2); // manual slide up + setfreq(chan); + break; + case 7: slide_down(chan,info2); // manual slide down + setfreq(chan); + break; + } + break; + case 15: // SA2 set speed + if(info <= 0x1f) + speed = info; + if(info >= 0x32) + tempo = info; + if(!info) + songend = 1; + break; + case 17: // alternate set volume + channel[chan].vol1 = info; + if(channel[chan].vol1 > 63) + channel[chan].vol1 = 63; + if(inst[channel[chan].inst].data[0] & 1) { + channel[chan].vol2 = info; + if(channel[chan].vol2 > 63) + channel[chan].vol2 = 63; + } + + 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; + else + channel[chan].vol2 = 63; + setvolume(chan); + break; + case 22: // set carrier volume + if(info <= 63) + channel[chan].vol1 = info; + else + 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); + if(info2 != 0x0f) + opl->write(0xe0 + op_table[chan],info2); + break; + case 27: // set chip tremolo/vibrato + if (info1) + regbd |= 128; + else + regbd &= 127; + if (info2) + regbd |= 64; + else + regbd &= 191; + opl->write(0xbd,regbd); + break; + } + } + + del = speed - 1; // speed compensation + if(!pattbreak) { // next row (only if no manual advance) + rw++; + if(rw >= nrows) { + rw = 0; + ord++; + } + } + if(ord < length) { + if(order[ord] >= JUMPMARKER) { // jump to order + ord = order[ord] - JUMPMARKER; + songend = 1; + } + } else + songend = 1; + + AdPlug_LogWrite("\n"); + return !songend; +} + +void CmodPlayer::rewind(int subsong) +{ + unsigned long i; + + // Reset playing variables + songend = del = ord = rw = regbd = 0; + tempo = bpm; speed = initspeed; + + // Reset channel data + memset(channel,0,sizeof(Channel)*nchans); + + // Compute number of patterns, if needed + if(!nop) + for(i=0;i<length;i++) + nop = (order[i] > nop ? order[i] : nop); + + opl->init(); // Reset OPL chip + opl->write(1,32); // Go to ym3812 mode +} + +float CmodPlayer::getrefresh() +{ + return (float) (tempo / 2.5); +} + +void CmodPlayer::init_trackord() +{ + unsigned long i; + + for(i=0;i<npats*nchans;i++) + trackord[i / nchans][i % nchans] = i + 1; +} + +bool CmodPlayer::init_specialarp() +{ + arplist = new unsigned char[SPECIALARPLEN]; + arpcmd = new unsigned char[SPECIALARPLEN]; + + return true; +} + +void CmodPlayer::init_notetable(const unsigned short *newnotetable) +{ + memcpy(notetable, newnotetable, 12 * 2); +} + +bool CmodPlayer::realloc_order(unsigned long len) +{ + if(order) delete [] order; + order = new unsigned char[len]; + return true; +} + +bool CmodPlayer::realloc_patterns(unsigned long pats, unsigned long rows, unsigned long chans) +{ + unsigned long i; + + dealloc_patterns(); + + // set new number of tracks, rows and channels + npats = pats; nrows = rows; nchans = chans; + + // alloc new patterns + tracks = new Tracks *[pats * chans]; + for(i=0;i<pats*chans;i++) tracks[i] = new Tracks[rows]; + trackord = new unsigned short *[pats]; + for(i=0;i<pats;i++) trackord[i] = new unsigned short[chans]; + channel = new Channel[chans]; + + // initialize new patterns + for(i=0;i<pats*chans;i++) memset(tracks[i],0,sizeof(Tracks)*rows); + for(i=0;i<pats;i++) memset(trackord[i],0,chans*2); + + return true; +} + +void CmodPlayer::dealloc_patterns() +{ + unsigned long i; + + // dealloc everything previously allocated + if(npats && nrows && nchans) { + for(i=0;i<npats*nchans;i++) delete [] tracks[i]; + delete [] tracks; + for(i=0;i<npats;i++) delete [] trackord[i]; + delete [] trackord; + delete [] channel; + } +} + +bool CmodPlayer::realloc_instruments(unsigned long len) +{ + // dealloc previous instance, if any + if(inst) delete [] inst; + + inst = new Instrument[len]; + memset(inst,0,sizeof(Instrument)*len); // reset instruments + return true; +} + +void CmodPlayer::dealloc() +{ + if(inst) delete [] inst; + if(order) delete [] order; + if(arplist) delete [] arplist; + if(arpcmd) delete [] arpcmd; + dealloc_patterns(); +} + +/*** private methods *************************************/ + +void CmodPlayer::setvolume(unsigned char 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)); + } +} + +void CmodPlayer::setvolume_alt(unsigned char 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)); +} + +void CmodPlayer::setfreq(unsigned char chan) +{ + opl->write(0xa0 + chan, channel[chan].freq & 255); + if(channel[chan].key) + opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2) | 32); + else + opl->write(0xb0 + chan, ((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; + + if(!(flags & NoKeyOn)) + opl->write(0xb0 + chan, 0); // stop old note + + // set instrument data + opl->write(0x20 + op, inst[insnr].data[1]); + opl->write(0x23 + op, inst[insnr].data[2]); + opl->write(0x60 + op, inst[insnr].data[3]); + opl->write(0x63 + op, inst[insnr].data[4]); + opl->write(0x80 + op, inst[insnr].data[5]); + 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(0xbd, inst[insnr].misc); // set misc. register + + // set frequency, volume & play + channel[chan].key = 1; + setfreq(chan); + + if (flags & Faust) { + channel[chan].vol2 = 63; + channel[chan].vol1 = 63; + } + setvolume(chan); +} + +void CmodPlayer::setnote(unsigned char chan, int note) +{ + if(note > 96) + if(note == 127) { // key off + channel[chan].key = 0; + setfreq(chan); + return; + } else + note = 96; + + if(note < 13) + channel[chan].freq = notetable[note - 1]; + else + if(note % 12 > 0) + channel[chan].freq = notetable[(note % 12) - 1]; + else + channel[chan].freq = notetable[11]; + channel[chan].oct = (note - 1) / 12; + channel[chan].freq += inst[channel[chan].inst].slide; // apply pre-slide +} + +void CmodPlayer::slide_down(unsigned char chan, int amount) +{ + channel[chan].freq -= amount; + if(channel[chan].freq <= 342) + if(channel[chan].oct) { + channel[chan].oct--; + channel[chan].freq <<= 1; + } else + channel[chan].freq = 342; +} + +void CmodPlayer::slide_up(unsigned char chan, int amount) +{ + channel[chan].freq += amount; + if(channel[chan].freq >= 686) + if(channel[chan].oct < 7) { + channel[chan].oct++; + channel[chan].freq >>= 1; + } else + channel[chan].freq = 686; +} + +void CmodPlayer::tone_portamento(unsigned char chan, unsigned char info) +{ + if(channel[chan].freq + (channel[chan].oct << 10) < channel[chan].nextfreq + + (channel[chan].nextoct << 10)) { + slide_up(chan,info); + if(channel[chan].freq + (channel[chan].oct << 10) > channel[chan].nextfreq + + (channel[chan].nextoct << 10)) { + channel[chan].freq = channel[chan].nextfreq; + channel[chan].oct = channel[chan].nextoct; + } + } + if(channel[chan].freq + (channel[chan].oct << 10) > channel[chan].nextfreq + + (channel[chan].nextoct << 10)) { + slide_down(chan,info); + if(channel[chan].freq + (channel[chan].oct << 10) < channel[chan].nextfreq + + (channel[chan].nextoct << 10)) { + channel[chan].freq = channel[chan].nextfreq; + channel[chan].oct = channel[chan].nextoct; + } + } + setfreq(chan); +} + +void CmodPlayer::vibrato(unsigned char chan, unsigned char speed, unsigned char depth) +{ + int i; + + if(!speed || !depth) + return; + + if(depth > 14) + depth = 14; + + for(i=0;i<speed;i++) { + channel[chan].trigger++; + while(channel[chan].trigger >= 64) + channel[chan].trigger -= 64; + if(channel[chan].trigger >= 16 && channel[chan].trigger < 48) + slide_down(chan,vibratotab[channel[chan].trigger - 16] / (16-depth)); + if(channel[chan].trigger < 16) + slide_up(chan,vibratotab[channel[chan].trigger + 16] / (16-depth)); + if(channel[chan].trigger >= 48) + slide_up(chan,vibratotab[channel[chan].trigger - 48] / (16-depth)); + } + setfreq(chan); +} + +void CmodPlayer::vol_up(unsigned char chan, int amount) +{ + if(channel[chan].vol1 + amount < 63) + channel[chan].vol1 += amount; + else + channel[chan].vol1 = 63; + + if(channel[chan].vol2 + amount < 63) + channel[chan].vol2 += amount; + else + channel[chan].vol2 = 63; +} + +void CmodPlayer::vol_down(unsigned char chan, int amount) +{ + if(channel[chan].vol1 - amount > 0) + channel[chan].vol1 -= amount; + else + channel[chan].vol1 = 0; + + if(channel[chan].vol2 - amount > 0) + channel[chan].vol2 -= amount; + else + channel[chan].vol2 = 0; +} + +void CmodPlayer::vol_up_alt(unsigned char chan, int amount) +{ + if(channel[chan].vol1 + amount < 63) + channel[chan].vol1 += amount; + else + channel[chan].vol1 = 63; + if(inst[channel[chan].inst].data[0] & 1) + if(channel[chan].vol2 + amount < 63) + channel[chan].vol2 += amount; + else + channel[chan].vol2 = 63; +} + +void CmodPlayer::vol_down_alt(unsigned char chan, int amount) +{ + if(channel[chan].vol1 - amount > 0) + channel[chan].vol1 -= amount; + else + channel[chan].vol1 = 0; + if(inst[channel[chan].inst].data[0] & 1) + if(channel[chan].vol2 - amount > 0) + channel[chan].vol2 -= amount; + else + channel[chan].vol2 = 0; +}
--- a/Plugins/Input/adplug/core/psi.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * 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] PSI player, by Riven the Mage <riven@ok.ru> - */ - -/* - - discovery - - - file(s) : 4BIDDEN.COM, PGRID.EXE - type : Forbidden Dreams BBStro - Power Grid BBStro - tune : by Friar Tuck [Shadow Faction/ICE] - player : by Psi [Future Crew] - comment : seems to me what 4bidden tune & player was ripped from pgrid - - file(s) : MYSTRUNE.COM - type : Mystical Runes BBStro - tune : by ? - player : by Psi [Future Crew] -*/ - -#include "psi.h" -#include "debug.h" - -const unsigned char CxadpsiPlayer::psi_adlib_registers[99] = -{ - 0x20, 0x23, 0x40, 0x43, 0x60, 0x63, 0x80, 0x83, 0xE0, 0xE3, 0xC0, - 0x21, 0x24, 0x41, 0x44, 0x61, 0x64, 0x81, 0x84, 0xE1, 0xE4, 0xC1, - 0x22, 0x25, 0x42, 0x45, 0x62, 0x65, 0x82, 0x85, 0xE2, 0xE5, 0xC2, - 0x28, 0x2B, 0x48, 0x4B, 0x68, 0x6B, 0x88, 0x8B, 0xE8, 0xEB, 0xC3, - 0x29, 0x2C, 0x49, 0x4C, 0x69, 0x6C, 0x89, 0x8C, 0xE9, 0xEC, 0xC4, - 0x2A, 0x2D, 0x4A, 0x4D, 0x6A, 0x6D, 0x8A, 0x8D, 0xEA, 0xED, 0xC5, - 0x30, 0x33, 0x50, 0x53, 0x70, 0x73, 0x90, 0x93, 0xF0, 0xF3, 0xC6, - 0x31, 0x34, 0x51, 0x54, 0x71, 0x74, 0x91, 0x94, 0xF1, 0xF4, 0xC7, - 0x32, 0x35, 0x52, 0x55, 0x72, 0x75, 0x92, 0x95, 0xF2, 0xF5, 0xC8 -}; - -const unsigned short CxadpsiPlayer::psi_notes[16] = -{ - 0x216B, 0x2181, 0x2198, 0x21B0, 0x21CA, 0x21E5, 0x2202, 0x2220, - 0x2241, 0x2263, 0x2287, 0x2364, - 0x0000, 0x0000, 0x0000, 0x0000 // by riven -}; - -CPlayer *CxadpsiPlayer::factory(Copl *newopl) -{ - return new CxadpsiPlayer(newopl); -} - -void CxadpsiPlayer::xadplayer_rewind(int subsong) -{ - opl_write(0x01, 0x20); - opl_write(0x08, 0x00); - opl_write(0xBD, 0x00); - - // get header - header.instr_ptr = (tune[1] << 8) + tune[0]; - header.seq_ptr = (tune[3] << 8) + tune[2]; - - // define instruments - psi.instr_table = &tune[header.instr_ptr]; - - for(int i=0; i<8; i++) - { - for(int j=0; j<11; j++) { - unsigned short inspos = (psi.instr_table[i * 2 + 1] << 8) + psi.instr_table[i * 2]; - - opl_write(psi_adlib_registers[i*11 + j],tune[inspos + j]); - } - - opl_write(0xA0+i, 0x00); - opl_write(0xB0+i, 0x00); - - psi.note_delay[i] = 1; - psi.note_curdelay[i] = 1; - psi.looping[i] = 0; - } - - // calculate sequence pointer - psi.seq_table = &tune[header.seq_ptr]; -} - -void CxadpsiPlayer::xadplayer_update() -{ - unsigned short ptr; - - for(int i=0; i<8; i++) - { - ptr = (psi.seq_table[(i<<1) * 2 + 1] << 8) + psi.seq_table[(i<<1) * 2]; - - psi.note_curdelay[i]--; - - if (!psi.note_curdelay[i]) - { - opl_write(0xA0+i, 0x00); - opl_write(0xB0+i, 0x00); - - unsigned char event = tune[ptr++]; -#ifdef DEBUG - AdPlug_LogWrite("channel %02X, event %02X:\n",i+1,event); -#endif - - // end of sequence ? - if (!event) - { - ptr = (psi.seq_table[(i<<1) * 2 + 3] << 8) + psi.seq_table[(i<<1) * 2 + 2]; - - event = tune[ptr++]; -#ifdef DEBUG - AdPlug_LogWrite(" channel %02X, event %02X:\n",i+1,event); -#endif - - // set sequence loop flag - psi.looping[i] = 1; - - // module loop ? - plr.looping = 1; - for(int j=0; j<8; j++) - plr.looping &= psi.looping[j]; - } - - // new note delay ? - if (event & 0x80) - { - psi.note_delay[i] = (event & 0x7F); - - event = tune[ptr++]; -#ifdef DEBUG - AdPlug_LogWrite(" channel %02X, event %02X:\n",i+1,event); -#endif - } - - psi.note_curdelay[i] = psi.note_delay[i]; - - // play note - unsigned short note = psi_notes[event & 0x0F]; - - opl_write(0xA0+i, note & 0xFF); - opl_write(0xB0+i, (note >> 8) + ((event >> 2) & 0xFC)); - - // save position - psi.seq_table[(i<<1) * 2] = ptr & 0xff; - psi.seq_table[(i<<1) * 2 + 1] = ptr >> 8; - } - } -} - -float CxadpsiPlayer::xadplayer_getrefresh() -{ - return 70.0f; -} - -std::string CxadpsiPlayer::xadplayer_gettype() -{ - return std::string("xad: psi player"); -} - -unsigned int CxadpsiPlayer::xadplayer_getinstruments() -{ - return 8; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/psi.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,177 @@ +/* + * 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] PSI player, by Riven the Mage <riven@ok.ru> + */ + +/* + - discovery - + + file(s) : 4BIDDEN.COM, PGRID.EXE + type : Forbidden Dreams BBStro + Power Grid BBStro + tune : by Friar Tuck [Shadow Faction/ICE] + player : by Psi [Future Crew] + comment : seems to me what 4bidden tune & player was ripped from pgrid + + file(s) : MYSTRUNE.COM + type : Mystical Runes BBStro + tune : by ? + player : by Psi [Future Crew] +*/ + +#include "psi.h" +#include "debug.h" + +const unsigned char CxadpsiPlayer::psi_adlib_registers[99] = +{ + 0x20, 0x23, 0x40, 0x43, 0x60, 0x63, 0x80, 0x83, 0xE0, 0xE3, 0xC0, + 0x21, 0x24, 0x41, 0x44, 0x61, 0x64, 0x81, 0x84, 0xE1, 0xE4, 0xC1, + 0x22, 0x25, 0x42, 0x45, 0x62, 0x65, 0x82, 0x85, 0xE2, 0xE5, 0xC2, + 0x28, 0x2B, 0x48, 0x4B, 0x68, 0x6B, 0x88, 0x8B, 0xE8, 0xEB, 0xC3, + 0x29, 0x2C, 0x49, 0x4C, 0x69, 0x6C, 0x89, 0x8C, 0xE9, 0xEC, 0xC4, + 0x2A, 0x2D, 0x4A, 0x4D, 0x6A, 0x6D, 0x8A, 0x8D, 0xEA, 0xED, 0xC5, + 0x30, 0x33, 0x50, 0x53, 0x70, 0x73, 0x90, 0x93, 0xF0, 0xF3, 0xC6, + 0x31, 0x34, 0x51, 0x54, 0x71, 0x74, 0x91, 0x94, 0xF1, 0xF4, 0xC7, + 0x32, 0x35, 0x52, 0x55, 0x72, 0x75, 0x92, 0x95, 0xF2, 0xF5, 0xC8 +}; + +const unsigned short CxadpsiPlayer::psi_notes[16] = +{ + 0x216B, 0x2181, 0x2198, 0x21B0, 0x21CA, 0x21E5, 0x2202, 0x2220, + 0x2241, 0x2263, 0x2287, 0x2364, + 0x0000, 0x0000, 0x0000, 0x0000 // by riven +}; + +CPlayer *CxadpsiPlayer::factory(Copl *newopl) +{ + return new CxadpsiPlayer(newopl); +} + +void CxadpsiPlayer::xadplayer_rewind(int subsong) +{ + opl_write(0x01, 0x20); + opl_write(0x08, 0x00); + opl_write(0xBD, 0x00); + + // get header + header.instr_ptr = (tune[1] << 8) + tune[0]; + header.seq_ptr = (tune[3] << 8) + tune[2]; + + // define instruments + psi.instr_table = &tune[header.instr_ptr]; + + for(int i=0; i<8; i++) + { + for(int j=0; j<11; j++) { + unsigned short inspos = (psi.instr_table[i * 2 + 1] << 8) + psi.instr_table[i * 2]; + + opl_write(psi_adlib_registers[i*11 + j],tune[inspos + j]); + } + + opl_write(0xA0+i, 0x00); + opl_write(0xB0+i, 0x00); + + psi.note_delay[i] = 1; + psi.note_curdelay[i] = 1; + psi.looping[i] = 0; + } + + // calculate sequence pointer + psi.seq_table = &tune[header.seq_ptr]; +} + +void CxadpsiPlayer::xadplayer_update() +{ + unsigned short ptr; + + for(int i=0; i<8; i++) + { + ptr = (psi.seq_table[(i<<1) * 2 + 1] << 8) + psi.seq_table[(i<<1) * 2]; + + psi.note_curdelay[i]--; + + if (!psi.note_curdelay[i]) + { + opl_write(0xA0+i, 0x00); + opl_write(0xB0+i, 0x00); + + unsigned char event = tune[ptr++]; +#ifdef DEBUG + AdPlug_LogWrite("channel %02X, event %02X:\n",i+1,event); +#endif + + // end of sequence ? + if (!event) + { + ptr = (psi.seq_table[(i<<1) * 2 + 3] << 8) + psi.seq_table[(i<<1) * 2 + 2]; + + event = tune[ptr++]; +#ifdef DEBUG + AdPlug_LogWrite(" channel %02X, event %02X:\n",i+1,event); +#endif + + // set sequence loop flag + psi.looping[i] = 1; + + // module loop ? + plr.looping = 1; + for(int j=0; j<8; j++) + plr.looping &= psi.looping[j]; + } + + // new note delay ? + if (event & 0x80) + { + psi.note_delay[i] = (event & 0x7F); + + event = tune[ptr++]; +#ifdef DEBUG + AdPlug_LogWrite(" channel %02X, event %02X:\n",i+1,event); +#endif + } + + psi.note_curdelay[i] = psi.note_delay[i]; + + // play note + unsigned short note = psi_notes[event & 0x0F]; + + opl_write(0xA0+i, note & 0xFF); + opl_write(0xB0+i, (note >> 8) + ((event >> 2) & 0xFC)); + + // save position + psi.seq_table[(i<<1) * 2] = ptr & 0xff; + psi.seq_table[(i<<1) * 2 + 1] = ptr >> 8; + } + } +} + +float CxadpsiPlayer::xadplayer_getrefresh() +{ + return 70.0f; +} + +std::string CxadpsiPlayer::xadplayer_gettype() +{ + return std::string("xad: psi player"); +} + +unsigned int CxadpsiPlayer::xadplayer_getinstruments() +{ + return 8; +}
--- a/Plugins/Input/adplug/core/rad.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * 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 - * - * rad.cpp - RAD Loader by Simon Peter <dn.tlp@gmx.net> - * - * BUGS: - * some volumes are dropped out - */ - -#include "rad.h" - -CPlayer *CradLoader::factory(Copl *newopl) -{ - return new CradLoader(newopl); -} - -bool CradLoader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - char id[16]; - unsigned char buf,ch,c,b,inp; - char bufstr[2] = "\0"; - unsigned int i,j; - unsigned short patofs[32]; - const unsigned char convfx[16] = {255,1,2,3,255,5,255,255,255,255,20,255,17,0xd,255,19}; - - // file validation section - f->readString(id, 16); version = f->readInt(1); - if(strncmp(id,"RAD by REALiTY!!",16) || version != 0x10) - { fp.close(f); return false; } - - // load section - radflags = f->readInt(1); - if(radflags & 128) { // description - memset(desc,0,80*22); - while((buf = f->readInt(1))) - if(buf == 1) - strcat(desc,"\n"); - else - if(buf >= 2 && buf <= 0x1f) - for(i=0;i<buf;i++) - strcat(desc," "); - else { - *bufstr = buf; - strcat(desc,bufstr); - } - } - while((buf = f->readInt(1))) { // instruments - buf--; - inst[buf].data[2] = f->readInt(1); inst[buf].data[1] = f->readInt(1); - inst[buf].data[10] = f->readInt(1); inst[buf].data[9] = f->readInt(1); - inst[buf].data[4] = f->readInt(1); inst[buf].data[3] = f->readInt(1); - inst[buf].data[6] = f->readInt(1); inst[buf].data[5] = f->readInt(1); - inst[buf].data[0] = f->readInt(1); - inst[buf].data[8] = f->readInt(1); inst[buf].data[7] = f->readInt(1); - } - length = f->readInt(1); - for(i = 0; i < length; i++) order[i] = f->readInt(1); // orderlist - for(i = 0; i < 32; i++) patofs[i] = f->readInt(2); // pattern offset table - init_trackord(); // patterns - for(i=0;i<32;i++) - if(patofs[i]) { - f->seek(patofs[i]); - do { - buf = f->readInt(1); b = buf & 127; - do { - ch = f->readInt(1); c = ch & 127; - inp = f->readInt(1); - tracks[i*9+c][b].note = inp & 127; - tracks[i*9+c][b].inst = (inp & 128) >> 3; - inp = f->readInt(1); - tracks[i*9+c][b].inst += inp >> 4; - tracks[i*9+c][b].command = inp & 15; - if(inp & 15) { - inp = f->readInt(1); - tracks[i*9+c][b].param1 = inp / 10; - tracks[i*9+c][b].param2 = inp % 10; - } - } while(!(ch & 128)); - } while(!(buf & 128)); - } else - memset(trackord[i],0,9*2); - fp.close(f); - - // convert replay data - for(i=0;i<32*9;i++) // convert patterns - for(j=0;j<64;j++) { - if(tracks[i][j].note == 15) - tracks[i][j].note = 127; - if(tracks[i][j].note > 16 && tracks[i][j].note < 127) - tracks[i][j].note -= 4 * (tracks[i][j].note >> 4); - if(tracks[i][j].note && tracks[i][j].note < 126) - tracks[i][j].note++; - tracks[i][j].command = convfx[tracks[i][j].command]; - } - restartpos = 0; activechan = 0xffff; initspeed = radflags & 31; - bpm = radflags & 64 ? 0 : 50; flags = Decimal; - - rewind(0); - return true; -} - -float CradLoader::getrefresh() -{ - if(tempo) - return (float) (tempo); - else - return 18.2f; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/rad.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,124 @@ +/* + * 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 + * + * rad.cpp - RAD Loader by Simon Peter <dn.tlp@gmx.net> + * + * BUGS: + * some volumes are dropped out + */ + +#include "rad.h" + +CPlayer *CradLoader::factory(Copl *newopl) +{ + return new CradLoader(newopl); +} + +bool CradLoader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[16]; + unsigned char buf,ch,c,b,inp; + char bufstr[2] = "\0"; + unsigned int i,j; + unsigned short patofs[32]; + const unsigned char convfx[16] = {255,1,2,3,255,5,255,255,255,255,20,255,17,0xd,255,19}; + + // file validation section + f->readString(id, 16); version = f->readInt(1); + if(strncmp(id,"RAD by REALiTY!!",16) || version != 0x10) + { fp.close(f); return false; } + + // load section + radflags = f->readInt(1); + if(radflags & 128) { // description + memset(desc,0,80*22); + while((buf = f->readInt(1))) + if(buf == 1) + strcat(desc,"\n"); + else + if(buf >= 2 && buf <= 0x1f) + for(i=0;i<buf;i++) + strcat(desc," "); + else { + *bufstr = buf; + strcat(desc,bufstr); + } + } + while((buf = f->readInt(1))) { // instruments + buf--; + inst[buf].data[2] = f->readInt(1); inst[buf].data[1] = f->readInt(1); + inst[buf].data[10] = f->readInt(1); inst[buf].data[9] = f->readInt(1); + inst[buf].data[4] = f->readInt(1); inst[buf].data[3] = f->readInt(1); + inst[buf].data[6] = f->readInt(1); inst[buf].data[5] = f->readInt(1); + inst[buf].data[0] = f->readInt(1); + inst[buf].data[8] = f->readInt(1); inst[buf].data[7] = f->readInt(1); + } + length = f->readInt(1); + for(i = 0; i < length; i++) order[i] = f->readInt(1); // orderlist + for(i = 0; i < 32; i++) patofs[i] = f->readInt(2); // pattern offset table + init_trackord(); // patterns + for(i=0;i<32;i++) + if(patofs[i]) { + f->seek(patofs[i]); + do { + buf = f->readInt(1); b = buf & 127; + do { + ch = f->readInt(1); c = ch & 127; + inp = f->readInt(1); + tracks[i*9+c][b].note = inp & 127; + tracks[i*9+c][b].inst = (inp & 128) >> 3; + inp = f->readInt(1); + tracks[i*9+c][b].inst += inp >> 4; + tracks[i*9+c][b].command = inp & 15; + if(inp & 15) { + inp = f->readInt(1); + tracks[i*9+c][b].param1 = inp / 10; + tracks[i*9+c][b].param2 = inp % 10; + } + } while(!(ch & 128)); + } while(!(buf & 128)); + } else + memset(trackord[i],0,9*2); + fp.close(f); + + // convert replay data + for(i=0;i<32*9;i++) // convert patterns + for(j=0;j<64;j++) { + if(tracks[i][j].note == 15) + tracks[i][j].note = 127; + if(tracks[i][j].note > 16 && tracks[i][j].note < 127) + tracks[i][j].note -= 4 * (tracks[i][j].note >> 4); + if(tracks[i][j].note && tracks[i][j].note < 126) + tracks[i][j].note++; + tracks[i][j].command = convfx[tracks[i][j].command]; + } + restartpos = 0; activechan = 0xffff; initspeed = radflags & 31; + bpm = radflags & 64 ? 0 : 50; flags = Decimal; + + rewind(0); + return true; +} + +float CradLoader::getrefresh() +{ + if(tempo) + return (float) (tempo); + else + return 18.2f; +}
--- a/Plugins/Input/adplug/core/rat.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,292 +0,0 @@ -/* - * 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; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/rat.cxx Sat Sep 16 07:33:28 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; +}
--- a/Plugins/Input/adplug/core/raw.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2005 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 - * - * raw.c - RAW Player by Simon Peter <dn.tlp@gmx.net> - */ - -#include "raw.h" - -/*** public methods *************************************/ - -CPlayer *CrawPlayer::factory(Copl *newopl) -{ - return new CrawPlayer(newopl); -} - -bool CrawPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - char id[8]; - unsigned long i; - - // file validation section - f->readString(id, 8); - if(strncmp(id,"RAWADATA",8)) { fp.close (f); return false; } - - // load section - clock = f->readInt(2); // clock speed - length = (fp.filesize(f) - 10) / 2; - data = new Tdata [length]; - for(i = 0; i < length; i++) { - data[i].param = f->readInt(1); - data[i].command = f->readInt(1); - } - - fp.close(f); - rewind(0); - return true; -} - -bool CrawPlayer::update() -{ - bool setspeed; - - if(pos >= length) return false; - - if(del) { - del--; - return !songend; - } - - do { - setspeed = false; - switch(data[pos].command) { - case 0: del = data[pos].param - 1; break; - case 2: - if(!data[pos].param) { - pos++; - speed = data[pos].param + (data[pos].command << 8); - setspeed = true; - } else - opl->setchip(data[pos].param - 1); - break; - case 0xff: - if(data[pos].param == 0xff) { - rewind(0); // auto-rewind song - songend = true; - return !songend; - } - break; - default: - opl->write(data[pos].command,data[pos].param); - break; - } - } while(data[pos++].command || setspeed); - - return !songend; -} - -void CrawPlayer::rewind(int subsong) -{ - pos = del = 0; speed = clock; songend = false; - opl->init(); opl->write(1, 32); // go to 9 channel mode -} - -float CrawPlayer::getrefresh() -{ - return 1193180.0 / (speed ? speed : 0xffff); // timer oscillator speed / wait register = clock frequency -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/raw.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,103 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2005 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 + * + * raw.c - RAW Player by Simon Peter <dn.tlp@gmx.net> + */ + +#include "raw.h" + +/*** public methods *************************************/ + +CPlayer *CrawPlayer::factory(Copl *newopl) +{ + return new CrawPlayer(newopl); +} + +bool CrawPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[8]; + unsigned long i; + + // file validation section + f->readString(id, 8); + if(strncmp(id,"RAWADATA",8)) { fp.close (f); return false; } + + // load section + clock = f->readInt(2); // clock speed + length = (fp.filesize(f) - 10) / 2; + data = new Tdata [length]; + for(i = 0; i < length; i++) { + data[i].param = f->readInt(1); + data[i].command = f->readInt(1); + } + + fp.close(f); + rewind(0); + return true; +} + +bool CrawPlayer::update() +{ + bool setspeed; + + if(pos >= length) return false; + + if(del) { + del--; + return !songend; + } + + do { + setspeed = false; + switch(data[pos].command) { + case 0: del = data[pos].param - 1; break; + case 2: + if(!data[pos].param) { + pos++; + speed = data[pos].param + (data[pos].command << 8); + setspeed = true; + } else + opl->setchip(data[pos].param - 1); + break; + case 0xff: + if(data[pos].param == 0xff) { + rewind(0); // auto-rewind song + songend = true; + return !songend; + } + break; + default: + opl->write(data[pos].command,data[pos].param); + break; + } + } while(data[pos++].command || setspeed); + + return !songend; +} + +void CrawPlayer::rewind(int subsong) +{ + pos = del = 0; speed = clock; songend = false; + opl->init(); opl->write(1, 32); // go to 9 channel mode +} + +float CrawPlayer::getrefresh() +{ + return 1193180.0 / (speed ? speed : 0xffff); // timer oscillator speed / wait register = clock frequency +}
--- a/Plugins/Input/adplug/core/rix.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,492 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 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 - * - * rix.cpp - Softstar RIX OPL Format Player by palxex <palxex.ys168.com> - * BSPAL <BSPAL.ys168.com> - */ - -#include "rix.h" -#include "debug.h" - -const unsigned char CrixPlayer::adflag[] = {0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,1,1,1}; -const unsigned char CrixPlayer::reg_data[] = {0,1,2,3,4,5,8,9,10,11,12,13,16,17,18,19,20,21}; -const unsigned char CrixPlayer::ad_C0_offs[] = {0,1,2,0,1,2,3,4,5,3,4,5,6,7,8,6,7,8}; -const unsigned char CrixPlayer::modify[] = {0,3,1,4,2,5,6,9,7,10,8,11,12,15,13,16,14,17,12,\ - 15,16,0,14,0,17,0,13,0}; -const unsigned char CrixPlayer::bd_reg_data[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x08,0x04,0x02,0x01, - 0x00,0x01,0x01,0x03,0x0F,0x05,0x00,0x01,0x03,0x0F,0x00, - 0x00,0x00,0x01,0x00,0x00,0x01,0x01,0x0F,0x07,0x00,0x02, - 0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0A, - 0x04,0x00,0x08,0x0C,0x0B,0x00,0x00,0x00,0x01,0x00,0x00, - 0x00,0x00,0x0D,0x04,0x00,0x06,0x0F,0x00,0x00,0x00,0x00, - 0x01,0x00,0x00,0x0C,0x00,0x0F,0x0B,0x00,0x08,0x05,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x0F,0x0B,0x00, - 0x07,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, - 0x0F,0x0B,0x00,0x05,0x05,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x01,0x00,0x0F,0x0B,0x00,0x07,0x05,0x00,0x00,0x00, - 0x00,0x00,0x00}; -unsigned char CrixPlayer::for40reg[] = {0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, - 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F}; -unsigned short CrixPlayer::mus_time = 0x4268; - -/*** public methods *************************************/ - -CPlayer *CrixPlayer::factory(Copl *newopl) -{ - return new CrixPlayer(newopl); -} - -CrixPlayer::CrixPlayer(Copl *newopl) - : CPlayer(newopl), flag_mkf(0), file_buffer(0), buf_addr(0) -{ -} - -CrixPlayer::~CrixPlayer() -{ - if(file_buffer) - delete [] file_buffer; -} - -bool CrixPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - unsigned long i=0; - - if(stricmp(filename.substr(filename.length()-4,4).c_str(),".mkf")==0) - { - flag_mkf=1; - f->seek(0); - int offset=f->readInt(4); - f->seek(offset); - } - if(f->readInt(2)!=0x55aa){ fp.close(f);return false; } - file_buffer = new unsigned char [fp.filesize(f) + 1]; - f->seek(0); - while(!f->eof()) - file_buffer[i++]=f->readInt(1); - length=i; - fp.close(f); - if(!flag_mkf) - buf_addr=file_buffer; - rewind(0); - return true; -} - -bool CrixPlayer::update() -{ - int_08h_entry(); - return !play_end; -} - -void CrixPlayer::rewind(int subsong) -{ - I = 0; T = 0; - mus_block = 0; - ins_block = 0; - rhythm = 0; - music_on = 0; - pause_flag = 0; - band = 0; - band_low = 0; - e0_reg_flag = 0; - bd_modify = 0; - sustain = 0; - play_end = 0; - pos = index = 0; - - memset(f_buffer, 0, sizeof(unsigned short) * 300); - memset(a0b0_data2, 0, sizeof(unsigned short) * 11); - memset(a0b0_data3, 0, 18); - memset(a0b0_data4, 0, 18); - memset(a0b0_data5, 0, 96); - memset(addrs_head, 0, 96); - memset(insbuf, 0, 28 * sizeof(unsigned short)); - memset(displace, 0, 11 * sizeof(unsigned short)); - memset(reg_bufs, 0, 18 * sizeof(ADDT)); - - if(flag_mkf) - { - unsigned int *buf_index=(unsigned int *)file_buffer; - int offset1=buf_index[subsong],offset2; - while((offset2=buf_index[++subsong])==offset1); - length=offset2-offset1+1; - buf_addr=file_buffer+offset1; - } - opl->init(); - opl->write(1,32); // go to OPL2 mode - set_new_int(); - data_initial(); -} -unsigned int CrixPlayer::getsubsongs() -{ - if(flag_mkf) - { - unsigned int *buf_index=(unsigned int *)file_buffer; - int songs=buf_index[0]/4,i=0; - for(i=0;i<songs;i++) - if(buf_index[i+1]==buf_index[i]) - songs--; - return songs; - } - else - return 1; -} - -float CrixPlayer::getrefresh() -{ - return 70.0f; -} - -/*------------------Implemention----------------------------*/ -inline void CrixPlayer::set_new_int() -{ - if(!ad_initial()) exit(1); -} -/*----------------------------------------------------------*/ -inline void CrixPlayer::Pause() -{ - register unsigned short i; - pause_flag = 1; - for(i=0;i<11;i++) - switch_ad_bd(i); -} -/*----------------------------------------------------------*/ -inline void CrixPlayer::ad_a0b0l_reg_(unsigned short index,unsigned short p2,unsigned short p3) -{ -// unsigned short i = p2+a0b0_data2[index]; - a0b0_data4[index] = p3; - a0b0_data3[index] = p2; -} -inline void CrixPlayer::data_initial() -{ - rhythm = buf_addr[2]; - mus_block = (buf_addr[0x0D]<<8)+buf_addr[0x0C]; - ins_block = (buf_addr[0x09]<<8)+buf_addr[0x08]; - I = mus_block+1; - if(rhythm != 0) - { - // ad_a0b0_reg(6); - // ad_a0b0_reg(7); - // ad_a0b0_reg(8); - ad_a0b0l_reg_(8,0x18,0); - ad_a0b0l_reg_(7,0x1F,0); - } - bd_modify = 0; - // ad_bd_reg(); - band = 0; music_on = 1; -} -/*----------------------------------------------------------*/ -inline unsigned short CrixPlayer::ad_initial() -{ - register unsigned short i,j,k = 0; - for(i=0;i<25;i++) - { - f_buffer[i*12]=(unsigned int)((i*24+10000)*0.27461678223+4)>>3; - for(int t=1;t<12;t++) - f_buffer[i*12+t]=(unsigned int)((double)f_buffer[i*12+t-1]*1.06); - } - for(i=0;i<8;i++) - for(j=0;j<12;j++) - { - a0b0_data5[k] = i; - addrs_head[k] = j; - k++; - } - //ad_bd_reg(); - //ad_08_reg(); - //for(i=0;i<9;i++) ad_a0b0_reg(i); - e0_reg_flag = 0x20; - //for(i=0;i<18;i++) ad_bop(0xE0+reg_data[i],0); - //ad_bop(1,e0_reg_flag); - return 1;//ad_test(); -} -/*----------------------------------------------------------*/ -inline void CrixPlayer::ad_bop(unsigned short reg,unsigned short value) -{ - if(reg == 2 || reg == 3) - AdPlug_LogWrite("switch OPL2/3 mode!\n"); - opl->write(reg & 0xff, value & 0xff); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::int_08h_entry() - { - unsigned short band_sus = 1; - while(band_sus) - { - if(sustain <= 0) - { - band_sus = rix_proc(); - if(band_sus) sustain += band_sus; - else - { - play_end=1; - break; - } - } - else - { - if(band_sus) sustain -= 14; /* aging */ - break; - } - } - } -/*--------------------------------------------------------------*/ -inline unsigned short CrixPlayer::rix_proc() -{ - unsigned char ctrl = 0; - if(music_on == 0||pause_flag == 1) return 0; - band = 0; - while(buf_addr[I] != 0x80 && I<length-1) - { - band_low = buf_addr[I-1]; - ctrl = buf_addr[I]; I+=2; - switch(ctrl&0xF0) - { - case 0x90: rix_get_ins(); rix_90_pro(ctrl&0x0F); break; - case 0xA0: rix_A0_pro(ctrl&0x0F,((unsigned short)band_low)<<6); break; - case 0xB0: rix_B0_pro(ctrl&0x0F,band_low); break; - case 0xC0: switch_ad_bd(ctrl&0x0F); - if(band_low != 0) rix_C0_pro(ctrl&0x0F,band_low); - break; - default: band = (ctrl<<8)+band_low; break; - } - if(band != 0) return band; - } - music_ctrl(); - I = mus_block+1; - band = 0; music_on = 1; - return 0; -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::rix_get_ins() -{ - int i; - unsigned char *baddr = (&buf_addr[ins_block])+(band_low<<6); - - for(i = 0; i < 28; i++) - insbuf[i] = (baddr[i * 2 + 1] << 8) + baddr[i * 2]; -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::rix_90_pro(unsigned short ctrl_l) -{ - if(rhythm == 0 || ctrl_l < 6) - { - ins_to_reg(modify[ctrl_l*2],insbuf,insbuf[26]); - ins_to_reg(modify[ctrl_l*2+1],insbuf+13,insbuf[27]); - return; - } - else if(ctrl_l > 6) - { - ins_to_reg(modify[ctrl_l*2+6],insbuf,insbuf[26]); - return; - } - else - { - ins_to_reg(12,insbuf,insbuf[26]); - ins_to_reg(15,insbuf+13,insbuf[27]); - return; - } -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::rix_A0_pro(unsigned short ctrl_l,unsigned short index) -{ - if(rhythm == 0 || ctrl_l <= 6) - { - prepare_a0b0(ctrl_l,index>0x3FFF?0x3FFF:index); - ad_a0b0l_reg(ctrl_l,a0b0_data3[ctrl_l],a0b0_data4[ctrl_l]); - } - else return; -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::prepare_a0b0(unsigned short index,unsigned short v) /* important !*/ -{ - short high = 0,low = 0; unsigned int res; - int res1 = (v-0x2000)*0x19; - if(res1 == (int)0xff) return; - low = res1/0x2000; - if(low < 0) - { - low = 0x18-low; high = (signed short)low<0?0xFFFF:0; - res = high; res<<=16; res+=low; - low = ((signed short)res)/(signed short)0xFFE7; - a0b0_data2[index] = low; - low = res; - res = low - 0x18; - high = (signed short)res%0x19; - low = (signed short)res/0x19; - if(high != 0) {low = 0x19; low = low-high;} - } - else - { - res = high = low; - low = (signed short)res/(signed short)0x19; - a0b0_data2[index] = low; - res = high; - low = (signed short)res%(signed short)0x19; - } - low = (signed short)low*(signed short)0x18; - displace[index] = low; -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::ad_a0b0l_reg(unsigned short index,unsigned short p2,unsigned short p3) -{ - unsigned short data; unsigned short i = p2+a0b0_data2[index]; - a0b0_data4[index] = p3; - a0b0_data3[index] = p2; - i = ((signed short)i<=0x5F?i:0x5F); - i = ((signed short)i>=0?i:0); - data = f_buffer[addrs_head[i]+displace[index]/2]; - ad_bop(0xA0+index,data); - data = a0b0_data5[i]*4+(p3<1?0:0x20)+((data>>8)&3); - ad_bop(0xB0+index,data); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::rix_B0_pro(unsigned short ctrl_l,unsigned short index) -{ - register int temp = 0; - if(rhythm == 0 || ctrl_l < 6) temp = modify[ctrl_l*2+1]; - else - { - temp = ctrl_l > 6?ctrl_l*2:ctrl_l*2+1; - temp = modify[temp+6]; - } - for40reg[temp] = index>0x7F?0x7F:index; - ad_40_reg(temp); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::rix_C0_pro(unsigned short ctrl_l,unsigned short index) -{ - register unsigned short i = index>=12?index-12:0; - if(ctrl_l < 6 || rhythm == 0) - { - ad_a0b0l_reg(ctrl_l,i,1); - return; - } - else - { - if(ctrl_l != 6) - { - if(ctrl_l == 8) - { - ad_a0b0l_reg(ctrl_l,i,0); - ad_a0b0l_reg(7,i+7,0); - } - } - else ad_a0b0l_reg(ctrl_l,i,0); - bd_modify |= bd_reg_data[ctrl_l]; - ad_bd_reg(); - return; - } -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::switch_ad_bd(unsigned short index) -{ - - if(rhythm == 0 || index < 6) ad_a0b0l_reg(index,a0b0_data3[index],0); - else - { - bd_modify &= (~bd_reg_data[index]), - ad_bd_reg(); - } -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::ins_to_reg(unsigned short index,unsigned short* insb,unsigned short value) -{ - register unsigned short i; - for(i=0;i<13;i++) reg_bufs[index].v[i] = insb[i]; - reg_bufs[index].v[13] = value&3; - ad_bd_reg(),ad_08_reg(), - ad_40_reg(index),ad_C0_reg(index),ad_60_reg(index), - ad_80_reg(index),ad_20_reg(index),ad_E0_reg(index); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::ad_E0_reg(unsigned short index) -{ - unsigned short data = e0_reg_flag == 0?0:(reg_bufs[index].v[13]&3); - ad_bop(0xE0+reg_data[index],data); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::ad_20_reg(unsigned short index) -{ - unsigned short data = (reg_bufs[index].v[9] < 1?0:0x80); - data += (reg_bufs[index].v[10] < 1?0:0x40); - data += (reg_bufs[index].v[5] < 1?0:0x20); - data += (reg_bufs[index].v[11] < 1?0:0x10); - data += (reg_bufs[index].v[1]&0x0F); - ad_bop(0x20+reg_data[index],data); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::ad_80_reg(unsigned short index) -{ - unsigned short data = (reg_bufs[index].v[7]&0x0F),temp = reg_bufs[index].v[4]; - data |= (temp << 4); - ad_bop(0x80+reg_data[index],data); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::ad_60_reg(unsigned short index) -{ - unsigned short data = reg_bufs[index].v[6]&0x0F,temp = reg_bufs[index].v[3]; - data |= (temp << 4); - ad_bop(0x60+reg_data[index],data); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::ad_C0_reg(unsigned short index) -{ - unsigned short data = reg_bufs[index].v[2]; - if(adflag[index] == 1) return; - data *= 2, - data |= (reg_bufs[index].v[12] < 1?1:0); - ad_bop(0xC0+ad_C0_offs[index],data); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::ad_40_reg(unsigned short index) -{ - unsigned int res = 0; - unsigned short data = 0,temp = reg_bufs[index].v[0]; - data = 0x3F - (0x3F & reg_bufs[index].v[8]), - data *= for40reg[index], - data *= 2, - data += 0x7F, - res = data; - data = res/0xFE, - data -= 0x3F, - data = -data, - data |= temp<<6; - ad_bop(0x40+reg_data[index],data); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::ad_bd_reg() -{ - unsigned short data = rhythm < 1? 0:0x20; - data |= bd_modify; - ad_bop(0xBD,data); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::ad_a0b0_reg(unsigned short index) -{ - ad_bop(0xA0+index,0); - ad_bop(0xB0+index,0); -} -/*--------------------------------------------------------------*/ -inline void CrixPlayer::music_ctrl() -{ - register int i; - for(i=0;i<11;i++) - switch_ad_bd(i); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/rix.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,492 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2006 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 + * + * rix.cpp - Softstar RIX OPL Format Player by palxex <palxex.ys168.com> + * BSPAL <BSPAL.ys168.com> + */ + +#include "rix.h" +#include "debug.h" + +const unsigned char CrixPlayer::adflag[] = {0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,1,1,1}; +const unsigned char CrixPlayer::reg_data[] = {0,1,2,3,4,5,8,9,10,11,12,13,16,17,18,19,20,21}; +const unsigned char CrixPlayer::ad_C0_offs[] = {0,1,2,0,1,2,3,4,5,3,4,5,6,7,8,6,7,8}; +const unsigned char CrixPlayer::modify[] = {0,3,1,4,2,5,6,9,7,10,8,11,12,15,13,16,14,17,12,\ + 15,16,0,14,0,17,0,13,0}; +const unsigned char CrixPlayer::bd_reg_data[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x08,0x04,0x02,0x01, + 0x00,0x01,0x01,0x03,0x0F,0x05,0x00,0x01,0x03,0x0F,0x00, + 0x00,0x00,0x01,0x00,0x00,0x01,0x01,0x0F,0x07,0x00,0x02, + 0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0A, + 0x04,0x00,0x08,0x0C,0x0B,0x00,0x00,0x00,0x01,0x00,0x00, + 0x00,0x00,0x0D,0x04,0x00,0x06,0x0F,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x0C,0x00,0x0F,0x0B,0x00,0x08,0x05,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x0F,0x0B,0x00, + 0x07,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x0F,0x0B,0x00,0x05,0x05,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0x00,0x0F,0x0B,0x00,0x07,0x05,0x00,0x00,0x00, + 0x00,0x00,0x00}; +unsigned char CrixPlayer::for40reg[] = {0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, + 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F}; +unsigned short CrixPlayer::mus_time = 0x4268; + +/*** public methods *************************************/ + +CPlayer *CrixPlayer::factory(Copl *newopl) +{ + return new CrixPlayer(newopl); +} + +CrixPlayer::CrixPlayer(Copl *newopl) + : CPlayer(newopl), flag_mkf(0), file_buffer(0), buf_addr(0) +{ +} + +CrixPlayer::~CrixPlayer() +{ + if(file_buffer) + delete [] file_buffer; +} + +bool CrixPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + unsigned long i=0; + + if(stricmp(filename.substr(filename.length()-4,4).c_str(),".mkf")==0) + { + flag_mkf=1; + f->seek(0); + int offset=f->readInt(4); + f->seek(offset); + } + if(f->readInt(2)!=0x55aa){ fp.close(f);return false; } + file_buffer = new unsigned char [fp.filesize(f) + 1]; + f->seek(0); + while(!f->eof()) + file_buffer[i++]=f->readInt(1); + length=i; + fp.close(f); + if(!flag_mkf) + buf_addr=file_buffer; + rewind(0); + return true; +} + +bool CrixPlayer::update() +{ + int_08h_entry(); + return !play_end; +} + +void CrixPlayer::rewind(int subsong) +{ + I = 0; T = 0; + mus_block = 0; + ins_block = 0; + rhythm = 0; + music_on = 0; + pause_flag = 0; + band = 0; + band_low = 0; + e0_reg_flag = 0; + bd_modify = 0; + sustain = 0; + play_end = 0; + pos = index = 0; + + memset(f_buffer, 0, sizeof(unsigned short) * 300); + memset(a0b0_data2, 0, sizeof(unsigned short) * 11); + memset(a0b0_data3, 0, 18); + memset(a0b0_data4, 0, 18); + memset(a0b0_data5, 0, 96); + memset(addrs_head, 0, 96); + memset(insbuf, 0, 28 * sizeof(unsigned short)); + memset(displace, 0, 11 * sizeof(unsigned short)); + memset(reg_bufs, 0, 18 * sizeof(ADDT)); + + if(flag_mkf) + { + unsigned int *buf_index=(unsigned int *)file_buffer; + int offset1=buf_index[subsong],offset2; + while((offset2=buf_index[++subsong])==offset1); + length=offset2-offset1+1; + buf_addr=file_buffer+offset1; + } + opl->init(); + opl->write(1,32); // go to OPL2 mode + set_new_int(); + data_initial(); +} +unsigned int CrixPlayer::getsubsongs() +{ + if(flag_mkf) + { + unsigned int *buf_index=(unsigned int *)file_buffer; + int songs=buf_index[0]/4,i=0; + for(i=0;i<songs;i++) + if(buf_index[i+1]==buf_index[i]) + songs--; + return songs; + } + else + return 1; +} + +float CrixPlayer::getrefresh() +{ + return 70.0f; +} + +/*------------------Implemention----------------------------*/ +inline void CrixPlayer::set_new_int() +{ + if(!ad_initial()) exit(1); +} +/*----------------------------------------------------------*/ +inline void CrixPlayer::Pause() +{ + register unsigned short i; + pause_flag = 1; + for(i=0;i<11;i++) + switch_ad_bd(i); +} +/*----------------------------------------------------------*/ +inline void CrixPlayer::ad_a0b0l_reg_(unsigned short index,unsigned short p2,unsigned short p3) +{ +// unsigned short i = p2+a0b0_data2[index]; + a0b0_data4[index] = p3; + a0b0_data3[index] = p2; +} +inline void CrixPlayer::data_initial() +{ + rhythm = buf_addr[2]; + mus_block = (buf_addr[0x0D]<<8)+buf_addr[0x0C]; + ins_block = (buf_addr[0x09]<<8)+buf_addr[0x08]; + I = mus_block+1; + if(rhythm != 0) + { + // ad_a0b0_reg(6); + // ad_a0b0_reg(7); + // ad_a0b0_reg(8); + ad_a0b0l_reg_(8,0x18,0); + ad_a0b0l_reg_(7,0x1F,0); + } + bd_modify = 0; + // ad_bd_reg(); + band = 0; music_on = 1; +} +/*----------------------------------------------------------*/ +inline unsigned short CrixPlayer::ad_initial() +{ + register unsigned short i,j,k = 0; + for(i=0;i<25;i++) + { + f_buffer[i*12]=(unsigned int)((i*24+10000)*0.27461678223+4)>>3; + for(int t=1;t<12;t++) + f_buffer[i*12+t]=(unsigned int)((double)f_buffer[i*12+t-1]*1.06); + } + for(i=0;i<8;i++) + for(j=0;j<12;j++) + { + a0b0_data5[k] = i; + addrs_head[k] = j; + k++; + } + //ad_bd_reg(); + //ad_08_reg(); + //for(i=0;i<9;i++) ad_a0b0_reg(i); + e0_reg_flag = 0x20; + //for(i=0;i<18;i++) ad_bop(0xE0+reg_data[i],0); + //ad_bop(1,e0_reg_flag); + return 1;//ad_test(); +} +/*----------------------------------------------------------*/ +inline void CrixPlayer::ad_bop(unsigned short reg,unsigned short value) +{ + if(reg == 2 || reg == 3) + AdPlug_LogWrite("switch OPL2/3 mode!\n"); + opl->write(reg & 0xff, value & 0xff); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::int_08h_entry() + { + unsigned short band_sus = 1; + while(band_sus) + { + if(sustain <= 0) + { + band_sus = rix_proc(); + if(band_sus) sustain += band_sus; + else + { + play_end=1; + break; + } + } + else + { + if(band_sus) sustain -= 14; /* aging */ + break; + } + } + } +/*--------------------------------------------------------------*/ +inline unsigned short CrixPlayer::rix_proc() +{ + unsigned char ctrl = 0; + if(music_on == 0||pause_flag == 1) return 0; + band = 0; + while(buf_addr[I] != 0x80 && I<length-1) + { + band_low = buf_addr[I-1]; + ctrl = buf_addr[I]; I+=2; + switch(ctrl&0xF0) + { + case 0x90: rix_get_ins(); rix_90_pro(ctrl&0x0F); break; + case 0xA0: rix_A0_pro(ctrl&0x0F,((unsigned short)band_low)<<6); break; + case 0xB0: rix_B0_pro(ctrl&0x0F,band_low); break; + case 0xC0: switch_ad_bd(ctrl&0x0F); + if(band_low != 0) rix_C0_pro(ctrl&0x0F,band_low); + break; + default: band = (ctrl<<8)+band_low; break; + } + if(band != 0) return band; + } + music_ctrl(); + I = mus_block+1; + band = 0; music_on = 1; + return 0; +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::rix_get_ins() +{ + int i; + unsigned char *baddr = (&buf_addr[ins_block])+(band_low<<6); + + for(i = 0; i < 28; i++) + insbuf[i] = (baddr[i * 2 + 1] << 8) + baddr[i * 2]; +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::rix_90_pro(unsigned short ctrl_l) +{ + if(rhythm == 0 || ctrl_l < 6) + { + ins_to_reg(modify[ctrl_l*2],insbuf,insbuf[26]); + ins_to_reg(modify[ctrl_l*2+1],insbuf+13,insbuf[27]); + return; + } + else if(ctrl_l > 6) + { + ins_to_reg(modify[ctrl_l*2+6],insbuf,insbuf[26]); + return; + } + else + { + ins_to_reg(12,insbuf,insbuf[26]); + ins_to_reg(15,insbuf+13,insbuf[27]); + return; + } +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::rix_A0_pro(unsigned short ctrl_l,unsigned short index) +{ + if(rhythm == 0 || ctrl_l <= 6) + { + prepare_a0b0(ctrl_l,index>0x3FFF?0x3FFF:index); + ad_a0b0l_reg(ctrl_l,a0b0_data3[ctrl_l],a0b0_data4[ctrl_l]); + } + else return; +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::prepare_a0b0(unsigned short index,unsigned short v) /* important !*/ +{ + short high = 0,low = 0; unsigned int res; + int res1 = (v-0x2000)*0x19; + if(res1 == (int)0xff) return; + low = res1/0x2000; + if(low < 0) + { + low = 0x18-low; high = (signed short)low<0?0xFFFF:0; + res = high; res<<=16; res+=low; + low = ((signed short)res)/(signed short)0xFFE7; + a0b0_data2[index] = low; + low = res; + res = low - 0x18; + high = (signed short)res%0x19; + low = (signed short)res/0x19; + if(high != 0) {low = 0x19; low = low-high;} + } + else + { + res = high = low; + low = (signed short)res/(signed short)0x19; + a0b0_data2[index] = low; + res = high; + low = (signed short)res%(signed short)0x19; + } + low = (signed short)low*(signed short)0x18; + displace[index] = low; +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::ad_a0b0l_reg(unsigned short index,unsigned short p2,unsigned short p3) +{ + unsigned short data; unsigned short i = p2+a0b0_data2[index]; + a0b0_data4[index] = p3; + a0b0_data3[index] = p2; + i = ((signed short)i<=0x5F?i:0x5F); + i = ((signed short)i>=0?i:0); + data = f_buffer[addrs_head[i]+displace[index]/2]; + ad_bop(0xA0+index,data); + data = a0b0_data5[i]*4+(p3<1?0:0x20)+((data>>8)&3); + ad_bop(0xB0+index,data); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::rix_B0_pro(unsigned short ctrl_l,unsigned short index) +{ + register int temp = 0; + if(rhythm == 0 || ctrl_l < 6) temp = modify[ctrl_l*2+1]; + else + { + temp = ctrl_l > 6?ctrl_l*2:ctrl_l*2+1; + temp = modify[temp+6]; + } + for40reg[temp] = index>0x7F?0x7F:index; + ad_40_reg(temp); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::rix_C0_pro(unsigned short ctrl_l,unsigned short index) +{ + register unsigned short i = index>=12?index-12:0; + if(ctrl_l < 6 || rhythm == 0) + { + ad_a0b0l_reg(ctrl_l,i,1); + return; + } + else + { + if(ctrl_l != 6) + { + if(ctrl_l == 8) + { + ad_a0b0l_reg(ctrl_l,i,0); + ad_a0b0l_reg(7,i+7,0); + } + } + else ad_a0b0l_reg(ctrl_l,i,0); + bd_modify |= bd_reg_data[ctrl_l]; + ad_bd_reg(); + return; + } +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::switch_ad_bd(unsigned short index) +{ + + if(rhythm == 0 || index < 6) ad_a0b0l_reg(index,a0b0_data3[index],0); + else + { + bd_modify &= (~bd_reg_data[index]), + ad_bd_reg(); + } +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::ins_to_reg(unsigned short index,unsigned short* insb,unsigned short value) +{ + register unsigned short i; + for(i=0;i<13;i++) reg_bufs[index].v[i] = insb[i]; + reg_bufs[index].v[13] = value&3; + ad_bd_reg(),ad_08_reg(), + ad_40_reg(index),ad_C0_reg(index),ad_60_reg(index), + ad_80_reg(index),ad_20_reg(index),ad_E0_reg(index); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::ad_E0_reg(unsigned short index) +{ + unsigned short data = e0_reg_flag == 0?0:(reg_bufs[index].v[13]&3); + ad_bop(0xE0+reg_data[index],data); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::ad_20_reg(unsigned short index) +{ + unsigned short data = (reg_bufs[index].v[9] < 1?0:0x80); + data += (reg_bufs[index].v[10] < 1?0:0x40); + data += (reg_bufs[index].v[5] < 1?0:0x20); + data += (reg_bufs[index].v[11] < 1?0:0x10); + data += (reg_bufs[index].v[1]&0x0F); + ad_bop(0x20+reg_data[index],data); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::ad_80_reg(unsigned short index) +{ + unsigned short data = (reg_bufs[index].v[7]&0x0F),temp = reg_bufs[index].v[4]; + data |= (temp << 4); + ad_bop(0x80+reg_data[index],data); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::ad_60_reg(unsigned short index) +{ + unsigned short data = reg_bufs[index].v[6]&0x0F,temp = reg_bufs[index].v[3]; + data |= (temp << 4); + ad_bop(0x60+reg_data[index],data); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::ad_C0_reg(unsigned short index) +{ + unsigned short data = reg_bufs[index].v[2]; + if(adflag[index] == 1) return; + data *= 2, + data |= (reg_bufs[index].v[12] < 1?1:0); + ad_bop(0xC0+ad_C0_offs[index],data); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::ad_40_reg(unsigned short index) +{ + unsigned int res = 0; + unsigned short data = 0,temp = reg_bufs[index].v[0]; + data = 0x3F - (0x3F & reg_bufs[index].v[8]), + data *= for40reg[index], + data *= 2, + data += 0x7F, + res = data; + data = res/0xFE, + data -= 0x3F, + data = -data, + data |= temp<<6; + ad_bop(0x40+reg_data[index],data); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::ad_bd_reg() +{ + unsigned short data = rhythm < 1? 0:0x20; + data |= bd_modify; + ad_bop(0xBD,data); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::ad_a0b0_reg(unsigned short index) +{ + ad_bop(0xA0+index,0); + ad_bop(0xB0+index,0); +} +/*--------------------------------------------------------------*/ +inline void CrixPlayer::music_ctrl() +{ + register int i; + for(i=0;i<11;i++) + switch_ad_bd(i); +}
--- a/Plugins/Input/adplug/core/rol.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,723 +0,0 @@ -/* - * 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 - * - * rol.h - ROL Player by OPLx <oplx@yahoo.com> - * - * Visit: http://tenacity.hispeed.com/aomit/oplx/ - */ -#include <algorithm> - -#include "rol.h" -#include "debug.h" - -int const CrolPlayer::kSizeofDataRecord = 30; -int const CrolPlayer::kMaxTickBeat = 60; -int const CrolPlayer::kSilenceNote = -12; -int const CrolPlayer::kNumMelodicVoices = 9; -int const CrolPlayer::kNumPercussiveVoices = 11; -int const CrolPlayer::kBassDrumChannel = 6; -int const CrolPlayer::kSnareDrumChannel = 7; -int const CrolPlayer::kTomtomChannel = 8; -int const CrolPlayer::kTomtomFreq = 2;//4; -int const CrolPlayer::kSnareDrumFreq = 2;//kTomtomFreq + 7; -float const CrolPlayer::kDefaultUpdateTme = 18.2f; -float const CrolPlayer::kPitchFactor = 400.0f; - -static const unsigned char drum_table[4] = {0x14, 0x12, 0x15, 0x11}; - -CrolPlayer::uint16 const CrolPlayer::kNoteTable[12] = -{ - 340, // C - 363, // C# - 385, // D - 408, // D# - 432, // E - 458, // F - 485, // F# - 514, // G - 544, // G# - 577, // A - 611, // A# - 647 // B -}; - -/*** public methods **************************************/ - -CPlayer *CrolPlayer::factory(Copl *newopl) -{ - return new CrolPlayer(newopl); -} -//--------------------------------------------------------- -CrolPlayer::CrolPlayer(Copl *newopl) -: CPlayer ( newopl ) - ,rol_header ( NULL ) - ,mNextTempoEvent ( 0 ) - ,mCurrTick ( 0 ) - ,mTimeOfLastNote ( 0 ) - ,mRefresh ( kDefaultUpdateTme ) - ,bdRegister ( 0 ) -{ - int n; - - memset(bxRegister, 0, sizeof(bxRegister) ); - memset(volumeCache, 0, sizeof(volumeCache) ); - memset(freqCache, 0, sizeof(freqCache) ); - - for(n=0; n<11; n++) - pitchCache[n]=1.0f; -} -//--------------------------------------------------------- -CrolPlayer::~CrolPlayer() -{ - if( rol_header != NULL ) - { - delete rol_header; - rol_header=NULL; - } -} -//--------------------------------------------------------- -bool CrolPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - - char *fn = new char[filename.length()+9]; - int i; - std::string bnk_filename; - - AdPlug_LogWrite("*** CrolPlayer::load(f, \"%s\") ***\n", filename.c_str()); - strcpy(fn,filename.data()); - for (i=strlen(fn)-1; i>=0; i--) - if (fn[i] == '/' || fn[i] == '\\') - break; - strcpy(fn+i+1,"standard.bnk"); - bnk_filename = fn; - delete [] fn; - AdPlug_LogWrite("bnk_filename = \"%s\"\n",bnk_filename.c_str()); - - rol_header = new SRolHeader; - memset( rol_header, 0, sizeof(SRolHeader) ); - - rol_header->version_major = f->readInt( 2 ); - rol_header->version_minor = f->readInt( 2 ); - - // Version check - if(rol_header->version_major != 0 || rol_header->version_minor != 4) { - AdPlug_LogWrite("Unsupported file version %d.%d or not a ROL file!\n", - rol_header->version_major, rol_header->version_minor); - AdPlug_LogWrite("--- CrolPlayer::load ---\n"); - fp.close(f); - return false; - } - - f->seek( 40, binio::Add ); - - rol_header->ticks_per_beat = f->readInt( 2 ); - rol_header->beats_per_measure = f->readInt( 2 ); - rol_header->edit_scale_y = f->readInt( 2 ); - rol_header->edit_scale_x = f->readInt( 2 ); - - f->seek( 1, binio::Add ); - - rol_header->mode = f->readInt(1); - - f->seek( 90+38+15, binio::Add ); - - rol_header->basic_tempo = f->readFloat( binio::Single ); - - load_tempo_events( f ); - - mTimeOfLastNote = 0; - - if( load_voice_data( f, bnk_filename, fp ) != true ) - { - AdPlug_LogWrite("CrolPlayer::load_voice_data(f) failed!\n"); - AdPlug_LogWrite("--- CrolPlayer::load ---\n"); - - fp.close( f ); - return false; - } - - fp.close( f ); - - rewind( 0 ); - AdPlug_LogWrite("--- CrolPlayer::load ---\n"); - return true; -} -//--------------------------------------------------------- -bool CrolPlayer::update() -{ - if( mNextTempoEvent < mTempoEvents.size() && - mTempoEvents[mNextTempoEvent].time == mCurrTick ) - { - SetRefresh( mTempoEvents[mNextTempoEvent].multiplier ); - ++mNextTempoEvent; - } - - TVoiceData::iterator curr = voice_data.begin(); - TVoiceData::iterator end = voice_data.end(); - int voice = 0; - - while( curr != end ) - { - UpdateVoice( voice, *curr ); - ++curr; - ++voice; - } - - ++mCurrTick; - - if( mCurrTick > mTimeOfLastNote ) - { - return false; - } - - return true; - //return ( mCurrTick > mTimeOfLastNote ) ? false : true; -} -//--------------------------------------------------------- -void CrolPlayer::rewind( int subsong ) -{ - TVoiceData::iterator curr = voice_data.begin(); - TVoiceData::iterator end = voice_data.end(); - - while( curr != end ) - { - CVoiceData &voice = *curr; - - voice.Reset(); - ++curr; - } - - memset(bxRegister, 0, sizeof(bxRegister) ); - memset(volumeCache, 0, sizeof(volumeCache) ); - - bdRegister = 0; - - opl->init(); // initialize to melodic by default - opl->write(1,0x20); // Enable waveform select (bit 5) - - if( rol_header->mode == 0 ) - { - opl->write( 0xbd, 0x20 ); // select rhythm mode (bit 5) - bdRegister = 0x20; - - SetFreq( kTomtomChannel, 24 ); - SetFreq( kSnareDrumChannel, 31 ); - } - - mNextTempoEvent = 0; - mCurrTick = 0; - - SetRefresh(1.0f); -} -//--------------------------------------------------------- -inline float fmin( int const a, int const b ) -{ - return static_cast<float>( a < b ? a : b ); -} -//--------------------------------------------------------- -void CrolPlayer::SetRefresh( float const multiplier ) -{ - float const tickBeat = fmin(kMaxTickBeat, rol_header->ticks_per_beat); - - mRefresh = (tickBeat*rol_header->basic_tempo*multiplier) / 60.0f; -} -//--------------------------------------------------------- -float CrolPlayer::getrefresh() -{ - return mRefresh; -} -//--------------------------------------------------------- -void CrolPlayer::UpdateVoice( int const voice, CVoiceData &voiceData ) -{ - TNoteEvents const &nEvents = voiceData.note_events; - - if( nEvents.empty() || voiceData.mEventStatus & CVoiceData::kES_NoteEnd ) - { - return; // no note data to process, don't bother doing anything. - } - - TInstrumentEvents &iEvents = voiceData.instrument_events; - TVolumeEvents &vEvents = voiceData.volume_events; - TPitchEvents &pEvents = voiceData.pitch_events; - - if( !(voiceData.mEventStatus & CVoiceData::kES_InstrEnd ) && - iEvents[voiceData.next_instrument_event].time == mCurrTick ) - { - if( voiceData.next_instrument_event < iEvents.size() ) - { - send_ins_data_to_chip( voice, iEvents[voiceData.next_instrument_event].ins_index ); - ++voiceData.next_instrument_event; - } - else - { - voiceData.mEventStatus |= CVoiceData::kES_InstrEnd; - } - } - - if( !(voiceData.mEventStatus & CVoiceData::kES_VolumeEnd ) && - vEvents[voiceData.next_volume_event].time == mCurrTick ) - { - SVolumeEvent const &volumeEvent = vEvents[voiceData.next_volume_event]; - - if( voiceData.next_volume_event < vEvents.size() ) - { - int const volume = (int)(63.0f*(1.0f - volumeEvent.multiplier)); - - SetVolume( voice, volume ); - - ++voiceData.next_volume_event; // move to next volume event - } - else - { - voiceData.mEventStatus |= CVoiceData::kES_VolumeEnd; - } - } - - if( voiceData.mForceNote || voiceData.current_note_duration > voiceData.mNoteDuration-1 ) - { - if( mCurrTick != 0 ) - { - ++voiceData.current_note; - } - - if( voiceData.current_note < nEvents.size() ) - { - SNoteEvent const ¬eEvent = nEvents[voiceData.current_note]; - - SetNote( voice, noteEvent.number ); - voiceData.current_note_duration = 0; - voiceData.mNoteDuration = noteEvent.duration; - voiceData.mForceNote = false; - } - else - { - SetNote( voice, kSilenceNote ); - voiceData.mEventStatus |= CVoiceData::kES_NoteEnd; - return; - } - } - - if( !(voiceData.mEventStatus & CVoiceData::kES_PitchEnd ) && - pEvents[voiceData.next_pitch_event].time == mCurrTick ) - { - if( voiceData.next_pitch_event < pEvents.size() ) - { - SetPitch(voice,pEvents[voiceData.next_pitch_event].variation); - ++voiceData.next_pitch_event; - } - else - { - voiceData.mEventStatus |= CVoiceData::kES_PitchEnd; - } - } - - ++voiceData.current_note_duration; -} -//--------------------------------------------------------- -void CrolPlayer::SetNote( int const voice, int const note ) -{ - if( voice < kBassDrumChannel || rol_header->mode ) - { - SetNoteMelodic( voice, note ); - } - else - { - SetNotePercussive( voice, note ); - } -} -//--------------------------------------------------------- -void CrolPlayer::SetNotePercussive( int const voice, int const note ) -{ - int const bit_pos = 4-voice+kBassDrumChannel; - - bdRegister &= ~( 1<<bit_pos ); - opl->write( 0xbd, bdRegister ); - - if( note != kSilenceNote ) - { - switch( voice ) - { - case kTomtomChannel: - SetFreq( kSnareDrumChannel, note+7 ); - case kBassDrumChannel: - SetFreq( voice, note ); - break; - } - - bdRegister |= 1<<bit_pos; - opl->write( 0xbd, bdRegister ); - } -} -//--------------------------------------------------------- -void CrolPlayer::SetNoteMelodic( int const voice, int const note ) -{ - opl->write( 0xb0+voice, bxRegister[voice] & ~0x20 ); - - if( note != kSilenceNote ) - { - SetFreq( voice, note, true ); - } -} -//--------------------------------------------------------- -void CrolPlayer::SetPitch(int const voice, real32 const variation) -{ - pitchCache[voice] = variation; - freqCache[voice] += (uint16)((((float)freqCache[voice])*(variation-1.0f)) / kPitchFactor); - - opl->write(0xa0+voice,freqCache[voice] & 0xff); -} -//--------------------------------------------------------- -void CrolPlayer::SetFreq( int const voice, int const note, bool const keyOn ) -{ - uint16 freq = kNoteTable[note%12] + ((note/12) << 10); - freq += (uint16)((((float)freq)*(pitchCache[voice]-1.0f))/kPitchFactor); - - freqCache[voice] = freq; - bxRegister[voice] = ((freq >> 8) & 0x1f); - - opl->write( 0xa0+voice, freq & 0xff ); - opl->write( 0xb0+voice, bxRegister[voice] | (keyOn ? 0x20 : 0x0) ); -} -//--------------------------------------------------------- -void CrolPlayer::SetVolume( int const voice, int const volume ) -{ - volumeCache[voice] = (volumeCache[voice] &0xc0) | volume; - - int const op_offset = ( voice < kSnareDrumChannel || rol_header->mode ) ? - op_table[voice]+3 : drum_table[voice-kSnareDrumChannel]; - - opl->write( 0x40+op_offset, volumeCache[voice] ); -} -//--------------------------------------------------------- -void CrolPlayer::send_ins_data_to_chip( int const voice, int const ins_index ) -{ - SRolInstrument &instrument = ins_list[ins_index].instrument; - - send_operator( voice, instrument.modulator, instrument.carrier ); -} -//--------------------------------------------------------- -void CrolPlayer::send_operator( int const voice, SOPL2Op const &modulator, SOPL2Op const &carrier ) -{ - if( voice < kSnareDrumChannel || rol_header->mode ) - { - int const op_offset = op_table[voice]; - - opl->write( 0x20+op_offset, modulator.ammulti ); - opl->write( 0x40+op_offset, modulator.ksltl ); - opl->write( 0x60+op_offset, modulator.ardr ); - opl->write( 0x80+op_offset, modulator.slrr ); - opl->write( 0xc0+voice , modulator.fbc ); - opl->write( 0xe0+op_offset, modulator.waveform ); - - volumeCache[voice] = (carrier.ksltl & 0xc0) | volumeCache[voice] & 0x3f; - - opl->write( 0x23+op_offset, carrier.ammulti ); - opl->write( 0x43+op_offset, volumeCache[voice] ); - opl->write( 0x63+op_offset, carrier.ardr ); - opl->write( 0x83+op_offset, carrier.slrr ); -// opl->write( 0xc3+voice , carrier.fbc ); <- don't bother writing this. - opl->write( 0xe3+op_offset, carrier.waveform ); - } - else - { - int const op_offset = drum_table[voice-kSnareDrumChannel]; - - volumeCache[voice] = (modulator.ksltl & 0xc0) | volumeCache[voice] & 0x3f; - - opl->write( 0x20+op_offset, modulator.ammulti ); - opl->write( 0x40+op_offset, volumeCache[voice] ); - opl->write( 0x60+op_offset, modulator.ardr ); - opl->write( 0x80+op_offset, modulator.slrr ); - opl->write( 0xc0+voice , modulator.fbc ); - opl->write( 0xe0+op_offset, modulator.waveform ); - } -} -//--------------------------------------------------------- -void CrolPlayer::load_tempo_events( binistream *f ) -{ - int16 const num_tempo_events = f->readInt( 2 ); - - mTempoEvents.reserve( num_tempo_events ); - - for(int i=0; i<num_tempo_events; ++i) - { - STempoEvent event; - - event.time = f->readInt( 2 ); - event.multiplier = f->readFloat( binio::Single ); - mTempoEvents.push_back( event ); - } -} -//--------------------------------------------------------- -bool CrolPlayer::load_voice_data( binistream *f, std::string const &bnk_filename, const CFileProvider &fp ) -{ - SBnkHeader bnk_header; - binistream *bnk_file = fp.open( bnk_filename.c_str() ); - - if( bnk_file ) - { - load_bnk_info( bnk_file, bnk_header ); - - int const numVoices = rol_header->mode ? kNumMelodicVoices : kNumPercussiveVoices; - - voice_data.reserve( numVoices ); - for(int i=0; i<numVoices; ++i) - { - CVoiceData voice; - - load_note_events( f, voice ); - load_instrument_events( f, voice, bnk_file, bnk_header ); - load_volume_events( f, voice ); - load_pitch_events( f, voice ); - - voice_data.push_back( voice ); - } - - fp.close(bnk_file); - - return true; - } - - return false; -} -//--------------------------------------------------------- -void CrolPlayer::load_note_events( binistream *f, CVoiceData &voice ) -{ - f->seek( 15, binio::Add ); - - int16 const time_of_last_note = f->readInt( 2 ); - - if( time_of_last_note != 0 ) - { - TNoteEvents ¬e_events = voice.note_events; - int16 total_duration = 0; - - do - { - SNoteEvent event; - - event.number = f->readInt( 2 ); - event.duration = f->readInt( 2 ); - - event.number += kSilenceNote; // adding -12 - - note_events.push_back( event ); - - total_duration += event.duration; - } while( total_duration < time_of_last_note ); - - if( time_of_last_note > mTimeOfLastNote ) - { - mTimeOfLastNote = time_of_last_note; - } - } - - f->seek( 15, binio::Add ); -} -//--------------------------------------------------------- -void CrolPlayer::load_instrument_events( binistream *f, CVoiceData &voice, - binistream *bnk_file, SBnkHeader const &bnk_header ) -{ - int16 const number_of_instrument_events = f->readInt( 2 ); - - TInstrumentEvents &instrument_events = voice.instrument_events; - - instrument_events.reserve( number_of_instrument_events ); - - for(int i=0; i<number_of_instrument_events; ++i) - { - SInstrumentEvent event; - event.time = f->readInt( 2 ); - f->readString( event.name, 9 ); - - std::string event_name = event.name; - event.ins_index = load_rol_instrument( bnk_file, bnk_header, event_name ); - - instrument_events.push_back( event ); - - f->seek( 1+2, binio::Add ); - } - - f->seek( 15, binio::Add ); -} -//--------------------------------------------------------- -void CrolPlayer::load_volume_events( binistream *f, CVoiceData &voice ) -{ - int16 const number_of_volume_events = f->readInt( 2 ); - - TVolumeEvents &volume_events = voice.volume_events; - - volume_events.reserve( number_of_volume_events ); - - for(int i=0; i<number_of_volume_events; ++i) - { - SVolumeEvent event; - event.time = f->readInt( 2 ); - event.multiplier = f->readFloat( binio::Single ); - - volume_events.push_back( event ); - } - - f->seek( 15, binio::Add ); -} -//--------------------------------------------------------- -void CrolPlayer::load_pitch_events( binistream *f, CVoiceData &voice ) -{ - int16 const number_of_pitch_events = f->readInt( 2 ); - - TPitchEvents &pitch_events = voice.pitch_events; - - pitch_events.reserve( number_of_pitch_events ); - - for(int i=0; i<number_of_pitch_events; ++i) - { - SPitchEvent event; - event.time = f->readInt( 2 ); - event.variation = f->readFloat( binio::Single ); - - pitch_events.push_back( event ); - } -} -//--------------------------------------------------------- -bool CrolPlayer::load_bnk_info( binistream *f, SBnkHeader &header ) -{ - header.version_major = f->readInt(1); - header.version_minor = f->readInt(1); - f->readString( header.signature, 6 ); - - header.number_of_list_entries_used = f->readInt( 2 ); - header.total_number_of_list_entries = f->readInt( 2 ); - - header.abs_offset_of_name_list = f->readInt( 4 ); - header.abs_offset_of_data = f->readInt( 4 ); - - f->seek( header.abs_offset_of_name_list, binio::Set ); - - TInstrumentNames &ins_name_list = header.ins_name_list; - ins_name_list.reserve( header.number_of_list_entries_used ); - - for(int i=0; i<header.number_of_list_entries_used; ++i) - { - SInstrumentName instrument; - - instrument.index = f->readInt( 2 ); - instrument.record_used = f->readInt(1); - f->readString( instrument.name, 9 ); - - // printf("%s = #%d\n", instrument.name, i ); - - ins_name_list.push_back( instrument ); - } - - //std::sort( ins_name_list.begin(), ins_name_list.end(), StringCompare() ); - - return true; -} -//--------------------------------------------------------- -int CrolPlayer::load_rol_instrument( binistream *f, SBnkHeader const &header, std::string &name ) -{ - TInstrumentNames const &ins_name_list = header.ins_name_list; - - int const ins_index = get_ins_index( name ); - - if( ins_index != -1 ) - { - return ins_index; - } - - typedef TInstrumentNames::const_iterator TInsIter; - typedef std::pair<TInsIter, TInsIter> TInsIterPair; - - TInsIterPair range = std::equal_range( ins_name_list.begin(), - ins_name_list.end(), - name, - StringCompare() ); - - if( range.first != range.second ) - { - int const seekOffs = header.abs_offset_of_data + (range.first->index*kSizeofDataRecord); - f->seek( seekOffs, binio::Set ); - } - - SUsedList usedIns; - usedIns.name = name; - - if( range.first != range.second ) - { - read_rol_instrument( f, usedIns.instrument ); - } - else - { - // set up default instrument data here - memset( &usedIns.instrument, 0, kSizeofDataRecord ); - } - ins_list.push_back( usedIns ); - - return ins_list.size()-1; -} -//--------------------------------------------------------- -int CrolPlayer::get_ins_index( std::string const &name ) const -{ - for(unsigned int i=0; i<ins_list.size(); ++i) - { - if( stricmp(ins_list[i].name.c_str(), name.c_str()) == 0 ) - { - return i; - } - } - - return -1; -} -//--------------------------------------------------------- -void CrolPlayer::read_rol_instrument( binistream *f, SRolInstrument &ins ) -{ - ins.mode = f->readInt(1); - ins.voice_number = f->readInt(1); - - read_fm_operator( f, ins.modulator ); - read_fm_operator( f, ins.carrier ); - - ins.modulator.waveform = f->readInt(1); - ins.carrier.waveform = f->readInt(1); -} -//--------------------------------------------------------- -void CrolPlayer::read_fm_operator( binistream *f, SOPL2Op &opl2_op ) -{ - SFMOperator fm_op; - - fm_op.key_scale_level = f->readInt(1); - fm_op.freq_multiplier = f->readInt(1); - fm_op.feed_back = f->readInt(1); - fm_op.attack_rate = f->readInt(1); - fm_op.sustain_level = f->readInt(1); - fm_op.sustaining_sound = f->readInt(1); - fm_op.decay_rate = f->readInt(1); - fm_op.release_rate = f->readInt(1); - fm_op.output_level = f->readInt(1); - fm_op.amplitude_vibrato = f->readInt(1); - fm_op.frequency_vibrato = f->readInt(1); - fm_op.envelope_scaling = f->readInt(1); - fm_op.fm_type = f->readInt(1); - - opl2_op.ammulti = fm_op.amplitude_vibrato << 7 | fm_op.frequency_vibrato << 6 | fm_op.sustaining_sound << 5 | fm_op.envelope_scaling << 4 | fm_op.freq_multiplier; - opl2_op.ksltl = fm_op.key_scale_level << 6 | fm_op.output_level; - opl2_op.ardr = fm_op.attack_rate << 4 | fm_op.decay_rate; - opl2_op.slrr = fm_op.sustain_level << 4 | fm_op.release_rate; - opl2_op.fbc = fm_op.feed_back << 1 | (fm_op.fm_type ^ 1); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/rol.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,723 @@ +/* + * 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 + * + * rol.h - ROL Player by OPLx <oplx@yahoo.com> + * + * Visit: http://tenacity.hispeed.com/aomit/oplx/ + */ +#include <algorithm> + +#include "rol.h" +#include "debug.h" + +int const CrolPlayer::kSizeofDataRecord = 30; +int const CrolPlayer::kMaxTickBeat = 60; +int const CrolPlayer::kSilenceNote = -12; +int const CrolPlayer::kNumMelodicVoices = 9; +int const CrolPlayer::kNumPercussiveVoices = 11; +int const CrolPlayer::kBassDrumChannel = 6; +int const CrolPlayer::kSnareDrumChannel = 7; +int const CrolPlayer::kTomtomChannel = 8; +int const CrolPlayer::kTomtomFreq = 2;//4; +int const CrolPlayer::kSnareDrumFreq = 2;//kTomtomFreq + 7; +float const CrolPlayer::kDefaultUpdateTme = 18.2f; +float const CrolPlayer::kPitchFactor = 400.0f; + +static const unsigned char drum_table[4] = {0x14, 0x12, 0x15, 0x11}; + +CrolPlayer::uint16 const CrolPlayer::kNoteTable[12] = +{ + 340, // C + 363, // C# + 385, // D + 408, // D# + 432, // E + 458, // F + 485, // F# + 514, // G + 544, // G# + 577, // A + 611, // A# + 647 // B +}; + +/*** public methods **************************************/ + +CPlayer *CrolPlayer::factory(Copl *newopl) +{ + return new CrolPlayer(newopl); +} +//--------------------------------------------------------- +CrolPlayer::CrolPlayer(Copl *newopl) +: CPlayer ( newopl ) + ,rol_header ( NULL ) + ,mNextTempoEvent ( 0 ) + ,mCurrTick ( 0 ) + ,mTimeOfLastNote ( 0 ) + ,mRefresh ( kDefaultUpdateTme ) + ,bdRegister ( 0 ) +{ + int n; + + memset(bxRegister, 0, sizeof(bxRegister) ); + memset(volumeCache, 0, sizeof(volumeCache) ); + memset(freqCache, 0, sizeof(freqCache) ); + + for(n=0; n<11; n++) + pitchCache[n]=1.0f; +} +//--------------------------------------------------------- +CrolPlayer::~CrolPlayer() +{ + if( rol_header != NULL ) + { + delete rol_header; + rol_header=NULL; + } +} +//--------------------------------------------------------- +bool CrolPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + + char *fn = new char[filename.length()+9]; + int i; + std::string bnk_filename; + + AdPlug_LogWrite("*** CrolPlayer::load(f, \"%s\") ***\n", filename.c_str()); + strcpy(fn,filename.data()); + for (i=strlen(fn)-1; i>=0; i--) + if (fn[i] == '/' || fn[i] == '\\') + break; + strcpy(fn+i+1,"standard.bnk"); + bnk_filename = fn; + delete [] fn; + AdPlug_LogWrite("bnk_filename = \"%s\"\n",bnk_filename.c_str()); + + rol_header = new SRolHeader; + memset( rol_header, 0, sizeof(SRolHeader) ); + + rol_header->version_major = f->readInt( 2 ); + rol_header->version_minor = f->readInt( 2 ); + + // Version check + if(rol_header->version_major != 0 || rol_header->version_minor != 4) { + AdPlug_LogWrite("Unsupported file version %d.%d or not a ROL file!\n", + rol_header->version_major, rol_header->version_minor); + AdPlug_LogWrite("--- CrolPlayer::load ---\n"); + fp.close(f); + return false; + } + + f->seek( 40, binio::Add ); + + rol_header->ticks_per_beat = f->readInt( 2 ); + rol_header->beats_per_measure = f->readInt( 2 ); + rol_header->edit_scale_y = f->readInt( 2 ); + rol_header->edit_scale_x = f->readInt( 2 ); + + f->seek( 1, binio::Add ); + + rol_header->mode = f->readInt(1); + + f->seek( 90+38+15, binio::Add ); + + rol_header->basic_tempo = f->readFloat( binio::Single ); + + load_tempo_events( f ); + + mTimeOfLastNote = 0; + + if( load_voice_data( f, bnk_filename, fp ) != true ) + { + AdPlug_LogWrite("CrolPlayer::load_voice_data(f) failed!\n"); + AdPlug_LogWrite("--- CrolPlayer::load ---\n"); + + fp.close( f ); + return false; + } + + fp.close( f ); + + rewind( 0 ); + AdPlug_LogWrite("--- CrolPlayer::load ---\n"); + return true; +} +//--------------------------------------------------------- +bool CrolPlayer::update() +{ + if( mNextTempoEvent < mTempoEvents.size() && + mTempoEvents[mNextTempoEvent].time == mCurrTick ) + { + SetRefresh( mTempoEvents[mNextTempoEvent].multiplier ); + ++mNextTempoEvent; + } + + TVoiceData::iterator curr = voice_data.begin(); + TVoiceData::iterator end = voice_data.end(); + int voice = 0; + + while( curr != end ) + { + UpdateVoice( voice, *curr ); + ++curr; + ++voice; + } + + ++mCurrTick; + + if( mCurrTick > mTimeOfLastNote ) + { + return false; + } + + return true; + //return ( mCurrTick > mTimeOfLastNote ) ? false : true; +} +//--------------------------------------------------------- +void CrolPlayer::rewind( int subsong ) +{ + TVoiceData::iterator curr = voice_data.begin(); + TVoiceData::iterator end = voice_data.end(); + + while( curr != end ) + { + CVoiceData &voice = *curr; + + voice.Reset(); + ++curr; + } + + memset(bxRegister, 0, sizeof(bxRegister) ); + memset(volumeCache, 0, sizeof(volumeCache) ); + + bdRegister = 0; + + opl->init(); // initialize to melodic by default + opl->write(1,0x20); // Enable waveform select (bit 5) + + if( rol_header->mode == 0 ) + { + opl->write( 0xbd, 0x20 ); // select rhythm mode (bit 5) + bdRegister = 0x20; + + SetFreq( kTomtomChannel, 24 ); + SetFreq( kSnareDrumChannel, 31 ); + } + + mNextTempoEvent = 0; + mCurrTick = 0; + + SetRefresh(1.0f); +} +//--------------------------------------------------------- +inline float fmin( int const a, int const b ) +{ + return static_cast<float>( a < b ? a : b ); +} +//--------------------------------------------------------- +void CrolPlayer::SetRefresh( float const multiplier ) +{ + float const tickBeat = fmin(kMaxTickBeat, rol_header->ticks_per_beat); + + mRefresh = (tickBeat*rol_header->basic_tempo*multiplier) / 60.0f; +} +//--------------------------------------------------------- +float CrolPlayer::getrefresh() +{ + return mRefresh; +} +//--------------------------------------------------------- +void CrolPlayer::UpdateVoice( int const voice, CVoiceData &voiceData ) +{ + TNoteEvents const &nEvents = voiceData.note_events; + + if( nEvents.empty() || voiceData.mEventStatus & CVoiceData::kES_NoteEnd ) + { + return; // no note data to process, don't bother doing anything. + } + + TInstrumentEvents &iEvents = voiceData.instrument_events; + TVolumeEvents &vEvents = voiceData.volume_events; + TPitchEvents &pEvents = voiceData.pitch_events; + + if( !(voiceData.mEventStatus & CVoiceData::kES_InstrEnd ) && + iEvents[voiceData.next_instrument_event].time == mCurrTick ) + { + if( voiceData.next_instrument_event < iEvents.size() ) + { + send_ins_data_to_chip( voice, iEvents[voiceData.next_instrument_event].ins_index ); + ++voiceData.next_instrument_event; + } + else + { + voiceData.mEventStatus |= CVoiceData::kES_InstrEnd; + } + } + + if( !(voiceData.mEventStatus & CVoiceData::kES_VolumeEnd ) && + vEvents[voiceData.next_volume_event].time == mCurrTick ) + { + SVolumeEvent const &volumeEvent = vEvents[voiceData.next_volume_event]; + + if( voiceData.next_volume_event < vEvents.size() ) + { + int const volume = (int)(63.0f*(1.0f - volumeEvent.multiplier)); + + SetVolume( voice, volume ); + + ++voiceData.next_volume_event; // move to next volume event + } + else + { + voiceData.mEventStatus |= CVoiceData::kES_VolumeEnd; + } + } + + if( voiceData.mForceNote || voiceData.current_note_duration > voiceData.mNoteDuration-1 ) + { + if( mCurrTick != 0 ) + { + ++voiceData.current_note; + } + + if( voiceData.current_note < nEvents.size() ) + { + SNoteEvent const ¬eEvent = nEvents[voiceData.current_note]; + + SetNote( voice, noteEvent.number ); + voiceData.current_note_duration = 0; + voiceData.mNoteDuration = noteEvent.duration; + voiceData.mForceNote = false; + } + else + { + SetNote( voice, kSilenceNote ); + voiceData.mEventStatus |= CVoiceData::kES_NoteEnd; + return; + } + } + + if( !(voiceData.mEventStatus & CVoiceData::kES_PitchEnd ) && + pEvents[voiceData.next_pitch_event].time == mCurrTick ) + { + if( voiceData.next_pitch_event < pEvents.size() ) + { + SetPitch(voice,pEvents[voiceData.next_pitch_event].variation); + ++voiceData.next_pitch_event; + } + else + { + voiceData.mEventStatus |= CVoiceData::kES_PitchEnd; + } + } + + ++voiceData.current_note_duration; +} +//--------------------------------------------------------- +void CrolPlayer::SetNote( int const voice, int const note ) +{ + if( voice < kBassDrumChannel || rol_header->mode ) + { + SetNoteMelodic( voice, note ); + } + else + { + SetNotePercussive( voice, note ); + } +} +//--------------------------------------------------------- +void CrolPlayer::SetNotePercussive( int const voice, int const note ) +{ + int const bit_pos = 4-voice+kBassDrumChannel; + + bdRegister &= ~( 1<<bit_pos ); + opl->write( 0xbd, bdRegister ); + + if( note != kSilenceNote ) + { + switch( voice ) + { + case kTomtomChannel: + SetFreq( kSnareDrumChannel, note+7 ); + case kBassDrumChannel: + SetFreq( voice, note ); + break; + } + + bdRegister |= 1<<bit_pos; + opl->write( 0xbd, bdRegister ); + } +} +//--------------------------------------------------------- +void CrolPlayer::SetNoteMelodic( int const voice, int const note ) +{ + opl->write( 0xb0+voice, bxRegister[voice] & ~0x20 ); + + if( note != kSilenceNote ) + { + SetFreq( voice, note, true ); + } +} +//--------------------------------------------------------- +void CrolPlayer::SetPitch(int const voice, real32 const variation) +{ + pitchCache[voice] = variation; + freqCache[voice] += (uint16)((((float)freqCache[voice])*(variation-1.0f)) / kPitchFactor); + + opl->write(0xa0+voice,freqCache[voice] & 0xff); +} +//--------------------------------------------------------- +void CrolPlayer::SetFreq( int const voice, int const note, bool const keyOn ) +{ + uint16 freq = kNoteTable[note%12] + ((note/12) << 10); + freq += (uint16)((((float)freq)*(pitchCache[voice]-1.0f))/kPitchFactor); + + freqCache[voice] = freq; + bxRegister[voice] = ((freq >> 8) & 0x1f); + + opl->write( 0xa0+voice, freq & 0xff ); + opl->write( 0xb0+voice, bxRegister[voice] | (keyOn ? 0x20 : 0x0) ); +} +//--------------------------------------------------------- +void CrolPlayer::SetVolume( int const voice, int const volume ) +{ + volumeCache[voice] = (volumeCache[voice] &0xc0) | volume; + + int const op_offset = ( voice < kSnareDrumChannel || rol_header->mode ) ? + op_table[voice]+3 : drum_table[voice-kSnareDrumChannel]; + + opl->write( 0x40+op_offset, volumeCache[voice] ); +} +//--------------------------------------------------------- +void CrolPlayer::send_ins_data_to_chip( int const voice, int const ins_index ) +{ + SRolInstrument &instrument = ins_list[ins_index].instrument; + + send_operator( voice, instrument.modulator, instrument.carrier ); +} +//--------------------------------------------------------- +void CrolPlayer::send_operator( int const voice, SOPL2Op const &modulator, SOPL2Op const &carrier ) +{ + if( voice < kSnareDrumChannel || rol_header->mode ) + { + int const op_offset = op_table[voice]; + + opl->write( 0x20+op_offset, modulator.ammulti ); + opl->write( 0x40+op_offset, modulator.ksltl ); + opl->write( 0x60+op_offset, modulator.ardr ); + opl->write( 0x80+op_offset, modulator.slrr ); + opl->write( 0xc0+voice , modulator.fbc ); + opl->write( 0xe0+op_offset, modulator.waveform ); + + volumeCache[voice] = (carrier.ksltl & 0xc0) | volumeCache[voice] & 0x3f; + + opl->write( 0x23+op_offset, carrier.ammulti ); + opl->write( 0x43+op_offset, volumeCache[voice] ); + opl->write( 0x63+op_offset, carrier.ardr ); + opl->write( 0x83+op_offset, carrier.slrr ); +// opl->write( 0xc3+voice , carrier.fbc ); <- don't bother writing this. + opl->write( 0xe3+op_offset, carrier.waveform ); + } + else + { + int const op_offset = drum_table[voice-kSnareDrumChannel]; + + volumeCache[voice] = (modulator.ksltl & 0xc0) | volumeCache[voice] & 0x3f; + + opl->write( 0x20+op_offset, modulator.ammulti ); + opl->write( 0x40+op_offset, volumeCache[voice] ); + opl->write( 0x60+op_offset, modulator.ardr ); + opl->write( 0x80+op_offset, modulator.slrr ); + opl->write( 0xc0+voice , modulator.fbc ); + opl->write( 0xe0+op_offset, modulator.waveform ); + } +} +//--------------------------------------------------------- +void CrolPlayer::load_tempo_events( binistream *f ) +{ + int16 const num_tempo_events = f->readInt( 2 ); + + mTempoEvents.reserve( num_tempo_events ); + + for(int i=0; i<num_tempo_events; ++i) + { + STempoEvent event; + + event.time = f->readInt( 2 ); + event.multiplier = f->readFloat( binio::Single ); + mTempoEvents.push_back( event ); + } +} +//--------------------------------------------------------- +bool CrolPlayer::load_voice_data( binistream *f, std::string const &bnk_filename, const CFileProvider &fp ) +{ + SBnkHeader bnk_header; + binistream *bnk_file = fp.open( bnk_filename.c_str() ); + + if( bnk_file ) + { + load_bnk_info( bnk_file, bnk_header ); + + int const numVoices = rol_header->mode ? kNumMelodicVoices : kNumPercussiveVoices; + + voice_data.reserve( numVoices ); + for(int i=0; i<numVoices; ++i) + { + CVoiceData voice; + + load_note_events( f, voice ); + load_instrument_events( f, voice, bnk_file, bnk_header ); + load_volume_events( f, voice ); + load_pitch_events( f, voice ); + + voice_data.push_back( voice ); + } + + fp.close(bnk_file); + + return true; + } + + return false; +} +//--------------------------------------------------------- +void CrolPlayer::load_note_events( binistream *f, CVoiceData &voice ) +{ + f->seek( 15, binio::Add ); + + int16 const time_of_last_note = f->readInt( 2 ); + + if( time_of_last_note != 0 ) + { + TNoteEvents ¬e_events = voice.note_events; + int16 total_duration = 0; + + do + { + SNoteEvent event; + + event.number = f->readInt( 2 ); + event.duration = f->readInt( 2 ); + + event.number += kSilenceNote; // adding -12 + + note_events.push_back( event ); + + total_duration += event.duration; + } while( total_duration < time_of_last_note ); + + if( time_of_last_note > mTimeOfLastNote ) + { + mTimeOfLastNote = time_of_last_note; + } + } + + f->seek( 15, binio::Add ); +} +//--------------------------------------------------------- +void CrolPlayer::load_instrument_events( binistream *f, CVoiceData &voice, + binistream *bnk_file, SBnkHeader const &bnk_header ) +{ + int16 const number_of_instrument_events = f->readInt( 2 ); + + TInstrumentEvents &instrument_events = voice.instrument_events; + + instrument_events.reserve( number_of_instrument_events ); + + for(int i=0; i<number_of_instrument_events; ++i) + { + SInstrumentEvent event; + event.time = f->readInt( 2 ); + f->readString( event.name, 9 ); + + std::string event_name = event.name; + event.ins_index = load_rol_instrument( bnk_file, bnk_header, event_name ); + + instrument_events.push_back( event ); + + f->seek( 1+2, binio::Add ); + } + + f->seek( 15, binio::Add ); +} +//--------------------------------------------------------- +void CrolPlayer::load_volume_events( binistream *f, CVoiceData &voice ) +{ + int16 const number_of_volume_events = f->readInt( 2 ); + + TVolumeEvents &volume_events = voice.volume_events; + + volume_events.reserve( number_of_volume_events ); + + for(int i=0; i<number_of_volume_events; ++i) + { + SVolumeEvent event; + event.time = f->readInt( 2 ); + event.multiplier = f->readFloat( binio::Single ); + + volume_events.push_back( event ); + } + + f->seek( 15, binio::Add ); +} +//--------------------------------------------------------- +void CrolPlayer::load_pitch_events( binistream *f, CVoiceData &voice ) +{ + int16 const number_of_pitch_events = f->readInt( 2 ); + + TPitchEvents &pitch_events = voice.pitch_events; + + pitch_events.reserve( number_of_pitch_events ); + + for(int i=0; i<number_of_pitch_events; ++i) + { + SPitchEvent event; + event.time = f->readInt( 2 ); + event.variation = f->readFloat( binio::Single ); + + pitch_events.push_back( event ); + } +} +//--------------------------------------------------------- +bool CrolPlayer::load_bnk_info( binistream *f, SBnkHeader &header ) +{ + header.version_major = f->readInt(1); + header.version_minor = f->readInt(1); + f->readString( header.signature, 6 ); + + header.number_of_list_entries_used = f->readInt( 2 ); + header.total_number_of_list_entries = f->readInt( 2 ); + + header.abs_offset_of_name_list = f->readInt( 4 ); + header.abs_offset_of_data = f->readInt( 4 ); + + f->seek( header.abs_offset_of_name_list, binio::Set ); + + TInstrumentNames &ins_name_list = header.ins_name_list; + ins_name_list.reserve( header.number_of_list_entries_used ); + + for(int i=0; i<header.number_of_list_entries_used; ++i) + { + SInstrumentName instrument; + + instrument.index = f->readInt( 2 ); + instrument.record_used = f->readInt(1); + f->readString( instrument.name, 9 ); + + // printf("%s = #%d\n", instrument.name, i ); + + ins_name_list.push_back( instrument ); + } + + //std::sort( ins_name_list.begin(), ins_name_list.end(), StringCompare() ); + + return true; +} +//--------------------------------------------------------- +int CrolPlayer::load_rol_instrument( binistream *f, SBnkHeader const &header, std::string &name ) +{ + TInstrumentNames const &ins_name_list = header.ins_name_list; + + int const ins_index = get_ins_index( name ); + + if( ins_index != -1 ) + { + return ins_index; + } + + typedef TInstrumentNames::const_iterator TInsIter; + typedef std::pair<TInsIter, TInsIter> TInsIterPair; + + TInsIterPair range = std::equal_range( ins_name_list.begin(), + ins_name_list.end(), + name, + StringCompare() ); + + if( range.first != range.second ) + { + int const seekOffs = header.abs_offset_of_data + (range.first->index*kSizeofDataRecord); + f->seek( seekOffs, binio::Set ); + } + + SUsedList usedIns; + usedIns.name = name; + + if( range.first != range.second ) + { + read_rol_instrument( f, usedIns.instrument ); + } + else + { + // set up default instrument data here + memset( &usedIns.instrument, 0, kSizeofDataRecord ); + } + ins_list.push_back( usedIns ); + + return ins_list.size()-1; +} +//--------------------------------------------------------- +int CrolPlayer::get_ins_index( std::string const &name ) const +{ + for(unsigned int i=0; i<ins_list.size(); ++i) + { + if( stricmp(ins_list[i].name.c_str(), name.c_str()) == 0 ) + { + return i; + } + } + + return -1; +} +//--------------------------------------------------------- +void CrolPlayer::read_rol_instrument( binistream *f, SRolInstrument &ins ) +{ + ins.mode = f->readInt(1); + ins.voice_number = f->readInt(1); + + read_fm_operator( f, ins.modulator ); + read_fm_operator( f, ins.carrier ); + + ins.modulator.waveform = f->readInt(1); + ins.carrier.waveform = f->readInt(1); +} +//--------------------------------------------------------- +void CrolPlayer::read_fm_operator( binistream *f, SOPL2Op &opl2_op ) +{ + SFMOperator fm_op; + + fm_op.key_scale_level = f->readInt(1); + fm_op.freq_multiplier = f->readInt(1); + fm_op.feed_back = f->readInt(1); + fm_op.attack_rate = f->readInt(1); + fm_op.sustain_level = f->readInt(1); + fm_op.sustaining_sound = f->readInt(1); + fm_op.decay_rate = f->readInt(1); + fm_op.release_rate = f->readInt(1); + fm_op.output_level = f->readInt(1); + fm_op.amplitude_vibrato = f->readInt(1); + fm_op.frequency_vibrato = f->readInt(1); + fm_op.envelope_scaling = f->readInt(1); + fm_op.fm_type = f->readInt(1); + + opl2_op.ammulti = fm_op.amplitude_vibrato << 7 | fm_op.frequency_vibrato << 6 | fm_op.sustaining_sound << 5 | fm_op.envelope_scaling << 4 | fm_op.freq_multiplier; + opl2_op.ksltl = fm_op.key_scale_level << 6 | fm_op.output_level; + opl2_op.ardr = fm_op.attack_rate << 4 | fm_op.decay_rate; + opl2_op.slrr = fm_op.sustain_level << 4 | fm_op.release_rate; + opl2_op.fbc = fm_op.feed_back << 1 | (fm_op.fm_type ^ 1); +}
--- a/Plugins/Input/adplug/core/s3m.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,535 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 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 - * - * s3m.c - S3M Player by Simon Peter <dn.tlp@gmx.net> - * - * BUGS: - * Extra Fine Slides (EEx, FEx) & Fine Vibrato (Uxy) are inaccurate - */ - -#include "s3m.h" - -const char Cs3mPlayer::chnresolv[] = // S3M -> adlib channel conversion - {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,-1,-1,-1,-1,-1,-1,-1}; - -const unsigned short Cs3mPlayer::notetable[12] = // S3M adlib note table - {340,363,385,408,432,458,485,514,544,577,611,647}; - -const unsigned char Cs3mPlayer::vibratotab[32] = // vibrato rate table - {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}; - -/*** public methods *************************************/ - -CPlayer *Cs3mPlayer::factory(Copl *newopl) -{ - return new Cs3mPlayer(newopl); -} - -Cs3mPlayer::Cs3mPlayer(Copl *newopl): CPlayer(newopl) -{ - int i,j,k; - - memset(pattern,255,sizeof(pattern)); - memset(orders,255,sizeof(orders)); - - for(i=0;i<99;i++) // setup pattern - for(j=0;j<64;j++) - for(k=0;k<32;k++) { - pattern[i][j][k].instrument = 0; - pattern[i][j][k].info = 0; - } -} - -bool Cs3mPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - unsigned short insptr[99],pattptr[99]; - int i,row; - unsigned char bufval,bufval2; - unsigned short ppatlen; - s3mheader *checkhead; - bool adlibins=false; - - // file validation section - checkhead = new s3mheader; - load_header(f, checkhead); - if(checkhead->kennung != 0x1a || checkhead->typ != 16 - || checkhead->insnum > 99) { - delete checkhead; fp.close(f); return false; - } else - if(strncmp(checkhead->scrm,"SCRM",4)) { - delete checkhead; fp.close(f); return false; - } else { // is an adlib module? - f->seek(checkhead->ordnum, binio::Add); - for(i = 0; i < checkhead->insnum; i++) - insptr[i] = f->readInt(2); - for(i=0;i<checkhead->insnum;i++) { - f->seek(insptr[i]*16); - if(f->readInt(1) >= 2) { - adlibins = true; - break; - } - } - delete checkhead; - if(!adlibins) { fp.close(f); return false; } - } - - // load section - f->seek(0); // rewind for load - load_header(f, &header); // read header - - // security check - if(header.ordnum > 256 || header.insnum > 99 || header.patnum > 99) { - fp.close(f); - return false; - } - - for(i = 0; i < header.ordnum; i++) orders[i] = f->readInt(1); // read orders - for(i = 0; i < header.insnum; i++) insptr[i] = f->readInt(2); // instrument parapointers - for(i = 0; i < header.patnum; i++) pattptr[i] = f->readInt(2); // pattern parapointers - - for(i=0;i<header.insnum;i++) { // load instruments - f->seek(insptr[i]*16); - inst[i].type = f->readInt(1); - f->readString(inst[i].filename, 15); - inst[i].d00 = f->readInt(1); inst[i].d01 = f->readInt(1); - inst[i].d02 = f->readInt(1); inst[i].d03 = f->readInt(1); - inst[i].d04 = f->readInt(1); inst[i].d05 = f->readInt(1); - inst[i].d06 = f->readInt(1); inst[i].d07 = f->readInt(1); - inst[i].d08 = f->readInt(1); inst[i].d09 = f->readInt(1); - inst[i].d0a = f->readInt(1); inst[i].d0b = f->readInt(1); - inst[i].volume = f->readInt(1); inst[i].dsk = f->readInt(1); - f->ignore(2); - inst[i].c2spd = f->readInt(4); - f->ignore(12); - f->readString(inst[i].name, 28); - f->readString(inst[i].scri, 4); - } - - for(i=0;i<header.patnum;i++) { // depack patterns - f->seek(pattptr[i]*16); - ppatlen = f->readInt(2); - unsigned long pattpos = f->pos(); - for(row=0;(row<64) && (pattpos-pattptr[i]*16<=ppatlen);row++) - do { - bufval = f->readInt(1); - if(bufval & 32) { - bufval2 = f->readInt(1); - pattern[i][row][bufval & 31].note = bufval2 & 15; - pattern[i][row][bufval & 31].oct = (bufval2 & 240) >> 4; - pattern[i][row][bufval & 31].instrument = f->readInt(1); - } - if(bufval & 64) - pattern[i][row][bufval & 31].volume = f->readInt(1); - if(bufval & 128) { - pattern[i][row][bufval & 31].command = f->readInt(1); - pattern[i][row][bufval & 31].info = f->readInt(1); - } - } while(bufval); - } - - fp.close(f); - rewind(0); - return true; // done -} - -bool Cs3mPlayer::update() -{ - unsigned char pattbreak=0,donote; // remember vars - unsigned char pattnr,chan,row,info; // cache vars - signed char realchan; - - // effect handling (timer dependant) - for(realchan=0; realchan<9; realchan++) { - info = channel[realchan].info; // fill infobyte cache - switch(channel[realchan].fx) { - case 11: - case 12: if(channel[realchan].fx == 11) // dual command: H00 and Dxy - vibrato(realchan,channel[realchan].dualinfo); - else // dual command: G00 and Dxy - tone_portamento(realchan,channel[realchan].dualinfo); - case 4: if(info <= 0x0f) // volume slide down - if(channel[realchan].vol - info >= 0) - channel[realchan].vol -= info; - else - channel[realchan].vol = 0; - if((info & 0x0f) == 0) // volume slide up - if(channel[realchan].vol + (info >> 4) <= 63) - channel[realchan].vol += info >> 4; - else - channel[realchan].vol = 63; - setvolume(realchan); - break; - case 5: if(info == 0xf0 || info <= 0xe0) { // slide down - slide_down(realchan,info); - setfreq(realchan); - } - break; - case 6: if(info == 0xf0 || info <= 0xe0) { // slide up - slide_up(realchan,info); - setfreq(realchan); - } - break; - case 7: tone_portamento(realchan,channel[realchan].dualinfo); break; // tone portamento - case 8: vibrato(realchan,channel[realchan].dualinfo); break; // vibrato - case 10: channel[realchan].nextfreq = channel[realchan].freq; // arpeggio - channel[realchan].nextoct = channel[realchan].oct; - switch(channel[realchan].trigger) { - case 0: channel[realchan].freq = notetable[channel[realchan].note]; break; - case 1: if(channel[realchan].note + ((info & 0xf0) >> 4) < 12) - channel[realchan].freq = notetable[channel[realchan].note + ((info & 0xf0) >> 4)]; - else { - channel[realchan].freq = notetable[channel[realchan].note + ((info & 0xf0) >> 4) - 12]; - channel[realchan].oct++; - } - break; - case 2: if(channel[realchan].note + (info & 0x0f) < 12) - channel[realchan].freq = notetable[channel[realchan].note + (info & 0x0f)]; - else { - channel[realchan].freq = notetable[channel[realchan].note + (info & 0x0f) - 12]; - channel[realchan].oct++; - } - break; - } - if(channel[realchan].trigger < 2) - channel[realchan].trigger++; - else - channel[realchan].trigger = 0; - setfreq(realchan); - channel[realchan].freq = channel[realchan].nextfreq; - channel[realchan].oct = channel[realchan].nextoct; - break; - case 21: vibrato(realchan,(unsigned char) (info / 4)); break; // fine vibrato - } - } - - if(del) { // speed compensation - del--; - return !songend; - } - - // arrangement handling - pattnr = orders[ord]; - if(pattnr == 0xff || ord > header.ordnum) { // "--" end of song - songend = 1; // set end-flag - ord = 0; - pattnr = orders[ord]; - if(pattnr == 0xff) - return !songend; - } - if(pattnr == 0xfe) { // "++" skip marker - ord++; pattnr = orders[ord]; - } - - // play row - row = crow; // fill row cache - for(chan=0;chan<32;chan++) { - if(!(header.chanset[chan] & 128)) // resolve S3M -> AdLib channels - realchan = chnresolv[header.chanset[chan] & 127]; - else - realchan = -1; // channel disabled - if(realchan != -1) { // channel playable? - // set channel values - donote = 0; - if(pattern[pattnr][row][chan].note < 14) - // tone portamento - if(pattern[pattnr][row][chan].command == 7 || pattern[pattnr][row][chan].command == 12) { - channel[realchan].nextfreq = notetable[pattern[pattnr][row][chan].note]; - channel[realchan].nextoct = pattern[pattnr][row][chan].oct; - } else { // normal note - channel[realchan].note = pattern[pattnr][row][chan].note; - channel[realchan].freq = notetable[pattern[pattnr][row][chan].note]; - channel[realchan].oct = pattern[pattnr][row][chan].oct; - channel[realchan].key = 1; - donote = 1; - } - if(pattern[pattnr][row][chan].note == 14) { // key off (is 14 here, cause note is only first 4 bits) - channel[realchan].key = 0; - setfreq(realchan); - } - if((channel[realchan].fx != 8 && channel[realchan].fx != 11) && // vibrato begins - (pattern[pattnr][row][chan].command == 8 || pattern[pattnr][row][chan].command == 11)) { - channel[realchan].nextfreq = channel[realchan].freq; - channel[realchan].nextoct = channel[realchan].oct; - } - if(pattern[pattnr][row][chan].note >= 14) - if((channel[realchan].fx == 8 || channel[realchan].fx == 11) && // vibrato ends - (pattern[pattnr][row][chan].command != 8 && pattern[pattnr][row][chan].command != 11)) { - channel[realchan].freq = channel[realchan].nextfreq; - channel[realchan].oct = channel[realchan].nextoct; - setfreq(realchan); - } - if(pattern[pattnr][row][chan].instrument) { // set instrument - channel[realchan].inst = pattern[pattnr][row][chan].instrument - 1; - if(inst[channel[realchan].inst].volume < 64) - channel[realchan].vol = inst[channel[realchan].inst].volume; - else - channel[realchan].vol = 63; - if(pattern[pattnr][row][chan].command != 7) - donote = 1; - } - if(pattern[pattnr][row][chan].volume != 255) - if(pattern[pattnr][row][chan].volume < 64) // set volume - channel[realchan].vol = pattern[pattnr][row][chan].volume; - else - channel[realchan].vol = 63; - channel[realchan].fx = pattern[pattnr][row][chan].command; // set command - if(pattern[pattnr][row][chan].info) // set infobyte - channel[realchan].info = pattern[pattnr][row][chan].info; - - // some commands reset the infobyte memory - switch(channel[realchan].fx) { - case 1: - case 2: - case 3: - case 20: - channel[realchan].info = pattern[pattnr][row][chan].info; - break; - } - - // play note - if(donote) - playnote(realchan); - if(pattern[pattnr][row][chan].volume != 255) // set volume - setvolume(realchan); - - // command handling (row dependant) - info = channel[realchan].info; // fill infobyte cache - switch(channel[realchan].fx) { - case 1: speed = info; break; // set speed - case 2: if(info <= ord) songend = 1; ord = info; crow = 0; pattbreak = 1; break; // jump to order - case 3: if(!pattbreak) { crow = info; ord++; pattbreak = 1; } break; // pattern break - case 4: if(info > 0xf0) // fine volume down - if(channel[realchan].vol - (info & 0x0f) >= 0) - channel[realchan].vol -= info & 0x0f; - else - channel[realchan].vol = 0; - if((info & 0x0f) == 0x0f && info >= 0x1f) // fine volume up - if(channel[realchan].vol + ((info & 0xf0) >> 4) <= 63) - channel[realchan].vol += (info & 0xf0) >> 4; - else - channel[realchan].vol = 63; - setvolume(realchan); - break; - case 5: if(info > 0xf0) { // fine slide down - slide_down(realchan,(unsigned char) (info & 0x0f)); - setfreq(realchan); - } - if(info > 0xe0 && info < 0xf0) { // extra fine slide down - slide_down(realchan,(unsigned char) ((info & 0x0f) / 4)); - setfreq(realchan); - } - break; - case 6: if(info > 0xf0) { // fine slide up - slide_up(realchan,(unsigned char) (info & 0x0f)); - setfreq(realchan); - } - if(info > 0xe0 && info < 0xf0) { // extra fine slide up - slide_up(realchan,(unsigned char) ((info & 0x0f) / 4)); - setfreq(realchan); - } - break; - case 7: // tone portamento - case 8: if((channel[realchan].fx == 7 || // vibrato (remember info for dual commands) - channel[realchan].fx == 8) && pattern[pattnr][row][chan].info) - channel[realchan].dualinfo = info; - break; - case 10: channel[realchan].trigger = 0; break; // arpeggio (set trigger) - case 19: if(info == 0xb0) // set loop start - loopstart = row; - if(info > 0xb0 && info <= 0xbf) // pattern loop - if(!loopcnt) { - loopcnt = info & 0x0f; - crow = loopstart; - pattbreak = 1; - } else - if(--loopcnt > 0) { - crow = loopstart; - pattbreak = 1; - } - if((info & 0xf0) == 0xe0) // patterndelay - del = speed * (info & 0x0f) - 1; - break; - case 20: tempo = info; break; // set tempo - } - } - } - - if(!del) - del = speed - 1; // speed compensation - if(!pattbreak) { // next row (only if no manual advance) - crow++; - if(crow > 63) { - crow = 0; - ord++; - loopstart = 0; - } - } - - return !songend; // still playing -} - -void Cs3mPlayer::rewind(int subsong) -{ - // set basic variables - songend = 0; ord = 0; crow = 0; tempo = header.it; - speed = header.is; del = 0; loopstart = 0; loopcnt = 0; - - memset(channel,0,sizeof(channel)); - - opl->init(); // reset OPL chip - opl->write(1,32); // Go to ym3812 mode -} - -std::string Cs3mPlayer::gettype() -{ - char filever[5]; - - switch(header.cwtv) { // determine version number - case 0x1300: strcpy(filever,"3.00"); break; - case 0x1301: strcpy(filever,"3.01"); break; - case 0x1303: strcpy(filever,"3.03"); break; - case 0x1320: strcpy(filever,"3.20"); break; - default: strcpy(filever,"3.??"); - } - - return (std::string("Scream Tracker ") + filever); -} - -float Cs3mPlayer::getrefresh() -{ - return (float) (tempo / 2.5); -} - -/*** private methods *************************************/ - -void Cs3mPlayer::load_header(binistream *f, s3mheader *h) -{ - int i; - - f->readString(h->name, 28); - h->kennung = f->readInt(1); h->typ = f->readInt(1); - f->ignore(2); - h->ordnum = f->readInt(2); h->insnum = f->readInt(2); - h->patnum = f->readInt(2); h->flags = f->readInt(2); - h->cwtv = f->readInt(2); h->ffi = f->readInt(2); - f->readString(h->scrm, 4); - h->gv = f->readInt(1); h->is = f->readInt(1); h->it = f->readInt(1); - h->mv = f->readInt(1); h->uc = f->readInt(1); h->dp = f->readInt(1); - f->ignore(8); - h->special = f->readInt(2); - for(i = 0; i < 32; i++) h->chanset[i] = f->readInt(1); -} - -void Cs3mPlayer::setvolume(unsigned char chan) -{ - unsigned char op = op_table[chan], insnr = channel[chan].inst; - - opl->write(0x43 + op,(int)(63-((63-(inst[insnr].d03 & 63))/63.0)*channel[chan].vol) + (inst[insnr].d03 & 192)); - if(inst[insnr].d0a & 1) - opl->write(0x40 + op,(int)(63-((63-(inst[insnr].d02 & 63))/63.0)*channel[chan].vol) + (inst[insnr].d02 & 192)); -} - -void Cs3mPlayer::setfreq(unsigned char chan) -{ - opl->write(0xa0 + chan, channel[chan].freq & 255); - if(channel[chan].key) - opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2) | 32); - else - opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2)); -} - -void Cs3mPlayer::playnote(unsigned char chan) -{ - unsigned char op = op_table[chan], insnr = channel[chan].inst; - - opl->write(0xb0 + chan, 0); // stop old note - - // set instrument data - opl->write(0x20 + op, inst[insnr].d00); - opl->write(0x23 + op, inst[insnr].d01); - opl->write(0x40 + op, inst[insnr].d02); - opl->write(0x43 + op, inst[insnr].d03); - opl->write(0x60 + op, inst[insnr].d04); - opl->write(0x63 + op, inst[insnr].d05); - opl->write(0x80 + op, inst[insnr].d06); - opl->write(0x83 + op, inst[insnr].d07); - opl->write(0xe0 + op, inst[insnr].d08); - opl->write(0xe3 + op, inst[insnr].d09); - opl->write(0xc0 + chan, inst[insnr].d0a); - - // set frequency & play - channel[chan].key = 1; - setfreq(chan); -} - -void Cs3mPlayer::slide_down(unsigned char chan, unsigned char amount) -{ - if(channel[chan].freq - amount > 340) - channel[chan].freq -= amount; - else - if(channel[chan].oct > 0) { - channel[chan].oct--; - channel[chan].freq = 684; - } else - channel[chan].freq = 340; -} - -void Cs3mPlayer::slide_up(unsigned char chan, unsigned char amount) -{ - if(channel[chan].freq + amount < 686) - channel[chan].freq += amount; - else - if(channel[chan].oct < 7) { - channel[chan].oct++; - channel[chan].freq = 341; - } else - channel[chan].freq = 686; -} - -void Cs3mPlayer::vibrato(unsigned char chan, unsigned char info) -{ - unsigned char i,speed,depth; - - speed = info >> 4; - depth = (info & 0x0f) / 2; - - for(i=0;i<speed;i++) { - channel[chan].trigger++; - while(channel[chan].trigger >= 64) - channel[chan].trigger -= 64; - if(channel[chan].trigger >= 16 && channel[chan].trigger < 48) - slide_down(chan,(unsigned char) (vibratotab[channel[chan].trigger - 16] / (16-depth))); - if(channel[chan].trigger < 16) - slide_up(chan,(unsigned char) (vibratotab[channel[chan].trigger + 16] / (16-depth))); - if(channel[chan].trigger >= 48) - slide_up(chan,(unsigned char) (vibratotab[channel[chan].trigger - 48] / (16-depth))); - } - setfreq(chan); -} - -void Cs3mPlayer::tone_portamento(unsigned char chan, unsigned char info) -{ - if(channel[chan].freq + (channel[chan].oct << 10) < channel[chan].nextfreq + - (channel[chan].nextoct << 10)) - slide_up(chan,info); - if(channel[chan].freq + (channel[chan].oct << 10) > channel[chan].nextfreq + - (channel[chan].nextoct << 10)) - slide_down(chan,info); - setfreq(chan); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/s3m.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,535 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2006 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 + * + * s3m.c - S3M Player by Simon Peter <dn.tlp@gmx.net> + * + * BUGS: + * Extra Fine Slides (EEx, FEx) & Fine Vibrato (Uxy) are inaccurate + */ + +#include "s3m.h" + +const char Cs3mPlayer::chnresolv[] = // S3M -> adlib channel conversion + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,-1,-1,-1,-1,-1,-1,-1}; + +const unsigned short Cs3mPlayer::notetable[12] = // S3M adlib note table + {340,363,385,408,432,458,485,514,544,577,611,647}; + +const unsigned char Cs3mPlayer::vibratotab[32] = // vibrato rate table + {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}; + +/*** public methods *************************************/ + +CPlayer *Cs3mPlayer::factory(Copl *newopl) +{ + return new Cs3mPlayer(newopl); +} + +Cs3mPlayer::Cs3mPlayer(Copl *newopl): CPlayer(newopl) +{ + int i,j,k; + + memset(pattern,255,sizeof(pattern)); + memset(orders,255,sizeof(orders)); + + for(i=0;i<99;i++) // setup pattern + for(j=0;j<64;j++) + for(k=0;k<32;k++) { + pattern[i][j][k].instrument = 0; + pattern[i][j][k].info = 0; + } +} + +bool Cs3mPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + unsigned short insptr[99],pattptr[99]; + int i,row; + unsigned char bufval,bufval2; + unsigned short ppatlen; + s3mheader *checkhead; + bool adlibins=false; + + // file validation section + checkhead = new s3mheader; + load_header(f, checkhead); + if(checkhead->kennung != 0x1a || checkhead->typ != 16 + || checkhead->insnum > 99) { + delete checkhead; fp.close(f); return false; + } else + if(strncmp(checkhead->scrm,"SCRM",4)) { + delete checkhead; fp.close(f); return false; + } else { // is an adlib module? + f->seek(checkhead->ordnum, binio::Add); + for(i = 0; i < checkhead->insnum; i++) + insptr[i] = f->readInt(2); + for(i=0;i<checkhead->insnum;i++) { + f->seek(insptr[i]*16); + if(f->readInt(1) >= 2) { + adlibins = true; + break; + } + } + delete checkhead; + if(!adlibins) { fp.close(f); return false; } + } + + // load section + f->seek(0); // rewind for load + load_header(f, &header); // read header + + // security check + if(header.ordnum > 256 || header.insnum > 99 || header.patnum > 99) { + fp.close(f); + return false; + } + + for(i = 0; i < header.ordnum; i++) orders[i] = f->readInt(1); // read orders + for(i = 0; i < header.insnum; i++) insptr[i] = f->readInt(2); // instrument parapointers + for(i = 0; i < header.patnum; i++) pattptr[i] = f->readInt(2); // pattern parapointers + + for(i=0;i<header.insnum;i++) { // load instruments + f->seek(insptr[i]*16); + inst[i].type = f->readInt(1); + f->readString(inst[i].filename, 15); + inst[i].d00 = f->readInt(1); inst[i].d01 = f->readInt(1); + inst[i].d02 = f->readInt(1); inst[i].d03 = f->readInt(1); + inst[i].d04 = f->readInt(1); inst[i].d05 = f->readInt(1); + inst[i].d06 = f->readInt(1); inst[i].d07 = f->readInt(1); + inst[i].d08 = f->readInt(1); inst[i].d09 = f->readInt(1); + inst[i].d0a = f->readInt(1); inst[i].d0b = f->readInt(1); + inst[i].volume = f->readInt(1); inst[i].dsk = f->readInt(1); + f->ignore(2); + inst[i].c2spd = f->readInt(4); + f->ignore(12); + f->readString(inst[i].name, 28); + f->readString(inst[i].scri, 4); + } + + for(i=0;i<header.patnum;i++) { // depack patterns + f->seek(pattptr[i]*16); + ppatlen = f->readInt(2); + unsigned long pattpos = f->pos(); + for(row=0;(row<64) && (pattpos-pattptr[i]*16<=ppatlen);row++) + do { + bufval = f->readInt(1); + if(bufval & 32) { + bufval2 = f->readInt(1); + pattern[i][row][bufval & 31].note = bufval2 & 15; + pattern[i][row][bufval & 31].oct = (bufval2 & 240) >> 4; + pattern[i][row][bufval & 31].instrument = f->readInt(1); + } + if(bufval & 64) + pattern[i][row][bufval & 31].volume = f->readInt(1); + if(bufval & 128) { + pattern[i][row][bufval & 31].command = f->readInt(1); + pattern[i][row][bufval & 31].info = f->readInt(1); + } + } while(bufval); + } + + fp.close(f); + rewind(0); + return true; // done +} + +bool Cs3mPlayer::update() +{ + unsigned char pattbreak=0,donote; // remember vars + unsigned char pattnr,chan,row,info; // cache vars + signed char realchan; + + // effect handling (timer dependant) + for(realchan=0; realchan<9; realchan++) { + info = channel[realchan].info; // fill infobyte cache + switch(channel[realchan].fx) { + case 11: + case 12: if(channel[realchan].fx == 11) // dual command: H00 and Dxy + vibrato(realchan,channel[realchan].dualinfo); + else // dual command: G00 and Dxy + tone_portamento(realchan,channel[realchan].dualinfo); + case 4: if(info <= 0x0f) // volume slide down + if(channel[realchan].vol - info >= 0) + channel[realchan].vol -= info; + else + channel[realchan].vol = 0; + if((info & 0x0f) == 0) // volume slide up + if(channel[realchan].vol + (info >> 4) <= 63) + channel[realchan].vol += info >> 4; + else + channel[realchan].vol = 63; + setvolume(realchan); + break; + case 5: if(info == 0xf0 || info <= 0xe0) { // slide down + slide_down(realchan,info); + setfreq(realchan); + } + break; + case 6: if(info == 0xf0 || info <= 0xe0) { // slide up + slide_up(realchan,info); + setfreq(realchan); + } + break; + case 7: tone_portamento(realchan,channel[realchan].dualinfo); break; // tone portamento + case 8: vibrato(realchan,channel[realchan].dualinfo); break; // vibrato + case 10: channel[realchan].nextfreq = channel[realchan].freq; // arpeggio + channel[realchan].nextoct = channel[realchan].oct; + switch(channel[realchan].trigger) { + case 0: channel[realchan].freq = notetable[channel[realchan].note]; break; + case 1: if(channel[realchan].note + ((info & 0xf0) >> 4) < 12) + channel[realchan].freq = notetable[channel[realchan].note + ((info & 0xf0) >> 4)]; + else { + channel[realchan].freq = notetable[channel[realchan].note + ((info & 0xf0) >> 4) - 12]; + channel[realchan].oct++; + } + break; + case 2: if(channel[realchan].note + (info & 0x0f) < 12) + channel[realchan].freq = notetable[channel[realchan].note + (info & 0x0f)]; + else { + channel[realchan].freq = notetable[channel[realchan].note + (info & 0x0f) - 12]; + channel[realchan].oct++; + } + break; + } + if(channel[realchan].trigger < 2) + channel[realchan].trigger++; + else + channel[realchan].trigger = 0; + setfreq(realchan); + channel[realchan].freq = channel[realchan].nextfreq; + channel[realchan].oct = channel[realchan].nextoct; + break; + case 21: vibrato(realchan,(unsigned char) (info / 4)); break; // fine vibrato + } + } + + if(del) { // speed compensation + del--; + return !songend; + } + + // arrangement handling + pattnr = orders[ord]; + if(pattnr == 0xff || ord > header.ordnum) { // "--" end of song + songend = 1; // set end-flag + ord = 0; + pattnr = orders[ord]; + if(pattnr == 0xff) + return !songend; + } + if(pattnr == 0xfe) { // "++" skip marker + ord++; pattnr = orders[ord]; + } + + // play row + row = crow; // fill row cache + for(chan=0;chan<32;chan++) { + if(!(header.chanset[chan] & 128)) // resolve S3M -> AdLib channels + realchan = chnresolv[header.chanset[chan] & 127]; + else + realchan = -1; // channel disabled + if(realchan != -1) { // channel playable? + // set channel values + donote = 0; + if(pattern[pattnr][row][chan].note < 14) + // tone portamento + if(pattern[pattnr][row][chan].command == 7 || pattern[pattnr][row][chan].command == 12) { + channel[realchan].nextfreq = notetable[pattern[pattnr][row][chan].note]; + channel[realchan].nextoct = pattern[pattnr][row][chan].oct; + } else { // normal note + channel[realchan].note = pattern[pattnr][row][chan].note; + channel[realchan].freq = notetable[pattern[pattnr][row][chan].note]; + channel[realchan].oct = pattern[pattnr][row][chan].oct; + channel[realchan].key = 1; + donote = 1; + } + if(pattern[pattnr][row][chan].note == 14) { // key off (is 14 here, cause note is only first 4 bits) + channel[realchan].key = 0; + setfreq(realchan); + } + if((channel[realchan].fx != 8 && channel[realchan].fx != 11) && // vibrato begins + (pattern[pattnr][row][chan].command == 8 || pattern[pattnr][row][chan].command == 11)) { + channel[realchan].nextfreq = channel[realchan].freq; + channel[realchan].nextoct = channel[realchan].oct; + } + if(pattern[pattnr][row][chan].note >= 14) + if((channel[realchan].fx == 8 || channel[realchan].fx == 11) && // vibrato ends + (pattern[pattnr][row][chan].command != 8 && pattern[pattnr][row][chan].command != 11)) { + channel[realchan].freq = channel[realchan].nextfreq; + channel[realchan].oct = channel[realchan].nextoct; + setfreq(realchan); + } + if(pattern[pattnr][row][chan].instrument) { // set instrument + channel[realchan].inst = pattern[pattnr][row][chan].instrument - 1; + if(inst[channel[realchan].inst].volume < 64) + channel[realchan].vol = inst[channel[realchan].inst].volume; + else + channel[realchan].vol = 63; + if(pattern[pattnr][row][chan].command != 7) + donote = 1; + } + if(pattern[pattnr][row][chan].volume != 255) + if(pattern[pattnr][row][chan].volume < 64) // set volume + channel[realchan].vol = pattern[pattnr][row][chan].volume; + else + channel[realchan].vol = 63; + channel[realchan].fx = pattern[pattnr][row][chan].command; // set command + if(pattern[pattnr][row][chan].info) // set infobyte + channel[realchan].info = pattern[pattnr][row][chan].info; + + // some commands reset the infobyte memory + switch(channel[realchan].fx) { + case 1: + case 2: + case 3: + case 20: + channel[realchan].info = pattern[pattnr][row][chan].info; + break; + } + + // play note + if(donote) + playnote(realchan); + if(pattern[pattnr][row][chan].volume != 255) // set volume + setvolume(realchan); + + // command handling (row dependant) + info = channel[realchan].info; // fill infobyte cache + switch(channel[realchan].fx) { + case 1: speed = info; break; // set speed + case 2: if(info <= ord) songend = 1; ord = info; crow = 0; pattbreak = 1; break; // jump to order + case 3: if(!pattbreak) { crow = info; ord++; pattbreak = 1; } break; // pattern break + case 4: if(info > 0xf0) // fine volume down + if(channel[realchan].vol - (info & 0x0f) >= 0) + channel[realchan].vol -= info & 0x0f; + else + channel[realchan].vol = 0; + if((info & 0x0f) == 0x0f && info >= 0x1f) // fine volume up + if(channel[realchan].vol + ((info & 0xf0) >> 4) <= 63) + channel[realchan].vol += (info & 0xf0) >> 4; + else + channel[realchan].vol = 63; + setvolume(realchan); + break; + case 5: if(info > 0xf0) { // fine slide down + slide_down(realchan,(unsigned char) (info & 0x0f)); + setfreq(realchan); + } + if(info > 0xe0 && info < 0xf0) { // extra fine slide down + slide_down(realchan,(unsigned char) ((info & 0x0f) / 4)); + setfreq(realchan); + } + break; + case 6: if(info > 0xf0) { // fine slide up + slide_up(realchan,(unsigned char) (info & 0x0f)); + setfreq(realchan); + } + if(info > 0xe0 && info < 0xf0) { // extra fine slide up + slide_up(realchan,(unsigned char) ((info & 0x0f) / 4)); + setfreq(realchan); + } + break; + case 7: // tone portamento + case 8: if((channel[realchan].fx == 7 || // vibrato (remember info for dual commands) + channel[realchan].fx == 8) && pattern[pattnr][row][chan].info) + channel[realchan].dualinfo = info; + break; + case 10: channel[realchan].trigger = 0; break; // arpeggio (set trigger) + case 19: if(info == 0xb0) // set loop start + loopstart = row; + if(info > 0xb0 && info <= 0xbf) // pattern loop + if(!loopcnt) { + loopcnt = info & 0x0f; + crow = loopstart; + pattbreak = 1; + } else + if(--loopcnt > 0) { + crow = loopstart; + pattbreak = 1; + } + if((info & 0xf0) == 0xe0) // patterndelay + del = speed * (info & 0x0f) - 1; + break; + case 20: tempo = info; break; // set tempo + } + } + } + + if(!del) + del = speed - 1; // speed compensation + if(!pattbreak) { // next row (only if no manual advance) + crow++; + if(crow > 63) { + crow = 0; + ord++; + loopstart = 0; + } + } + + return !songend; // still playing +} + +void Cs3mPlayer::rewind(int subsong) +{ + // set basic variables + songend = 0; ord = 0; crow = 0; tempo = header.it; + speed = header.is; del = 0; loopstart = 0; loopcnt = 0; + + memset(channel,0,sizeof(channel)); + + opl->init(); // reset OPL chip + opl->write(1,32); // Go to ym3812 mode +} + +std::string Cs3mPlayer::gettype() +{ + char filever[5]; + + switch(header.cwtv) { // determine version number + case 0x1300: strcpy(filever,"3.00"); break; + case 0x1301: strcpy(filever,"3.01"); break; + case 0x1303: strcpy(filever,"3.03"); break; + case 0x1320: strcpy(filever,"3.20"); break; + default: strcpy(filever,"3.??"); + } + + return (std::string("Scream Tracker ") + filever); +} + +float Cs3mPlayer::getrefresh() +{ + return (float) (tempo / 2.5); +} + +/*** private methods *************************************/ + +void Cs3mPlayer::load_header(binistream *f, s3mheader *h) +{ + int i; + + f->readString(h->name, 28); + h->kennung = f->readInt(1); h->typ = f->readInt(1); + f->ignore(2); + h->ordnum = f->readInt(2); h->insnum = f->readInt(2); + h->patnum = f->readInt(2); h->flags = f->readInt(2); + h->cwtv = f->readInt(2); h->ffi = f->readInt(2); + f->readString(h->scrm, 4); + h->gv = f->readInt(1); h->is = f->readInt(1); h->it = f->readInt(1); + h->mv = f->readInt(1); h->uc = f->readInt(1); h->dp = f->readInt(1); + f->ignore(8); + h->special = f->readInt(2); + for(i = 0; i < 32; i++) h->chanset[i] = f->readInt(1); +} + +void Cs3mPlayer::setvolume(unsigned char chan) +{ + unsigned char op = op_table[chan], insnr = channel[chan].inst; + + opl->write(0x43 + op,(int)(63-((63-(inst[insnr].d03 & 63))/63.0)*channel[chan].vol) + (inst[insnr].d03 & 192)); + if(inst[insnr].d0a & 1) + opl->write(0x40 + op,(int)(63-((63-(inst[insnr].d02 & 63))/63.0)*channel[chan].vol) + (inst[insnr].d02 & 192)); +} + +void Cs3mPlayer::setfreq(unsigned char chan) +{ + opl->write(0xa0 + chan, channel[chan].freq & 255); + if(channel[chan].key) + opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2) | 32); + else + opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2)); +} + +void Cs3mPlayer::playnote(unsigned char chan) +{ + unsigned char op = op_table[chan], insnr = channel[chan].inst; + + opl->write(0xb0 + chan, 0); // stop old note + + // set instrument data + opl->write(0x20 + op, inst[insnr].d00); + opl->write(0x23 + op, inst[insnr].d01); + opl->write(0x40 + op, inst[insnr].d02); + opl->write(0x43 + op, inst[insnr].d03); + opl->write(0x60 + op, inst[insnr].d04); + opl->write(0x63 + op, inst[insnr].d05); + opl->write(0x80 + op, inst[insnr].d06); + opl->write(0x83 + op, inst[insnr].d07); + opl->write(0xe0 + op, inst[insnr].d08); + opl->write(0xe3 + op, inst[insnr].d09); + opl->write(0xc0 + chan, inst[insnr].d0a); + + // set frequency & play + channel[chan].key = 1; + setfreq(chan); +} + +void Cs3mPlayer::slide_down(unsigned char chan, unsigned char amount) +{ + if(channel[chan].freq - amount > 340) + channel[chan].freq -= amount; + else + if(channel[chan].oct > 0) { + channel[chan].oct--; + channel[chan].freq = 684; + } else + channel[chan].freq = 340; +} + +void Cs3mPlayer::slide_up(unsigned char chan, unsigned char amount) +{ + if(channel[chan].freq + amount < 686) + channel[chan].freq += amount; + else + if(channel[chan].oct < 7) { + channel[chan].oct++; + channel[chan].freq = 341; + } else + channel[chan].freq = 686; +} + +void Cs3mPlayer::vibrato(unsigned char chan, unsigned char info) +{ + unsigned char i,speed,depth; + + speed = info >> 4; + depth = (info & 0x0f) / 2; + + for(i=0;i<speed;i++) { + channel[chan].trigger++; + while(channel[chan].trigger >= 64) + channel[chan].trigger -= 64; + if(channel[chan].trigger >= 16 && channel[chan].trigger < 48) + slide_down(chan,(unsigned char) (vibratotab[channel[chan].trigger - 16] / (16-depth))); + if(channel[chan].trigger < 16) + slide_up(chan,(unsigned char) (vibratotab[channel[chan].trigger + 16] / (16-depth))); + if(channel[chan].trigger >= 48) + slide_up(chan,(unsigned char) (vibratotab[channel[chan].trigger - 48] / (16-depth))); + } + setfreq(chan); +} + +void Cs3mPlayer::tone_portamento(unsigned char chan, unsigned char info) +{ + if(channel[chan].freq + (channel[chan].oct << 10) < channel[chan].nextfreq + + (channel[chan].nextoct << 10)) + slide_up(chan,info); + if(channel[chan].freq + (channel[chan].oct << 10) > channel[chan].nextfreq + + (channel[chan].nextoct << 10)) + slide_down(chan,info); + setfreq(chan); +}
--- a/Plugins/Input/adplug/core/sa2.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,263 +0,0 @@ -/* - * 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 - * - * sa2.cpp - SAdT2 Loader by Simon Peter <dn.tlp@gmx.net> - * SAdT Loader by Mamiya <mamiya@users.sourceforge.net> - */ - -#include <stdio.h> - -#include "sa2.h" -#include "debug.h" - -CPlayer *Csa2Loader::factory(Copl *newopl) -{ - return new Csa2Loader(newopl); -} - -bool Csa2Loader::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - struct { - unsigned char data[11],arpstart,arpspeed,arppos,arpspdcnt; - } insts; - unsigned char buf; - int i,j, k, notedis = 0; - const unsigned char convfx[16] = {0,1,2,3,4,5,6,255,8,255,10,11,12,13,255,15}; - unsigned char sat_type; - enum SAT_TYPE { - HAS_ARPEGIOLIST = (1 << 7), - HAS_V7PATTERNS = (1 << 6), - HAS_ACTIVECHANNELS = (1 << 5), - HAS_TRACKORDER = (1 << 4), - HAS_ARPEGIO = (1 << 3), - HAS_OLDBPM = (1 << 2), - HAS_OLDPATTERNS = (1 << 1), - HAS_UNKNOWN127 = (1 << 0) - }; - - // read header - f->readString(header.sadt, 4); - header.version = f->readInt(1); - - // file validation section - if(strncmp(header.sadt,"SAdT",4)) { fp.close(f); return false; } - switch(header.version) { - case 1: - notedis = +0x18; - sat_type = HAS_UNKNOWN127 | HAS_OLDPATTERNS | HAS_OLDBPM; - break; - case 2: - notedis = +0x18; - sat_type = HAS_OLDPATTERNS | HAS_OLDBPM; - break; - case 3: - notedis = +0x0c; - sat_type = HAS_OLDPATTERNS | HAS_OLDBPM; - break; - case 4: - notedis = +0x0c; - sat_type = HAS_ARPEGIO | HAS_OLDPATTERNS | HAS_OLDBPM; - break; - case 5: - notedis = +0x0c; - sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_OLDPATTERNS | HAS_OLDBPM; - break; - case 6: - sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_OLDPATTERNS | HAS_OLDBPM; - break; - case 7: - sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_V7PATTERNS; - break; - case 8: - sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_TRACKORDER; - break; - case 9: - sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_TRACKORDER | HAS_ACTIVECHANNELS; - break; - default: /* unknown */ - fp.close(f); - return false; - } - - // load section - // instruments - for(i = 0; i < 31; i++) { - if(sat_type & HAS_ARPEGIO) { - for(j = 0; j < 11; j++) insts.data[j] = f->readInt(1); - insts.arpstart = f->readInt(1); - insts.arpspeed = f->readInt(1); - insts.arppos = f->readInt(1); - insts.arpspdcnt = f->readInt(1); - inst[i].arpstart = insts.arpstart; - inst[i].arpspeed = insts.arpspeed; - inst[i].arppos = insts.arppos; - inst[i].arpspdcnt = insts.arpspdcnt; - } else { - for(j = 0; j < 11; j++) insts.data[j] = f->readInt(1); - inst[i].arpstart = 0; - inst[i].arpspeed = 0; - inst[i].arppos = 0; - inst[i].arpspdcnt = 0; - } - for(j=0;j<11;j++) - inst[i].data[j] = insts.data[j]; - inst[i].misc = 0; - inst[i].slide = 0; - } - - // instrument names - for(i = 0; i < 29; i++) f->readString(instname[i], 17); - - f->ignore(3); // dummy bytes - for(i = 0; i < 128; i++) order[i] = f->readInt(1); // pattern orders - if(sat_type & HAS_UNKNOWN127) f->ignore(127); - - // infos - nop = f->readInt(2); length = f->readInt(1); restartpos = f->readInt(1); - - // bpm - bpm = f->readInt(2); - if(sat_type & HAS_OLDBPM) { - bpm = bpm * 125 / 50; // cps -> bpm - } - - if(sat_type & HAS_ARPEGIOLIST) { - init_specialarp(); - for(i = 0; i < 256; i++) arplist[i] = f->readInt(1); // arpeggio list - for(i = 0; i < 256; i++) arpcmd[i] = f->readInt(1); // arpeggio commands - } - - for(i=0;i<64;i++) { // track orders - for(j=0;j<9;j++) { - if(sat_type & HAS_TRACKORDER) - trackord[i][j] = f->readInt(1); - else - { - trackord[i][j] = i * 9 + j; - } - } - } - - if(sat_type & HAS_ACTIVECHANNELS) - activechan = f->readInt(2); // active channels - else - activechan = 0xffff; - - AdPlug_LogWrite("Csa2Loader::load(\"%s\"): sat_type = %x, nop = %d, " - "length = %d, restartpos = %d, activechan = %x, bpm = %d\n", - filename.c_str(), sat_type, nop, length, restartpos, activechan, bpm); - - // track data - if(sat_type & HAS_OLDPATTERNS) { - i = 0; - while(!f->ateof()) { - for(j=0;j<64;j++) { - for(k=0;k<9;k++) { - buf = f->readInt(1); - tracks[i+k][j].note = buf ? (buf + notedis) : 0; - tracks[i+k][j].inst = f->readInt(1); - tracks[i+k][j].command = convfx[f->readInt(1) & 0xf]; - tracks[i+k][j].param1 = f->readInt(1); - tracks[i+k][j].param2 = f->readInt(1); - } - } - i+=9; - } - } else - if(sat_type & HAS_V7PATTERNS) { - i = 0; - while(!f->ateof()) { - for(j=0;j<64;j++) { - for(k=0;k<9;k++) { - buf = f->readInt(1); - tracks[i+k][j].note = buf >> 1; - tracks[i+k][j].inst = (buf & 1) << 4; - buf = f->readInt(1); - tracks[i+k][j].inst += buf >> 4; - tracks[i+k][j].command = convfx[buf & 0x0f]; - buf = f->readInt(1); - tracks[i+k][j].param1 = buf >> 4; - tracks[i+k][j].param2 = buf & 0x0f; - } - } - i+=9; - } - } else { - i = 0; - while(!f->ateof()) { - for(j=0;j<64;j++) { - buf = f->readInt(1); - tracks[i][j].note = buf >> 1; - tracks[i][j].inst = (buf & 1) << 4; - buf = f->readInt(1); - tracks[i][j].inst += buf >> 4; - tracks[i][j].command = convfx[buf & 0x0f]; - buf = f->readInt(1); - tracks[i][j].param1 = buf >> 4; - tracks[i][j].param2 = buf & 0x0f; - } - i++; - } - } - fp.close(f); - - // fix instrument names - for(i=0;i<29;i++) - for(j=0;j<17;j++) - if(!instname[i][j]) - instname[i][j] = ' '; - - rewind(0); // rewind module - return true; -} - -std::string Csa2Loader::gettype() -{ - char tmpstr[40]; - - sprintf(tmpstr,"Surprise! Adlib Tracker 2 (version %d)",header.version); - return std::string(tmpstr); -} - -std::string Csa2Loader::gettitle() -{ - char bufinst[29*17],buf[18]; - int i,ptr; - - // parse instrument names for song name - memset(bufinst,'\0',29*17); - for(i=0;i<29;i++) { - buf[16] = ' '; buf[17] = '\0'; - memcpy(buf,instname[i]+1,16); - for(ptr=16;ptr>0;ptr--) - if(buf[ptr] == ' ') - buf[ptr] = '\0'; - else { - if(ptr<16) - buf[ptr+1] = ' '; - break; - } - strcat(bufinst,buf); - } - - if(strchr(bufinst,'"')) - return std::string(bufinst,strchr(bufinst,'"')-bufinst+1,strrchr(bufinst,'"')-strchr(bufinst,'"')-1); - else - return std::string(); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/sa2.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,263 @@ +/* + * 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 + * + * sa2.cpp - SAdT2 Loader by Simon Peter <dn.tlp@gmx.net> + * SAdT Loader by Mamiya <mamiya@users.sourceforge.net> + */ + +#include <stdio.h> + +#include "sa2.h" +#include "debug.h" + +CPlayer *Csa2Loader::factory(Copl *newopl) +{ + return new Csa2Loader(newopl); +} + +bool Csa2Loader::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + struct { + unsigned char data[11],arpstart,arpspeed,arppos,arpspdcnt; + } insts; + unsigned char buf; + int i,j, k, notedis = 0; + const unsigned char convfx[16] = {0,1,2,3,4,5,6,255,8,255,10,11,12,13,255,15}; + unsigned char sat_type; + enum SAT_TYPE { + HAS_ARPEGIOLIST = (1 << 7), + HAS_V7PATTERNS = (1 << 6), + HAS_ACTIVECHANNELS = (1 << 5), + HAS_TRACKORDER = (1 << 4), + HAS_ARPEGIO = (1 << 3), + HAS_OLDBPM = (1 << 2), + HAS_OLDPATTERNS = (1 << 1), + HAS_UNKNOWN127 = (1 << 0) + }; + + // read header + f->readString(header.sadt, 4); + header.version = f->readInt(1); + + // file validation section + if(strncmp(header.sadt,"SAdT",4)) { fp.close(f); return false; } + switch(header.version) { + case 1: + notedis = +0x18; + sat_type = HAS_UNKNOWN127 | HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 2: + notedis = +0x18; + sat_type = HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 3: + notedis = +0x0c; + sat_type = HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 4: + notedis = +0x0c; + sat_type = HAS_ARPEGIO | HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 5: + notedis = +0x0c; + sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 6: + sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_OLDPATTERNS | HAS_OLDBPM; + break; + case 7: + sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_V7PATTERNS; + break; + case 8: + sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_TRACKORDER; + break; + case 9: + sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_TRACKORDER | HAS_ACTIVECHANNELS; + break; + default: /* unknown */ + fp.close(f); + return false; + } + + // load section + // instruments + for(i = 0; i < 31; i++) { + if(sat_type & HAS_ARPEGIO) { + for(j = 0; j < 11; j++) insts.data[j] = f->readInt(1); + insts.arpstart = f->readInt(1); + insts.arpspeed = f->readInt(1); + insts.arppos = f->readInt(1); + insts.arpspdcnt = f->readInt(1); + inst[i].arpstart = insts.arpstart; + inst[i].arpspeed = insts.arpspeed; + inst[i].arppos = insts.arppos; + inst[i].arpspdcnt = insts.arpspdcnt; + } else { + for(j = 0; j < 11; j++) insts.data[j] = f->readInt(1); + inst[i].arpstart = 0; + inst[i].arpspeed = 0; + inst[i].arppos = 0; + inst[i].arpspdcnt = 0; + } + for(j=0;j<11;j++) + inst[i].data[j] = insts.data[j]; + inst[i].misc = 0; + inst[i].slide = 0; + } + + // instrument names + for(i = 0; i < 29; i++) f->readString(instname[i], 17); + + f->ignore(3); // dummy bytes + for(i = 0; i < 128; i++) order[i] = f->readInt(1); // pattern orders + if(sat_type & HAS_UNKNOWN127) f->ignore(127); + + // infos + nop = f->readInt(2); length = f->readInt(1); restartpos = f->readInt(1); + + // bpm + bpm = f->readInt(2); + if(sat_type & HAS_OLDBPM) { + bpm = bpm * 125 / 50; // cps -> bpm + } + + if(sat_type & HAS_ARPEGIOLIST) { + init_specialarp(); + for(i = 0; i < 256; i++) arplist[i] = f->readInt(1); // arpeggio list + for(i = 0; i < 256; i++) arpcmd[i] = f->readInt(1); // arpeggio commands + } + + for(i=0;i<64;i++) { // track orders + for(j=0;j<9;j++) { + if(sat_type & HAS_TRACKORDER) + trackord[i][j] = f->readInt(1); + else + { + trackord[i][j] = i * 9 + j; + } + } + } + + if(sat_type & HAS_ACTIVECHANNELS) + activechan = f->readInt(2); // active channels + else + activechan = 0xffff; + + AdPlug_LogWrite("Csa2Loader::load(\"%s\"): sat_type = %x, nop = %d, " + "length = %d, restartpos = %d, activechan = %x, bpm = %d\n", + filename.c_str(), sat_type, nop, length, restartpos, activechan, bpm); + + // track data + if(sat_type & HAS_OLDPATTERNS) { + i = 0; + while(!f->ateof()) { + for(j=0;j<64;j++) { + for(k=0;k<9;k++) { + buf = f->readInt(1); + tracks[i+k][j].note = buf ? (buf + notedis) : 0; + tracks[i+k][j].inst = f->readInt(1); + tracks[i+k][j].command = convfx[f->readInt(1) & 0xf]; + tracks[i+k][j].param1 = f->readInt(1); + tracks[i+k][j].param2 = f->readInt(1); + } + } + i+=9; + } + } else + if(sat_type & HAS_V7PATTERNS) { + i = 0; + while(!f->ateof()) { + for(j=0;j<64;j++) { + for(k=0;k<9;k++) { + buf = f->readInt(1); + tracks[i+k][j].note = buf >> 1; + tracks[i+k][j].inst = (buf & 1) << 4; + buf = f->readInt(1); + tracks[i+k][j].inst += buf >> 4; + tracks[i+k][j].command = convfx[buf & 0x0f]; + buf = f->readInt(1); + tracks[i+k][j].param1 = buf >> 4; + tracks[i+k][j].param2 = buf & 0x0f; + } + } + i+=9; + } + } else { + i = 0; + while(!f->ateof()) { + for(j=0;j<64;j++) { + buf = f->readInt(1); + tracks[i][j].note = buf >> 1; + tracks[i][j].inst = (buf & 1) << 4; + buf = f->readInt(1); + tracks[i][j].inst += buf >> 4; + tracks[i][j].command = convfx[buf & 0x0f]; + buf = f->readInt(1); + tracks[i][j].param1 = buf >> 4; + tracks[i][j].param2 = buf & 0x0f; + } + i++; + } + } + fp.close(f); + + // fix instrument names + for(i=0;i<29;i++) + for(j=0;j<17;j++) + if(!instname[i][j]) + instname[i][j] = ' '; + + rewind(0); // rewind module + return true; +} + +std::string Csa2Loader::gettype() +{ + char tmpstr[40]; + + sprintf(tmpstr,"Surprise! Adlib Tracker 2 (version %d)",header.version); + return std::string(tmpstr); +} + +std::string Csa2Loader::gettitle() +{ + char bufinst[29*17],buf[18]; + int i,ptr; + + // parse instrument names for song name + memset(bufinst,'\0',29*17); + for(i=0;i<29;i++) { + buf[16] = ' '; buf[17] = '\0'; + memcpy(buf,instname[i]+1,16); + for(ptr=16;ptr>0;ptr--) + if(buf[ptr] == ' ') + buf[ptr] = '\0'; + else { + if(ptr<16) + buf[ptr+1] = ' '; + break; + } + strcat(bufinst,buf); + } + + if(strchr(bufinst,'"')) + return std::string(bufinst,strchr(bufinst,'"')-bufinst+1,strrchr(bufinst,'"')-strchr(bufinst,'"')-1); + else + return std::string(); +}
--- a/Plugins/Input/adplug/core/sng.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2002 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 - * - * sng.cpp - SNG Player by Simon Peter <dn.tlp@gmx.net> - */ - -#include "sng.h" - -CPlayer *CsngPlayer::factory(Copl *newopl) -{ - return new CsngPlayer(newopl); -} - -bool CsngPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - int i; - - // load header - f->readString(header.id, 4); - header.length = f->readInt(2); header.start = f->readInt(2); - header.loop = f->readInt(2); header.delay = f->readInt(1); - header.compressed = f->readInt(1) ? true : false; - - // file validation section - if(strncmp(header.id,"ObsM",4)) { fp.close(f); return false; } - - // load section - header.length /= 2; header.start /= 2; header.loop /= 2; - data = new Sdata [header.length]; - for(i = 0; i < header.length; i++) { - data[i].val = f->readInt(1); - data[i].reg = f->readInt(1); - } - - rewind(0); - fp.close(f); - return true; -} - -bool CsngPlayer::update() -{ - if(header.compressed && del) { - del--; - return !songend; - } - - while(data[pos].reg) { - opl->write(data[pos].reg, data[pos].val); - pos++; - if(pos >= header.length) { - songend = true; - pos = header.loop; - } - } - - if(!header.compressed) - opl->write(data[pos].reg, data[pos].val); - - if(data[pos].val) del = data[pos].val - 1; pos++; - if(pos >= header.length) { songend = true; pos = header.loop; } - return !songend; -} - -void CsngPlayer::rewind(int subsong) -{ - pos = header.start; del = header.delay; songend = false; - opl->init(); opl->write(1,32); // go to OPL2 mode -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/sng.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,84 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2002 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 + * + * sng.cpp - SNG Player by Simon Peter <dn.tlp@gmx.net> + */ + +#include "sng.h" + +CPlayer *CsngPlayer::factory(Copl *newopl) +{ + return new CsngPlayer(newopl); +} + +bool CsngPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + int i; + + // load header + f->readString(header.id, 4); + header.length = f->readInt(2); header.start = f->readInt(2); + header.loop = f->readInt(2); header.delay = f->readInt(1); + header.compressed = f->readInt(1) ? true : false; + + // file validation section + if(strncmp(header.id,"ObsM",4)) { fp.close(f); return false; } + + // load section + header.length /= 2; header.start /= 2; header.loop /= 2; + data = new Sdata [header.length]; + for(i = 0; i < header.length; i++) { + data[i].val = f->readInt(1); + data[i].reg = f->readInt(1); + } + + rewind(0); + fp.close(f); + return true; +} + +bool CsngPlayer::update() +{ + if(header.compressed && del) { + del--; + return !songend; + } + + while(data[pos].reg) { + opl->write(data[pos].reg, data[pos].val); + pos++; + if(pos >= header.length) { + songend = true; + pos = header.loop; + } + } + + if(!header.compressed) + opl->write(data[pos].reg, data[pos].val); + + if(data[pos].val) del = data[pos].val - 1; pos++; + if(pos >= header.length) { songend = true; pos = header.loop; } + return !songend; +} + +void CsngPlayer::rewind(int subsong) +{ + pos = header.start; del = header.delay; songend = false; + opl->init(); opl->write(1,32); // go to OPL2 mode +}
--- a/Plugins/Input/adplug/core/temuopl.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * AdPlug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2004 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 - * - * temuopl.cpp - Tatsuyuki Satoh's OPL2 emulator, by Simon Peter <dn.tlp@gmx.net> - */ - -#include "temuopl.h" - -CTemuopl::CTemuopl(int rate, bool bit16, bool usestereo) - : use16bit(bit16), stereo(usestereo) -{ - opl = OPLCreate(OPL_TYPE_YM3812, 3579545, rate); -} - -CTemuopl::~CTemuopl() -{ - OPLDestroy(opl); -} - -void CTemuopl::update(short *buf, int samples) -{ - int i; - - if(use16bit) { - YM3812UpdateOne(opl,buf,samples); - - if(stereo) - for(i=samples-1;i>=0;i--) { - buf[i*2] = buf[i]; - buf[i*2+1] = buf[i]; - } - } else { - short *tempbuf = new short[stereo ? samples*2 : samples]; - int i; - - YM3812UpdateOne(opl,tempbuf,samples); - - if(stereo) - for(i=samples-1;i>=0;i--) { - tempbuf[i*2] = tempbuf[i]; - tempbuf[i*2+1] = tempbuf[i]; - } - - for(i=0;i<(stereo ? samples*2 : samples);i++) - ((char *)buf)[i] = (tempbuf[i] >> 8) ^ 0x80; - - delete [] tempbuf; - } -} - -void CTemuopl::write(int reg, int val) -{ - OPLWrite(opl,0,reg); - OPLWrite(opl,1,val); -} - -void CTemuopl::init() -{ - OPLResetChip(opl); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/temuopl.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,75 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 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 + * + * temuopl.cpp - Tatsuyuki Satoh's OPL2 emulator, by Simon Peter <dn.tlp@gmx.net> + */ + +#include "temuopl.h" + +CTemuopl::CTemuopl(int rate, bool bit16, bool usestereo) + : use16bit(bit16), stereo(usestereo) +{ + opl = OPLCreate(OPL_TYPE_YM3812, 3579545, rate); +} + +CTemuopl::~CTemuopl() +{ + OPLDestroy(opl); +} + +void CTemuopl::update(short *buf, int samples) +{ + int i; + + if(use16bit) { + YM3812UpdateOne(opl,buf,samples); + + if(stereo) + for(i=samples-1;i>=0;i--) { + buf[i*2] = buf[i]; + buf[i*2+1] = buf[i]; + } + } else { + short *tempbuf = new short[stereo ? samples*2 : samples]; + int i; + + YM3812UpdateOne(opl,tempbuf,samples); + + if(stereo) + for(i=samples-1;i>=0;i--) { + tempbuf[i*2] = tempbuf[i]; + tempbuf[i*2+1] = tempbuf[i]; + } + + for(i=0;i<(stereo ? samples*2 : samples);i++) + ((char *)buf)[i] = (tempbuf[i] >> 8) ^ 0x80; + + delete [] tempbuf; + } +} + +void CTemuopl::write(int reg, int val) +{ + OPLWrite(opl,0,reg); + OPLWrite(opl,1,val); +} + +void CTemuopl::init() +{ + OPLResetChip(opl); +}
--- a/Plugins/Input/adplug/core/u6m.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,935 +0,0 @@ -/* - * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 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 - * - * u6m.cpp - Ultima 6 Music Player by Marc Winterrowd. - * This code extends the Adlib Winamp plug-in by Simon Peter <dn.tlp@gmx.net> - */ - -#include "u6m.h" - -// Makes security checks on output buffer before writing -#define SAVE_OUTPUT_ROOT(c, d, p) \ -if(p < d.size) \ - output_root(c, d.data, p); \ -else \ - return false; - -CPlayer *Cu6mPlayer::factory(Copl *newopl) -{ - return new Cu6mPlayer(newopl); -} - -bool Cu6mPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - // file validation section - // this section only checks a few *necessary* conditions - unsigned long filesize, decompressed_filesize; - binistream *f; - - f = fp.open(filename); if(!f) return false; - filesize = fp.filesize(f); - - if (filesize >= 6) - { - // check if the file has a valid pseudo-header - unsigned char pseudo_header[6]; - f->readString((char *)pseudo_header, 6); - decompressed_filesize = pseudo_header[0] + (pseudo_header[1] << 8); - - if (!( (pseudo_header[2]==0) && (pseudo_header[3]==0) && - (pseudo_header[4] + ((pseudo_header[5] & 0x1)<<8) == 0x100) && - (decompressed_filesize > (filesize-4)) )) - { - fp.close(f); - return(false); - } - } - else - { - fp.close(f); - return(false); - } - - // load section - song_data = new unsigned char[decompressed_filesize]; - unsigned char* compressed_song_data = new unsigned char[filesize-3]; - - f->seek(4); - f->readString((char *)compressed_song_data, filesize - 4); - fp.close(f); - - // attempt to decompress the song data - // if unsuccessful, deallocate song_data[] on the spot, and return(false) - data_block source, destination; - source.size = filesize-4; - source.data = compressed_song_data; - destination.size = decompressed_filesize; - destination.data = song_data; - - if (!lzw_decompress(source,destination)) - { - delete[] compressed_song_data; - delete[] song_data; - return(false); - } - - // deallocation section - delete[] compressed_song_data; - - rewind(0); - return (true); -} - - -bool Cu6mPlayer::update() -{ - if (!driver_active) - { - driver_active = true; - dec_clip(read_delay); - if (read_delay == 0) - { - command_loop(); - } - - // on all Adlib channels: freq slide/vibrato, mute factor slide - for (int i = 0; i < 9; i++) - { - if (channel_freq_signed_delta[i]!=0) - // frequency slide + mute factor slide - { - // freq slide - freq_slide(i); - - // mute factor slide - if (carrier_mf_signed_delta[i]!=0) - { - mf_slide(i); - } - } - else - // vibrato + mute factor slide - { - // vibrato - if ((vb_multiplier[i]!=0) && ((channel_freq[i].hi & 0x20)==0x20)) - { - vibrato(i); - } - - // mute factor slide - if (carrier_mf_signed_delta[i]!=0) - { - mf_slide(i); - } - } - } - - driver_active = false; - } - - return !songend; -} - - -void Cu6mPlayer::rewind(int subsong) -{ - played_ticks = 0; - songend = false; - - // set the driver's internal variables - byte_pair freq_word = {0,0}; - - driver_active = false; - song_pos = 0; - loop_position = 0; // position of the loop point - read_delay = 0; // delay (in timer ticks) before further song data is read - - for (int i = 0; i < 9; i++) - { - // frequency - channel_freq_signed_delta[i] = 0; - channel_freq[i] = freq_word; // Adlib freq settings for each channel - - // vibrato ("vb") - vb_current_value[i] = 0; - vb_double_amplitude[i] = 0; - vb_multiplier[i] = 0; - vb_direction_flag[i] = 0; - - // mute factor ("mf") == ~(volume) - carrier_mf[i] = 0; - carrier_mf_signed_delta[i] = 0; - carrier_mf_mod_delay_backup[i] = 0; - carrier_mf_mod_delay[i] = 0; - } - - while (!subsong_stack.empty()) // empty subsong stack - subsong_stack.pop(); - - opl->init(); - out_adlib(1,32); // go to OPL2 mode -} - - -float Cu6mPlayer::getrefresh() -{ - return ((float)60); // the Ultima 6 music driver expects to be called at 60 Hz -} - - -// ============================================================================================ -// -// -// Functions called by load() -// -// -// ============================================================================================ - - -// decompress from memory to memory -bool Cu6mPlayer::lzw_decompress(Cu6mPlayer::data_block source, Cu6mPlayer::data_block dest) -{ - bool end_marker_reached = false; - int codeword_size = 9; - long bits_read = 0; - int next_free_codeword = 0x102; - int dictionary_size = 0x200; - MyDict dictionary = MyDict(); - std::stack<unsigned char> root_stack; - - long bytes_written = 0; - - int cW; - int pW; - unsigned char C; - - while (!end_marker_reached) - { - cW = get_next_codeword(bits_read, source.data, codeword_size); - switch (cW) - { - // re-init the dictionary - case 0x100: - codeword_size = 9; - next_free_codeword = 0x102; - dictionary_size = 0x200; - dictionary.reset(); - cW = get_next_codeword(bits_read, source.data, codeword_size); - SAVE_OUTPUT_ROOT((unsigned char)cW, dest, bytes_written); - break; - // end of compressed file has been reached - case 0x101: - end_marker_reached = true; - break; - // (cW <> 0x100) && (cW <> 0x101) - default: - if (cW < next_free_codeword) // codeword is already in the dictionary - { - // create the string associated with cW (on the stack) - get_string(cW,dictionary,root_stack); - C = root_stack.top(); - // output the string represented by cW - while (!root_stack.empty()) - { - SAVE_OUTPUT_ROOT(root_stack.top(), dest, bytes_written); - root_stack.pop(); - } - // add pW+C to the dictionary - dictionary.add(C,pW); - - next_free_codeword++; - if (next_free_codeword >= dictionary_size) - { - if (codeword_size < max_codeword_length) - { - codeword_size += 1; - dictionary_size *= 2; - } - } - } - else // codeword is not yet defined - { - // create the string associated with pW (on the stack) - get_string(pW,dictionary,root_stack); - C = root_stack.top(); - // output the string represented by pW - while (!root_stack.empty()) - { - SAVE_OUTPUT_ROOT(root_stack.top(), dest, bytes_written); - root_stack.pop(); - } - // output the char C - SAVE_OUTPUT_ROOT(C, dest, bytes_written); - - // the new dictionary entry must correspond to cW - // if it doesn't, something is wrong with the lzw-compressed data. - if (cW != next_free_codeword) - { - /* printf("cW != next_free_codeword!\n"); - exit(-1); */ - return false; - } - // add pW+C to the dictionary - dictionary.add(C,pW); - - next_free_codeword++; - if (next_free_codeword >= dictionary_size) - { - if (codeword_size < max_codeword_length) - { - codeword_size += 1; - dictionary_size *= 2; - } - } - }; - break; - } - // shift roles - the current cW becomes the new pW - pW = cW; - } - - return(true); // indicate successful decompression -} - - -// -------------------- -// Additional functions -// -------------------- - - -// Read the next code word from the source buffer -int Cu6mPlayer::get_next_codeword (long& bits_read, unsigned char *source, int codeword_size) -{ - unsigned char b0,b1,b2; - int codeword; - - b0 = source[bits_read/8]; - b1 = source[bits_read/8+1]; - b2 = source[bits_read/8+2]; - - codeword = ((b2 << 16) + (b1 << 8) + b0); - codeword = codeword >> (bits_read % 8); - switch (codeword_size) - { - case 0x9: - codeword = codeword & 0x1ff; - break; - case 0xa: - codeword = codeword & 0x3ff; - break; - case 0xb: - codeword = codeword & 0x7ff; - break; - case 0xc: - codeword = codeword & 0xfff; - break; - default: - codeword = -1; // indicates that an error has occurred - break; - } - - bits_read += codeword_size; - return (codeword); -} - - -// output a root to memory -void Cu6mPlayer::output_root(unsigned char root, unsigned char *destination, long& position) -{ - destination[position] = root; - position++; -} - - -// output the string represented by a codeword -void Cu6mPlayer::get_string(int codeword, Cu6mPlayer::MyDict& dictionary, std::stack<unsigned char>& root_stack) -{ - unsigned char root; - int current_codeword; - - current_codeword = codeword; - - while (current_codeword > 0xff) - { - root = dictionary.get_root(current_codeword); - current_codeword = dictionary.get_codeword(current_codeword); - root_stack.push(root); - } - - // push the root at the leaf - root_stack.push((unsigned char)current_codeword); -} - - -// ============================================================================================ -// -// -// Functions called by update() -// -// -// ============================================================================================ - - -// This function reads the song data and executes the embedded commands. -void Cu6mPlayer::command_loop() -{ - unsigned char command_byte; // current command byte - int command_nibble_hi; // command byte, bits 4-7 - int command_nibble_lo; // command byte, bite 0-3 - bool repeat_loop = true; // - - do - { - // extract low and high command nibbles - command_byte = read_song_byte(); // implicitly increments song_pos - command_nibble_hi = command_byte >> 4; - command_nibble_lo = command_byte & 0xf; - - switch (command_nibble_hi) - { - case 0x0: command_0(command_nibble_lo); break; - case 0x1: command_1(command_nibble_lo); break; - case 0x2: command_2(command_nibble_lo); break; - case 0x3: command_3(command_nibble_lo); break; - case 0x4: command_4(command_nibble_lo); break; - case 0x5: command_5(command_nibble_lo); break; - case 0x6: command_6(command_nibble_lo); break; - case 0x7: command_7(command_nibble_lo); break; - case 0x8: - switch (command_nibble_lo) - { - case 1: command_81(); break; - case 2: command_82(); repeat_loop = false; break; - case 3: command_83(); break; - case 5: command_85(); break; - case 6: command_86(); break; - default: break; // maybe generate an error? - } - break; - case 0xE: command_E(); break; - case 0xF: command_F(); break; - default: break; // maybe generate an error? - } - - } while (repeat_loop); -} - - -// -------------------------------------------------------- -// The commands supported by the U6 music file format -// -------------------------------------------------------- - -// ---------------------------------------- -// Set octave and frequency, note off -// Format: 0c nn -// c = channel, nn = packed Adlib frequency -// ---------------------------------------- -void Cu6mPlayer::command_0(int channel) -{ - unsigned char freq_byte; - byte_pair freq_word; - - freq_byte = read_song_byte(); - freq_word = expand_freq_byte(freq_byte); - set_adlib_freq(channel,freq_word); -} - - -// --------------------------------------------------- -// Set octave and frequency, old note off, new note on -// Format: 1c nn -// c = channel, nn = packed Adlib frequency -// --------------------------------------------------- -void Cu6mPlayer::command_1(int channel) -{ - unsigned char freq_byte; - byte_pair freq_word; - - vb_direction_flag[channel] = 0; - vb_current_value[channel] = 0; - - freq_byte = read_song_byte(); - freq_word = expand_freq_byte(freq_byte); - set_adlib_freq(channel,freq_word); - - freq_word.hi = freq_word.hi | 0x20; // note on - set_adlib_freq(channel,freq_word); -} - - -// ---------------------------------------- -// Set octave and frequency, note on -// Format: 2c nn -// c = channel, nn = packed Adlib frequency -// ---------------------------------------- -void Cu6mPlayer::command_2(int channel) -{ - unsigned char freq_byte; - byte_pair freq_word; - - freq_byte = read_song_byte(); - freq_word = expand_freq_byte(freq_byte); - freq_word.hi = freq_word.hi | 0x20; // note on - set_adlib_freq(channel,freq_word); -} - - -// -------------------------------------- -// Set "carrier mute factor"==not(volume) -// Format: 3c nn -// c = channel, nn = mute factor -// -------------------------------------- -void Cu6mPlayer::command_3(int channel) -{ - unsigned char mf_byte; - - carrier_mf_signed_delta[channel] = 0; - mf_byte = read_song_byte(); - set_carrier_mf(channel,mf_byte); -} - - -// ---------------------------------------- -// set "modulator mute factor"==not(volume) -// Format: 4c nn -// c = channel, nn = mute factor -// ---------------------------------------- -void Cu6mPlayer::command_4(int channel) -{ - unsigned char mf_byte; - - mf_byte = read_song_byte(); - set_modulator_mf(channel,mf_byte); -} - - -// -------------------------------------------- -// Set portamento (pitch slide) -// Format: 5c nn -// c = channel, nn = signed channel pitch delta -// -------------------------------------------- -void Cu6mPlayer::command_5(int channel) -{ - channel_freq_signed_delta[channel] = read_signed_song_byte(); -} - - -// -------------------------------------------- -// Set vibrato paramters -// Format: 6c mn -// c = channel -// m = vibrato double amplitude -// n = vibrato multiplier -// -------------------------------------------- -void Cu6mPlayer::command_6(int channel) -{ - unsigned char vb_parameters; - - vb_parameters = read_song_byte(); - vb_double_amplitude[channel] = vb_parameters >> 4; // high nibble - vb_multiplier[channel] = vb_parameters & 0xF; // low nibble -} - - -// ---------------------------------------- -// Assign Adlib instrument to Adlib channel -// Format: 7c nn -// c = channel, nn = instrument number -// ---------------------------------------- -void Cu6mPlayer::command_7(int channel) -{ - int instrument_offset = instrument_offsets[read_song_byte()]; - out_adlib_opcell(channel, false, 0x20, *(song_data + instrument_offset+0)); - out_adlib_opcell(channel, false, 0x40, *(song_data + instrument_offset+1)); - out_adlib_opcell(channel, false, 0x60, *(song_data + instrument_offset+2)); - out_adlib_opcell(channel, false, 0x80, *(song_data + instrument_offset+3)); - out_adlib_opcell(channel, false, 0xE0, *(song_data + instrument_offset+4)); - out_adlib_opcell(channel, true, 0x20, *(song_data + instrument_offset+5)); - out_adlib_opcell(channel, true, 0x40, *(song_data + instrument_offset+6)); - out_adlib_opcell(channel, true, 0x60, *(song_data + instrument_offset+7)); - out_adlib_opcell(channel, true, 0x80, *(song_data + instrument_offset+8)); - out_adlib_opcell(channel, true, 0xE0, *(song_data + instrument_offset+9)); - out_adlib(0xC0+channel, *(song_data + instrument_offset+10)); -} - - -// ------------------------------------------- -// Branch to a new subsong -// Format: 81 nn aa bb -// nn == number of times to repeat the subsong -// aa == subsong offset (low byte) -// bb == subsong offset (high byte) -// ------------------------------------------- -void Cu6mPlayer::command_81() -{ - subsong_info new_ss_info; - - new_ss_info.subsong_repetitions = read_song_byte(); - new_ss_info.subsong_start = read_song_byte(); new_ss_info.subsong_start += read_song_byte() << 8; - new_ss_info.continue_pos = song_pos; - - subsong_stack.push(new_ss_info); - song_pos = new_ss_info.subsong_start; -} - - -// ------------------------------------------------------------ -// Stop interpreting commands for this timer tick -// Format: 82 nn -// nn == delay (in timer ticks) until further data will be read -// ------------------------------------------------------------ -void Cu6mPlayer::command_82() -{ - read_delay = read_song_byte(); -} - - -// ----------------------------- -// Adlib instrument data follows -// Format: 83 nn <11 bytes> -// nn == instrument number -// ----------------------------- -void Cu6mPlayer::command_83() -{ - unsigned char instrument_number = read_song_byte(); - instrument_offsets[instrument_number] = song_pos; - song_pos += 11; -} - - -// ---------------------------------------------- -// Set -1 mute factor slide (upward volume slide) -// Format: 85 cn -// c == channel -// n == slide delay -// ---------------------------------------------- -void Cu6mPlayer::command_85() -{ - unsigned char data_byte = read_song_byte(); - int channel = data_byte >> 4; // high nibble - unsigned char slide_delay = data_byte & 0xF; // low nibble - carrier_mf_signed_delta[channel] = +1; - carrier_mf_mod_delay[channel] = slide_delay + 1; - carrier_mf_mod_delay_backup[channel] = slide_delay + 1; -} - - -// ------------------------------------------------ -// Set +1 mute factor slide (downward volume slide) -// Format: 86 cn -// c == channel -// n == slide speed -// ------------------------------------------------ -void Cu6mPlayer::command_86() -{ - unsigned char data_byte = read_song_byte(); - int channel = data_byte >> 4; // high nibble - unsigned char slide_delay = data_byte & 0xF; // low nibble - carrier_mf_signed_delta[channel] = -1; - carrier_mf_mod_delay[channel] = slide_delay + 1; - carrier_mf_mod_delay_backup[channel] = slide_delay + 1; -} - - -// -------------- -// Set loop point -// Format: E? -// -------------- -void Cu6mPlayer::command_E() -{ - loop_position = song_pos; -} - - -// --------------------------- -// Return from current subsong -// Format: F? -// --------------------------- -void Cu6mPlayer::command_F() -{ - if (!subsong_stack.empty()) - { - subsong_info temp = subsong_stack.top(); - subsong_stack.pop(); - temp.subsong_repetitions--; - if (temp.subsong_repetitions==0) - { - song_pos = temp.continue_pos; - } - else - { - song_pos = temp.subsong_start; - subsong_stack.push(temp); - } - } - else - { - song_pos = loop_position; - songend = true; - } -} - - -// -------------------- -// Additional functions -// -------------------- - -// This function decrements its argument, without allowing it to become negative. -void Cu6mPlayer::dec_clip(int& param) -{ - param--; - if (param < 0) { param = 0; } -} - - -// Returns the byte at the current song position. -// Side effect: increments song_pos. -unsigned char Cu6mPlayer::read_song_byte() -{ - unsigned char song_byte; - song_byte = song_data[song_pos]; - song_pos++; - return(song_byte); -} - - -// Same as read_song_byte(), except that it returns a signed byte -signed char Cu6mPlayer::read_signed_song_byte() -{ - unsigned char song_byte; - int signed_value; - song_byte = *(song_data + song_pos); - song_pos++; - if (song_byte <= 127) - { - signed_value = song_byte; - } - else - { - signed_value = (int)song_byte - 0x100; - } - return((signed char)signed_value); -} - - -Cu6mPlayer::byte_pair Cu6mPlayer::expand_freq_byte(unsigned char freq_byte) -{ - const byte_pair freq_table[24] = - { - {0x00,0x00}, {0x58,0x01}, {0x82,0x01}, {0xB0,0x01}, - {0xCC,0x01}, {0x03,0x02}, {0x41,0x02}, {0x86,0x02}, - {0x00,0x00}, {0x6A,0x01}, {0x96,0x01}, {0xC7,0x01}, - {0xE4,0x01}, {0x1E,0x02}, {0x5F,0x02}, {0xA8,0x02}, - {0x00,0x00}, {0x47,0x01}, {0x6E,0x01}, {0x9A,0x01}, - {0xB5,0x01}, {0xE9,0x01}, {0x24,0x02}, {0x66,0x02} - }; - - int packed_freq; - int octave; - byte_pair freq_word; - - packed_freq = freq_byte & 0x1F; - octave = freq_byte >> 5; - - // range check (not present in the original U6 music driver) - if (packed_freq >= 24) { packed_freq = 0; } - - freq_word.hi = freq_table[packed_freq].hi + (octave << 2); - freq_word.lo = freq_table[packed_freq].lo; - - return(freq_word); -} - - -void Cu6mPlayer::set_adlib_freq(int channel,Cu6mPlayer::byte_pair freq_word) -{ - out_adlib(0xA0+channel,freq_word.lo); - out_adlib(0xB0+channel,freq_word.hi); - // update the Adlib register backups - channel_freq[channel] = freq_word; -} - - -// this function sets the Adlib frequency, but does not update the register backups -void Cu6mPlayer::set_adlib_freq_no_update(int channel,Cu6mPlayer::byte_pair freq_word) -{ - out_adlib(0xA0+channel,freq_word.lo); - out_adlib(0xB0+channel,freq_word.hi); -} - - -void Cu6mPlayer::set_carrier_mf(int channel,unsigned char mute_factor) -{ - out_adlib_opcell(channel,true,0x40,mute_factor); - carrier_mf[channel] = mute_factor; -} - - -void Cu6mPlayer::set_modulator_mf(int channel,unsigned char mute_factor) -{ - out_adlib_opcell(channel,false,0x40,mute_factor); -} - - -void Cu6mPlayer::freq_slide(int channel) -{ - byte_pair freq = channel_freq[channel]; - - long freq_word = freq.lo + (freq.hi << 8) + channel_freq_signed_delta[channel]; - if (freq_word < 0) { freq_word += 0x10000; } - if (freq_word > 0xFFFF) { freq_word -= 0x10000; } - - freq.lo = freq_word & 0xFF; - freq.hi = (freq_word >> 8) & 0xFF; - set_adlib_freq(channel,freq); -} - - -void Cu6mPlayer::vibrato(int channel) -{ - byte_pair freq; - - if (vb_current_value[channel] >= vb_double_amplitude[channel]) - { vb_direction_flag[channel] = 1; } - else if (vb_current_value[channel] <= 0) - { vb_direction_flag[channel] = 0; } - - if (vb_direction_flag[channel]==0) - { vb_current_value[channel]++; } - else - { vb_current_value[channel]--; } - - long freq_word = channel_freq[channel].lo + (channel_freq[channel].hi << 8); - freq_word += (vb_current_value[channel] - (vb_double_amplitude[channel] >> 1)) - * vb_multiplier[channel]; - if (freq_word < 0) { freq_word += 0x10000; } - if (freq_word > 0xFFFF) { freq_word -= 0x10000; } - - freq.lo = freq_word & 0xFF; - freq.hi = (freq_word >> 8) & 0xFF; - set_adlib_freq_no_update(channel,freq); -} - - -void Cu6mPlayer::mf_slide(int channel) -{ - carrier_mf_mod_delay[channel]--; - if (carrier_mf_mod_delay[channel]==0) - { - carrier_mf_mod_delay[channel] = carrier_mf_mod_delay_backup[channel]; - int current_mf = carrier_mf[channel] + carrier_mf_signed_delta[channel]; - if (current_mf > 0x3F) - { - current_mf = 0x3F; - carrier_mf_signed_delta[channel] = 0; - } - else if (current_mf < 0) - { - current_mf = 0; - carrier_mf_signed_delta[channel] = 0; - } - - set_carrier_mf(channel,(unsigned char)current_mf); - } -} - - -void Cu6mPlayer::out_adlib(unsigned char adlib_register, unsigned char adlib_data) -{ - opl->write(adlib_register,adlib_data); -} - - -void Cu6mPlayer::out_adlib_opcell(int channel, bool carrier, unsigned char adlib_register, unsigned char out_byte) -{ - const unsigned char adlib_channel_to_carrier_offset[9] = - {0x03,0x04,0x05,0x0B,0x0C,0x0D,0x13,0x14,0x15}; - const unsigned char adlib_channel_to_modulator_offset[9] = - {0x00,0x01,0x02,0x08,0x09,0x0A,0x10,0x11,0x12}; - - if (carrier) - { - out_adlib(adlib_register+adlib_channel_to_carrier_offset[channel],out_byte); - } - else - { - out_adlib(adlib_register+adlib_channel_to_modulator_offset[channel],out_byte); - } -} - - -// ============================================================================================ -// -// -// The Dictionary -// -// -// ============================================================================================ - - -Cu6mPlayer::MyDict::MyDict() -{ - dict_size = default_dict_size; - dictionary = new dict_entry[dict_size-0x100]; // don't allocate space for the roots - contains = 0x102; -} - - -Cu6mPlayer::MyDict::MyDict(int max_size) -{ - dict_size = max_size; - dictionary = new dict_entry[dict_size-0x100]; // don't allocate space for the roots - contains = 0x102; -} - - -Cu6mPlayer::MyDict::~MyDict() -{ - delete [] dictionary; -} - -// re-initializes the dictionary -void Cu6mPlayer::MyDict::reset() -{ - contains = 0x102; -} - - -// Note: If the dictionary is already full, this function does nothing. -void Cu6mPlayer::MyDict::add(unsigned char root, int codeword) -{ - if (contains < dict_size) - { - dictionary[contains-0x100].root = root; - dictionary[contains-0x100].codeword = codeword; - contains++; - } -} - - -unsigned char Cu6mPlayer::MyDict::get_root(int codeword) -{ - return (dictionary[codeword-0x100].root); -} - - -int Cu6mPlayer::MyDict::get_codeword(int codeword) -{ - return (dictionary[codeword-0x100].codeword); -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/u6m.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,935 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2006 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 + * + * u6m.cpp - Ultima 6 Music Player by Marc Winterrowd. + * This code extends the Adlib Winamp plug-in by Simon Peter <dn.tlp@gmx.net> + */ + +#include "u6m.h" + +// Makes security checks on output buffer before writing +#define SAVE_OUTPUT_ROOT(c, d, p) \ +if(p < d.size) \ + output_root(c, d.data, p); \ +else \ + return false; + +CPlayer *Cu6mPlayer::factory(Copl *newopl) +{ + return new Cu6mPlayer(newopl); +} + +bool Cu6mPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + // file validation section + // this section only checks a few *necessary* conditions + unsigned long filesize, decompressed_filesize; + binistream *f; + + f = fp.open(filename); if(!f) return false; + filesize = fp.filesize(f); + + if (filesize >= 6) + { + // check if the file has a valid pseudo-header + unsigned char pseudo_header[6]; + f->readString((char *)pseudo_header, 6); + decompressed_filesize = pseudo_header[0] + (pseudo_header[1] << 8); + + if (!( (pseudo_header[2]==0) && (pseudo_header[3]==0) && + (pseudo_header[4] + ((pseudo_header[5] & 0x1)<<8) == 0x100) && + (decompressed_filesize > (filesize-4)) )) + { + fp.close(f); + return(false); + } + } + else + { + fp.close(f); + return(false); + } + + // load section + song_data = new unsigned char[decompressed_filesize]; + unsigned char* compressed_song_data = new unsigned char[filesize-3]; + + f->seek(4); + f->readString((char *)compressed_song_data, filesize - 4); + fp.close(f); + + // attempt to decompress the song data + // if unsuccessful, deallocate song_data[] on the spot, and return(false) + data_block source, destination; + source.size = filesize-4; + source.data = compressed_song_data; + destination.size = decompressed_filesize; + destination.data = song_data; + + if (!lzw_decompress(source,destination)) + { + delete[] compressed_song_data; + delete[] song_data; + return(false); + } + + // deallocation section + delete[] compressed_song_data; + + rewind(0); + return (true); +} + + +bool Cu6mPlayer::update() +{ + if (!driver_active) + { + driver_active = true; + dec_clip(read_delay); + if (read_delay == 0) + { + command_loop(); + } + + // on all Adlib channels: freq slide/vibrato, mute factor slide + for (int i = 0; i < 9; i++) + { + if (channel_freq_signed_delta[i]!=0) + // frequency slide + mute factor slide + { + // freq slide + freq_slide(i); + + // mute factor slide + if (carrier_mf_signed_delta[i]!=0) + { + mf_slide(i); + } + } + else + // vibrato + mute factor slide + { + // vibrato + if ((vb_multiplier[i]!=0) && ((channel_freq[i].hi & 0x20)==0x20)) + { + vibrato(i); + } + + // mute factor slide + if (carrier_mf_signed_delta[i]!=0) + { + mf_slide(i); + } + } + } + + driver_active = false; + } + + return !songend; +} + + +void Cu6mPlayer::rewind(int subsong) +{ + played_ticks = 0; + songend = false; + + // set the driver's internal variables + byte_pair freq_word = {0,0}; + + driver_active = false; + song_pos = 0; + loop_position = 0; // position of the loop point + read_delay = 0; // delay (in timer ticks) before further song data is read + + for (int i = 0; i < 9; i++) + { + // frequency + channel_freq_signed_delta[i] = 0; + channel_freq[i] = freq_word; // Adlib freq settings for each channel + + // vibrato ("vb") + vb_current_value[i] = 0; + vb_double_amplitude[i] = 0; + vb_multiplier[i] = 0; + vb_direction_flag[i] = 0; + + // mute factor ("mf") == ~(volume) + carrier_mf[i] = 0; + carrier_mf_signed_delta[i] = 0; + carrier_mf_mod_delay_backup[i] = 0; + carrier_mf_mod_delay[i] = 0; + } + + while (!subsong_stack.empty()) // empty subsong stack + subsong_stack.pop(); + + opl->init(); + out_adlib(1,32); // go to OPL2 mode +} + + +float Cu6mPlayer::getrefresh() +{ + return ((float)60); // the Ultima 6 music driver expects to be called at 60 Hz +} + + +// ============================================================================================ +// +// +// Functions called by load() +// +// +// ============================================================================================ + + +// decompress from memory to memory +bool Cu6mPlayer::lzw_decompress(Cu6mPlayer::data_block source, Cu6mPlayer::data_block dest) +{ + bool end_marker_reached = false; + int codeword_size = 9; + long bits_read = 0; + int next_free_codeword = 0x102; + int dictionary_size = 0x200; + MyDict dictionary = MyDict(); + std::stack<unsigned char> root_stack; + + long bytes_written = 0; + + int cW; + int pW; + unsigned char C; + + while (!end_marker_reached) + { + cW = get_next_codeword(bits_read, source.data, codeword_size); + switch (cW) + { + // re-init the dictionary + case 0x100: + codeword_size = 9; + next_free_codeword = 0x102; + dictionary_size = 0x200; + dictionary.reset(); + cW = get_next_codeword(bits_read, source.data, codeword_size); + SAVE_OUTPUT_ROOT((unsigned char)cW, dest, bytes_written); + break; + // end of compressed file has been reached + case 0x101: + end_marker_reached = true; + break; + // (cW <> 0x100) && (cW <> 0x101) + default: + if (cW < next_free_codeword) // codeword is already in the dictionary + { + // create the string associated with cW (on the stack) + get_string(cW,dictionary,root_stack); + C = root_stack.top(); + // output the string represented by cW + while (!root_stack.empty()) + { + SAVE_OUTPUT_ROOT(root_stack.top(), dest, bytes_written); + root_stack.pop(); + } + // add pW+C to the dictionary + dictionary.add(C,pW); + + next_free_codeword++; + if (next_free_codeword >= dictionary_size) + { + if (codeword_size < max_codeword_length) + { + codeword_size += 1; + dictionary_size *= 2; + } + } + } + else // codeword is not yet defined + { + // create the string associated with pW (on the stack) + get_string(pW,dictionary,root_stack); + C = root_stack.top(); + // output the string represented by pW + while (!root_stack.empty()) + { + SAVE_OUTPUT_ROOT(root_stack.top(), dest, bytes_written); + root_stack.pop(); + } + // output the char C + SAVE_OUTPUT_ROOT(C, dest, bytes_written); + + // the new dictionary entry must correspond to cW + // if it doesn't, something is wrong with the lzw-compressed data. + if (cW != next_free_codeword) + { + /* printf("cW != next_free_codeword!\n"); + exit(-1); */ + return false; + } + // add pW+C to the dictionary + dictionary.add(C,pW); + + next_free_codeword++; + if (next_free_codeword >= dictionary_size) + { + if (codeword_size < max_codeword_length) + { + codeword_size += 1; + dictionary_size *= 2; + } + } + }; + break; + } + // shift roles - the current cW becomes the new pW + pW = cW; + } + + return(true); // indicate successful decompression +} + + +// -------------------- +// Additional functions +// -------------------- + + +// Read the next code word from the source buffer +int Cu6mPlayer::get_next_codeword (long& bits_read, unsigned char *source, int codeword_size) +{ + unsigned char b0,b1,b2; + int codeword; + + b0 = source[bits_read/8]; + b1 = source[bits_read/8+1]; + b2 = source[bits_read/8+2]; + + codeword = ((b2 << 16) + (b1 << 8) + b0); + codeword = codeword >> (bits_read % 8); + switch (codeword_size) + { + case 0x9: + codeword = codeword & 0x1ff; + break; + case 0xa: + codeword = codeword & 0x3ff; + break; + case 0xb: + codeword = codeword & 0x7ff; + break; + case 0xc: + codeword = codeword & 0xfff; + break; + default: + codeword = -1; // indicates that an error has occurred + break; + } + + bits_read += codeword_size; + return (codeword); +} + + +// output a root to memory +void Cu6mPlayer::output_root(unsigned char root, unsigned char *destination, long& position) +{ + destination[position] = root; + position++; +} + + +// output the string represented by a codeword +void Cu6mPlayer::get_string(int codeword, Cu6mPlayer::MyDict& dictionary, std::stack<unsigned char>& root_stack) +{ + unsigned char root; + int current_codeword; + + current_codeword = codeword; + + while (current_codeword > 0xff) + { + root = dictionary.get_root(current_codeword); + current_codeword = dictionary.get_codeword(current_codeword); + root_stack.push(root); + } + + // push the root at the leaf + root_stack.push((unsigned char)current_codeword); +} + + +// ============================================================================================ +// +// +// Functions called by update() +// +// +// ============================================================================================ + + +// This function reads the song data and executes the embedded commands. +void Cu6mPlayer::command_loop() +{ + unsigned char command_byte; // current command byte + int command_nibble_hi; // command byte, bits 4-7 + int command_nibble_lo; // command byte, bite 0-3 + bool repeat_loop = true; // + + do + { + // extract low and high command nibbles + command_byte = read_song_byte(); // implicitly increments song_pos + command_nibble_hi = command_byte >> 4; + command_nibble_lo = command_byte & 0xf; + + switch (command_nibble_hi) + { + case 0x0: command_0(command_nibble_lo); break; + case 0x1: command_1(command_nibble_lo); break; + case 0x2: command_2(command_nibble_lo); break; + case 0x3: command_3(command_nibble_lo); break; + case 0x4: command_4(command_nibble_lo); break; + case 0x5: command_5(command_nibble_lo); break; + case 0x6: command_6(command_nibble_lo); break; + case 0x7: command_7(command_nibble_lo); break; + case 0x8: + switch (command_nibble_lo) + { + case 1: command_81(); break; + case 2: command_82(); repeat_loop = false; break; + case 3: command_83(); break; + case 5: command_85(); break; + case 6: command_86(); break; + default: break; // maybe generate an error? + } + break; + case 0xE: command_E(); break; + case 0xF: command_F(); break; + default: break; // maybe generate an error? + } + + } while (repeat_loop); +} + + +// -------------------------------------------------------- +// The commands supported by the U6 music file format +// -------------------------------------------------------- + +// ---------------------------------------- +// Set octave and frequency, note off +// Format: 0c nn +// c = channel, nn = packed Adlib frequency +// ---------------------------------------- +void Cu6mPlayer::command_0(int channel) +{ + unsigned char freq_byte; + byte_pair freq_word; + + freq_byte = read_song_byte(); + freq_word = expand_freq_byte(freq_byte); + set_adlib_freq(channel,freq_word); +} + + +// --------------------------------------------------- +// Set octave and frequency, old note off, new note on +// Format: 1c nn +// c = channel, nn = packed Adlib frequency +// --------------------------------------------------- +void Cu6mPlayer::command_1(int channel) +{ + unsigned char freq_byte; + byte_pair freq_word; + + vb_direction_flag[channel] = 0; + vb_current_value[channel] = 0; + + freq_byte = read_song_byte(); + freq_word = expand_freq_byte(freq_byte); + set_adlib_freq(channel,freq_word); + + freq_word.hi = freq_word.hi | 0x20; // note on + set_adlib_freq(channel,freq_word); +} + + +// ---------------------------------------- +// Set octave and frequency, note on +// Format: 2c nn +// c = channel, nn = packed Adlib frequency +// ---------------------------------------- +void Cu6mPlayer::command_2(int channel) +{ + unsigned char freq_byte; + byte_pair freq_word; + + freq_byte = read_song_byte(); + freq_word = expand_freq_byte(freq_byte); + freq_word.hi = freq_word.hi | 0x20; // note on + set_adlib_freq(channel,freq_word); +} + + +// -------------------------------------- +// Set "carrier mute factor"==not(volume) +// Format: 3c nn +// c = channel, nn = mute factor +// -------------------------------------- +void Cu6mPlayer::command_3(int channel) +{ + unsigned char mf_byte; + + carrier_mf_signed_delta[channel] = 0; + mf_byte = read_song_byte(); + set_carrier_mf(channel,mf_byte); +} + + +// ---------------------------------------- +// set "modulator mute factor"==not(volume) +// Format: 4c nn +// c = channel, nn = mute factor +// ---------------------------------------- +void Cu6mPlayer::command_4(int channel) +{ + unsigned char mf_byte; + + mf_byte = read_song_byte(); + set_modulator_mf(channel,mf_byte); +} + + +// -------------------------------------------- +// Set portamento (pitch slide) +// Format: 5c nn +// c = channel, nn = signed channel pitch delta +// -------------------------------------------- +void Cu6mPlayer::command_5(int channel) +{ + channel_freq_signed_delta[channel] = read_signed_song_byte(); +} + + +// -------------------------------------------- +// Set vibrato paramters +// Format: 6c mn +// c = channel +// m = vibrato double amplitude +// n = vibrato multiplier +// -------------------------------------------- +void Cu6mPlayer::command_6(int channel) +{ + unsigned char vb_parameters; + + vb_parameters = read_song_byte(); + vb_double_amplitude[channel] = vb_parameters >> 4; // high nibble + vb_multiplier[channel] = vb_parameters & 0xF; // low nibble +} + + +// ---------------------------------------- +// Assign Adlib instrument to Adlib channel +// Format: 7c nn +// c = channel, nn = instrument number +// ---------------------------------------- +void Cu6mPlayer::command_7(int channel) +{ + int instrument_offset = instrument_offsets[read_song_byte()]; + out_adlib_opcell(channel, false, 0x20, *(song_data + instrument_offset+0)); + out_adlib_opcell(channel, false, 0x40, *(song_data + instrument_offset+1)); + out_adlib_opcell(channel, false, 0x60, *(song_data + instrument_offset+2)); + out_adlib_opcell(channel, false, 0x80, *(song_data + instrument_offset+3)); + out_adlib_opcell(channel, false, 0xE0, *(song_data + instrument_offset+4)); + out_adlib_opcell(channel, true, 0x20, *(song_data + instrument_offset+5)); + out_adlib_opcell(channel, true, 0x40, *(song_data + instrument_offset+6)); + out_adlib_opcell(channel, true, 0x60, *(song_data + instrument_offset+7)); + out_adlib_opcell(channel, true, 0x80, *(song_data + instrument_offset+8)); + out_adlib_opcell(channel, true, 0xE0, *(song_data + instrument_offset+9)); + out_adlib(0xC0+channel, *(song_data + instrument_offset+10)); +} + + +// ------------------------------------------- +// Branch to a new subsong +// Format: 81 nn aa bb +// nn == number of times to repeat the subsong +// aa == subsong offset (low byte) +// bb == subsong offset (high byte) +// ------------------------------------------- +void Cu6mPlayer::command_81() +{ + subsong_info new_ss_info; + + new_ss_info.subsong_repetitions = read_song_byte(); + new_ss_info.subsong_start = read_song_byte(); new_ss_info.subsong_start += read_song_byte() << 8; + new_ss_info.continue_pos = song_pos; + + subsong_stack.push(new_ss_info); + song_pos = new_ss_info.subsong_start; +} + + +// ------------------------------------------------------------ +// Stop interpreting commands for this timer tick +// Format: 82 nn +// nn == delay (in timer ticks) until further data will be read +// ------------------------------------------------------------ +void Cu6mPlayer::command_82() +{ + read_delay = read_song_byte(); +} + + +// ----------------------------- +// Adlib instrument data follows +// Format: 83 nn <11 bytes> +// nn == instrument number +// ----------------------------- +void Cu6mPlayer::command_83() +{ + unsigned char instrument_number = read_song_byte(); + instrument_offsets[instrument_number] = song_pos; + song_pos += 11; +} + + +// ---------------------------------------------- +// Set -1 mute factor slide (upward volume slide) +// Format: 85 cn +// c == channel +// n == slide delay +// ---------------------------------------------- +void Cu6mPlayer::command_85() +{ + unsigned char data_byte = read_song_byte(); + int channel = data_byte >> 4; // high nibble + unsigned char slide_delay = data_byte & 0xF; // low nibble + carrier_mf_signed_delta[channel] = +1; + carrier_mf_mod_delay[channel] = slide_delay + 1; + carrier_mf_mod_delay_backup[channel] = slide_delay + 1; +} + + +// ------------------------------------------------ +// Set +1 mute factor slide (downward volume slide) +// Format: 86 cn +// c == channel +// n == slide speed +// ------------------------------------------------ +void Cu6mPlayer::command_86() +{ + unsigned char data_byte = read_song_byte(); + int channel = data_byte >> 4; // high nibble + unsigned char slide_delay = data_byte & 0xF; // low nibble + carrier_mf_signed_delta[channel] = -1; + carrier_mf_mod_delay[channel] = slide_delay + 1; + carrier_mf_mod_delay_backup[channel] = slide_delay + 1; +} + + +// -------------- +// Set loop point +// Format: E? +// -------------- +void Cu6mPlayer::command_E() +{ + loop_position = song_pos; +} + + +// --------------------------- +// Return from current subsong +// Format: F? +// --------------------------- +void Cu6mPlayer::command_F() +{ + if (!subsong_stack.empty()) + { + subsong_info temp = subsong_stack.top(); + subsong_stack.pop(); + temp.subsong_repetitions--; + if (temp.subsong_repetitions==0) + { + song_pos = temp.continue_pos; + } + else + { + song_pos = temp.subsong_start; + subsong_stack.push(temp); + } + } + else + { + song_pos = loop_position; + songend = true; + } +} + + +// -------------------- +// Additional functions +// -------------------- + +// This function decrements its argument, without allowing it to become negative. +void Cu6mPlayer::dec_clip(int& param) +{ + param--; + if (param < 0) { param = 0; } +} + + +// Returns the byte at the current song position. +// Side effect: increments song_pos. +unsigned char Cu6mPlayer::read_song_byte() +{ + unsigned char song_byte; + song_byte = song_data[song_pos]; + song_pos++; + return(song_byte); +} + + +// Same as read_song_byte(), except that it returns a signed byte +signed char Cu6mPlayer::read_signed_song_byte() +{ + unsigned char song_byte; + int signed_value; + song_byte = *(song_data + song_pos); + song_pos++; + if (song_byte <= 127) + { + signed_value = song_byte; + } + else + { + signed_value = (int)song_byte - 0x100; + } + return((signed char)signed_value); +} + + +Cu6mPlayer::byte_pair Cu6mPlayer::expand_freq_byte(unsigned char freq_byte) +{ + const byte_pair freq_table[24] = + { + {0x00,0x00}, {0x58,0x01}, {0x82,0x01}, {0xB0,0x01}, + {0xCC,0x01}, {0x03,0x02}, {0x41,0x02}, {0x86,0x02}, + {0x00,0x00}, {0x6A,0x01}, {0x96,0x01}, {0xC7,0x01}, + {0xE4,0x01}, {0x1E,0x02}, {0x5F,0x02}, {0xA8,0x02}, + {0x00,0x00}, {0x47,0x01}, {0x6E,0x01}, {0x9A,0x01}, + {0xB5,0x01}, {0xE9,0x01}, {0x24,0x02}, {0x66,0x02} + }; + + int packed_freq; + int octave; + byte_pair freq_word; + + packed_freq = freq_byte & 0x1F; + octave = freq_byte >> 5; + + // range check (not present in the original U6 music driver) + if (packed_freq >= 24) { packed_freq = 0; } + + freq_word.hi = freq_table[packed_freq].hi + (octave << 2); + freq_word.lo = freq_table[packed_freq].lo; + + return(freq_word); +} + + +void Cu6mPlayer::set_adlib_freq(int channel,Cu6mPlayer::byte_pair freq_word) +{ + out_adlib(0xA0+channel,freq_word.lo); + out_adlib(0xB0+channel,freq_word.hi); + // update the Adlib register backups + channel_freq[channel] = freq_word; +} + + +// this function sets the Adlib frequency, but does not update the register backups +void Cu6mPlayer::set_adlib_freq_no_update(int channel,Cu6mPlayer::byte_pair freq_word) +{ + out_adlib(0xA0+channel,freq_word.lo); + out_adlib(0xB0+channel,freq_word.hi); +} + + +void Cu6mPlayer::set_carrier_mf(int channel,unsigned char mute_factor) +{ + out_adlib_opcell(channel,true,0x40,mute_factor); + carrier_mf[channel] = mute_factor; +} + + +void Cu6mPlayer::set_modulator_mf(int channel,unsigned char mute_factor) +{ + out_adlib_opcell(channel,false,0x40,mute_factor); +} + + +void Cu6mPlayer::freq_slide(int channel) +{ + byte_pair freq = channel_freq[channel]; + + long freq_word = freq.lo + (freq.hi << 8) + channel_freq_signed_delta[channel]; + if (freq_word < 0) { freq_word += 0x10000; } + if (freq_word > 0xFFFF) { freq_word -= 0x10000; } + + freq.lo = freq_word & 0xFF; + freq.hi = (freq_word >> 8) & 0xFF; + set_adlib_freq(channel,freq); +} + + +void Cu6mPlayer::vibrato(int channel) +{ + byte_pair freq; + + if (vb_current_value[channel] >= vb_double_amplitude[channel]) + { vb_direction_flag[channel] = 1; } + else if (vb_current_value[channel] <= 0) + { vb_direction_flag[channel] = 0; } + + if (vb_direction_flag[channel]==0) + { vb_current_value[channel]++; } + else + { vb_current_value[channel]--; } + + long freq_word = channel_freq[channel].lo + (channel_freq[channel].hi << 8); + freq_word += (vb_current_value[channel] - (vb_double_amplitude[channel] >> 1)) + * vb_multiplier[channel]; + if (freq_word < 0) { freq_word += 0x10000; } + if (freq_word > 0xFFFF) { freq_word -= 0x10000; } + + freq.lo = freq_word & 0xFF; + freq.hi = (freq_word >> 8) & 0xFF; + set_adlib_freq_no_update(channel,freq); +} + + +void Cu6mPlayer::mf_slide(int channel) +{ + carrier_mf_mod_delay[channel]--; + if (carrier_mf_mod_delay[channel]==0) + { + carrier_mf_mod_delay[channel] = carrier_mf_mod_delay_backup[channel]; + int current_mf = carrier_mf[channel] + carrier_mf_signed_delta[channel]; + if (current_mf > 0x3F) + { + current_mf = 0x3F; + carrier_mf_signed_delta[channel] = 0; + } + else if (current_mf < 0) + { + current_mf = 0; + carrier_mf_signed_delta[channel] = 0; + } + + set_carrier_mf(channel,(unsigned char)current_mf); + } +} + + +void Cu6mPlayer::out_adlib(unsigned char adlib_register, unsigned char adlib_data) +{ + opl->write(adlib_register,adlib_data); +} + + +void Cu6mPlayer::out_adlib_opcell(int channel, bool carrier, unsigned char adlib_register, unsigned char out_byte) +{ + const unsigned char adlib_channel_to_carrier_offset[9] = + {0x03,0x04,0x05,0x0B,0x0C,0x0D,0x13,0x14,0x15}; + const unsigned char adlib_channel_to_modulator_offset[9] = + {0x00,0x01,0x02,0x08,0x09,0x0A,0x10,0x11,0x12}; + + if (carrier) + { + out_adlib(adlib_register+adlib_channel_to_carrier_offset[channel],out_byte); + } + else + { + out_adlib(adlib_register+adlib_channel_to_modulator_offset[channel],out_byte); + } +} + + +// ============================================================================================ +// +// +// The Dictionary +// +// +// ============================================================================================ + + +Cu6mPlayer::MyDict::MyDict() +{ + dict_size = default_dict_size; + dictionary = new dict_entry[dict_size-0x100]; // don't allocate space for the roots + contains = 0x102; +} + + +Cu6mPlayer::MyDict::MyDict(int max_size) +{ + dict_size = max_size; + dictionary = new dict_entry[dict_size-0x100]; // don't allocate space for the roots + contains = 0x102; +} + + +Cu6mPlayer::MyDict::~MyDict() +{ + delete [] dictionary; +} + +// re-initializes the dictionary +void Cu6mPlayer::MyDict::reset() +{ + contains = 0x102; +} + + +// Note: If the dictionary is already full, this function does nothing. +void Cu6mPlayer::MyDict::add(unsigned char root, int codeword) +{ + if (contains < dict_size) + { + dictionary[contains-0x100].root = root; + dictionary[contains-0x100].codeword = codeword; + contains++; + } +} + + +unsigned char Cu6mPlayer::MyDict::get_root(int codeword) +{ + return (dictionary[codeword-0x100].root); +} + + +int Cu6mPlayer::MyDict::get_codeword(int codeword) +{ + return (dictionary[codeword-0x100].codeword); +} +
--- a/Plugins/Input/adplug/core/xad.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* - 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.cpp - XAD shell player by Riven the Mage <riven@ok.ru> -*/ - -#include "xad.h" -#include "debug.h" - -/* -------- Public Methods -------------------------------- */ - -CxadPlayer::CxadPlayer(Copl * newopl) : CPlayer(newopl) -{ - tune = 0; -} - -CxadPlayer::~CxadPlayer() -{ - if (tune) - delete [] tune; -} - -bool CxadPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - bool ret = false; - - // load header - xad.id = f->readInt(4); - f->readString(xad.title, 36); - f->readString(xad.author, 36); - xad.fmt = f->readInt(2); - xad.speed = f->readInt(1); - xad.reserved_a = f->readInt(1); - - // 'XAD!' - signed ? - if(xad.id != 0x21444158) { fp.close(f); return false; } - - // get file size - tune_size = fp.filesize(f) - 80; - - // load() - tune = new unsigned char [tune_size]; - f->readString((char *)tune, tune_size); - fp.close(f); - - ret = xadplayer_load(); - - if (ret) - rewind(0); - - return ret; -} - -void CxadPlayer::rewind(int subsong) -{ - opl->init(); - - plr.speed = xad.speed; - plr.speed_counter = 1; - plr.playing = 1; - plr.looping = 0; - - // rewind() - xadplayer_rewind(subsong); - -#ifdef DEBUG - AdPlug_LogWrite("-----------\n"); -#endif -} - -bool CxadPlayer::update() -{ - if (--plr.speed_counter) - goto update_end; - - plr.speed_counter = plr.speed; - - // update() - xadplayer_update(); - -update_end: - return (plr.playing && (!plr.looping)); -} - -float CxadPlayer::getrefresh() -{ - return xadplayer_getrefresh(); -} - -std::string CxadPlayer::gettype() -{ - return xadplayer_gettype(); -} - -std::string CxadPlayer::gettitle() -{ - return xadplayer_gettitle(); -} - -std::string CxadPlayer::getauthor() -{ - return xadplayer_getauthor(); -} - -std::string CxadPlayer::getinstrument(unsigned int i) -{ - return xadplayer_getinstrument(i); -} - -unsigned int CxadPlayer::getinstruments() -{ - return xadplayer_getinstruments(); -} - -/* -------- Protected Methods ------------------------------- */ - -void CxadPlayer::opl_write(int reg, int val) -{ - adlib[reg] = val; -#ifdef DEBUG - AdPlug_LogWrite("[ %02X ] = %02X\n",reg,val); -#endif - opl->write(reg,val); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/xad.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,140 @@ +/* + 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.cpp - XAD shell player by Riven the Mage <riven@ok.ru> +*/ + +#include "xad.h" +#include "debug.h" + +/* -------- Public Methods -------------------------------- */ + +CxadPlayer::CxadPlayer(Copl * newopl) : CPlayer(newopl) +{ + tune = 0; +} + +CxadPlayer::~CxadPlayer() +{ + if (tune) + delete [] tune; +} + +bool CxadPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + bool ret = false; + + // load header + xad.id = f->readInt(4); + f->readString(xad.title, 36); + f->readString(xad.author, 36); + xad.fmt = f->readInt(2); + xad.speed = f->readInt(1); + xad.reserved_a = f->readInt(1); + + // 'XAD!' - signed ? + if(xad.id != 0x21444158) { fp.close(f); return false; } + + // get file size + tune_size = fp.filesize(f) - 80; + + // load() + tune = new unsigned char [tune_size]; + f->readString((char *)tune, tune_size); + fp.close(f); + + ret = xadplayer_load(); + + if (ret) + rewind(0); + + return ret; +} + +void CxadPlayer::rewind(int subsong) +{ + opl->init(); + + plr.speed = xad.speed; + plr.speed_counter = 1; + plr.playing = 1; + plr.looping = 0; + + // rewind() + xadplayer_rewind(subsong); + +#ifdef DEBUG + AdPlug_LogWrite("-----------\n"); +#endif +} + +bool CxadPlayer::update() +{ + if (--plr.speed_counter) + goto update_end; + + plr.speed_counter = plr.speed; + + // update() + xadplayer_update(); + +update_end: + return (plr.playing && (!plr.looping)); +} + +float CxadPlayer::getrefresh() +{ + return xadplayer_getrefresh(); +} + +std::string CxadPlayer::gettype() +{ + return xadplayer_gettype(); +} + +std::string CxadPlayer::gettitle() +{ + return xadplayer_gettitle(); +} + +std::string CxadPlayer::getauthor() +{ + return xadplayer_getauthor(); +} + +std::string CxadPlayer::getinstrument(unsigned int i) +{ + return xadplayer_getinstrument(i); +} + +unsigned int CxadPlayer::getinstruments() +{ + return xadplayer_getinstruments(); +} + +/* -------- Protected Methods ------------------------------- */ + +void CxadPlayer::opl_write(int reg, int val) +{ + adlib[reg] = val; +#ifdef DEBUG + AdPlug_LogWrite("[ %02X ] = %02X\n",reg,val); +#endif + opl->write(reg,val); +}
--- a/Plugins/Input/adplug/core/xsm.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * 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 - * - * xsm.cpp - eXtra Simple Music Player, by Simon Peter <dn.tlp@gmx.net> - */ - -#include <string.h> - -#include "xsm.h" - -CxsmPlayer::CxsmPlayer(Copl *newopl) - : CPlayer(newopl), music(0) -{ -} - -CxsmPlayer::~CxsmPlayer() -{ - if(music) delete [] music; -} - -bool CxsmPlayer::load(const std::string &filename, const CFileProvider &fp) -{ - binistream *f = fp.open(filename); if(!f) return false; - char id[6]; - int i, j; - - // check if header matches - f->readString(id, 6); songlen = f->readInt(2); - if(strncmp(id, "ofTAZ!", 6) || songlen > 3200) { fp.close(f); return false; } - - // read and set instruments - for(i = 0; i < 9; i++) { - opl->write(0x20 + op_table[i], f->readInt(1)); - opl->write(0x23 + op_table[i], f->readInt(1)); - opl->write(0x40 + op_table[i], f->readInt(1)); - opl->write(0x43 + op_table[i], f->readInt(1)); - opl->write(0x60 + op_table[i], f->readInt(1)); - opl->write(0x63 + op_table[i], f->readInt(1)); - opl->write(0x80 + op_table[i], f->readInt(1)); - opl->write(0x83 + op_table[i], f->readInt(1)); - opl->write(0xe0 + op_table[i], f->readInt(1)); - opl->write(0xe3 + op_table[i], f->readInt(1)); - opl->write(0xc0 + op_table[i], f->readInt(1)); - f->ignore(5); - } - - // read song data - music = new char [songlen * 9]; - for(i = 0; i < 9; i++) - for(j = 0; j < songlen; j++) - music[j * 9 + i] = f->readInt(1); - - // success - fp.close(f); - rewind(0); - return true; -} - -bool CxsmPlayer::update() -{ - int c; - - if(notenum >= songlen) { - songend = true; - notenum = last = 0; - } - - for(c = 0; c < 9; c++) - if(music[notenum * 9 + c] != music[last * 9 + c]) - opl->write(0xb0 + c, 0); - - for(c = 0; c < 9; c++) { - if(music[notenum * 9 + c]) - play_note(c, music[notenum * 9 + c] % 12, music[notenum * 9 + c] / 12); - else - play_note(c, 0, 0); - } - - last = notenum; - notenum++; - return !songend; -} - -void CxsmPlayer::rewind(int subsong) -{ - notenum = last = 0; - songend = false; -} - -float CxsmPlayer::getrefresh() -{ - return 5.0f; -} - -void CxsmPlayer::play_note(int c, int note, int octv) -{ - int freq = note_table[note]; - - if(!note && !octv) freq = 0; - opl->write(0xa0 + c, freq & 0xff); - opl->write(0xb0 + c, (freq / 0xff) | 32 | (octv * 4)); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/adplug/core/xsm.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,117 @@ +/* + * 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 + * + * xsm.cpp - eXtra Simple Music Player, by Simon Peter <dn.tlp@gmx.net> + */ + +#include <string.h> + +#include "xsm.h" + +CxsmPlayer::CxsmPlayer(Copl *newopl) + : CPlayer(newopl), music(0) +{ +} + +CxsmPlayer::~CxsmPlayer() +{ + if(music) delete [] music; +} + +bool CxsmPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + char id[6]; + int i, j; + + // check if header matches + f->readString(id, 6); songlen = f->readInt(2); + if(strncmp(id, "ofTAZ!", 6) || songlen > 3200) { fp.close(f); return false; } + + // read and set instruments + for(i = 0; i < 9; i++) { + opl->write(0x20 + op_table[i], f->readInt(1)); + opl->write(0x23 + op_table[i], f->readInt(1)); + opl->write(0x40 + op_table[i], f->readInt(1)); + opl->write(0x43 + op_table[i], f->readInt(1)); + opl->write(0x60 + op_table[i], f->readInt(1)); + opl->write(0x63 + op_table[i], f->readInt(1)); + opl->write(0x80 + op_table[i], f->readInt(1)); + opl->write(0x83 + op_table[i], f->readInt(1)); + opl->write(0xe0 + op_table[i], f->readInt(1)); + opl->write(0xe3 + op_table[i], f->readInt(1)); + opl->write(0xc0 + op_table[i], f->readInt(1)); + f->ignore(5); + } + + // read song data + music = new char [songlen * 9]; + for(i = 0; i < 9; i++) + for(j = 0; j < songlen; j++) + music[j * 9 + i] = f->readInt(1); + + // success + fp.close(f); + rewind(0); + return true; +} + +bool CxsmPlayer::update() +{ + int c; + + if(notenum >= songlen) { + songend = true; + notenum = last = 0; + } + + for(c = 0; c < 9; c++) + if(music[notenum * 9 + c] != music[last * 9 + c]) + opl->write(0xb0 + c, 0); + + for(c = 0; c < 9; c++) { + if(music[notenum * 9 + c]) + play_note(c, music[notenum * 9 + c] % 12, music[notenum * 9 + c] / 12); + else + play_note(c, 0, 0); + } + + last = notenum; + notenum++; + return !songend; +} + +void CxsmPlayer::rewind(int subsong) +{ + notenum = last = 0; + songend = false; +} + +float CxsmPlayer::getrefresh() +{ + return 5.0f; +} + +void CxsmPlayer::play_note(int c, int note, int octv) +{ + int freq = note_table[note]; + + if(!note && !octv) freq = 0; + opl->write(0xa0 + c, freq & 0xff); + opl->write(0xb0 + c, (freq / 0xff) | 32 | (octv * 4)); +}
--- a/Plugins/Input/modplug/Makefile.in Sat Sep 16 07:18:18 2006 -0700 +++ b/Plugins/Input/modplug/Makefile.in Sat Sep 16 07:33:28 2006 -0700 @@ -8,8 +8,8 @@ CXXFLAGS += $(PICFLAGS) $(GTK_CFLAGS) -I.. -I../../.. -I../../../intl LIBADD = $(GTK_LIBS) -lstdc++ -lmodplug ./archive/libarchive.a ./gui/libgui.a -SOURCES = plugin.cpp modplugbmp.cpp +SOURCES = plugin.cxx modplugbmp.cxx -OBJECTS = ${SOURCES:.cpp=.o} +OBJECTS = ${SOURCES:.cxx=.o} include ../../../mk/objective.mk
--- a/Plugins/Input/modplug/archive/Makefile.in Sat Sep 16 07:18:18 2006 -0700 +++ b/Plugins/Input/modplug/archive/Makefile.in Sat Sep 16 07:33:28 2006 -0700 @@ -5,14 +5,14 @@ OBJECTIVE_LIBS_NOINST = libarchive.a -SOURCES = archive.cpp \ - open.cpp \ - arch_raw.cpp \ - arch_gzip.cpp \ - arch_zip.cpp \ - arch_rar.cpp \ - arch_bz2.cpp +SOURCES = archive.cxx \ + open.cxx \ + arch_raw.cxx \ + arch_gzip.cxx \ + arch_zip.cxx \ + arch_rar.cxx \ + arch_bz2.cxx -OBJECTS = ${SOURCES:.cpp=.o} +OBJECTS = ${SOURCES:.cxx=.o} include ../../../../mk/objective.mk
--- a/Plugins/Input/modplug/archive/arch_bz2.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* Modplug XMMS Plugin - * Authors: Kenton Varda <temporal@gauge3d.org> - * Colin DeVilbiss <crdevilb@mtu.edu> - * - * This source code is public domain. - */ - -// BZ2 support added by Colin DeVilbiss <crdevilb@mtu.edu> - -//open() -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> - -#include "arch_bz2.h" -#include <iostream> - -arch_Bzip2::arch_Bzip2(const string& aFileName) -{ - //check if file exists - int lFileDesc = open(aFileName.c_str(), O_RDONLY); - - if(lFileDesc == -1) - { - mSize = 0; - return; - } - - close(lFileDesc); - - //ok, continue - string lCommand = "bzcat \'" + aFileName + "\' | wc -c"; //get info - FILE *f = popen(lCommand.c_str(), "r"); - - if (f <= 0) - { - mSize = 0; - return; - } - - fscanf(f, "%u", &mSize); // this is the size. - - pclose(f); - - mMap = new char[mSize]; - if(mMap == NULL) - { - mSize = 0; - return; - } - - lCommand = "bzcat \'" + aFileName + '\''; //decompress to stdout - popen(lCommand.c_str(), "r"); - - if (f <= 0) - { - mSize = 0; - return; - } - - fread((char *)mMap, sizeof(char), mSize, f); - - pclose(f); -} - -arch_Bzip2::~arch_Bzip2() -{ - if(mSize != 0) - delete [] (char*)mMap; -} - -bool arch_Bzip2::ContainsMod(const string& aFileName) -{ - string lName; - int lFileDesc = open(aFileName.c_str(), O_RDONLY); - if(lFileDesc == -1) - return false; - - close(lFileDesc); - - lName = aFileName.substr(0, aFileName.find_last_of('.')); - return IsOurFile(lName); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/archive/arch_bz2.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,85 @@ +/* Modplug XMMS Plugin + * Authors: Kenton Varda <temporal@gauge3d.org> + * Colin DeVilbiss <crdevilb@mtu.edu> + * + * This source code is public domain. + */ + +// BZ2 support added by Colin DeVilbiss <crdevilb@mtu.edu> + +//open() +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> + +#include "arch_bz2.h" +#include <iostream> + +arch_Bzip2::arch_Bzip2(const string& aFileName) +{ + //check if file exists + int lFileDesc = open(aFileName.c_str(), O_RDONLY); + + if(lFileDesc == -1) + { + mSize = 0; + return; + } + + close(lFileDesc); + + //ok, continue + string lCommand = "bzcat \'" + aFileName + "\' | wc -c"; //get info + FILE *f = popen(lCommand.c_str(), "r"); + + if (f <= 0) + { + mSize = 0; + return; + } + + fscanf(f, "%u", &mSize); // this is the size. + + pclose(f); + + mMap = new char[mSize]; + if(mMap == NULL) + { + mSize = 0; + return; + } + + lCommand = "bzcat \'" + aFileName + '\''; //decompress to stdout + popen(lCommand.c_str(), "r"); + + if (f <= 0) + { + mSize = 0; + return; + } + + fread((char *)mMap, sizeof(char), mSize, f); + + pclose(f); +} + +arch_Bzip2::~arch_Bzip2() +{ + if(mSize != 0) + delete [] (char*)mMap; +} + +bool arch_Bzip2::ContainsMod(const string& aFileName) +{ + string lName; + int lFileDesc = open(aFileName.c_str(), O_RDONLY); + if(lFileDesc == -1) + return false; + + close(lFileDesc); + + lName = aFileName.substr(0, aFileName.find_last_of('.')); + return IsOurFile(lName); +}
--- a/Plugins/Input/modplug/archive/arch_gzip.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* Modplug XMMS Plugin - * Authors: Kenton Varda <temporal@gauge3d.org> - * - * This source code is public domain. - */ - -//open() -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> - -#include "arch_gzip.h" - - -arch_Gzip::arch_Gzip(const string& aFileName) -{ - //check if file exists - int lFileDesc = open(aFileName.c_str(), O_RDONLY); - - if(lFileDesc == -1) - { - mSize = 0; - return; - } - close(lFileDesc); - - // file exists. - string lCommand = "gunzip -l \"" + aFileName + '\"'; //get info - FILE *f = popen(lCommand.c_str(), "r"); - - if (f <= 0) - { - mSize = 0; - return; - } - - char line[81]; - fgets(line, 80, f); // ignore a line. - fscanf(f, "%u", &mSize); // ignore first number. - fscanf(f, "%u", &mSize); // keep second number. - - pclose(f); - - mMap = new char[mSize]; - if(mMap == NULL) - { - mSize = 0; - return; - } - - lCommand = "gunzip -c \"" + aFileName + '\"'; //decompress to stdout - f = popen(lCommand.c_str(), "r"); - - if (f <= 0) - { - mSize = 0; - return; - } - - fread((char *)mMap, sizeof(char), mSize, f); - - pclose(f); - -} - -arch_Gzip::~arch_Gzip() -{ - if(mSize != 0) - delete [] (char*)mMap; -} - -bool arch_Gzip::ContainsMod(const string& aFileName) -{ - string lName; - int lFileDesc = open(aFileName.c_str(), O_RDONLY); - uint32 num; - float fnum; - - if(lFileDesc == -1) - return false; - - close(lFileDesc); - - // file exists. - string lCommand = "gunzip -l \"" + aFileName + '\"'; //get info - FILE *f = popen(lCommand.c_str(),"r"); - - if (f <= 0) { - pclose(f); - return false; - } - - char line[300]; - fgets(line, 80, f); // ignore a line. - fscanf(f, "%i", &num); // ignore first number - fscanf(f, "%i", &num); // ignore second number - fscanf(f, "%f%%", &fnum); // ignore ratio - fgets(line, 300, f); // read in correct line safely. - if (strlen(line) > 1) - line[strlen(line)-1] = 0; - lName = line; - - pclose(f); - - return IsOurFile(lName); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/archive/arch_gzip.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,108 @@ +/* Modplug XMMS Plugin + * Authors: Kenton Varda <temporal@gauge3d.org> + * + * This source code is public domain. + */ + +//open() +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> + +#include "arch_gzip.h" + + +arch_Gzip::arch_Gzip(const string& aFileName) +{ + //check if file exists + int lFileDesc = open(aFileName.c_str(), O_RDONLY); + + if(lFileDesc == -1) + { + mSize = 0; + return; + } + close(lFileDesc); + + // file exists. + string lCommand = "gunzip -l \"" + aFileName + '\"'; //get info + FILE *f = popen(lCommand.c_str(), "r"); + + if (f <= 0) + { + mSize = 0; + return; + } + + char line[81]; + fgets(line, 80, f); // ignore a line. + fscanf(f, "%u", &mSize); // ignore first number. + fscanf(f, "%u", &mSize); // keep second number. + + pclose(f); + + mMap = new char[mSize]; + if(mMap == NULL) + { + mSize = 0; + return; + } + + lCommand = "gunzip -c \"" + aFileName + '\"'; //decompress to stdout + f = popen(lCommand.c_str(), "r"); + + if (f <= 0) + { + mSize = 0; + return; + } + + fread((char *)mMap, sizeof(char), mSize, f); + + pclose(f); + +} + +arch_Gzip::~arch_Gzip() +{ + if(mSize != 0) + delete [] (char*)mMap; +} + +bool arch_Gzip::ContainsMod(const string& aFileName) +{ + string lName; + int lFileDesc = open(aFileName.c_str(), O_RDONLY); + uint32 num; + float fnum; + + if(lFileDesc == -1) + return false; + + close(lFileDesc); + + // file exists. + string lCommand = "gunzip -l \"" + aFileName + '\"'; //get info + FILE *f = popen(lCommand.c_str(),"r"); + + if (f <= 0) { + pclose(f); + return false; + } + + char line[300]; + fgets(line, 80, f); // ignore a line. + fscanf(f, "%i", &num); // ignore first number + fscanf(f, "%i", &num); // ignore second number + fscanf(f, "%f%%", &fnum); // ignore ratio + fgets(line, 300, f); // read in correct line safely. + if (strlen(line) > 1) + line[strlen(line)-1] = 0; + lName = line; + + pclose(f); + + return IsOurFile(lName); +}
--- a/Plugins/Input/modplug/archive/arch_rar.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -/* Modplug XMMS Plugin - * Authors: Kenton Varda <temporal@gauge3d.org> - * - * This source code is public domain. - */ - -//open() -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> - -#include "arch_rar.h" -#include <iostream> -#include <vector> - -arch_Rar::arch_Rar(const string& aFileName) -{ - //check if file exists - int lFileDesc = open(aFileName.c_str(), O_RDONLY); - char lBuffer[350]; - uint32 lLength; - uint32 lCount; - uint32 lPos = 0; - bool lFound = false; - string lName, lGoodName; - - if(lFileDesc == -1) - { - mSize = 0; - return; - } - - close(lFileDesc); - - string lCommand = "unrar l \"" + aFileName + '\"'; //get info - FILE *f = popen(lCommand.c_str(), "r"); - - if(f <= 0) - { - mSize = 0; - return; - } - - int num = 7; - while (num--) // ignore 7 lines. - fgets(lBuffer, 90, f); - - bool eof = false; - while(!eof) - { - if(fgets(lBuffer, 350, f) <= 0 || f <= 0) - break; - if (strlen(lBuffer) > 1) - lBuffer[strlen(lBuffer)-1] = 0; - - lLength = strlen(lBuffer); - lCount = 0; - for(uint32 i = lLength - 1; i > 0; i--) - { - if(lBuffer[i] == ' ') - { - lBuffer[i] = 0; - if(lBuffer[i - 1] != ' ') - { - lCount++; - if(lCount == 9) - { - lPos = i; - break; - } - } - } - } - - while(lBuffer[lPos] == '\0') - lPos++; - lName = &lBuffer[1]; // get rid of the space. - - mSize = strtol(lBuffer + lPos, NULL, 10); - - if(IsOurFile(lName)) - { - lFound = true; - break; - } - } - - if(!lFound) - { - mSize = 0; - return; - } - - pclose(f); - - mMap = new char[mSize]; - if(mMap == NULL) - { - mSize = 0; - return; - } - - lCommand = "unrar p -inul \"" + aFileName + "\" \"" + lName + '\"'; - //decompress to stdout - f = popen(lCommand.c_str(), "r"); - - if (f <= 0) - { - mSize = 0; - return; - } - - fread((char *)mMap, sizeof(char), mSize, f); - - pclose(f); -} - -arch_Rar::~arch_Rar() -{ - if(mSize != 0) - delete [] (char*)mMap; -} - -bool arch_Rar::ContainsMod(const string& aFileName) -{ - //check if file exists - string lName; - int lFileDesc = open(aFileName.c_str(), O_RDONLY); - char lBuffer[350]; - uint32 lLength; - uint32 lCount; - - if(lFileDesc == -1) - return false; - - close(lFileDesc); - - string lCommand = "unrar l \"" + aFileName + '\"'; //get info - FILE *f = popen(lCommand.c_str(), "r"); - - if(f <= 0) - return false; - - int num = 7; - while (num--) - fgets(lBuffer, 90, f); //ignore a line. - - bool eof = false; - while(!eof) - { - if(fgets(lBuffer, 350, f) || f <= 0) - if(f <= 0) - break; - if (strlen(lBuffer) > 1) - lBuffer[strlen(lBuffer)-1] = 0; - - lLength = strlen(lBuffer); - lCount = 0; - for(uint32 i = lLength - 1; i > 0; i--) - { - if(lBuffer[i] == ' ') - { - lBuffer[i] = 0; - if(lBuffer[i - 1] != ' ') - { - lCount++; - if(lCount == 9) - break; - } - } - } - - lName = lBuffer; - - if(IsOurFile(lName)) { - pclose(f); - return true; - } - } - - pclose(f); - return false; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/archive/arch_rar.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,185 @@ +/* Modplug XMMS Plugin + * Authors: Kenton Varda <temporal@gauge3d.org> + * + * This source code is public domain. + */ + +//open() +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> + +#include "arch_rar.h" +#include <iostream> +#include <vector> + +arch_Rar::arch_Rar(const string& aFileName) +{ + //check if file exists + int lFileDesc = open(aFileName.c_str(), O_RDONLY); + char lBuffer[350]; + uint32 lLength; + uint32 lCount; + uint32 lPos = 0; + bool lFound = false; + string lName, lGoodName; + + if(lFileDesc == -1) + { + mSize = 0; + return; + } + + close(lFileDesc); + + string lCommand = "unrar l \"" + aFileName + '\"'; //get info + FILE *f = popen(lCommand.c_str(), "r"); + + if(f <= 0) + { + mSize = 0; + return; + } + + int num = 7; + while (num--) // ignore 7 lines. + fgets(lBuffer, 90, f); + + bool eof = false; + while(!eof) + { + if(fgets(lBuffer, 350, f) <= 0 || f <= 0) + break; + if (strlen(lBuffer) > 1) + lBuffer[strlen(lBuffer)-1] = 0; + + lLength = strlen(lBuffer); + lCount = 0; + for(uint32 i = lLength - 1; i > 0; i--) + { + if(lBuffer[i] == ' ') + { + lBuffer[i] = 0; + if(lBuffer[i - 1] != ' ') + { + lCount++; + if(lCount == 9) + { + lPos = i; + break; + } + } + } + } + + while(lBuffer[lPos] == '\0') + lPos++; + lName = &lBuffer[1]; // get rid of the space. + + mSize = strtol(lBuffer + lPos, NULL, 10); + + if(IsOurFile(lName)) + { + lFound = true; + break; + } + } + + if(!lFound) + { + mSize = 0; + return; + } + + pclose(f); + + mMap = new char[mSize]; + if(mMap == NULL) + { + mSize = 0; + return; + } + + lCommand = "unrar p -inul \"" + aFileName + "\" \"" + lName + '\"'; + //decompress to stdout + f = popen(lCommand.c_str(), "r"); + + if (f <= 0) + { + mSize = 0; + return; + } + + fread((char *)mMap, sizeof(char), mSize, f); + + pclose(f); +} + +arch_Rar::~arch_Rar() +{ + if(mSize != 0) + delete [] (char*)mMap; +} + +bool arch_Rar::ContainsMod(const string& aFileName) +{ + //check if file exists + string lName; + int lFileDesc = open(aFileName.c_str(), O_RDONLY); + char lBuffer[350]; + uint32 lLength; + uint32 lCount; + + if(lFileDesc == -1) + return false; + + close(lFileDesc); + + string lCommand = "unrar l \"" + aFileName + '\"'; //get info + FILE *f = popen(lCommand.c_str(), "r"); + + if(f <= 0) + return false; + + int num = 7; + while (num--) + fgets(lBuffer, 90, f); //ignore a line. + + bool eof = false; + while(!eof) + { + if(fgets(lBuffer, 350, f) || f <= 0) + if(f <= 0) + break; + if (strlen(lBuffer) > 1) + lBuffer[strlen(lBuffer)-1] = 0; + + lLength = strlen(lBuffer); + lCount = 0; + for(uint32 i = lLength - 1; i > 0; i--) + { + if(lBuffer[i] == ' ') + { + lBuffer[i] = 0; + if(lBuffer[i - 1] != ' ') + { + lCount++; + if(lCount == 9) + break; + } + } + } + + lName = lBuffer; + + if(IsOurFile(lName)) { + pclose(f); + return true; + } + } + + pclose(f); + return false; +}
--- a/Plugins/Input/modplug/archive/arch_raw.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* Modplug XMMS Plugin - * Authors: Kenton Varda <temporal@gauge3d.org> - * - * This source code is public domain. - */ - -//open() -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -//mmap() -#include <unistd.h> -#include <sys/mman.h> - -#include "arch_raw.h" - -arch_Raw::arch_Raw(const string& aFileName) -{ - mFileDesc = open(aFileName.c_str(), O_RDONLY); - - struct stat lStat; - - //open and mmap the file - if(mFileDesc == -1) - { - mSize = 0; - return; - } - fstat(mFileDesc, &lStat); - mSize = lStat.st_size; - - mMap = - (uchar*)mmap(0, mSize, PROT_READ, - MAP_PRIVATE, mFileDesc, 0); - if(!mMap) - { - close(mFileDesc); - mSize = 0; - return; - } -} - -arch_Raw::~arch_Raw() -{ - if(mSize != 0) - { - munmap(mMap, mSize); - close(mFileDesc); - } -} - -bool arch_Raw::ContainsMod(const string& aFileName) -{ - return IsOurFile(aFileName); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/archive/arch_raw.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,55 @@ +/* Modplug XMMS Plugin + * Authors: Kenton Varda <temporal@gauge3d.org> + * + * This source code is public domain. + */ + +//open() +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +//mmap() +#include <unistd.h> +#include <sys/mman.h> + +#include "arch_raw.h" + +arch_Raw::arch_Raw(const string& aFileName) +{ + mFileDesc = open(aFileName.c_str(), O_RDONLY); + + struct stat lStat; + + //open and mmap the file + if(mFileDesc == -1) + { + mSize = 0; + return; + } + fstat(mFileDesc, &lStat); + mSize = lStat.st_size; + + mMap = + (uchar*)mmap(0, mSize, PROT_READ, + MAP_PRIVATE, mFileDesc, 0); + if(!mMap) + { + close(mFileDesc); + mSize = 0; + return; + } +} + +arch_Raw::~arch_Raw() +{ + if(mSize != 0) + { + munmap(mMap, mSize); + close(mFileDesc); + } +} + +bool arch_Raw::ContainsMod(const string& aFileName) +{ + return IsOurFile(aFileName); +}
--- a/Plugins/Input/modplug/archive/arch_zip.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* Modplug XMMS Plugin - * Authors: Kenton Varda <temporal@gauge3d.org> - * - * This source code is public domain. - */ - -//open() -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> - -#include "arch_zip.h" -#include <iostream> -#include <vector> - -arch_Zip::arch_Zip(const string& aFileName) -{ - //check if file exists - int lFileDesc = open(aFileName.c_str(), O_RDONLY); - string lGoodName; - bool bFound = false; - - if(lFileDesc == -1) - { - mSize = 0; - return; - } - - close(lFileDesc); - - // file exists. - string lCommand = "unzip -l -qq \"" + aFileName + '\"'; //get info - FILE *f = popen(lCommand.c_str(), "r"); - - if(f <= 0) - { - mSize = 0; - return; - } - - - bool eof = false; - while(!eof) - { - char line[301]; - char lUncompName[300]; - if (fgets(line, 300, f) <= 0) - { - eof = true; - break; - } - - if (processLine(line, &mSize, lUncompName)) - { - lGoodName = lUncompName; - bFound = true; - break; - } - - } - if(!bFound) - { - mSize = 0; - return; - } - - pclose(f); - - mMap = new char[mSize]; - - lCommand = "unzip -p \"" + aFileName + "\" \"" + lGoodName + '\"'; - //decompress to stdout - f = popen(lCommand.c_str(), "r"); - - if (f <= 0) - { - mSize = 0; - return; - } - - fread((char *)mMap, sizeof(char), mSize, f); - - pclose(f); - -} - -bool arch_Zip::processLine(char *buffer, uint32 *mSize, char *filename) -{ - uint32 mlSize; - mlSize = 0; - - if (sscanf(buffer, "%u %*s %*s %s\n", &mlSize, &filename[0]) <= 0) - return false; - - *mSize = mlSize; - string lName = filename; - - // size date time name - return IsOurFile(lName); -} - -arch_Zip::~arch_Zip() -{ - if(mSize != 0) - delete [] (char*)mMap; -} - -bool arch_Zip::ContainsMod(const string& aFileName) -{ - int lFileDesc = open(aFileName.c_str(), O_RDONLY); - - if(lFileDesc == -1) - return false; - - close(lFileDesc); - - // file exists. - string lCommand = "unzip -l -qq \"" + aFileName + '\"'; //get info - FILE *f = popen(lCommand.c_str(), "r"); - - if(f <= 0) - return false; - - bool eof = false; - while(!eof) - { - char line[301], lName[300]; - if (fgets(line, 300, f) <= 0) - return false; - - uint32 tempSize; - // Simplification of previous if statement - pclose(f); - return (processLine(line, &tempSize, lName)); - - } - - pclose(f); - return false; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/archive/arch_zip.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,143 @@ +/* Modplug XMMS Plugin + * Authors: Kenton Varda <temporal@gauge3d.org> + * + * This source code is public domain. + */ + +//open() +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +#include "arch_zip.h" +#include <iostream> +#include <vector> + +arch_Zip::arch_Zip(const string& aFileName) +{ + //check if file exists + int lFileDesc = open(aFileName.c_str(), O_RDONLY); + string lGoodName; + bool bFound = false; + + if(lFileDesc == -1) + { + mSize = 0; + return; + } + + close(lFileDesc); + + // file exists. + string lCommand = "unzip -l -qq \"" + aFileName + '\"'; //get info + FILE *f = popen(lCommand.c_str(), "r"); + + if(f <= 0) + { + mSize = 0; + return; + } + + + bool eof = false; + while(!eof) + { + char line[301]; + char lUncompName[300]; + if (fgets(line, 300, f) <= 0) + { + eof = true; + break; + } + + if (processLine(line, &mSize, lUncompName)) + { + lGoodName = lUncompName; + bFound = true; + break; + } + + } + if(!bFound) + { + mSize = 0; + return; + } + + pclose(f); + + mMap = new char[mSize]; + + lCommand = "unzip -p \"" + aFileName + "\" \"" + lGoodName + '\"'; + //decompress to stdout + f = popen(lCommand.c_str(), "r"); + + if (f <= 0) + { + mSize = 0; + return; + } + + fread((char *)mMap, sizeof(char), mSize, f); + + pclose(f); + +} + +bool arch_Zip::processLine(char *buffer, uint32 *mSize, char *filename) +{ + uint32 mlSize; + mlSize = 0; + + if (sscanf(buffer, "%u %*s %*s %s\n", &mlSize, &filename[0]) <= 0) + return false; + + *mSize = mlSize; + string lName = filename; + + // size date time name + return IsOurFile(lName); +} + +arch_Zip::~arch_Zip() +{ + if(mSize != 0) + delete [] (char*)mMap; +} + +bool arch_Zip::ContainsMod(const string& aFileName) +{ + int lFileDesc = open(aFileName.c_str(), O_RDONLY); + + if(lFileDesc == -1) + return false; + + close(lFileDesc); + + // file exists. + string lCommand = "unzip -l -qq \"" + aFileName + '\"'; //get info + FILE *f = popen(lCommand.c_str(), "r"); + + if(f <= 0) + return false; + + bool eof = false; + while(!eof) + { + char line[301], lName[300]; + if (fgets(line, 300, f) <= 0) + return false; + + uint32 tempSize; + // Simplification of previous if statement + pclose(f); + return (processLine(line, &tempSize, lName)); + + } + + pclose(f); + return false; +}
--- a/Plugins/Input/modplug/archive/archive.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* Modplug XMMS Plugin - * Authors: Kenton Varda <temporal@gauge3d.org> - * - * This source code is public domain. - */ - -#include "archive.h" - - - -///* Open a read pipe */ File f; -//f=popen("gzip -d compressed.file.name","r"); -///* Read some data in the usual manner, for example */ -//fscanf(f,"%d %f %f",name,&age,$id); -///* Close the pipe */ -//pclose(f); - -Archive::~Archive() -{ -} - -bool Archive::IsOurFile(const string& aFileName) -{ - string lExt; - uint32 lPos; - - lPos = aFileName.find_last_of('.'); - if((int)lPos == -1) - return false; - lExt = aFileName.substr(lPos); - for(uint32 i = 0; i < lExt.length(); i++) - lExt[i] = tolower(lExt[i]); - - if (lExt == ".669") - return true; - if (lExt == ".amf") - return true; - if (lExt == ".ams") - return true; - if (lExt == ".dbm") - return true; - if (lExt == ".dbf") - return true; - if (lExt == ".dsm") - return true; - if (lExt == ".far") - return true; - if (lExt == ".it") - return true; - if (lExt == ".mdl") - return true; - if (lExt == ".med") - return true; - if (lExt == ".mod") - return true; - if (lExt == ".mtm") - return true; - if (lExt == ".okt") - return true; - if (lExt == ".ptm") - return true; - if (lExt == ".s3m") - return true; - if (lExt == ".stm") - return true; - if (lExt == ".ult") - return true; - if (lExt == ".umx") //Unreal rocks! - return true; - if (lExt == ".xm") - return true; - if (lExt == ".j2b") - return true; - if (lExt == ".mt2") - return true; - if (lExt == ".psm") - return true; - - return false; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/archive/archive.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,80 @@ +/* Modplug XMMS Plugin + * Authors: Kenton Varda <temporal@gauge3d.org> + * + * This source code is public domain. + */ + +#include "archive.h" + + + +///* Open a read pipe */ File f; +//f=popen("gzip -d compressed.file.name","r"); +///* Read some data in the usual manner, for example */ +//fscanf(f,"%d %f %f",name,&age,$id); +///* Close the pipe */ +//pclose(f); + +Archive::~Archive() +{ +} + +bool Archive::IsOurFile(const string& aFileName) +{ + string lExt; + uint32 lPos; + + lPos = aFileName.find_last_of('.'); + if((int)lPos == -1) + return false; + lExt = aFileName.substr(lPos); + for(uint32 i = 0; i < lExt.length(); i++) + lExt[i] = tolower(lExt[i]); + + if (lExt == ".669") + return true; + if (lExt == ".amf") + return true; + if (lExt == ".ams") + return true; + if (lExt == ".dbm") + return true; + if (lExt == ".dbf") + return true; + if (lExt == ".dsm") + return true; + if (lExt == ".far") + return true; + if (lExt == ".it") + return true; + if (lExt == ".mdl") + return true; + if (lExt == ".med") + return true; + if (lExt == ".mod") + return true; + if (lExt == ".mtm") + return true; + if (lExt == ".okt") + return true; + if (lExt == ".ptm") + return true; + if (lExt == ".s3m") + return true; + if (lExt == ".stm") + return true; + if (lExt == ".ult") + return true; + if (lExt == ".umx") //Unreal rocks! + return true; + if (lExt == ".xm") + return true; + if (lExt == ".j2b") + return true; + if (lExt == ".mt2") + return true; + if (lExt == ".psm") + return true; + + return false; +}
--- a/Plugins/Input/modplug/archive/open.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* Modplug XMMS Plugin - * Authors: Kenton Varda <temporal@gauge3d.org> - * - * This source code is public domain. - */ - -#include "open.h" -#include "arch_raw.h" -#include "arch_gzip.h" -#include "arch_zip.h" -#include "arch_rar.h" -#include "arch_bz2.h" - -Archive* OpenArchive(const string& aFileName) -{ - string lExt; - uint32 lPos; - - lPos = aFileName.find_last_of('.'); - if(lPos > aFileName.length()) - return NULL; - lExt = aFileName.substr(lPos); - for(uint32 i = 0; i < lExt.length(); i++) - lExt[i] = tolower(lExt[i]); - - if (lExt == ".mdz") - return new arch_Zip(aFileName); - if (lExt == ".mdr") - return new arch_Rar(aFileName); - if (lExt == ".mdgz") - return new arch_Gzip(aFileName); - if (lExt == ".mdbz") - return new arch_Bzip2(aFileName); - if (lExt == ".s3z") - return new arch_Zip(aFileName); - if (lExt == ".s3r") - return new arch_Rar(aFileName); - if (lExt == ".s3gz") - return new arch_Gzip(aFileName); - if (lExt == ".xmz") - return new arch_Zip(aFileName); - if (lExt == ".xmr") - return new arch_Rar(aFileName); - if (lExt == ".xmgz") - return new arch_Gzip(aFileName); - if (lExt == ".itz") - return new arch_Zip(aFileName); - if (lExt == ".itr") - return new arch_Rar(aFileName); - if (lExt == ".itgz") - return new arch_Gzip(aFileName); - if (lExt == ".zip") - return new arch_Zip(aFileName); - if (lExt == ".rar") - return new arch_Rar(aFileName); - if (lExt == ".gz") - return new arch_Gzip(aFileName); - if (lExt == ".bz2") - return new arch_Bzip2(aFileName); - - return new arch_Raw(aFileName); -} - -bool ContainsMod(const string& aFileName) -{ - string lExt; - uint32 lPos; - - lPos = aFileName.find_last_of('.'); - if(lPos > aFileName.length()) - return false; - lExt = aFileName.substr(lPos); - for(uint32 i = 0; i < lExt.length(); i++) - lExt[i] = tolower(lExt[i]); - - if (lExt == ".mdz") - return arch_Zip::ContainsMod(aFileName); - if (lExt == ".mdr") - return arch_Rar::ContainsMod(aFileName); - if (lExt == ".mdgz") - return arch_Gzip::ContainsMod(aFileName); - if (lExt == ".mdbz") - return arch_Bzip2::ContainsMod(aFileName); - if (lExt == ".s3z") - return arch_Zip::ContainsMod(aFileName); - if (lExt == ".s3r") - return arch_Rar::ContainsMod(aFileName); - if (lExt == ".s3gz") - return arch_Gzip::ContainsMod(aFileName); - if (lExt == ".xmz") - return arch_Zip::ContainsMod(aFileName); - if (lExt == ".xmr") - return arch_Rar::ContainsMod(aFileName); - if (lExt == ".xmgz") - return arch_Gzip::ContainsMod(aFileName); - if (lExt == ".itz") - return arch_Zip::ContainsMod(aFileName); - if (lExt == ".itr") - return arch_Rar::ContainsMod(aFileName); - if (lExt == ".itgz") - return arch_Gzip::ContainsMod(aFileName); - if (lExt == ".zip") - return arch_Zip::ContainsMod(aFileName); - if (lExt == ".rar") - return arch_Rar::ContainsMod(aFileName); - if (lExt == ".gz") - return arch_Gzip::ContainsMod(aFileName); - if (lExt == ".bz2") - return arch_Bzip2::ContainsMod(aFileName); - - return arch_Raw::ContainsMod(aFileName); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/archive/open.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,112 @@ +/* Modplug XMMS Plugin + * Authors: Kenton Varda <temporal@gauge3d.org> + * + * This source code is public domain. + */ + +#include "open.h" +#include "arch_raw.h" +#include "arch_gzip.h" +#include "arch_zip.h" +#include "arch_rar.h" +#include "arch_bz2.h" + +Archive* OpenArchive(const string& aFileName) +{ + string lExt; + uint32 lPos; + + lPos = aFileName.find_last_of('.'); + if(lPos > aFileName.length()) + return NULL; + lExt = aFileName.substr(lPos); + for(uint32 i = 0; i < lExt.length(); i++) + lExt[i] = tolower(lExt[i]); + + if (lExt == ".mdz") + return new arch_Zip(aFileName); + if (lExt == ".mdr") + return new arch_Rar(aFileName); + if (lExt == ".mdgz") + return new arch_Gzip(aFileName); + if (lExt == ".mdbz") + return new arch_Bzip2(aFileName); + if (lExt == ".s3z") + return new arch_Zip(aFileName); + if (lExt == ".s3r") + return new arch_Rar(aFileName); + if (lExt == ".s3gz") + return new arch_Gzip(aFileName); + if (lExt == ".xmz") + return new arch_Zip(aFileName); + if (lExt == ".xmr") + return new arch_Rar(aFileName); + if (lExt == ".xmgz") + return new arch_Gzip(aFileName); + if (lExt == ".itz") + return new arch_Zip(aFileName); + if (lExt == ".itr") + return new arch_Rar(aFileName); + if (lExt == ".itgz") + return new arch_Gzip(aFileName); + if (lExt == ".zip") + return new arch_Zip(aFileName); + if (lExt == ".rar") + return new arch_Rar(aFileName); + if (lExt == ".gz") + return new arch_Gzip(aFileName); + if (lExt == ".bz2") + return new arch_Bzip2(aFileName); + + return new arch_Raw(aFileName); +} + +bool ContainsMod(const string& aFileName) +{ + string lExt; + uint32 lPos; + + lPos = aFileName.find_last_of('.'); + if(lPos > aFileName.length()) + return false; + lExt = aFileName.substr(lPos); + for(uint32 i = 0; i < lExt.length(); i++) + lExt[i] = tolower(lExt[i]); + + if (lExt == ".mdz") + return arch_Zip::ContainsMod(aFileName); + if (lExt == ".mdr") + return arch_Rar::ContainsMod(aFileName); + if (lExt == ".mdgz") + return arch_Gzip::ContainsMod(aFileName); + if (lExt == ".mdbz") + return arch_Bzip2::ContainsMod(aFileName); + if (lExt == ".s3z") + return arch_Zip::ContainsMod(aFileName); + if (lExt == ".s3r") + return arch_Rar::ContainsMod(aFileName); + if (lExt == ".s3gz") + return arch_Gzip::ContainsMod(aFileName); + if (lExt == ".xmz") + return arch_Zip::ContainsMod(aFileName); + if (lExt == ".xmr") + return arch_Rar::ContainsMod(aFileName); + if (lExt == ".xmgz") + return arch_Gzip::ContainsMod(aFileName); + if (lExt == ".itz") + return arch_Zip::ContainsMod(aFileName); + if (lExt == ".itr") + return arch_Rar::ContainsMod(aFileName); + if (lExt == ".itgz") + return arch_Gzip::ContainsMod(aFileName); + if (lExt == ".zip") + return arch_Zip::ContainsMod(aFileName); + if (lExt == ".rar") + return arch_Rar::ContainsMod(aFileName); + if (lExt == ".gz") + return arch_Gzip::ContainsMod(aFileName); + if (lExt == ".bz2") + return arch_Bzip2::ContainsMod(aFileName); + + return arch_Raw::ContainsMod(aFileName); +}
--- a/Plugins/Input/modplug/gui/Makefile.in Sat Sep 16 07:18:18 2006 -0700 +++ b/Plugins/Input/modplug/gui/Makefile.in Sat Sep 16 07:33:28 2006 -0700 @@ -5,8 +5,8 @@ CXXFLAGS += $(PICFLAGS) $(GTK_CFLAGS) -I../../../../intl -I../../../.. OBJECTIVE_LIBS_NOINST = libgui.a -SOURCES = main.cpp support.cpp interface.cpp callbacks.cpp +SOURCES = main.cxx support.cxx interface.cxx callbacks.cxx -OBJECTS = ${SOURCES:.cpp=.o} +OBJECTS = ${SOURCES:.cxx=.o} include ../../../../mk/objective.mk
--- a/Plugins/Input/modplug/gui/callbacks.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <gtk/gtk.h> -#include <iostream> - -#include "callbacks.h" -#include "interface.h" -#include "support.h" - -#include "../modplugbmp.h" - - -gboolean -hide_window (GtkWidget *widget, - GdkEvent *event, - gpointer user_data) -{ - gtk_widget_hide(widget); - return TRUE; -} - - -void -on_config_apply_clicked (GtkButton *button, - gpointer user_data) -{ - ModplugXMMS::Settings lProps; - - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "bit8"))) - lProps.mBits = 8; - else - lProps.mBits = 16; - - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "samp11"))) - lProps.mFrequency = 11025; - else if (gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "samp22"))) - lProps.mFrequency = 22050; - else if (gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "samp48"))) - lProps.mFrequency = 48000; - else - lProps.mFrequency = 44100; - - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "resampNearest"))) - lProps.mResamplingMode = 0; - else if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "resampLinear"))) - lProps.mResamplingMode = 1; - else if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "resampSpline"))) - lProps.mResamplingMode = 2; - else - lProps.mResamplingMode = 3; - - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "mono"))) - lProps.mChannels = 1; - else - lProps.mChannels = 2; - - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxNR"))) - lProps.mNoiseReduction = true; - else - lProps.mNoiseReduction = false; - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxAmigaMOD"))) - lProps.mGrabAmigaMOD = true; - else - lProps.mGrabAmigaMOD = false; - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxFastInfo"))) - lProps.mFastinfo = true; - else - lProps.mFastinfo = false; - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxUseFilename"))) - lProps.mUseFilename = true; - else - lProps.mUseFilename = false; - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxReverb"))) - lProps.mReverb = true; - else - lProps.mReverb = false; - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxBassBoost"))) - lProps.mMegabass = true; - else - lProps.mMegabass = false; - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxSurround"))) - lProps.mSurround = true; - else - lProps.mSurround = false; - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxPreamp"))) - lProps.mPreamp = true; - else - lProps.mPreamp = false; - - if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxLoopForever"))) - lProps.mLoopCount = -1; - else if (gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxLoopFinite"))) - { - lProps.mLoopCount = - (uint32)gtk_spin_button_get_adjustment( - (GtkSpinButton*)lookup_widget((GtkWidget*)button, "fxLoopCount"))->value; - } - else - lProps.mLoopCount = 0; - - //hmm... GTK objects have un-protected data members? That's not good... - lProps.mReverbDepth = - (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxReverbDepth"))->value; - lProps.mReverbDelay = - (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxReverbDelay"))->value; - lProps.mBassAmount = - (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxBassAmount"))->value; - lProps.mBassRange = - (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxBassRange"))->value; - lProps.mSurroundDepth = - (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxSurroundDepth"))->value; - lProps.mSurroundDelay = - (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxSurroundDelay"))->value; - lProps.mPreampLevel = - (float)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxPreampLevel"))->value; - - gModplugXMMS.SetModProps(lProps); -} - - -void -on_config_ok_clicked (GtkButton *button, - gpointer user_data) -{ - GtkWidget* lConfigWindow; - - on_config_apply_clicked(button, user_data); - - lConfigWindow = lookup_widget((GtkWidget*)button, "Config"); - if(!lConfigWindow) - cerr << "ModPlug: on_config_ok_clicked: Could not find config window!" << endl; - else - gtk_widget_hide(lConfigWindow); -} - - -void -on_config_cancel_clicked (GtkButton *button, - gpointer user_data) -{ - GtkWidget* lConfigWindow; - - lConfigWindow = lookup_widget((GtkWidget*)button, "Config"); - if(!lConfigWindow) - cerr << "ModPlug: on_config_ok_clicked: Could not find config window!" << endl; - else - gtk_widget_hide(lConfigWindow); -} - - -void -on_info_close_clicked (GtkButton *button, - gpointer user_data) -{ - GtkWidget* lInfoWindow; - - lInfoWindow = lookup_widget((GtkWidget*)button, "Info"); - if(!lInfoWindow) - cerr << "ModPlug: on_info_close_clicked: Could not find info window!" << endl; - else - gtk_widget_hide(lInfoWindow); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/gui/callbacks.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,164 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gtk/gtk.h> +#include <iostream> + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +#include "../modplugbmp.h" + + +gboolean +hide_window (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + gtk_widget_hide(widget); + return TRUE; +} + + +void +on_config_apply_clicked (GtkButton *button, + gpointer user_data) +{ + ModplugXMMS::Settings lProps; + + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "bit8"))) + lProps.mBits = 8; + else + lProps.mBits = 16; + + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "samp11"))) + lProps.mFrequency = 11025; + else if (gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "samp22"))) + lProps.mFrequency = 22050; + else if (gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "samp48"))) + lProps.mFrequency = 48000; + else + lProps.mFrequency = 44100; + + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "resampNearest"))) + lProps.mResamplingMode = 0; + else if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "resampLinear"))) + lProps.mResamplingMode = 1; + else if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "resampSpline"))) + lProps.mResamplingMode = 2; + else + lProps.mResamplingMode = 3; + + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "mono"))) + lProps.mChannels = 1; + else + lProps.mChannels = 2; + + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxNR"))) + lProps.mNoiseReduction = true; + else + lProps.mNoiseReduction = false; + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxAmigaMOD"))) + lProps.mGrabAmigaMOD = true; + else + lProps.mGrabAmigaMOD = false; + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxFastInfo"))) + lProps.mFastinfo = true; + else + lProps.mFastinfo = false; + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxUseFilename"))) + lProps.mUseFilename = true; + else + lProps.mUseFilename = false; + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxReverb"))) + lProps.mReverb = true; + else + lProps.mReverb = false; + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxBassBoost"))) + lProps.mMegabass = true; + else + lProps.mMegabass = false; + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxSurround"))) + lProps.mSurround = true; + else + lProps.mSurround = false; + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxPreamp"))) + lProps.mPreamp = true; + else + lProps.mPreamp = false; + + if(gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxLoopForever"))) + lProps.mLoopCount = -1; + else if (gtk_toggle_button_get_active((GtkToggleButton*)lookup_widget((GtkWidget*)button, "fxLoopFinite"))) + { + lProps.mLoopCount = + (uint32)gtk_spin_button_get_adjustment( + (GtkSpinButton*)lookup_widget((GtkWidget*)button, "fxLoopCount"))->value; + } + else + lProps.mLoopCount = 0; + + //hmm... GTK objects have un-protected data members? That's not good... + lProps.mReverbDepth = + (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxReverbDepth"))->value; + lProps.mReverbDelay = + (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxReverbDelay"))->value; + lProps.mBassAmount = + (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxBassAmount"))->value; + lProps.mBassRange = + (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxBassRange"))->value; + lProps.mSurroundDepth = + (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxSurroundDepth"))->value; + lProps.mSurroundDelay = + (uint32)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxSurroundDelay"))->value; + lProps.mPreampLevel = + (float)gtk_range_get_adjustment((GtkRange*)lookup_widget((GtkWidget*)button, "fxPreampLevel"))->value; + + gModplugXMMS.SetModProps(lProps); +} + + +void +on_config_ok_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget* lConfigWindow; + + on_config_apply_clicked(button, user_data); + + lConfigWindow = lookup_widget((GtkWidget*)button, "Config"); + if(!lConfigWindow) + cerr << "ModPlug: on_config_ok_clicked: Could not find config window!" << endl; + else + gtk_widget_hide(lConfigWindow); +} + + +void +on_config_cancel_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget* lConfigWindow; + + lConfigWindow = lookup_widget((GtkWidget*)button, "Config"); + if(!lConfigWindow) + cerr << "ModPlug: on_config_ok_clicked: Could not find config window!" << endl; + else + gtk_widget_hide(lConfigWindow); +} + + +void +on_info_close_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget* lInfoWindow; + + lInfoWindow = lookup_widget((GtkWidget*)button, "Info"); + if(!lInfoWindow) + cerr << "ModPlug: on_info_close_clicked: Could not find info window!" << endl; + else + gtk_widget_hide(lInfoWindow); +}
--- a/Plugins/Input/modplug/gui/interface.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,963 +0,0 @@ -/* - * DO NOT EDIT THIS FILE - it is generated by Glade. - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> - -#include <gdk/gdkkeysyms.h> -#include <gtk/gtk.h> - -#include "callbacks.h" -#include "interface.h" -#include "support.h" - -GtkWidget* -create_Config (void) -{ - GtkWidget *Config; - GtkWidget *vbox2; - GtkWidget *notebook1; - GtkWidget *vbox3; - GtkWidget *hbox2; - GtkWidget *frame1; - GtkWidget *vbox4; - GSList *vbox4_group = NULL; - GtkWidget *bit16; - GtkWidget *bit8; - GtkWidget *frame2; - GtkWidget *vbox5; - GSList *vbox5_group = NULL; - GtkWidget *stereo; - GtkWidget *mono; - GtkWidget *hbox10; - GtkWidget *frame3; - GtkWidget *vbox6; - GSList *vbox6_group = NULL; - GtkWidget *samp48; - GtkWidget *samp44; - GtkWidget *samp22; - GtkWidget *samp11; - GtkWidget *frame9; - GtkWidget *vbox15; - GSList *vbox15_group = NULL; - GtkWidget *resampNearest; - GtkWidget *resampLinear; - GtkWidget *resampSpline; - GtkWidget *resampPolyphase; - GtkWidget *label2; - GtkWidget *vbox7; - GtkWidget *frame4; - GtkWidget *hbox3; - GtkWidget *vbox8; - GtkWidget *fxUseFilename; - GtkWidget *fxFastInfo; - GtkWidget *vbox9; - GtkWidget *fxNR; - GtkWidget *fxAmigaMOD; - GtkWidget *frame5; - GtkWidget *hbox4; - GtkWidget *fxReverb; - GtkWidget *vbox10; - GtkWidget *table1; - GtkWidget *fxReverbDepth; - GtkWidget *fxReverbDelay; - GtkWidget *label3; - GtkWidget *label4; - GtkWidget *frame6; - GtkWidget *hbox5; - GtkWidget *fxBassBoost; - GtkWidget *vbox11; - GtkWidget *table2; - GtkWidget *fxBassAmount; - GtkWidget *fxBassRange; - GtkWidget *label5; - GtkWidget *label6; - GtkWidget *frame7; - GtkWidget *hbox6; - GtkWidget *fxSurround; - GtkWidget *vbox12; - GtkWidget *table3; - GtkWidget *fxSurroundDepth; - GtkWidget *fxSurroundDelay; - GtkWidget *label7; - GtkWidget *label8; - GtkWidget *frame10; - GtkWidget *vbox16; - GtkWidget *label20; - GtkWidget *hbox11; - GtkWidget *fxPreamp; - GtkWidget *label19; - GtkWidget *fxPreampLevel; - GtkWidget *frame11; - GtkWidget *vbox17; - GSList *loopGroup_group = NULL; - GtkWidget *fxNoLoop; - GtkWidget *hbox13; - GtkWidget *fxLoopFinite; - GtkObject *fxLoopCount_adj; - GtkWidget *fxLoopCount; - GtkWidget *label21; - GtkWidget *fxLoopForever; - GtkWidget *label10; - GtkWidget *hbuttonbox2; - GtkWidget *config_ok; - GtkWidget *config_apply; - GtkWidget *config_cancel; - - Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); - gtk_widget_set_usize (Config, 350, -2); - gtk_window_set_title (GTK_WINDOW (Config), _("ModPlug Configuration")); - gtk_window_set_policy (GTK_WINDOW (Config), FALSE, FALSE, FALSE); - - vbox2 = gtk_vbox_new (FALSE, 0); - gtk_container_set_border_width(GTK_CONTAINER(vbox2),5); - gtk_widget_ref (vbox2); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox2", vbox2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (Config), vbox2); - - notebook1 = gtk_notebook_new (); - gtk_widget_ref (notebook1); - gtk_object_set_data_full (GTK_OBJECT (Config), "notebook1", notebook1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (notebook1); - gtk_box_pack_start (GTK_BOX (vbox2), notebook1, TRUE, TRUE, 5); - gtk_container_set_border_width (GTK_CONTAINER (notebook1), 0); - - vbox3 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox3); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox3", vbox3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox3); - gtk_container_add (GTK_CONTAINER (notebook1), vbox3); - gtk_container_set_border_width (GTK_CONTAINER (vbox3), 6); - - hbox2 = gtk_hbox_new (FALSE, 0); - gtk_widget_ref (hbox2); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox3), hbox2, TRUE, TRUE, 0); - - frame1 = gtk_frame_new (_("Resolution")); - gtk_widget_ref (frame1); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame1", frame1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame1); - gtk_box_pack_start (GTK_BOX (hbox2), frame1, TRUE, TRUE, 0); - - vbox4 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox4); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox4", vbox4, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox4); - gtk_container_add (GTK_CONTAINER (frame1), vbox4); - - bit16 = gtk_radio_button_new_with_label (vbox4_group, _("16 bit")); - vbox4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (bit16)); - gtk_widget_ref (bit16); - gtk_object_set_data_full (GTK_OBJECT (Config), "bit16", bit16, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (bit16); - gtk_box_pack_start (GTK_BOX (vbox4), bit16, FALSE, FALSE, 0); - - bit8 = gtk_radio_button_new_with_label (vbox4_group, _("8 bit")); - vbox4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (bit8)); - gtk_widget_ref (bit8); - gtk_object_set_data_full (GTK_OBJECT (Config), "bit8", bit8, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (bit8); - gtk_box_pack_start (GTK_BOX (vbox4), bit8, FALSE, FALSE, 0); - - frame2 = gtk_frame_new (_("Channels")); - gtk_widget_ref (frame2); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame2); - gtk_box_pack_start (GTK_BOX (hbox2), frame2, TRUE, TRUE, 0); - - vbox5 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox5); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox5", vbox5, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox5); - gtk_container_add (GTK_CONTAINER (frame2), vbox5); - - stereo = gtk_radio_button_new_with_label (vbox5_group, _("Stereo")); - vbox5_group = gtk_radio_button_group (GTK_RADIO_BUTTON (stereo)); - gtk_widget_ref (stereo); - gtk_object_set_data_full (GTK_OBJECT (Config), "stereo", stereo, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (stereo); - gtk_box_pack_start (GTK_BOX (vbox5), stereo, FALSE, FALSE, 0); - - mono = gtk_radio_button_new_with_label (vbox5_group, _("Mono (downmix)")); - vbox5_group = gtk_radio_button_group (GTK_RADIO_BUTTON (mono)); - gtk_widget_ref (mono); - gtk_object_set_data_full (GTK_OBJECT (Config), "mono", mono, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (mono); - gtk_box_pack_start (GTK_BOX (vbox5), mono, FALSE, FALSE, 0); - - hbox10 = gtk_hbox_new (FALSE, 0); - gtk_widget_ref (hbox10); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox10", hbox10, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox10); - gtk_box_pack_start (GTK_BOX (vbox3), hbox10, TRUE, TRUE, 0); - - frame3 = gtk_frame_new (_("Sampling Rate")); - gtk_widget_ref (frame3); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame3); - gtk_box_pack_start (GTK_BOX (hbox10), frame3, TRUE, TRUE, 0); - - vbox6 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox6); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox6", vbox6, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox6); - gtk_container_add (GTK_CONTAINER (frame3), vbox6); - - samp48 = gtk_radio_button_new_with_label (vbox6_group, _("48 kHz")); - vbox6_group = gtk_radio_button_group (GTK_RADIO_BUTTON (samp48)); - gtk_widget_ref (samp48); - gtk_object_set_data_full (GTK_OBJECT (Config), "samp48", samp48, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (samp48); - gtk_box_pack_start (GTK_BOX (vbox6), samp48, FALSE, FALSE, 0); - - samp44 = gtk_radio_button_new_with_label (vbox6_group, _("44 kHz")); - vbox6_group = gtk_radio_button_group (GTK_RADIO_BUTTON (samp44)); - gtk_widget_ref (samp44); - gtk_object_set_data_full (GTK_OBJECT (Config), "samp44", samp44, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (samp44); - gtk_box_pack_start (GTK_BOX (vbox6), samp44, FALSE, FALSE, 0); - - samp22 = gtk_radio_button_new_with_label (vbox6_group, _("22 kHz")); - vbox6_group = gtk_radio_button_group (GTK_RADIO_BUTTON (samp22)); - gtk_widget_ref (samp22); - gtk_object_set_data_full (GTK_OBJECT (Config), "samp22", samp22, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (samp22); - gtk_box_pack_start (GTK_BOX (vbox6), samp22, FALSE, FALSE, 0); - - samp11 = gtk_radio_button_new_with_label (vbox6_group, _("11 kHz")); - vbox6_group = gtk_radio_button_group (GTK_RADIO_BUTTON (samp11)); - gtk_widget_ref (samp11); - gtk_object_set_data_full (GTK_OBJECT (Config), "samp11", samp11, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (samp11); - gtk_box_pack_start (GTK_BOX (vbox6), samp11, FALSE, FALSE, 0); - - frame9 = gtk_frame_new (_("Resampling")); - gtk_widget_ref (frame9); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame9", frame9, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame9); - gtk_box_pack_start (GTK_BOX (hbox10), frame9, TRUE, TRUE, 0); - - vbox15 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox15); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox15", vbox15, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox15); - gtk_container_add (GTK_CONTAINER (frame9), vbox15); - - resampNearest = gtk_radio_button_new_with_label (vbox15_group, _("Nearest (fastest)")); - vbox15_group = gtk_radio_button_group (GTK_RADIO_BUTTON (resampNearest)); - gtk_widget_ref (resampNearest); - gtk_object_set_data_full (GTK_OBJECT (Config), "resampNearest", resampNearest, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (resampNearest); - gtk_box_pack_start (GTK_BOX (vbox15), resampNearest, FALSE, FALSE, 0); - - resampLinear = gtk_radio_button_new_with_label (vbox15_group, _("Linear (fast)")); - vbox15_group = gtk_radio_button_group (GTK_RADIO_BUTTON (resampLinear)); - gtk_widget_ref (resampLinear); - gtk_object_set_data_full (GTK_OBJECT (Config), "resampLinear", resampLinear, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (resampLinear); - gtk_box_pack_start (GTK_BOX (vbox15), resampLinear, FALSE, FALSE, 0); - - resampSpline = gtk_radio_button_new_with_label (vbox15_group, _("Spline (good quality)")); - vbox15_group = gtk_radio_button_group (GTK_RADIO_BUTTON (resampSpline)); - gtk_widget_ref (resampSpline); - gtk_object_set_data_full (GTK_OBJECT (Config), "resampSpline", resampSpline, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (resampSpline); - gtk_box_pack_start (GTK_BOX (vbox15), resampSpline, FALSE, FALSE, 0); - - resampPolyphase = gtk_radio_button_new_with_label (vbox15_group, _("8-tap Fir (extremely high quality)")); - vbox15_group = gtk_radio_button_group (GTK_RADIO_BUTTON (resampPolyphase)); - gtk_widget_ref (resampPolyphase); - gtk_object_set_data_full (GTK_OBJECT (Config), "resampPolyphase", resampPolyphase, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (resampPolyphase); - gtk_box_pack_start (GTK_BOX (vbox15), resampPolyphase, FALSE, FALSE, 0); - - label2 = gtk_label_new (_("Quality")); - gtk_widget_ref (label2); - gtk_object_set_data_full (GTK_OBJECT (Config), "label2", label2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label2); - gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), label2); - - vbox7 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox7); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox7", vbox7, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox7); - gtk_container_add (GTK_CONTAINER (notebook1), vbox7); - gtk_container_set_border_width (GTK_CONTAINER (vbox7), 6); - - frame4 = gtk_frame_new (_("General")); - gtk_widget_ref (frame4); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame4", frame4, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame4); - gtk_box_pack_start (GTK_BOX (vbox7), frame4, TRUE, TRUE, 0); - - hbox3 = gtk_hbox_new (FALSE, 0); - gtk_widget_ref (hbox3); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox3", hbox3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox3); - gtk_container_add (GTK_CONTAINER (frame4), hbox3); - - vbox8 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox8); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox8", vbox8, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox8); - gtk_box_pack_start (GTK_BOX (hbox3), vbox8, TRUE, TRUE, 0); - - fxUseFilename = gtk_check_button_new_with_label (_("Use Filename as Song Title")); - gtk_widget_ref (fxUseFilename); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxUseFilename", fxUseFilename, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxUseFilename); - gtk_box_pack_start (GTK_BOX (vbox8), fxUseFilename, FALSE, FALSE, 0); - - fxFastInfo = gtk_check_button_new_with_label (_("Fast Playlist Info")); - gtk_widget_ref (fxFastInfo); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxFastInfo", fxFastInfo, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxFastInfo); - gtk_box_pack_start (GTK_BOX (vbox8), fxFastInfo, FALSE, FALSE, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxFastInfo), TRUE); - - vbox9 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox9); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox9", vbox9, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox9); - gtk_box_pack_start (GTK_BOX (hbox3), vbox9, TRUE, TRUE, 0); - - fxNR = gtk_check_button_new_with_label (_("Noise Reduction")); - gtk_widget_ref (fxNR); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxNR", fxNR, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxNR); - gtk_box_pack_start (GTK_BOX (vbox9), fxNR, FALSE, FALSE, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxNR), TRUE); - - fxAmigaMOD = gtk_check_button_new_with_label (_("Play Amiga MOD")); - gtk_widget_ref (fxAmigaMOD); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxAmigaMOD", fxAmigaMOD, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxAmigaMOD); - gtk_box_pack_start (GTK_BOX (vbox9), fxAmigaMOD, FALSE, FALSE, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxAmigaMOD), TRUE); - - frame5 = gtk_frame_new (_("Reverb")); - gtk_widget_ref (frame5); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame5", frame5, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame5); - gtk_box_pack_start (GTK_BOX (vbox7), frame5, TRUE, TRUE, 0); - - hbox4 = gtk_hbox_new (FALSE, 0); - gtk_widget_ref (hbox4); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox4", hbox4, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox4); - gtk_container_add (GTK_CONTAINER (frame5), hbox4); - - fxReverb = gtk_check_button_new_with_label (_("Enable")); - gtk_widget_ref (fxReverb); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxReverb", fxReverb, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxReverb); - gtk_box_pack_start (GTK_BOX (hbox4), fxReverb, FALSE, FALSE, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxReverb), TRUE); - - vbox10 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox10); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox10", vbox10, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox10); - gtk_box_pack_start (GTK_BOX (hbox4), vbox10, TRUE, TRUE, 0); - - table1 = gtk_table_new (2, 2, FALSE); - gtk_widget_ref (table1); - gtk_object_set_data_full (GTK_OBJECT (Config), "table1", table1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (table1); - gtk_box_pack_start (GTK_BOX (vbox10), table1, TRUE, TRUE, 0); - - fxReverbDepth = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (30, 0, 100, 0, 0, 0))); - gtk_widget_ref (fxReverbDepth); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxReverbDepth", fxReverbDepth, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxReverbDepth); - gtk_table_attach (GTK_TABLE (table1), fxReverbDepth, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - fxReverbDelay = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (90, 40, 200, 0, 0, 0))); - gtk_widget_ref (fxReverbDelay); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxReverbDelay", fxReverbDelay, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxReverbDelay); - gtk_table_attach (GTK_TABLE (table1), fxReverbDelay, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - label3 = gtk_label_new (_("Depth")); - gtk_widget_ref (label3); - gtk_object_set_data_full (GTK_OBJECT (Config), "label3", label3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label3); - gtk_table_attach (GTK_TABLE (table1), label3, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - label4 = gtk_label_new (_("Delay")); - gtk_widget_ref (label4); - gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label4); - gtk_table_attach (GTK_TABLE (table1), label4, 0, 1, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - frame6 = gtk_frame_new (_("Bass Boost")); - gtk_widget_ref (frame6); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame6", frame6, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame6); - gtk_box_pack_start (GTK_BOX (vbox7), frame6, TRUE, TRUE, 0); - - hbox5 = gtk_hbox_new (FALSE, 0); - gtk_widget_ref (hbox5); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox5", hbox5, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox5); - gtk_container_add (GTK_CONTAINER (frame6), hbox5); - - fxBassBoost = gtk_check_button_new_with_label (_("Enable")); - gtk_widget_ref (fxBassBoost); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxBassBoost", fxBassBoost, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxBassBoost); - gtk_box_pack_start (GTK_BOX (hbox5), fxBassBoost, FALSE, FALSE, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxBassBoost), TRUE); - - vbox11 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox11); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox11", vbox11, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox11); - gtk_box_pack_start (GTK_BOX (hbox5), vbox11, TRUE, TRUE, 0); - - table2 = gtk_table_new (2, 2, FALSE); - gtk_widget_ref (table2); - gtk_object_set_data_full (GTK_OBJECT (Config), "table2", table2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (table2); - gtk_box_pack_start (GTK_BOX (vbox11), table2, TRUE, TRUE, 0); - - fxBassAmount = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (30, 0, 100, 0, 0, 0))); - gtk_widget_ref (fxBassAmount); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxBassAmount", fxBassAmount, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxBassAmount); - gtk_table_attach (GTK_TABLE (table2), fxBassAmount, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - fxBassRange = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (30, 10, 100, 0, 0, 0))); - gtk_widget_ref (fxBassRange); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxBassRange", fxBassRange, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxBassRange); - gtk_table_attach (GTK_TABLE (table2), fxBassRange, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - label5 = gtk_label_new (_("Amount")); - gtk_widget_ref (label5); - gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label5); - gtk_table_attach (GTK_TABLE (table2), label5, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - label6 = gtk_label_new (_("Range")); - gtk_widget_ref (label6); - gtk_object_set_data_full (GTK_OBJECT (Config), "label6", label6, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label6); - gtk_table_attach (GTK_TABLE (table2), label6, 0, 1, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - frame7 = gtk_frame_new (_("Surround")); - gtk_widget_ref (frame7); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame7", frame7, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame7); - gtk_box_pack_start (GTK_BOX (vbox7), frame7, TRUE, TRUE, 0); - - hbox6 = gtk_hbox_new (FALSE, 0); - gtk_widget_ref (hbox6); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox6", hbox6, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox6); - gtk_container_add (GTK_CONTAINER (frame7), hbox6); - - fxSurround = gtk_check_button_new_with_label (_("Enable")); - gtk_widget_ref (fxSurround); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxSurround", fxSurround, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxSurround); - gtk_box_pack_start (GTK_BOX (hbox6), fxSurround, FALSE, FALSE, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxSurround), TRUE); - - vbox12 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox12); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox12", vbox12, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox12); - gtk_box_pack_start (GTK_BOX (hbox6), vbox12, TRUE, TRUE, 0); - - table3 = gtk_table_new (2, 2, FALSE); - gtk_widget_ref (table3); - gtk_object_set_data_full (GTK_OBJECT (Config), "table3", table3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (table3); - gtk_box_pack_start (GTK_BOX (vbox12), table3, TRUE, TRUE, 0); - - fxSurroundDepth = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (20, 0, 100, 0, 0, 0))); - gtk_widget_ref (fxSurroundDepth); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxSurroundDepth", fxSurroundDepth, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxSurroundDepth); - gtk_table_attach (GTK_TABLE (table3), fxSurroundDepth, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - fxSurroundDelay = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (20, 5, 40, 0, 0, 0))); - gtk_widget_ref (fxSurroundDelay); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxSurroundDelay", fxSurroundDelay, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxSurroundDelay); - gtk_table_attach (GTK_TABLE (table3), fxSurroundDelay, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - label7 = gtk_label_new (_("Depth")); - gtk_widget_ref (label7); - gtk_object_set_data_full (GTK_OBJECT (Config), "label7", label7, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label7); - gtk_table_attach (GTK_TABLE (table3), label7, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - label8 = gtk_label_new (_("Delay")); - gtk_widget_ref (label8); - gtk_object_set_data_full (GTK_OBJECT (Config), "label8", label8, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label8); - gtk_table_attach (GTK_TABLE (table3), label8, 0, 1, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - frame10 = gtk_frame_new (_("Preamp")); - gtk_widget_ref (frame10); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame10", frame10, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame10); - gtk_box_pack_start (GTK_BOX (vbox7), frame10, TRUE, TRUE, 0); - - vbox16 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox16); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox16", vbox16, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox16); - gtk_container_add (GTK_CONTAINER (frame10), vbox16); - - label20 = gtk_label_new (_("Note: Setting the preamp too high may cause\nclipping / distortion!")); - gtk_widget_ref (label20); - gtk_object_set_data_full (GTK_OBJECT (Config), "label20", label20, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label20); - gtk_box_pack_start (GTK_BOX (vbox16), label20, FALSE, FALSE, 0); - - hbox11 = gtk_hbox_new (FALSE, 0); - gtk_widget_ref (hbox11); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox11", hbox11, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox11); - gtk_box_pack_start (GTK_BOX (vbox16), hbox11, TRUE, TRUE, 0); - - fxPreamp = gtk_check_button_new_with_label (_("Enable")); - gtk_widget_ref (fxPreamp); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxPreamp", fxPreamp, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxPreamp); - gtk_box_pack_start (GTK_BOX (hbox11), fxPreamp, FALSE, FALSE, 0); - - label19 = gtk_label_new (_("Volume")); - gtk_widget_ref (label19); - gtk_object_set_data_full (GTK_OBJECT (Config), "label19", label19, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label19); - gtk_box_pack_start (GTK_BOX (hbox11), label19, FALSE, FALSE, 0); - - fxPreampLevel = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -3, 3, 1, 0, 0))); - gtk_widget_ref (fxPreampLevel); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxPreampLevel", fxPreampLevel, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxPreampLevel); - gtk_box_pack_start (GTK_BOX (hbox11), fxPreampLevel, TRUE, TRUE, 0); - - frame11 = gtk_frame_new (_("Looping")); - gtk_widget_ref (frame11); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame11", frame11, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame11); - gtk_box_pack_start (GTK_BOX (vbox7), frame11, TRUE, TRUE, 0); - - vbox17 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox17); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox17", vbox17, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox17); - gtk_container_add (GTK_CONTAINER (frame11), vbox17); - - fxNoLoop = gtk_radio_button_new_with_label (loopGroup_group, _("Don't loop")); - loopGroup_group = gtk_radio_button_group (GTK_RADIO_BUTTON (fxNoLoop)); - gtk_widget_ref (fxNoLoop); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxNoLoop", fxNoLoop, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxNoLoop); - gtk_box_pack_start (GTK_BOX (vbox17), fxNoLoop, FALSE, FALSE, 0); - - hbox13 = gtk_hbox_new (FALSE, 0); - gtk_widget_ref (hbox13); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox13", hbox13, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox13); - gtk_box_pack_start (GTK_BOX (vbox17), hbox13, FALSE, FALSE, 0); - - fxLoopFinite = gtk_radio_button_new_with_label (loopGroup_group, _("Loop")); - loopGroup_group = gtk_radio_button_group (GTK_RADIO_BUTTON (fxLoopFinite)); - gtk_widget_ref (fxLoopFinite); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxLoopFinite", fxLoopFinite, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxLoopFinite); - gtk_box_pack_start (GTK_BOX (hbox13), fxLoopFinite, FALSE, FALSE, 0); - - fxLoopCount_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); - fxLoopCount = gtk_spin_button_new (GTK_ADJUSTMENT (fxLoopCount_adj), 1, 0); - gtk_widget_ref (fxLoopCount); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxLoopCount", fxLoopCount, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxLoopCount); - gtk_box_pack_start (GTK_BOX (hbox13), fxLoopCount, FALSE, TRUE, 0); - - label21 = gtk_label_new (_("time(s)")); - gtk_widget_ref (label21); - gtk_object_set_data_full (GTK_OBJECT (Config), "label21", label21, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label21); - gtk_box_pack_start (GTK_BOX (hbox13), label21, FALSE, FALSE, 0); - - fxLoopForever = gtk_radio_button_new_with_label (loopGroup_group, _("Loop forever")); - loopGroup_group = gtk_radio_button_group (GTK_RADIO_BUTTON (fxLoopForever)); - gtk_widget_ref (fxLoopForever); - gtk_object_set_data_full (GTK_OBJECT (Config), "fxLoopForever", fxLoopForever, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (fxLoopForever); - gtk_box_pack_start (GTK_BOX (vbox17), fxLoopForever, FALSE, FALSE, 0); - - label10 = gtk_label_new (_("Effects")); - gtk_widget_ref (label10); - gtk_object_set_data_full (GTK_OBJECT (Config), "label10", label10, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label10); - gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 1), label10); - - hbuttonbox2 = gtk_hbutton_box_new (); - gtk_widget_ref (hbuttonbox2); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox2", hbuttonbox2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbuttonbox2); - gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); - gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox2), GTK_BUTTONBOX_END); - gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox2), 5); - - config_ok = gtk_button_new_with_label (_("OK")); - gtk_widget_ref (config_ok); - gtk_object_set_data_full (GTK_OBJECT (Config), "config_ok", config_ok, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (config_ok); - gtk_container_add (GTK_CONTAINER (hbuttonbox2), config_ok); - GTK_WIDGET_SET_FLAGS (config_ok, GTK_CAN_DEFAULT); - - config_apply = gtk_button_new_with_label (_("Apply")); - gtk_widget_ref (config_apply); - gtk_object_set_data_full (GTK_OBJECT (Config), "config_apply", config_apply, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (config_apply); - gtk_container_add (GTK_CONTAINER (hbuttonbox2), config_apply); - GTK_WIDGET_SET_FLAGS (config_apply, GTK_CAN_DEFAULT); - - config_cancel = gtk_button_new_with_label (_("Cancel")); - gtk_widget_ref (config_cancel); - gtk_object_set_data_full (GTK_OBJECT (Config), "config_cancel", config_cancel, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (config_cancel); - gtk_container_add (GTK_CONTAINER (hbuttonbox2), config_cancel); - GTK_WIDGET_SET_FLAGS (config_cancel, GTK_CAN_DEFAULT); - - gtk_signal_connect (GTK_OBJECT (Config), "delete_event", - GTK_SIGNAL_FUNC (hide_window), - NULL); - gtk_signal_connect (GTK_OBJECT (config_ok), "clicked", - GTK_SIGNAL_FUNC (on_config_ok_clicked), - NULL); - gtk_signal_connect (GTK_OBJECT (config_apply), "clicked", - GTK_SIGNAL_FUNC (on_config_apply_clicked), - NULL); - gtk_signal_connect (GTK_OBJECT (config_cancel), "clicked", - GTK_SIGNAL_FUNC (on_config_cancel_clicked), - NULL); - - return Config; -} - -GtkWidget* -create_Info (void) -{ - GtkWidget *Info; - GtkWidget *vbox14; - GtkWidget *notebook2; - GtkWidget *hbox9; - GtkWidget *label11; - GtkWidget *info_general; - GtkWidget *label13; - GtkWidget *scrolledwindow1; - GtkWidget *viewport1; - GtkWidget *info_samples; - GtkWidget *label15; - GtkWidget *scrolledwindow2; - GtkWidget *viewport2; - GtkWidget *info_instruments; - GtkWidget *label17; - GtkWidget *scrolledwindow3; - GtkWidget *viewport3; - GtkWidget *info_message; - GtkWidget *label18; - GtkWidget *hbuttonbox3; - GtkWidget *info_close; - - Info = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_object_set_data (GTK_OBJECT (Info), "Info", Info); - gtk_widget_set_usize (Info, 290, 264); - gtk_window_set_title (GTK_WINDOW (Info), _("MOD Info")); - - vbox14 = gtk_vbox_new (FALSE, 0); - gtk_widget_ref (vbox14); - gtk_object_set_data_full (GTK_OBJECT (Info), "vbox14", vbox14, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox14); - gtk_container_add (GTK_CONTAINER (Info), vbox14); - - notebook2 = gtk_notebook_new (); - gtk_widget_ref (notebook2); - gtk_object_set_data_full (GTK_OBJECT (Info), "notebook2", notebook2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (notebook2); - gtk_box_pack_start (GTK_BOX (vbox14), notebook2, TRUE, TRUE, 8); - gtk_container_set_border_width (GTK_CONTAINER (notebook2), 6); - - hbox9 = gtk_hbox_new (FALSE, 0); - gtk_widget_ref (hbox9); - gtk_object_set_data_full (GTK_OBJECT (Info), "hbox9", hbox9, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox9); - gtk_container_add (GTK_CONTAINER (notebook2), hbox9); - - label11 = gtk_label_new (_("Filename:\nTitle:\nType:\nLength:\nSpeed:\nTempo:\nSamples:\nInstruments:\nPatterns:\nChannels:")); - gtk_widget_ref (label11); - gtk_object_set_data_full (GTK_OBJECT (Info), "label11", label11, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label11); - gtk_box_pack_start (GTK_BOX (hbox9), label11, FALSE, FALSE, 4); - gtk_label_set_justify (GTK_LABEL (label11), GTK_JUSTIFY_LEFT); - - info_general = gtk_label_new ("---\n---\n---\n---\n---\n---\n---\n---\n---\n---"); - gtk_widget_ref (info_general); - gtk_object_set_data_full (GTK_OBJECT (Info), "info_general", info_general, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (info_general); - gtk_box_pack_start (GTK_BOX (hbox9), info_general, FALSE, FALSE, 4); - gtk_label_set_justify (GTK_LABEL (info_general), GTK_JUSTIFY_LEFT); - - label13 = gtk_label_new (_("General")); - gtk_widget_ref (label13); - gtk_object_set_data_full (GTK_OBJECT (Info), "label13", label13, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label13); - gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 0), label13); - - scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_ref (scrolledwindow1); - gtk_object_set_data_full (GTK_OBJECT (Info), "scrolledwindow1", scrolledwindow1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (scrolledwindow1); - gtk_container_add (GTK_CONTAINER (notebook2), scrolledwindow1); - gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow1), 6); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - - viewport1 = gtk_viewport_new (NULL, NULL); - gtk_widget_ref (viewport1); - gtk_object_set_data_full (GTK_OBJECT (Info), "viewport1", viewport1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (viewport1); - gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1); - - info_samples = gtk_label_new (""); - gtk_widget_ref (info_samples); - gtk_object_set_data_full (GTK_OBJECT (Info), "info_samples", info_samples, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (info_samples); - gtk_container_add (GTK_CONTAINER (viewport1), info_samples); - gtk_label_set_justify (GTK_LABEL (info_samples), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (info_samples), 7.45058e-09, 7.45058e-09); - gtk_label_set_selectable(GTK_LABEL (info_samples), TRUE); - - label15 = gtk_label_new (_("Samples")); - gtk_widget_ref (label15); - gtk_object_set_data_full (GTK_OBJECT (Info), "label15", label15, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label15); - gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 1), label15); - - scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_ref (scrolledwindow2); - gtk_object_set_data_full (GTK_OBJECT (Info), "scrolledwindow2", scrolledwindow2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (scrolledwindow2); - gtk_container_add (GTK_CONTAINER (notebook2), scrolledwindow2); - gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow2), 6); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - - viewport2 = gtk_viewport_new (NULL, NULL); - gtk_widget_ref (viewport2); - gtk_object_set_data_full (GTK_OBJECT (Info), "viewport2", viewport2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (viewport2); - gtk_container_add (GTK_CONTAINER (scrolledwindow2), viewport2); - - info_instruments = gtk_label_new (""); - gtk_widget_ref (info_instruments); - gtk_object_set_data_full (GTK_OBJECT (Info), "info_instruments", info_instruments, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (info_instruments); - gtk_container_add (GTK_CONTAINER (viewport2), info_instruments); - gtk_label_set_justify (GTK_LABEL (info_instruments), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (info_instruments), 1.49012e-08, 7.45058e-09); - gtk_label_set_selectable(GTK_LABEL (info_instruments), TRUE); - - label17 = gtk_label_new (_("Instruments")); - gtk_widget_ref (label17); - gtk_object_set_data_full (GTK_OBJECT (Info), "label17", label17, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label17); - gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 2), label17); - - scrolledwindow3 = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_ref (scrolledwindow3); - gtk_object_set_data_full (GTK_OBJECT (Info), "scrolledwindow3", scrolledwindow3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (scrolledwindow3); - gtk_container_add (GTK_CONTAINER (notebook2), scrolledwindow3); - gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow3), 6); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow3), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - - viewport3 = gtk_viewport_new (NULL, NULL); - gtk_widget_ref (viewport3); - gtk_object_set_data_full (GTK_OBJECT (Info), "viewport3", viewport3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (viewport3); - gtk_container_add (GTK_CONTAINER (scrolledwindow3), viewport3); - - info_message = gtk_label_new (""); - gtk_widget_ref (info_message); - gtk_object_set_data_full (GTK_OBJECT (Info), "info_message", info_message, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (info_message); - gtk_container_add (GTK_CONTAINER (viewport3), info_message); - gtk_label_set_justify (GTK_LABEL (info_message), GTK_JUSTIFY_LEFT); - gtk_label_set_line_wrap(GTK_LABEL (info_message), TRUE); - gtk_label_set_selectable(GTK_LABEL (info_message), TRUE); - - label18 = gtk_label_new (_("Message")); - gtk_widget_ref (label18); - gtk_object_set_data_full (GTK_OBJECT (Info), "label18", label18, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label18); - gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 3), label18); - - hbuttonbox3 = gtk_hbutton_box_new (); - gtk_widget_ref (hbuttonbox3); - gtk_object_set_data_full (GTK_OBJECT (Info), "hbuttonbox3", hbuttonbox3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbuttonbox3); - gtk_box_pack_start (GTK_BOX (vbox14), hbuttonbox3, FALSE, FALSE, 0); - - info_close = gtk_button_new_with_label (_("Close")); - gtk_widget_ref (info_close); - gtk_object_set_data_full (GTK_OBJECT (Info), "info_close", info_close, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (info_close); - gtk_container_add (GTK_CONTAINER (hbuttonbox3), info_close); - GTK_WIDGET_SET_FLAGS (info_close, GTK_CAN_DEFAULT); - - gtk_signal_connect (GTK_OBJECT (Info), "delete_event", - GTK_SIGNAL_FUNC (hide_window), - NULL); - gtk_signal_connect (GTK_OBJECT (info_close), "clicked", - GTK_SIGNAL_FUNC (on_info_close_clicked), - NULL); - - return Info; -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/gui/interface.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,963 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +#include <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox2; + GtkWidget *notebook1; + GtkWidget *vbox3; + GtkWidget *hbox2; + GtkWidget *frame1; + GtkWidget *vbox4; + GSList *vbox4_group = NULL; + GtkWidget *bit16; + GtkWidget *bit8; + GtkWidget *frame2; + GtkWidget *vbox5; + GSList *vbox5_group = NULL; + GtkWidget *stereo; + GtkWidget *mono; + GtkWidget *hbox10; + GtkWidget *frame3; + GtkWidget *vbox6; + GSList *vbox6_group = NULL; + GtkWidget *samp48; + GtkWidget *samp44; + GtkWidget *samp22; + GtkWidget *samp11; + GtkWidget *frame9; + GtkWidget *vbox15; + GSList *vbox15_group = NULL; + GtkWidget *resampNearest; + GtkWidget *resampLinear; + GtkWidget *resampSpline; + GtkWidget *resampPolyphase; + GtkWidget *label2; + GtkWidget *vbox7; + GtkWidget *frame4; + GtkWidget *hbox3; + GtkWidget *vbox8; + GtkWidget *fxUseFilename; + GtkWidget *fxFastInfo; + GtkWidget *vbox9; + GtkWidget *fxNR; + GtkWidget *fxAmigaMOD; + GtkWidget *frame5; + GtkWidget *hbox4; + GtkWidget *fxReverb; + GtkWidget *vbox10; + GtkWidget *table1; + GtkWidget *fxReverbDepth; + GtkWidget *fxReverbDelay; + GtkWidget *label3; + GtkWidget *label4; + GtkWidget *frame6; + GtkWidget *hbox5; + GtkWidget *fxBassBoost; + GtkWidget *vbox11; + GtkWidget *table2; + GtkWidget *fxBassAmount; + GtkWidget *fxBassRange; + GtkWidget *label5; + GtkWidget *label6; + GtkWidget *frame7; + GtkWidget *hbox6; + GtkWidget *fxSurround; + GtkWidget *vbox12; + GtkWidget *table3; + GtkWidget *fxSurroundDepth; + GtkWidget *fxSurroundDelay; + GtkWidget *label7; + GtkWidget *label8; + GtkWidget *frame10; + GtkWidget *vbox16; + GtkWidget *label20; + GtkWidget *hbox11; + GtkWidget *fxPreamp; + GtkWidget *label19; + GtkWidget *fxPreampLevel; + GtkWidget *frame11; + GtkWidget *vbox17; + GSList *loopGroup_group = NULL; + GtkWidget *fxNoLoop; + GtkWidget *hbox13; + GtkWidget *fxLoopFinite; + GtkObject *fxLoopCount_adj; + GtkWidget *fxLoopCount; + GtkWidget *label21; + GtkWidget *fxLoopForever; + GtkWidget *label10; + GtkWidget *hbuttonbox2; + GtkWidget *config_ok; + GtkWidget *config_apply; + GtkWidget *config_cancel; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_widget_set_usize (Config, 350, -2); + gtk_window_set_title (GTK_WINDOW (Config), _("ModPlug Configuration")); + gtk_window_set_policy (GTK_WINDOW (Config), FALSE, FALSE, FALSE); + + vbox2 = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox2),5); + gtk_widget_ref (vbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox2", vbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (Config), vbox2); + + notebook1 = gtk_notebook_new (); + gtk_widget_ref (notebook1); + gtk_object_set_data_full (GTK_OBJECT (Config), "notebook1", notebook1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (notebook1); + gtk_box_pack_start (GTK_BOX (vbox2), notebook1, TRUE, TRUE, 5); + gtk_container_set_border_width (GTK_CONTAINER (notebook1), 0); + + vbox3 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox3); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox3", vbox3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox3); + gtk_container_add (GTK_CONTAINER (notebook1), vbox3); + gtk_container_set_border_width (GTK_CONTAINER (vbox3), 6); + + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox3), hbox2, TRUE, TRUE, 0); + + frame1 = gtk_frame_new (_("Resolution")); + gtk_widget_ref (frame1); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame1", frame1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame1); + gtk_box_pack_start (GTK_BOX (hbox2), frame1, TRUE, TRUE, 0); + + vbox4 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox4); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox4", vbox4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox4); + gtk_container_add (GTK_CONTAINER (frame1), vbox4); + + bit16 = gtk_radio_button_new_with_label (vbox4_group, _("16 bit")); + vbox4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (bit16)); + gtk_widget_ref (bit16); + gtk_object_set_data_full (GTK_OBJECT (Config), "bit16", bit16, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (bit16); + gtk_box_pack_start (GTK_BOX (vbox4), bit16, FALSE, FALSE, 0); + + bit8 = gtk_radio_button_new_with_label (vbox4_group, _("8 bit")); + vbox4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (bit8)); + gtk_widget_ref (bit8); + gtk_object_set_data_full (GTK_OBJECT (Config), "bit8", bit8, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (bit8); + gtk_box_pack_start (GTK_BOX (vbox4), bit8, FALSE, FALSE, 0); + + frame2 = gtk_frame_new (_("Channels")); + gtk_widget_ref (frame2); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (hbox2), frame2, TRUE, TRUE, 0); + + vbox5 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox5); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox5", vbox5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox5); + gtk_container_add (GTK_CONTAINER (frame2), vbox5); + + stereo = gtk_radio_button_new_with_label (vbox5_group, _("Stereo")); + vbox5_group = gtk_radio_button_group (GTK_RADIO_BUTTON (stereo)); + gtk_widget_ref (stereo); + gtk_object_set_data_full (GTK_OBJECT (Config), "stereo", stereo, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (stereo); + gtk_box_pack_start (GTK_BOX (vbox5), stereo, FALSE, FALSE, 0); + + mono = gtk_radio_button_new_with_label (vbox5_group, _("Mono (downmix)")); + vbox5_group = gtk_radio_button_group (GTK_RADIO_BUTTON (mono)); + gtk_widget_ref (mono); + gtk_object_set_data_full (GTK_OBJECT (Config), "mono", mono, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (mono); + gtk_box_pack_start (GTK_BOX (vbox5), mono, FALSE, FALSE, 0); + + hbox10 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox10); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox10", hbox10, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox10); + gtk_box_pack_start (GTK_BOX (vbox3), hbox10, TRUE, TRUE, 0); + + frame3 = gtk_frame_new (_("Sampling Rate")); + gtk_widget_ref (frame3); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame3); + gtk_box_pack_start (GTK_BOX (hbox10), frame3, TRUE, TRUE, 0); + + vbox6 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox6); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox6", vbox6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox6); + gtk_container_add (GTK_CONTAINER (frame3), vbox6); + + samp48 = gtk_radio_button_new_with_label (vbox6_group, _("48 kHz")); + vbox6_group = gtk_radio_button_group (GTK_RADIO_BUTTON (samp48)); + gtk_widget_ref (samp48); + gtk_object_set_data_full (GTK_OBJECT (Config), "samp48", samp48, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (samp48); + gtk_box_pack_start (GTK_BOX (vbox6), samp48, FALSE, FALSE, 0); + + samp44 = gtk_radio_button_new_with_label (vbox6_group, _("44 kHz")); + vbox6_group = gtk_radio_button_group (GTK_RADIO_BUTTON (samp44)); + gtk_widget_ref (samp44); + gtk_object_set_data_full (GTK_OBJECT (Config), "samp44", samp44, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (samp44); + gtk_box_pack_start (GTK_BOX (vbox6), samp44, FALSE, FALSE, 0); + + samp22 = gtk_radio_button_new_with_label (vbox6_group, _("22 kHz")); + vbox6_group = gtk_radio_button_group (GTK_RADIO_BUTTON (samp22)); + gtk_widget_ref (samp22); + gtk_object_set_data_full (GTK_OBJECT (Config), "samp22", samp22, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (samp22); + gtk_box_pack_start (GTK_BOX (vbox6), samp22, FALSE, FALSE, 0); + + samp11 = gtk_radio_button_new_with_label (vbox6_group, _("11 kHz")); + vbox6_group = gtk_radio_button_group (GTK_RADIO_BUTTON (samp11)); + gtk_widget_ref (samp11); + gtk_object_set_data_full (GTK_OBJECT (Config), "samp11", samp11, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (samp11); + gtk_box_pack_start (GTK_BOX (vbox6), samp11, FALSE, FALSE, 0); + + frame9 = gtk_frame_new (_("Resampling")); + gtk_widget_ref (frame9); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame9", frame9, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame9); + gtk_box_pack_start (GTK_BOX (hbox10), frame9, TRUE, TRUE, 0); + + vbox15 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox15); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox15", vbox15, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox15); + gtk_container_add (GTK_CONTAINER (frame9), vbox15); + + resampNearest = gtk_radio_button_new_with_label (vbox15_group, _("Nearest (fastest)")); + vbox15_group = gtk_radio_button_group (GTK_RADIO_BUTTON (resampNearest)); + gtk_widget_ref (resampNearest); + gtk_object_set_data_full (GTK_OBJECT (Config), "resampNearest", resampNearest, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (resampNearest); + gtk_box_pack_start (GTK_BOX (vbox15), resampNearest, FALSE, FALSE, 0); + + resampLinear = gtk_radio_button_new_with_label (vbox15_group, _("Linear (fast)")); + vbox15_group = gtk_radio_button_group (GTK_RADIO_BUTTON (resampLinear)); + gtk_widget_ref (resampLinear); + gtk_object_set_data_full (GTK_OBJECT (Config), "resampLinear", resampLinear, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (resampLinear); + gtk_box_pack_start (GTK_BOX (vbox15), resampLinear, FALSE, FALSE, 0); + + resampSpline = gtk_radio_button_new_with_label (vbox15_group, _("Spline (good quality)")); + vbox15_group = gtk_radio_button_group (GTK_RADIO_BUTTON (resampSpline)); + gtk_widget_ref (resampSpline); + gtk_object_set_data_full (GTK_OBJECT (Config), "resampSpline", resampSpline, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (resampSpline); + gtk_box_pack_start (GTK_BOX (vbox15), resampSpline, FALSE, FALSE, 0); + + resampPolyphase = gtk_radio_button_new_with_label (vbox15_group, _("8-tap Fir (extremely high quality)")); + vbox15_group = gtk_radio_button_group (GTK_RADIO_BUTTON (resampPolyphase)); + gtk_widget_ref (resampPolyphase); + gtk_object_set_data_full (GTK_OBJECT (Config), "resampPolyphase", resampPolyphase, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (resampPolyphase); + gtk_box_pack_start (GTK_BOX (vbox15), resampPolyphase, FALSE, FALSE, 0); + + label2 = gtk_label_new (_("Quality")); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (Config), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), label2); + + vbox7 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox7); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox7", vbox7, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox7); + gtk_container_add (GTK_CONTAINER (notebook1), vbox7); + gtk_container_set_border_width (GTK_CONTAINER (vbox7), 6); + + frame4 = gtk_frame_new (_("General")); + gtk_widget_ref (frame4); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame4", frame4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame4); + gtk_box_pack_start (GTK_BOX (vbox7), frame4, TRUE, TRUE, 0); + + hbox3 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox3); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox3", hbox3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox3); + gtk_container_add (GTK_CONTAINER (frame4), hbox3); + + vbox8 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox8); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox8", vbox8, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox8); + gtk_box_pack_start (GTK_BOX (hbox3), vbox8, TRUE, TRUE, 0); + + fxUseFilename = gtk_check_button_new_with_label (_("Use Filename as Song Title")); + gtk_widget_ref (fxUseFilename); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxUseFilename", fxUseFilename, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxUseFilename); + gtk_box_pack_start (GTK_BOX (vbox8), fxUseFilename, FALSE, FALSE, 0); + + fxFastInfo = gtk_check_button_new_with_label (_("Fast Playlist Info")); + gtk_widget_ref (fxFastInfo); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxFastInfo", fxFastInfo, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxFastInfo); + gtk_box_pack_start (GTK_BOX (vbox8), fxFastInfo, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxFastInfo), TRUE); + + vbox9 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox9); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox9", vbox9, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox9); + gtk_box_pack_start (GTK_BOX (hbox3), vbox9, TRUE, TRUE, 0); + + fxNR = gtk_check_button_new_with_label (_("Noise Reduction")); + gtk_widget_ref (fxNR); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxNR", fxNR, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxNR); + gtk_box_pack_start (GTK_BOX (vbox9), fxNR, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxNR), TRUE); + + fxAmigaMOD = gtk_check_button_new_with_label (_("Play Amiga MOD")); + gtk_widget_ref (fxAmigaMOD); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxAmigaMOD", fxAmigaMOD, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxAmigaMOD); + gtk_box_pack_start (GTK_BOX (vbox9), fxAmigaMOD, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxAmigaMOD), TRUE); + + frame5 = gtk_frame_new (_("Reverb")); + gtk_widget_ref (frame5); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame5", frame5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame5); + gtk_box_pack_start (GTK_BOX (vbox7), frame5, TRUE, TRUE, 0); + + hbox4 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox4); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox4", hbox4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox4); + gtk_container_add (GTK_CONTAINER (frame5), hbox4); + + fxReverb = gtk_check_button_new_with_label (_("Enable")); + gtk_widget_ref (fxReverb); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxReverb", fxReverb, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxReverb); + gtk_box_pack_start (GTK_BOX (hbox4), fxReverb, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxReverb), TRUE); + + vbox10 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox10); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox10", vbox10, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox10); + gtk_box_pack_start (GTK_BOX (hbox4), vbox10, TRUE, TRUE, 0); + + table1 = gtk_table_new (2, 2, FALSE); + gtk_widget_ref (table1); + gtk_object_set_data_full (GTK_OBJECT (Config), "table1", table1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (table1); + gtk_box_pack_start (GTK_BOX (vbox10), table1, TRUE, TRUE, 0); + + fxReverbDepth = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (30, 0, 100, 0, 0, 0))); + gtk_widget_ref (fxReverbDepth); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxReverbDepth", fxReverbDepth, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxReverbDepth); + gtk_table_attach (GTK_TABLE (table1), fxReverbDepth, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + fxReverbDelay = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (90, 40, 200, 0, 0, 0))); + gtk_widget_ref (fxReverbDelay); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxReverbDelay", fxReverbDelay, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxReverbDelay); + gtk_table_attach (GTK_TABLE (table1), fxReverbDelay, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + label3 = gtk_label_new (_("Depth")); + gtk_widget_ref (label3); + gtk_object_set_data_full (GTK_OBJECT (Config), "label3", label3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label3); + gtk_table_attach (GTK_TABLE (table1), label3, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label4 = gtk_label_new (_("Delay")); + gtk_widget_ref (label4); + gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label4); + gtk_table_attach (GTK_TABLE (table1), label4, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + frame6 = gtk_frame_new (_("Bass Boost")); + gtk_widget_ref (frame6); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame6", frame6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame6); + gtk_box_pack_start (GTK_BOX (vbox7), frame6, TRUE, TRUE, 0); + + hbox5 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox5); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox5", hbox5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox5); + gtk_container_add (GTK_CONTAINER (frame6), hbox5); + + fxBassBoost = gtk_check_button_new_with_label (_("Enable")); + gtk_widget_ref (fxBassBoost); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxBassBoost", fxBassBoost, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxBassBoost); + gtk_box_pack_start (GTK_BOX (hbox5), fxBassBoost, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxBassBoost), TRUE); + + vbox11 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox11); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox11", vbox11, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox11); + gtk_box_pack_start (GTK_BOX (hbox5), vbox11, TRUE, TRUE, 0); + + table2 = gtk_table_new (2, 2, FALSE); + gtk_widget_ref (table2); + gtk_object_set_data_full (GTK_OBJECT (Config), "table2", table2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (table2); + gtk_box_pack_start (GTK_BOX (vbox11), table2, TRUE, TRUE, 0); + + fxBassAmount = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (30, 0, 100, 0, 0, 0))); + gtk_widget_ref (fxBassAmount); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxBassAmount", fxBassAmount, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxBassAmount); + gtk_table_attach (GTK_TABLE (table2), fxBassAmount, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + fxBassRange = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (30, 10, 100, 0, 0, 0))); + gtk_widget_ref (fxBassRange); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxBassRange", fxBassRange, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxBassRange); + gtk_table_attach (GTK_TABLE (table2), fxBassRange, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + label5 = gtk_label_new (_("Amount")); + gtk_widget_ref (label5); + gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label5); + gtk_table_attach (GTK_TABLE (table2), label5, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label6 = gtk_label_new (_("Range")); + gtk_widget_ref (label6); + gtk_object_set_data_full (GTK_OBJECT (Config), "label6", label6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label6); + gtk_table_attach (GTK_TABLE (table2), label6, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + frame7 = gtk_frame_new (_("Surround")); + gtk_widget_ref (frame7); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame7", frame7, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame7); + gtk_box_pack_start (GTK_BOX (vbox7), frame7, TRUE, TRUE, 0); + + hbox6 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox6); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox6", hbox6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox6); + gtk_container_add (GTK_CONTAINER (frame7), hbox6); + + fxSurround = gtk_check_button_new_with_label (_("Enable")); + gtk_widget_ref (fxSurround); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxSurround", fxSurround, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxSurround); + gtk_box_pack_start (GTK_BOX (hbox6), fxSurround, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fxSurround), TRUE); + + vbox12 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox12); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox12", vbox12, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox12); + gtk_box_pack_start (GTK_BOX (hbox6), vbox12, TRUE, TRUE, 0); + + table3 = gtk_table_new (2, 2, FALSE); + gtk_widget_ref (table3); + gtk_object_set_data_full (GTK_OBJECT (Config), "table3", table3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (table3); + gtk_box_pack_start (GTK_BOX (vbox12), table3, TRUE, TRUE, 0); + + fxSurroundDepth = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (20, 0, 100, 0, 0, 0))); + gtk_widget_ref (fxSurroundDepth); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxSurroundDepth", fxSurroundDepth, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxSurroundDepth); + gtk_table_attach (GTK_TABLE (table3), fxSurroundDepth, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + fxSurroundDelay = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (20, 5, 40, 0, 0, 0))); + gtk_widget_ref (fxSurroundDelay); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxSurroundDelay", fxSurroundDelay, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxSurroundDelay); + gtk_table_attach (GTK_TABLE (table3), fxSurroundDelay, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + label7 = gtk_label_new (_("Depth")); + gtk_widget_ref (label7); + gtk_object_set_data_full (GTK_OBJECT (Config), "label7", label7, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label7); + gtk_table_attach (GTK_TABLE (table3), label7, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label8 = gtk_label_new (_("Delay")); + gtk_widget_ref (label8); + gtk_object_set_data_full (GTK_OBJECT (Config), "label8", label8, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label8); + gtk_table_attach (GTK_TABLE (table3), label8, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + frame10 = gtk_frame_new (_("Preamp")); + gtk_widget_ref (frame10); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame10", frame10, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame10); + gtk_box_pack_start (GTK_BOX (vbox7), frame10, TRUE, TRUE, 0); + + vbox16 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox16); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox16", vbox16, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox16); + gtk_container_add (GTK_CONTAINER (frame10), vbox16); + + label20 = gtk_label_new (_("Note: Setting the preamp too high may cause\nclipping / distortion!")); + gtk_widget_ref (label20); + gtk_object_set_data_full (GTK_OBJECT (Config), "label20", label20, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label20); + gtk_box_pack_start (GTK_BOX (vbox16), label20, FALSE, FALSE, 0); + + hbox11 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox11); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox11", hbox11, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox11); + gtk_box_pack_start (GTK_BOX (vbox16), hbox11, TRUE, TRUE, 0); + + fxPreamp = gtk_check_button_new_with_label (_("Enable")); + gtk_widget_ref (fxPreamp); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxPreamp", fxPreamp, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxPreamp); + gtk_box_pack_start (GTK_BOX (hbox11), fxPreamp, FALSE, FALSE, 0); + + label19 = gtk_label_new (_("Volume")); + gtk_widget_ref (label19); + gtk_object_set_data_full (GTK_OBJECT (Config), "label19", label19, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label19); + gtk_box_pack_start (GTK_BOX (hbox11), label19, FALSE, FALSE, 0); + + fxPreampLevel = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -3, 3, 1, 0, 0))); + gtk_widget_ref (fxPreampLevel); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxPreampLevel", fxPreampLevel, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxPreampLevel); + gtk_box_pack_start (GTK_BOX (hbox11), fxPreampLevel, TRUE, TRUE, 0); + + frame11 = gtk_frame_new (_("Looping")); + gtk_widget_ref (frame11); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame11", frame11, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame11); + gtk_box_pack_start (GTK_BOX (vbox7), frame11, TRUE, TRUE, 0); + + vbox17 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox17); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox17", vbox17, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox17); + gtk_container_add (GTK_CONTAINER (frame11), vbox17); + + fxNoLoop = gtk_radio_button_new_with_label (loopGroup_group, _("Don't loop")); + loopGroup_group = gtk_radio_button_group (GTK_RADIO_BUTTON (fxNoLoop)); + gtk_widget_ref (fxNoLoop); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxNoLoop", fxNoLoop, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxNoLoop); + gtk_box_pack_start (GTK_BOX (vbox17), fxNoLoop, FALSE, FALSE, 0); + + hbox13 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox13); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox13", hbox13, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox13); + gtk_box_pack_start (GTK_BOX (vbox17), hbox13, FALSE, FALSE, 0); + + fxLoopFinite = gtk_radio_button_new_with_label (loopGroup_group, _("Loop")); + loopGroup_group = gtk_radio_button_group (GTK_RADIO_BUTTON (fxLoopFinite)); + gtk_widget_ref (fxLoopFinite); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxLoopFinite", fxLoopFinite, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxLoopFinite); + gtk_box_pack_start (GTK_BOX (hbox13), fxLoopFinite, FALSE, FALSE, 0); + + fxLoopCount_adj = gtk_adjustment_new (1, 0, 100, 1, 10, 10); + fxLoopCount = gtk_spin_button_new (GTK_ADJUSTMENT (fxLoopCount_adj), 1, 0); + gtk_widget_ref (fxLoopCount); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxLoopCount", fxLoopCount, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxLoopCount); + gtk_box_pack_start (GTK_BOX (hbox13), fxLoopCount, FALSE, TRUE, 0); + + label21 = gtk_label_new (_("time(s)")); + gtk_widget_ref (label21); + gtk_object_set_data_full (GTK_OBJECT (Config), "label21", label21, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label21); + gtk_box_pack_start (GTK_BOX (hbox13), label21, FALSE, FALSE, 0); + + fxLoopForever = gtk_radio_button_new_with_label (loopGroup_group, _("Loop forever")); + loopGroup_group = gtk_radio_button_group (GTK_RADIO_BUTTON (fxLoopForever)); + gtk_widget_ref (fxLoopForever); + gtk_object_set_data_full (GTK_OBJECT (Config), "fxLoopForever", fxLoopForever, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fxLoopForever); + gtk_box_pack_start (GTK_BOX (vbox17), fxLoopForever, FALSE, FALSE, 0); + + label10 = gtk_label_new (_("Effects")); + gtk_widget_ref (label10); + gtk_object_set_data_full (GTK_OBJECT (Config), "label10", label10, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label10); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 1), label10); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox2), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox2), 5); + + config_ok = gtk_button_new_with_label (_("OK")); + gtk_widget_ref (config_ok); + gtk_object_set_data_full (GTK_OBJECT (Config), "config_ok", config_ok, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (config_ok); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), config_ok); + GTK_WIDGET_SET_FLAGS (config_ok, GTK_CAN_DEFAULT); + + config_apply = gtk_button_new_with_label (_("Apply")); + gtk_widget_ref (config_apply); + gtk_object_set_data_full (GTK_OBJECT (Config), "config_apply", config_apply, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (config_apply); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), config_apply); + GTK_WIDGET_SET_FLAGS (config_apply, GTK_CAN_DEFAULT); + + config_cancel = gtk_button_new_with_label (_("Cancel")); + gtk_widget_ref (config_cancel); + gtk_object_set_data_full (GTK_OBJECT (Config), "config_cancel", config_cancel, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (config_cancel); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), config_cancel); + GTK_WIDGET_SET_FLAGS (config_cancel, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (Config), "delete_event", + GTK_SIGNAL_FUNC (hide_window), + NULL); + gtk_signal_connect (GTK_OBJECT (config_ok), "clicked", + GTK_SIGNAL_FUNC (on_config_ok_clicked), + NULL); + gtk_signal_connect (GTK_OBJECT (config_apply), "clicked", + GTK_SIGNAL_FUNC (on_config_apply_clicked), + NULL); + gtk_signal_connect (GTK_OBJECT (config_cancel), "clicked", + GTK_SIGNAL_FUNC (on_config_cancel_clicked), + NULL); + + return Config; +} + +GtkWidget* +create_Info (void) +{ + GtkWidget *Info; + GtkWidget *vbox14; + GtkWidget *notebook2; + GtkWidget *hbox9; + GtkWidget *label11; + GtkWidget *info_general; + GtkWidget *label13; + GtkWidget *scrolledwindow1; + GtkWidget *viewport1; + GtkWidget *info_samples; + GtkWidget *label15; + GtkWidget *scrolledwindow2; + GtkWidget *viewport2; + GtkWidget *info_instruments; + GtkWidget *label17; + GtkWidget *scrolledwindow3; + GtkWidget *viewport3; + GtkWidget *info_message; + GtkWidget *label18; + GtkWidget *hbuttonbox3; + GtkWidget *info_close; + + Info = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Info), "Info", Info); + gtk_widget_set_usize (Info, 290, 264); + gtk_window_set_title (GTK_WINDOW (Info), _("MOD Info")); + + vbox14 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox14); + gtk_object_set_data_full (GTK_OBJECT (Info), "vbox14", vbox14, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox14); + gtk_container_add (GTK_CONTAINER (Info), vbox14); + + notebook2 = gtk_notebook_new (); + gtk_widget_ref (notebook2); + gtk_object_set_data_full (GTK_OBJECT (Info), "notebook2", notebook2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (notebook2); + gtk_box_pack_start (GTK_BOX (vbox14), notebook2, TRUE, TRUE, 8); + gtk_container_set_border_width (GTK_CONTAINER (notebook2), 6); + + hbox9 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox9); + gtk_object_set_data_full (GTK_OBJECT (Info), "hbox9", hbox9, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox9); + gtk_container_add (GTK_CONTAINER (notebook2), hbox9); + + label11 = gtk_label_new (_("Filename:\nTitle:\nType:\nLength:\nSpeed:\nTempo:\nSamples:\nInstruments:\nPatterns:\nChannels:")); + gtk_widget_ref (label11); + gtk_object_set_data_full (GTK_OBJECT (Info), "label11", label11, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label11); + gtk_box_pack_start (GTK_BOX (hbox9), label11, FALSE, FALSE, 4); + gtk_label_set_justify (GTK_LABEL (label11), GTK_JUSTIFY_LEFT); + + info_general = gtk_label_new ("---\n---\n---\n---\n---\n---\n---\n---\n---\n---"); + gtk_widget_ref (info_general); + gtk_object_set_data_full (GTK_OBJECT (Info), "info_general", info_general, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (info_general); + gtk_box_pack_start (GTK_BOX (hbox9), info_general, FALSE, FALSE, 4); + gtk_label_set_justify (GTK_LABEL (info_general), GTK_JUSTIFY_LEFT); + + label13 = gtk_label_new (_("General")); + gtk_widget_ref (label13); + gtk_object_set_data_full (GTK_OBJECT (Info), "label13", label13, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label13); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 0), label13); + + scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_ref (scrolledwindow1); + gtk_object_set_data_full (GTK_OBJECT (Info), "scrolledwindow1", scrolledwindow1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (scrolledwindow1); + gtk_container_add (GTK_CONTAINER (notebook2), scrolledwindow1); + gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow1), 6); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + + viewport1 = gtk_viewport_new (NULL, NULL); + gtk_widget_ref (viewport1); + gtk_object_set_data_full (GTK_OBJECT (Info), "viewport1", viewport1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (viewport1); + gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1); + + info_samples = gtk_label_new (""); + gtk_widget_ref (info_samples); + gtk_object_set_data_full (GTK_OBJECT (Info), "info_samples", info_samples, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (info_samples); + gtk_container_add (GTK_CONTAINER (viewport1), info_samples); + gtk_label_set_justify (GTK_LABEL (info_samples), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (info_samples), 7.45058e-09, 7.45058e-09); + gtk_label_set_selectable(GTK_LABEL (info_samples), TRUE); + + label15 = gtk_label_new (_("Samples")); + gtk_widget_ref (label15); + gtk_object_set_data_full (GTK_OBJECT (Info), "label15", label15, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label15); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 1), label15); + + scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_ref (scrolledwindow2); + gtk_object_set_data_full (GTK_OBJECT (Info), "scrolledwindow2", scrolledwindow2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (scrolledwindow2); + gtk_container_add (GTK_CONTAINER (notebook2), scrolledwindow2); + gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow2), 6); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + + viewport2 = gtk_viewport_new (NULL, NULL); + gtk_widget_ref (viewport2); + gtk_object_set_data_full (GTK_OBJECT (Info), "viewport2", viewport2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (viewport2); + gtk_container_add (GTK_CONTAINER (scrolledwindow2), viewport2); + + info_instruments = gtk_label_new (""); + gtk_widget_ref (info_instruments); + gtk_object_set_data_full (GTK_OBJECT (Info), "info_instruments", info_instruments, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (info_instruments); + gtk_container_add (GTK_CONTAINER (viewport2), info_instruments); + gtk_label_set_justify (GTK_LABEL (info_instruments), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (info_instruments), 1.49012e-08, 7.45058e-09); + gtk_label_set_selectable(GTK_LABEL (info_instruments), TRUE); + + label17 = gtk_label_new (_("Instruments")); + gtk_widget_ref (label17); + gtk_object_set_data_full (GTK_OBJECT (Info), "label17", label17, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label17); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 2), label17); + + scrolledwindow3 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_ref (scrolledwindow3); + gtk_object_set_data_full (GTK_OBJECT (Info), "scrolledwindow3", scrolledwindow3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (scrolledwindow3); + gtk_container_add (GTK_CONTAINER (notebook2), scrolledwindow3); + gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow3), 6); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow3), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + + viewport3 = gtk_viewport_new (NULL, NULL); + gtk_widget_ref (viewport3); + gtk_object_set_data_full (GTK_OBJECT (Info), "viewport3", viewport3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (viewport3); + gtk_container_add (GTK_CONTAINER (scrolledwindow3), viewport3); + + info_message = gtk_label_new (""); + gtk_widget_ref (info_message); + gtk_object_set_data_full (GTK_OBJECT (Info), "info_message", info_message, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (info_message); + gtk_container_add (GTK_CONTAINER (viewport3), info_message); + gtk_label_set_justify (GTK_LABEL (info_message), GTK_JUSTIFY_LEFT); + gtk_label_set_line_wrap(GTK_LABEL (info_message), TRUE); + gtk_label_set_selectable(GTK_LABEL (info_message), TRUE); + + label18 = gtk_label_new (_("Message")); + gtk_widget_ref (label18); + gtk_object_set_data_full (GTK_OBJECT (Info), "label18", label18, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label18); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 3), label18); + + hbuttonbox3 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox3); + gtk_object_set_data_full (GTK_OBJECT (Info), "hbuttonbox3", hbuttonbox3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox3); + gtk_box_pack_start (GTK_BOX (vbox14), hbuttonbox3, FALSE, FALSE, 0); + + info_close = gtk_button_new_with_label (_("Close")); + gtk_widget_ref (info_close); + gtk_object_set_data_full (GTK_OBJECT (Info), "info_close", info_close, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (info_close); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), info_close); + GTK_WIDGET_SET_FLAGS (info_close, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (Info), "delete_event", + GTK_SIGNAL_FUNC (hide_window), + NULL); + gtk_signal_connect (GTK_OBJECT (info_close), "clicked", + GTK_SIGNAL_FUNC (on_info_close_clicked), + NULL); + + return Info; +} +
--- a/Plugins/Input/modplug/gui/main.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,308 +0,0 @@ -/* - * Initial main.c file generated by Glade. Edit as required. - * Glade will not overwrite this file. - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <gtk/gtk.h> -#include <libintl.h> -#include "libaudacious/util.c" - -#include "interface.h" -#include "support.h" -#include "main.h" - -#include <sstream> -//open() -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -//mmap() -#include <unistd.h> -#include <sys/mman.h> -#include <fstream> - -#include "../stddefs.h" -#include <libmodplug/stdafx.h> -#include <libmodplug/sndfile.h> -#include "../archive/open.h" - -#define MAX_MESSAGE_LENGTH 4000 - -GtkWidget *AboutWin = NULL; -GtkWidget *ConfigWin = NULL; -GtkWidget *InfoWin = NULL; - -void ShowAboutWindow() -{ - if(!AboutWin) - { - gchar * about_text = g_strjoin( "" , _("Modplug Input Plugin for Audacious ver") , - VERSION , _("\nModplug sound engine written by Olivier Lapicque.\nXMMS interface for Modplug by Kenton Varda.\n(c)2000 Olivier Lapicque and Kenton Varda.\nUpdates and Maintainance by Konstanty Bialkowski.\nPorted to BMP by Theofilos Intzoglou.") , NULL ); - AboutWin = xmms_show_message( _("About Modplug") , about_text , _("Ok") , FALSE , NULL , NULL ); - gtk_signal_connect( GTK_OBJECT(AboutWin) , "destroy" , - GTK_SIGNAL_FUNC(gtk_widget_destroyed), &AboutWin); - g_free( about_text ); - } - gtk_widget_show(AboutWin); -} - -void ShowConfigureWindow(const ModplugXMMS::Settings& aProps) -{ - if(!ConfigWin) - ConfigWin = create_Config(); - - if(aProps.mBits == 8) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "bit8"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "bit16"), TRUE); - - if(aProps.mFrequency == 11025) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "samp11"), TRUE); - else if (aProps.mFrequency == 22050) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "samp22"), TRUE); - else if (aProps.mFrequency == 48000) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "samp48"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "samp44"), TRUE); - - if(aProps.mChannels == 1) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "mono"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "stereo"), TRUE); - - if(aProps.mResamplingMode == 0) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "resampNearest"), TRUE); - else if(aProps.mResamplingMode == 1) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "resampLinear"), TRUE); - else if(aProps.mResamplingMode == 2) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "resampSpline"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "resampPolyphase"), TRUE); - - if(aProps.mNoiseReduction) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxNR"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxNR"), FALSE); - - if(aProps.mGrabAmigaMOD) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxAmigaMOD"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxAmigaMOD"), FALSE); - - if(aProps.mFastinfo) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxFastInfo"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxFastInfo"), FALSE); - - if(aProps.mUseFilename) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxUseFilename"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxUseFilename"), FALSE); - - if(aProps.mReverb) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxReverb"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxReverb"), FALSE); - - if(aProps.mMegabass) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxBassBoost"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxBassBoost"), FALSE); - - if(aProps.mSurround) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxSurround"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxSurround"), FALSE); - - if(aProps.mPreamp) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxPreamp"), TRUE); - else - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxPreamp"), FALSE); - - gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxReverbDepth")), aProps.mReverbDepth); - gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxReverbDelay")), aProps.mReverbDelay); - gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxBassAmount")), aProps.mBassAmount); - gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxBassRange")), aProps.mBassRange); - gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxSurroundDepth")), aProps.mSurroundDepth); - gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxSurroundDelay")), aProps.mSurroundDelay); - gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxPreampLevel")), aProps.mPreampLevel); - - if(aProps.mLoopCount < 0) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxLoopForever"), TRUE); - else if(aProps.mLoopCount == 0) - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxNoLoop"), TRUE); - else - { - gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxLoopFinite"), TRUE); - gtk_adjustment_set_value(gtk_spin_button_get_adjustment( - (GtkSpinButton*)lookup_widget(ConfigWin, "fxLoopCount")), aProps.mLoopCount); - } - - gtk_widget_show(ConfigWin); -} - -void ShowInfoWindow(const string& aFilename) -{ - if(!InfoWin) - InfoWin = create_Info(); - - uint32 lSongTime, lNumSamples, lNumInstruments, i; - string lInfo; - char lBuffer[33]; - stringstream lStrStream(ios::out); //C++ replacement for sprintf() - - CSoundFile* lSoundFile; - - Archive* lArchive; - string lShortFN; - uint32 lPos; - - lPos = aFilename.find_last_of('/') + 1; - lShortFN = aFilename.substr(lPos); - - //open and mmap the file - lArchive = OpenArchive(aFilename); - if(lArchive->Size() == 0) - { - delete lArchive; - return; - } - - lSoundFile = new CSoundFile; - lSoundFile->Create((uchar*)lArchive->Map(), lArchive->Size()); - - lInfo = lShortFN; - lInfo += '\n'; - lInfo += lSoundFile->GetTitle(); - lInfo += '\n'; - - switch(lSoundFile->GetType()) - { - case MOD_TYPE_MOD: - lInfo+= "ProTracker"; - break; - case MOD_TYPE_S3M: - lInfo+= "Scream Tracker 3"; - break; - case MOD_TYPE_XM: - lInfo+= "Fast Tracker 2"; - break; - case MOD_TYPE_IT: - lInfo+= "Impulse Tracker"; - break; - case MOD_TYPE_MED: - lInfo+= "OctaMed"; - break; - case MOD_TYPE_MTM: - lInfo+= "MTM"; - break; - case MOD_TYPE_669: - lInfo+= "669 Composer / UNIS 669"; - break; - case MOD_TYPE_ULT: - lInfo+= "ULT"; - break; - case MOD_TYPE_STM: - lInfo+= "Scream Tracker"; - break; - case MOD_TYPE_FAR: - lInfo+= "Farandole"; - break; - case MOD_TYPE_AMF: - lInfo+= "ASYLUM Music Format"; - break; - case MOD_TYPE_AMS: - lInfo+= "AMS module"; - break; - case MOD_TYPE_DSM: - lInfo+= "DSIK Internal Format"; - break; - case MOD_TYPE_MDL: - lInfo+= "DigiTracker"; - break; - case MOD_TYPE_OKT: - lInfo+= "Oktalyzer"; - break; - case MOD_TYPE_DMF: - lInfo+= "Delusion Digital Music Fileformat (X-Tracker)"; - break; - case MOD_TYPE_PTM: - lInfo+= "PolyTracker"; - break; - case MOD_TYPE_DBM: - lInfo+= "DigiBooster Pro"; - break; - case MOD_TYPE_MT2: - lInfo+= "MT2"; - break; - case MOD_TYPE_AMF0: - lInfo+= "AMF0"; - break; - case MOD_TYPE_PSM: - lInfo+= "PSM"; - break; - default: - lInfo+= "Unknown"; - break; - } - lInfo += '\n'; - - lSongTime = lSoundFile->GetSongTime(); - lStrStream.clear(); - lStrStream << (int)(lSongTime / 60) << ":"; - if(lSongTime % 60 < 10) //single digit for seconds? - lStrStream << '0'; //yes, so add a 0. - lStrStream << (int)(lSongTime % 60); - - lStrStream << '\n'; - - lStrStream << (int)lSoundFile->GetMusicSpeed() << '\n'; - lStrStream << (int)lSoundFile->GetMusicTempo() << '\n'; - lStrStream << (int)(lNumSamples = lSoundFile->GetNumSamples()) << '\n'; - lStrStream << (int)(lNumInstruments = lSoundFile->GetNumInstruments()); - lStrStream << '\n'; - lStrStream << (int)(lSoundFile->GetNumPatterns()) << '\n'; - lStrStream << (int)lSoundFile->GetNumChannels(); - lInfo += lStrStream.str(); - - gtk_label_set_text((GtkLabel*)lookup_widget(InfoWin, "info_general"), lInfo.c_str()); - - lInfo = ""; - for(i = 0; i < lNumSamples; i++) - { - lSoundFile->GetSampleName(i, lBuffer); - lInfo += lBuffer; - lInfo += '\n'; - } - gtk_label_set_text((GtkLabel*)lookup_widget(InfoWin, "info_samples"), lInfo.c_str()); - - lInfo = ""; - for(i = 0; i < lNumInstruments; i++) - { - lSoundFile->GetInstrumentName(i, lBuffer); - lInfo += lBuffer; - lInfo += '\n'; - } - gtk_label_set_text((GtkLabel*)lookup_widget(InfoWin, "info_instruments"), lInfo.c_str()); - - char message[MAX_MESSAGE_LENGTH]; - static int length = 0; - - //textbox = (GtkLabel*)lookup_widget(InfoWin, "info_message"); - //gtk_text_backward_delete(textbox, length); - length = lSoundFile->GetSongComments(message, MAX_MESSAGE_LENGTH, 80); - if (length != 0) { - gtk_label_set_text((GtkLabel*)lookup_widget(InfoWin, "info_message"), message); - } - - //unload the file - lSoundFile->Destroy(); - delete lSoundFile; - delete lArchive; - - gtk_widget_show(InfoWin); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/gui/main.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,308 @@ +/* + * Initial main.c file generated by Glade. Edit as required. + * Glade will not overwrite this file. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gtk/gtk.h> +#include <libintl.h> +#include "libaudacious/util.c" + +#include "interface.h" +#include "support.h" +#include "main.h" + +#include <sstream> +//open() +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +//mmap() +#include <unistd.h> +#include <sys/mman.h> +#include <fstream> + +#include "../stddefs.h" +#include <libmodplug/stdafx.h> +#include <libmodplug/sndfile.h> +#include "../archive/open.h" + +#define MAX_MESSAGE_LENGTH 4000 + +GtkWidget *AboutWin = NULL; +GtkWidget *ConfigWin = NULL; +GtkWidget *InfoWin = NULL; + +void ShowAboutWindow() +{ + if(!AboutWin) + { + gchar * about_text = g_strjoin( "" , _("Modplug Input Plugin for Audacious ver") , + VERSION , _("\nModplug sound engine written by Olivier Lapicque.\nXMMS interface for Modplug by Kenton Varda.\n(c)2000 Olivier Lapicque and Kenton Varda.\nUpdates and Maintainance by Konstanty Bialkowski.\nPorted to BMP by Theofilos Intzoglou.") , NULL ); + AboutWin = xmms_show_message( _("About Modplug") , about_text , _("Ok") , FALSE , NULL , NULL ); + gtk_signal_connect( GTK_OBJECT(AboutWin) , "destroy" , + GTK_SIGNAL_FUNC(gtk_widget_destroyed), &AboutWin); + g_free( about_text ); + } + gtk_widget_show(AboutWin); +} + +void ShowConfigureWindow(const ModplugXMMS::Settings& aProps) +{ + if(!ConfigWin) + ConfigWin = create_Config(); + + if(aProps.mBits == 8) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "bit8"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "bit16"), TRUE); + + if(aProps.mFrequency == 11025) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "samp11"), TRUE); + else if (aProps.mFrequency == 22050) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "samp22"), TRUE); + else if (aProps.mFrequency == 48000) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "samp48"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "samp44"), TRUE); + + if(aProps.mChannels == 1) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "mono"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "stereo"), TRUE); + + if(aProps.mResamplingMode == 0) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "resampNearest"), TRUE); + else if(aProps.mResamplingMode == 1) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "resampLinear"), TRUE); + else if(aProps.mResamplingMode == 2) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "resampSpline"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "resampPolyphase"), TRUE); + + if(aProps.mNoiseReduction) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxNR"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxNR"), FALSE); + + if(aProps.mGrabAmigaMOD) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxAmigaMOD"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxAmigaMOD"), FALSE); + + if(aProps.mFastinfo) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxFastInfo"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxFastInfo"), FALSE); + + if(aProps.mUseFilename) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxUseFilename"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxUseFilename"), FALSE); + + if(aProps.mReverb) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxReverb"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxReverb"), FALSE); + + if(aProps.mMegabass) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxBassBoost"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxBassBoost"), FALSE); + + if(aProps.mSurround) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxSurround"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxSurround"), FALSE); + + if(aProps.mPreamp) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxPreamp"), TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxPreamp"), FALSE); + + gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxReverbDepth")), aProps.mReverbDepth); + gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxReverbDelay")), aProps.mReverbDelay); + gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxBassAmount")), aProps.mBassAmount); + gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxBassRange")), aProps.mBassRange); + gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxSurroundDepth")), aProps.mSurroundDepth); + gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxSurroundDelay")), aProps.mSurroundDelay); + gtk_adjustment_set_value(gtk_range_get_adjustment((GtkRange*)lookup_widget(ConfigWin, "fxPreampLevel")), aProps.mPreampLevel); + + if(aProps.mLoopCount < 0) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxLoopForever"), TRUE); + else if(aProps.mLoopCount == 0) + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxNoLoop"), TRUE); + else + { + gtk_toggle_button_set_active((GtkToggleButton*)lookup_widget(ConfigWin, "fxLoopFinite"), TRUE); + gtk_adjustment_set_value(gtk_spin_button_get_adjustment( + (GtkSpinButton*)lookup_widget(ConfigWin, "fxLoopCount")), aProps.mLoopCount); + } + + gtk_widget_show(ConfigWin); +} + +void ShowInfoWindow(const string& aFilename) +{ + if(!InfoWin) + InfoWin = create_Info(); + + uint32 lSongTime, lNumSamples, lNumInstruments, i; + string lInfo; + char lBuffer[33]; + stringstream lStrStream(ios::out); //C++ replacement for sprintf() + + CSoundFile* lSoundFile; + + Archive* lArchive; + string lShortFN; + uint32 lPos; + + lPos = aFilename.find_last_of('/') + 1; + lShortFN = aFilename.substr(lPos); + + //open and mmap the file + lArchive = OpenArchive(aFilename); + if(lArchive->Size() == 0) + { + delete lArchive; + return; + } + + lSoundFile = new CSoundFile; + lSoundFile->Create((uchar*)lArchive->Map(), lArchive->Size()); + + lInfo = lShortFN; + lInfo += '\n'; + lInfo += lSoundFile->GetTitle(); + lInfo += '\n'; + + switch(lSoundFile->GetType()) + { + case MOD_TYPE_MOD: + lInfo+= "ProTracker"; + break; + case MOD_TYPE_S3M: + lInfo+= "Scream Tracker 3"; + break; + case MOD_TYPE_XM: + lInfo+= "Fast Tracker 2"; + break; + case MOD_TYPE_IT: + lInfo+= "Impulse Tracker"; + break; + case MOD_TYPE_MED: + lInfo+= "OctaMed"; + break; + case MOD_TYPE_MTM: + lInfo+= "MTM"; + break; + case MOD_TYPE_669: + lInfo+= "669 Composer / UNIS 669"; + break; + case MOD_TYPE_ULT: + lInfo+= "ULT"; + break; + case MOD_TYPE_STM: + lInfo+= "Scream Tracker"; + break; + case MOD_TYPE_FAR: + lInfo+= "Farandole"; + break; + case MOD_TYPE_AMF: + lInfo+= "ASYLUM Music Format"; + break; + case MOD_TYPE_AMS: + lInfo+= "AMS module"; + break; + case MOD_TYPE_DSM: + lInfo+= "DSIK Internal Format"; + break; + case MOD_TYPE_MDL: + lInfo+= "DigiTracker"; + break; + case MOD_TYPE_OKT: + lInfo+= "Oktalyzer"; + break; + case MOD_TYPE_DMF: + lInfo+= "Delusion Digital Music Fileformat (X-Tracker)"; + break; + case MOD_TYPE_PTM: + lInfo+= "PolyTracker"; + break; + case MOD_TYPE_DBM: + lInfo+= "DigiBooster Pro"; + break; + case MOD_TYPE_MT2: + lInfo+= "MT2"; + break; + case MOD_TYPE_AMF0: + lInfo+= "AMF0"; + break; + case MOD_TYPE_PSM: + lInfo+= "PSM"; + break; + default: + lInfo+= "Unknown"; + break; + } + lInfo += '\n'; + + lSongTime = lSoundFile->GetSongTime(); + lStrStream.clear(); + lStrStream << (int)(lSongTime / 60) << ":"; + if(lSongTime % 60 < 10) //single digit for seconds? + lStrStream << '0'; //yes, so add a 0. + lStrStream << (int)(lSongTime % 60); + + lStrStream << '\n'; + + lStrStream << (int)lSoundFile->GetMusicSpeed() << '\n'; + lStrStream << (int)lSoundFile->GetMusicTempo() << '\n'; + lStrStream << (int)(lNumSamples = lSoundFile->GetNumSamples()) << '\n'; + lStrStream << (int)(lNumInstruments = lSoundFile->GetNumInstruments()); + lStrStream << '\n'; + lStrStream << (int)(lSoundFile->GetNumPatterns()) << '\n'; + lStrStream << (int)lSoundFile->GetNumChannels(); + lInfo += lStrStream.str(); + + gtk_label_set_text((GtkLabel*)lookup_widget(InfoWin, "info_general"), lInfo.c_str()); + + lInfo = ""; + for(i = 0; i < lNumSamples; i++) + { + lSoundFile->GetSampleName(i, lBuffer); + lInfo += lBuffer; + lInfo += '\n'; + } + gtk_label_set_text((GtkLabel*)lookup_widget(InfoWin, "info_samples"), lInfo.c_str()); + + lInfo = ""; + for(i = 0; i < lNumInstruments; i++) + { + lSoundFile->GetInstrumentName(i, lBuffer); + lInfo += lBuffer; + lInfo += '\n'; + } + gtk_label_set_text((GtkLabel*)lookup_widget(InfoWin, "info_instruments"), lInfo.c_str()); + + char message[MAX_MESSAGE_LENGTH]; + static int length = 0; + + //textbox = (GtkLabel*)lookup_widget(InfoWin, "info_message"); + //gtk_text_backward_delete(textbox, length); + length = lSoundFile->GetSongComments(message, MAX_MESSAGE_LENGTH, 80); + if (length != 0) { + gtk_label_set_text((GtkLabel*)lookup_widget(InfoWin, "info_message"), message); + } + + //unload the file + lSoundFile->Destroy(); + delete lSoundFile; + delete lArchive; + + gtk_widget_show(InfoWin); +}
--- a/Plugins/Input/modplug/gui/support.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* - * DO NOT EDIT THIS FILE - it is generated by Glade. - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> - -#include <gtk/gtk.h> - -#include "support.h" - -/* This is an internally used function to check if a pixmap file exists. */ -static gchar* check_file_exists (const gchar *directory, - const gchar *filename); - -/* This is an internally used function to create pixmaps. */ -static GtkWidget* create_dummy_pixmap (GtkWidget *widget); - -GtkWidget* -lookup_widget (GtkWidget *widget, - const gchar *widget_name) -{ - GtkWidget *parent, *found_widget; - - for (;;) - { - if (GTK_IS_MENU (widget)) - parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); - else - parent = widget->parent; - if (parent == NULL) - break; - widget = parent; - } - - found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), - widget_name); - if (!found_widget) - g_warning ("Widget not found: %s", widget_name); - return found_widget; -} - -/* This is a dummy pixmap we use when a pixmap can't be found. */ -static char *dummy_pixmap_xpm[] = { -/* columns rows colors chars-per-pixel */ -"1 1 1 1", -" c None", -/* pixels */ -" " -}; - -/* This is an internally used function to create pixmaps. */ -static GtkWidget* -create_dummy_pixmap (GtkWidget *widget) -{ - GdkColormap *colormap; - GdkPixmap *gdkpixmap; - GdkBitmap *mask; - GtkWidget *pixmap; - - colormap = gtk_widget_get_colormap (widget); - gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, - NULL, dummy_pixmap_xpm); - if (gdkpixmap == NULL) - g_error ("Couldn't create replacement pixmap."); - pixmap = gtk_pixmap_new (gdkpixmap, mask); - gdk_pixmap_unref (gdkpixmap); - gdk_bitmap_unref (mask); - return pixmap; -} - -static GList *pixmaps_directories = NULL; - -/* Use this function to set the directory containing installed pixmaps. */ -void -add_pixmap_directory (const gchar *directory) -{ - pixmaps_directories = g_list_prepend (pixmaps_directories, - g_strdup (directory)); -} - -/* This is an internally used function to create pixmaps. */ -GtkWidget* -create_pixmap (GtkWidget *widget, - const gchar *filename) -{ - gchar *found_filename = NULL; - GdkColormap *colormap; - GdkPixmap *gdkpixmap; - GdkBitmap *mask; - GtkWidget *pixmap; - GList *elem; - - /* We first try any pixmaps directories set by the application. */ - elem = pixmaps_directories; - while (elem) - { - found_filename = check_file_exists ((gchar*)elem->data, filename); - if (found_filename) - break; - elem = elem->next; - } - - /* If we haven't found the pixmap, try the source directory. */ - if (!found_filename) - { - found_filename = check_file_exists ("../pixmaps", filename); - } - - if (!found_filename) - { - g_warning (_("Couldn't find pixmap file: %s"), filename); - return create_dummy_pixmap (widget); - } - - colormap = gtk_widget_get_colormap (widget); - gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, - NULL, found_filename); - if (gdkpixmap == NULL) - { - g_warning (_("Error loading pixmap file: %s"), found_filename); - g_free (found_filename); - return create_dummy_pixmap (widget); - } - g_free (found_filename); - pixmap = gtk_pixmap_new (gdkpixmap, mask); - gdk_pixmap_unref (gdkpixmap); - gdk_bitmap_unref (mask); - return pixmap; -} - -/* This is an internally used function to check if a pixmap file exists. */ -gchar* -check_file_exists (const gchar *directory, - const gchar *filename) -{ - gchar *full_filename; - struct stat s; - gint status; - - full_filename = (gchar*) g_malloc (strlen (directory) + 1 - + strlen (filename) + 1); - strcpy (full_filename, directory); - strcat (full_filename, G_DIR_SEPARATOR_S); - strcat (full_filename, filename); - - status = stat (full_filename, &s); - if (status == 0 && S_ISREG (s.st_mode)) - return full_filename; - g_free (full_filename); - return NULL; -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/gui/support.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,159 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +#include <gtk/gtk.h> + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("../pixmaps", filename); + } + + if (!found_filename) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning (_("Error loading pixmap file: %s"), found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} +
--- a/Plugins/Input/modplug/modplugbmp.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,800 +0,0 @@ -/* Modplug XMMS Plugin - * Authors: Kenton Varda <temporal@gauge3d.org> - * - * This source code is public domain. - */ - -#include <fstream> -#include <unistd.h> -#include <math.h> - -#include "modplugbmp.h" -#include <libmodplug/stdafx.h> -#include <libmodplug/sndfile.h> -#include "stddefs.h" -#include "archive/open.h" -#include "libaudacious/configdb.h" -#include "libaudacious/vfs.h" -extern "C" { -#include "audacious/output.h" -} - -// ModplugXMMS member functions =============================== - -// operations ---------------------------------------- -ModplugXMMS::ModplugXMMS() -{ - mSoundFile = new CSoundFile; -} -ModplugXMMS::~ModplugXMMS() -{ - delete mSoundFile; -} - -ModplugXMMS::Settings::Settings() -{ - mSurround = true; - mOversamp = true; - mReverb = false; - mMegabass = false; - mNoiseReduction = true; - mVolumeRamp = true; - mFastinfo = true; - mUseFilename = false; - mGrabAmigaMOD = true; - - mChannels = 2; - mFrequency = 44100; - mBits = 16; - mResamplingMode = SRCMODE_POLYPHASE; - - mReverbDepth = 30; - mReverbDelay = 100; - mBassAmount = 40; - mBassRange = 30; - mSurroundDepth = 20; - mSurroundDelay = 20; - - mPreamp = false; - mPreampLevel = 0.0f; - - mLoopCount = 0; //don't loop -} - -void ModplugXMMS::Init(void) -{ - ConfigDb *db; - - db = bmp_cfg_db_open(); - - bmp_cfg_db_get_bool(db,"modplug","Surround", &mModProps.mSurround); - bmp_cfg_db_get_bool(db,"modplug","Oversampling", &mModProps.mOversamp); - bmp_cfg_db_get_bool(db,"modplug","Megabass", &mModProps.mMegabass); - bmp_cfg_db_get_bool(db,"modplug","NoiseReduction", &mModProps.mNoiseReduction); - bmp_cfg_db_get_bool(db,"modplug","VolumeRamp", &mModProps.mVolumeRamp); - bmp_cfg_db_get_bool(db,"modplug","Reverb", &mModProps.mReverb); - bmp_cfg_db_get_bool(db,"modplug","FastInfo", &mModProps.mFastinfo); - bmp_cfg_db_get_bool(db,"modplug","UseFileName", &mModProps.mUseFilename); - bmp_cfg_db_get_bool(db,"modplug","GrabAmigaMOD", &mModProps.mGrabAmigaMOD); - bmp_cfg_db_get_bool(db,"modplug","PreAmp", &mModProps.mPreamp); - bmp_cfg_db_get_float(db,"modplug","PreAmpLevel", &mModProps.mPreampLevel); - bmp_cfg_db_get_int(db,"modplug", "Channels", &mModProps.mChannels); - bmp_cfg_db_get_int(db,"modplug", "Bits", &mModProps.mBits); - bmp_cfg_db_get_int(db,"modplug", "Frequency", &mModProps.mFrequency); - bmp_cfg_db_get_int(db,"modplug", "ResamplineMode", &mModProps.mResamplingMode); - bmp_cfg_db_get_int(db,"modplug", "ReverbDepth", &mModProps.mReverbDepth); - bmp_cfg_db_get_int(db,"modplug", "ReverbDelay", &mModProps.mReverbDelay); - bmp_cfg_db_get_int(db,"modplug", "BassAmount", &mModProps.mBassAmount); - bmp_cfg_db_get_int(db,"modplug", "BassRange", &mModProps.mBassRange); - bmp_cfg_db_get_int(db,"modplug", "SurroundDepth", &mModProps.mSurroundDepth); - bmp_cfg_db_get_int(db,"modplug", "SurroundDelay", &mModProps.mSurroundDelay); - bmp_cfg_db_get_int(db,"modplug", "LoopCount", &mModProps.mLoopCount); - - bmp_cfg_db_close(db); -} - -bool ModplugXMMS::CanPlayFile(const string& aFilename) -{ - string lExt; - uint32 lPos; - - VFSFile *file; - gchar magic[4]; - - if ((file = vfs_fopen(aFilename.c_str(), "rb"))) { - vfs_fread(magic, 1, 4, file); - if (!memcmp(magic, UMX_MAGIC, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, XM_MAGIC, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, M669_MAGIC, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, IT_MAGIC, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MTM_MAGIC, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, PSM_MAGIC, 4)) { - vfs_fclose(file); - return 1; - } - vfs_fseek(file, 44, SEEK_SET); - vfs_fread(magic, 1, 4, file); - if (!memcmp(magic, S3M_MAGIC, 4)) { - vfs_fclose(file); - return 1; - } - if(mModProps.mGrabAmigaMOD) { - vfs_fseek(file, 1080, SEEK_SET); - vfs_fread(magic, 1, 4, file); - if (!memcmp(magic, MOD_MAGIC_PROTRACKER4, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_PROTRACKER4X, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_NOISETRACKER, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_STARTRACKER4, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_STARTRACKER8, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_STARTRACKER4X, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_STARTRACKER8X, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_FASTTRACKER4, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_FASTTRACKER6, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_FASTTRACKER8, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_OKTALYZER8, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_OKTALYZER8X, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_TAKETRACKER16, 4)) { - vfs_fclose(file); - return 1; - } - if (!memcmp(magic, MOD_MAGIC_TAKETRACKER32, 4)) { - vfs_fclose(file); - return 1; - } - } /* end of if(mModProps.mGrabAmigaMOD) */ - - /* We didn't find the magic bytes, fall back to extension check */ - vfs_fclose(file); - } /* end of vfs_open main if statement */ - - lPos = aFilename.find_last_of('.'); - if((int)lPos == -1) - return false; - lExt = aFilename.substr(lPos); - for(uint32 i = 0; i < lExt.length(); i++) - lExt[i] = tolower(lExt[i]); - - if (lExt == ".amf") - return true; - if (lExt == ".ams") - return true; - if (lExt == ".dbm") - return true; - if (lExt == ".dbf") - return true; - if (lExt == ".dsm") - return true; - if (lExt == ".far") - return true; - if (lExt == ".mdl") - return true; - if (lExt == ".stm") - return true; - if (lExt == ".ult") - return true; - if (lExt == ".j2b") - return true; - if (lExt == ".mt2") - return true; - - if (lExt == ".mdz") - return true; - if (lExt == ".mdr") - return true; - if (lExt == ".mdgz") - return true; - if (lExt == ".mdbz") - return true; - if (lExt == ".s3z") - return true; - if (lExt == ".s3r") - return true; - if (lExt == ".s3gz") - return true; - if (lExt == ".xmz") - return true; - if (lExt == ".xmr") - return true; - if (lExt == ".xmgz") - return true; - if (lExt == ".itz") - return true; - if (lExt == ".itr") - return true; - if (lExt == ".itgz") - return true; - if (lExt == ".dmf") - return true; - - if (lExt == ".zip") - return ContainsMod(aFilename); - if (lExt == ".gz") - return ContainsMod(aFilename); - if (lExt == ".bz2") - return ContainsMod(aFilename); - - return false; -} - -void* ModplugXMMS::PlayThread(void* arg) -{ - ((ModplugXMMS*)arg)->PlayLoop(); - return NULL; -} - -void ModplugXMMS::PlayLoop() -{ - uint32 lLength; - //the user might change the number of channels while playing. - // we don't want this to take effect until we are done! - uint8 lChannels = mModProps.mChannels; - - while(!mStopped) - { - if(!(lLength = mSoundFile->Read( - mBuffer, - mBufSize))) - { - //no more to play. Wait for output to finish and then stop. - while((mOutPlug->buffer_playing()) - && (!mStopped)) - usleep(10000); - break; - } - - if(mModProps.mPreamp) - { - //apply preamp - if(mModProps.mBits == 16) - { - uint n = mBufSize >> 1; - for(uint i = 0; i < n; i++) { - short old = ((short*)mBuffer)[i]; - ((short*)mBuffer)[i] *= (short int)mPreampFactor; - // detect overflow and clip! - if ((old & 0x8000) != - (((short*)mBuffer)[i] & 0x8000)) - ((short*)mBuffer)[i] = old | 0x7FFF; - - } - } - else - { - for(uint i = 0; i < mBufSize; i++) { - uchar old = ((uchar*)mBuffer)[i]; - ((uchar*)mBuffer)[i] *= (short int)mPreampFactor; - // detect overflow and clip! - if ((old & 0x80) != - (((uchar*)mBuffer)[i] & 0x80)) - ((uchar*)mBuffer)[i] = old | 0x7F; - } - } - } - - if(mStopped) - break; - - //wait for buffer space to free up. - while(((mOutPlug->buffer_free() - < (int)mBufSize)) - && (!mStopped)) - usleep(10000); - - if(mStopped) - break; - - produce_audio - ( - mPlayed, - mFormat, - lChannels, - mBufSize, - mBuffer, - NULL - ); - - mPlayed += mBufTime; - } - -// mOutPlug->flush(0); - mOutPlug->close_audio(); - - //Unload the file - mSoundFile->Destroy(); - delete mArchive; - - if (mBuffer) - { - delete [] mBuffer; - mBuffer = NULL; - } - - mPaused = false; - mStopped = true; - - g_thread_exit(NULL); -} - -void ModplugXMMS::PlayFile(const string& aFilename) -{ - mStopped = true; - mPaused = false; - - //open and mmap the file - mArchive = OpenArchive(aFilename); - if(mArchive->Size() == 0) - { - delete mArchive; - return; - } - - if (mBuffer) - delete [] mBuffer; - - //find buftime to get approx. 512 samples/block - mBufTime = 512000 / mModProps.mFrequency + 1; - - mBufSize = mBufTime; - mBufSize *= mModProps.mFrequency; - mBufSize /= 1000; //milliseconds - mBufSize *= mModProps.mChannels; - mBufSize *= mModProps.mBits / 8; - - mBuffer = new uchar[mBufSize]; - if(!mBuffer) - return; //out of memory! - - CSoundFile::SetWaveConfig - ( - mModProps.mFrequency, - mModProps.mBits, - mModProps.mChannels - ); - CSoundFile::SetWaveConfigEx - ( - mModProps.mSurround, - !mModProps.mOversamp, - mModProps.mReverb, - true, - mModProps.mMegabass, - mModProps.mNoiseReduction, - false - ); - - // [Reverb level 0(quiet)-100(loud)], [delay in ms, usually 40-200ms] - if(mModProps.mReverb) - { - CSoundFile::SetReverbParameters - ( - mModProps.mReverbDepth, - mModProps.mReverbDelay - ); - } - // [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100] - if(mModProps.mMegabass) - { - CSoundFile::SetXBassParameters - ( - mModProps.mBassAmount, - mModProps.mBassRange - ); - } - // [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-40ms] - if(mModProps.mSurround) - { - CSoundFile::SetSurroundParameters - ( - mModProps.mSurroundDepth, - mModProps.mSurroundDelay - ); - } - CSoundFile::SetResamplingMode(mModProps.mResamplingMode); - mSoundFile->SetRepeatCount(mModProps.mLoopCount); - mPreampFactor = exp(mModProps.mPreampLevel); - - mPaused = false; - mStopped = false; - - mSoundFile->Create - ( - (uchar*)mArchive->Map(), - mArchive->Size() - ); - mPlayed = 0; - - bool useFilename = mModProps.mUseFilename; - - if(!useFilename) - { - strncpy(mModName, mSoundFile->GetTitle(), 100); - - for(int i = 0; mModName[i] == ' ' || mModName[i] == 0; i++) - { - if(mModName[i] == 0) - { - useFilename = true; //mod name is blank -- use filename - break; - } - } - } - - if(useFilename) - { - strncpy(mModName, strrchr(aFilename.c_str(), '/') + 1, 100); - char* ext = strrchr(mModName, '.'); - if(ext) *ext = '\0'; - } - - mInPlug->set_info - ( - mModName, - mSoundFile->GetSongTime() * 1000, - mSoundFile->GetNumChannels() * 1000, - mModProps.mFrequency, - mModProps.mChannels - ); - - mStopped = mPaused = false; - - if(mModProps.mBits == 16) - mFormat = FMT_S16_NE; - else - mFormat = FMT_U8; - - mOutPlug->open_audio - ( - mFormat, - mModProps.mFrequency, - mModProps.mChannels - ); - - mDecodeThread = g_thread_create( - (GThreadFunc)PlayThread, - this, - TRUE, - NULL - ); -} - -void ModplugXMMS::Stop(void) -{ - if(mStopped) - return; - - mStopped = true; - mPaused = false; - - g_thread_join(mDecodeThread); -} - -void ModplugXMMS::Pause(bool aPaused) -{ - if(aPaused) - mPaused = true; - else - mPaused = false; - - mOutPlug->pause(aPaused); -} - -void ModplugXMMS::Seek(float32 aTime) -{ - uint32 lMax; - uint32 lMaxtime; - float32 lPostime; - - if(aTime > (lMaxtime = mSoundFile->GetSongTime())) - aTime = lMaxtime; - lMax = mSoundFile->GetMaxPosition(); - lPostime = float(lMax) / lMaxtime; - - mSoundFile->SetCurrentPos(int(aTime * lPostime)); - - mOutPlug->flush(int(aTime * 1000)); - mPlayed = uint32(aTime * 1000); -} - -float32 ModplugXMMS::GetTime(void) -{ - if(mStopped) - return -1; - return (float32)mOutPlug->output_time() / 1000; -} - -void ModplugXMMS::GetSongInfo(const string& aFilename, char*& aTitle, int32& aLength) -{ - aLength = -1; - fstream lTestFile; - string lError; - bool lDone; - - lTestFile.open(aFilename.c_str(), ios::in); - if(!lTestFile) - { - lError = "**no such file: "; - lError += strrchr(aFilename.c_str(), '/') + 1; - aTitle = new char[lError.length() + 1]; - strcpy(aTitle, lError.c_str()); - return; - } - - lTestFile.close(); - - if(mModProps.mFastinfo) - { - if(mModProps.mUseFilename) - { - //Use filename as name - aTitle = new char[aFilename.length() + 1]; - strcpy(aTitle, strrchr(aFilename.c_str(), '/') + 1); - *strrchr(aTitle, '.') = '\0'; - return; - } - - fstream lModFile; - string lExt; - uint32 lPos; - - lDone = true; - - // previously ios::nocreate was used (X Standard C++ Library) - lModFile.open(aFilename.c_str(), ios::in); - - lPos = aFilename.find_last_of('.'); - if((int)lPos == 0) - return; - lExt = aFilename.substr(lPos); - for(uint32 i = 0; i < lExt.length(); i++) - lExt[i] = tolower(lExt[i]); - - if (lExt == ".mod") - { - lModFile.read(mModName, 20); - mModName[20] = 0; - } - else if (lExt == ".s3m") - { - lModFile.read(mModName, 28); - mModName[28] = 0; - } - else if (lExt == ".xm") - { - lModFile.seekg(17); - lModFile.read(mModName, 20); - mModName[20] = 0; - } - else if (lExt == ".it") - { - lModFile.seekg(4); - lModFile.read(mModName, 28); - mModName[28] = 0; - } - else - lDone = false; //fall back to slow info - - lModFile.close(); - - if(lDone) - { - for(int i = 0; mModName[i] != 0; i++) - { - if(mModName[i] != ' ') - { - aTitle = new char[strlen(mModName) + 1]; - strcpy(aTitle, mModName); - - return; - } - } - - //mod name is blank. Use filename instead. - aTitle = new char[aFilename.length() + 1]; - strcpy(aTitle, strrchr(aFilename.c_str(), '/') + 1); - *strrchr(aTitle, '.') = '\0'; - return; - } - } - - Archive* lArchive; - CSoundFile* lSoundFile; - const char* lTitle; - - //open and mmap the file - lArchive = OpenArchive(aFilename); - if(lArchive->Size() == 0) - { - lError = "**bad mod file: "; - lError += strrchr(aFilename.c_str(), '/') + 1; - aTitle = new char[lError.length() + 1]; - strcpy(aTitle, lError.c_str()); - delete lArchive; - return; - } - - lSoundFile = new CSoundFile; - lSoundFile->Create((uchar*)lArchive->Map(), lArchive->Size()); - - if(!mModProps.mUseFilename) - { - lTitle = lSoundFile->GetTitle(); - - for(int i = 0; lTitle[i] != 0; i++) - { - if(lTitle[i] != ' ') - { - aTitle = new char[strlen(lTitle) + 1]; - strcpy(aTitle, lTitle); - goto therest; //sorry - } - } - } - - //mod name is blank, or user wants the filename to be used as the title. - aTitle = new char[aFilename.length() + 1]; - strcpy(aTitle, strrchr(aFilename.c_str(), '/') + 1); - *strrchr(aTitle, '.') = '\0'; - -therest: - aLength = lSoundFile->GetSongTime() * 1000; //It wants milliseconds!?! - - //unload the file - lSoundFile->Destroy(); - delete lSoundFile; - delete lArchive; -} - -void ModplugXMMS::SetInputPlugin(InputPlugin& aInPlugin) -{ - mInPlug = &aInPlugin; -} -void ModplugXMMS::SetOutputPlugin(OutputPlugin& aOutPlugin) -{ - mOutPlug = &aOutPlugin; -} - -const ModplugXMMS::Settings& ModplugXMMS::GetModProps() -{ - return mModProps; -} - -const char* ModplugXMMS::Bool2OnOff(bool aValue) -{ - if(aValue) - return "on"; - else - return "off"; -} - -void ModplugXMMS::SetModProps(const Settings& aModProps) -{ - ConfigDb *db; - mModProps = aModProps; - - // [Reverb level 0(quiet)-100(loud)], [delay in ms, usually 40-200ms] - if(mModProps.mReverb) - { - CSoundFile::SetReverbParameters - ( - mModProps.mReverbDepth, - mModProps.mReverbDelay - ); - } - // [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100] - if(mModProps.mMegabass) - { - CSoundFile::SetXBassParameters - ( - mModProps.mBassAmount, - mModProps.mBassRange - ); - } - else //modplug seems to ignore the SetWaveConfigEx() setting for bass boost - { - CSoundFile::SetXBassParameters - ( - 0, - 0 - ); - } - // [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-40ms] - if(mModProps.mSurround) - { - CSoundFile::SetSurroundParameters - ( - mModProps.mSurroundDepth, - mModProps.mSurroundDelay - ); - } - CSoundFile::SetWaveConfigEx - ( - mModProps.mSurround, - !mModProps.mOversamp, - mModProps.mReverb, - true, - mModProps.mMegabass, - mModProps.mNoiseReduction, - false - ); - CSoundFile::SetResamplingMode(mModProps.mResamplingMode); - mPreampFactor = exp(mModProps.mPreampLevel); - - db = bmp_cfg_db_open(); - - bmp_cfg_db_set_bool(db,"modplug","Surround", mModProps.mSurround); - bmp_cfg_db_set_bool(db,"modplug","Oversampling", mModProps.mOversamp); - bmp_cfg_db_set_bool(db,"modplug","Megabass", mModProps.mMegabass); - bmp_cfg_db_set_bool(db,"modplug","NoiseReduction", mModProps.mNoiseReduction); - bmp_cfg_db_set_bool(db,"modplug","VolumeRamp", mModProps.mVolumeRamp); - bmp_cfg_db_set_bool(db,"modplug","Reverb", mModProps.mReverb); - bmp_cfg_db_set_bool(db,"modplug","FastInfo", mModProps.mFastinfo); - bmp_cfg_db_set_bool(db,"modplug","UseFileName", mModProps.mUseFilename); - bmp_cfg_db_set_bool(db,"modplug","GrabAmigaMOD", mModProps.mGrabAmigaMOD); - bmp_cfg_db_set_bool(db,"modplug","PreAmp", mModProps.mPreamp); - bmp_cfg_db_set_float(db,"modplug","PreAmpLevel", mModProps.mPreampLevel); - bmp_cfg_db_set_int(db,"modplug", "Channels", mModProps.mChannels); - bmp_cfg_db_set_int(db,"modplug", "Bits", mModProps.mBits); - bmp_cfg_db_set_int(db,"modplug", "Frequency", mModProps.mFrequency); - bmp_cfg_db_set_int(db,"modplug", "ResamplineMode", mModProps.mResamplingMode); - bmp_cfg_db_set_int(db,"modplug", "ReverbDepth", mModProps.mReverbDepth); - bmp_cfg_db_set_int(db,"modplug", "ReverbDelay", mModProps.mReverbDelay); - bmp_cfg_db_set_int(db,"modplug", "BassAmount", mModProps.mBassAmount); - bmp_cfg_db_set_int(db,"modplug", "BassRange", mModProps.mBassRange); - bmp_cfg_db_set_int(db,"modplug", "SurroundDepth", mModProps.mSurroundDepth); - bmp_cfg_db_set_int(db,"modplug", "SurroundDelay", mModProps.mSurroundDelay); - bmp_cfg_db_set_int(db,"modplug", "LoopCount", mModProps.mLoopCount); - - bmp_cfg_db_close(db); -} - -ModplugXMMS gModplugXMMS;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/modplugbmp.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,800 @@ +/* Modplug XMMS Plugin + * Authors: Kenton Varda <temporal@gauge3d.org> + * + * This source code is public domain. + */ + +#include <fstream> +#include <unistd.h> +#include <math.h> + +#include "modplugbmp.h" +#include <libmodplug/stdafx.h> +#include <libmodplug/sndfile.h> +#include "stddefs.h" +#include "archive/open.h" +#include "libaudacious/configdb.h" +#include "libaudacious/vfs.h" +extern "C" { +#include "audacious/output.h" +} + +// ModplugXMMS member functions =============================== + +// operations ---------------------------------------- +ModplugXMMS::ModplugXMMS() +{ + mSoundFile = new CSoundFile; +} +ModplugXMMS::~ModplugXMMS() +{ + delete mSoundFile; +} + +ModplugXMMS::Settings::Settings() +{ + mSurround = true; + mOversamp = true; + mReverb = false; + mMegabass = false; + mNoiseReduction = true; + mVolumeRamp = true; + mFastinfo = true; + mUseFilename = false; + mGrabAmigaMOD = true; + + mChannels = 2; + mFrequency = 44100; + mBits = 16; + mResamplingMode = SRCMODE_POLYPHASE; + + mReverbDepth = 30; + mReverbDelay = 100; + mBassAmount = 40; + mBassRange = 30; + mSurroundDepth = 20; + mSurroundDelay = 20; + + mPreamp = false; + mPreampLevel = 0.0f; + + mLoopCount = 0; //don't loop +} + +void ModplugXMMS::Init(void) +{ + ConfigDb *db; + + db = bmp_cfg_db_open(); + + bmp_cfg_db_get_bool(db,"modplug","Surround", &mModProps.mSurround); + bmp_cfg_db_get_bool(db,"modplug","Oversampling", &mModProps.mOversamp); + bmp_cfg_db_get_bool(db,"modplug","Megabass", &mModProps.mMegabass); + bmp_cfg_db_get_bool(db,"modplug","NoiseReduction", &mModProps.mNoiseReduction); + bmp_cfg_db_get_bool(db,"modplug","VolumeRamp", &mModProps.mVolumeRamp); + bmp_cfg_db_get_bool(db,"modplug","Reverb", &mModProps.mReverb); + bmp_cfg_db_get_bool(db,"modplug","FastInfo", &mModProps.mFastinfo); + bmp_cfg_db_get_bool(db,"modplug","UseFileName", &mModProps.mUseFilename); + bmp_cfg_db_get_bool(db,"modplug","GrabAmigaMOD", &mModProps.mGrabAmigaMOD); + bmp_cfg_db_get_bool(db,"modplug","PreAmp", &mModProps.mPreamp); + bmp_cfg_db_get_float(db,"modplug","PreAmpLevel", &mModProps.mPreampLevel); + bmp_cfg_db_get_int(db,"modplug", "Channels", &mModProps.mChannels); + bmp_cfg_db_get_int(db,"modplug", "Bits", &mModProps.mBits); + bmp_cfg_db_get_int(db,"modplug", "Frequency", &mModProps.mFrequency); + bmp_cfg_db_get_int(db,"modplug", "ResamplineMode", &mModProps.mResamplingMode); + bmp_cfg_db_get_int(db,"modplug", "ReverbDepth", &mModProps.mReverbDepth); + bmp_cfg_db_get_int(db,"modplug", "ReverbDelay", &mModProps.mReverbDelay); + bmp_cfg_db_get_int(db,"modplug", "BassAmount", &mModProps.mBassAmount); + bmp_cfg_db_get_int(db,"modplug", "BassRange", &mModProps.mBassRange); + bmp_cfg_db_get_int(db,"modplug", "SurroundDepth", &mModProps.mSurroundDepth); + bmp_cfg_db_get_int(db,"modplug", "SurroundDelay", &mModProps.mSurroundDelay); + bmp_cfg_db_get_int(db,"modplug", "LoopCount", &mModProps.mLoopCount); + + bmp_cfg_db_close(db); +} + +bool ModplugXMMS::CanPlayFile(const string& aFilename) +{ + string lExt; + uint32 lPos; + + VFSFile *file; + gchar magic[4]; + + if ((file = vfs_fopen(aFilename.c_str(), "rb"))) { + vfs_fread(magic, 1, 4, file); + if (!memcmp(magic, UMX_MAGIC, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, XM_MAGIC, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, M669_MAGIC, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, IT_MAGIC, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MTM_MAGIC, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, PSM_MAGIC, 4)) { + vfs_fclose(file); + return 1; + } + vfs_fseek(file, 44, SEEK_SET); + vfs_fread(magic, 1, 4, file); + if (!memcmp(magic, S3M_MAGIC, 4)) { + vfs_fclose(file); + return 1; + } + if(mModProps.mGrabAmigaMOD) { + vfs_fseek(file, 1080, SEEK_SET); + vfs_fread(magic, 1, 4, file); + if (!memcmp(magic, MOD_MAGIC_PROTRACKER4, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_PROTRACKER4X, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_NOISETRACKER, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_STARTRACKER4, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_STARTRACKER8, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_STARTRACKER4X, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_STARTRACKER8X, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_FASTTRACKER4, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_FASTTRACKER6, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_FASTTRACKER8, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_OKTALYZER8, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_OKTALYZER8X, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_TAKETRACKER16, 4)) { + vfs_fclose(file); + return 1; + } + if (!memcmp(magic, MOD_MAGIC_TAKETRACKER32, 4)) { + vfs_fclose(file); + return 1; + } + } /* end of if(mModProps.mGrabAmigaMOD) */ + + /* We didn't find the magic bytes, fall back to extension check */ + vfs_fclose(file); + } /* end of vfs_open main if statement */ + + lPos = aFilename.find_last_of('.'); + if((int)lPos == -1) + return false; + lExt = aFilename.substr(lPos); + for(uint32 i = 0; i < lExt.length(); i++) + lExt[i] = tolower(lExt[i]); + + if (lExt == ".amf") + return true; + if (lExt == ".ams") + return true; + if (lExt == ".dbm") + return true; + if (lExt == ".dbf") + return true; + if (lExt == ".dsm") + return true; + if (lExt == ".far") + return true; + if (lExt == ".mdl") + return true; + if (lExt == ".stm") + return true; + if (lExt == ".ult") + return true; + if (lExt == ".j2b") + return true; + if (lExt == ".mt2") + return true; + + if (lExt == ".mdz") + return true; + if (lExt == ".mdr") + return true; + if (lExt == ".mdgz") + return true; + if (lExt == ".mdbz") + return true; + if (lExt == ".s3z") + return true; + if (lExt == ".s3r") + return true; + if (lExt == ".s3gz") + return true; + if (lExt == ".xmz") + return true; + if (lExt == ".xmr") + return true; + if (lExt == ".xmgz") + return true; + if (lExt == ".itz") + return true; + if (lExt == ".itr") + return true; + if (lExt == ".itgz") + return true; + if (lExt == ".dmf") + return true; + + if (lExt == ".zip") + return ContainsMod(aFilename); + if (lExt == ".gz") + return ContainsMod(aFilename); + if (lExt == ".bz2") + return ContainsMod(aFilename); + + return false; +} + +void* ModplugXMMS::PlayThread(void* arg) +{ + ((ModplugXMMS*)arg)->PlayLoop(); + return NULL; +} + +void ModplugXMMS::PlayLoop() +{ + uint32 lLength; + //the user might change the number of channels while playing. + // we don't want this to take effect until we are done! + uint8 lChannels = mModProps.mChannels; + + while(!mStopped) + { + if(!(lLength = mSoundFile->Read( + mBuffer, + mBufSize))) + { + //no more to play. Wait for output to finish and then stop. + while((mOutPlug->buffer_playing()) + && (!mStopped)) + usleep(10000); + break; + } + + if(mModProps.mPreamp) + { + //apply preamp + if(mModProps.mBits == 16) + { + uint n = mBufSize >> 1; + for(uint i = 0; i < n; i++) { + short old = ((short*)mBuffer)[i]; + ((short*)mBuffer)[i] *= (short int)mPreampFactor; + // detect overflow and clip! + if ((old & 0x8000) != + (((short*)mBuffer)[i] & 0x8000)) + ((short*)mBuffer)[i] = old | 0x7FFF; + + } + } + else + { + for(uint i = 0; i < mBufSize; i++) { + uchar old = ((uchar*)mBuffer)[i]; + ((uchar*)mBuffer)[i] *= (short int)mPreampFactor; + // detect overflow and clip! + if ((old & 0x80) != + (((uchar*)mBuffer)[i] & 0x80)) + ((uchar*)mBuffer)[i] = old | 0x7F; + } + } + } + + if(mStopped) + break; + + //wait for buffer space to free up. + while(((mOutPlug->buffer_free() + < (int)mBufSize)) + && (!mStopped)) + usleep(10000); + + if(mStopped) + break; + + produce_audio + ( + mPlayed, + mFormat, + lChannels, + mBufSize, + mBuffer, + NULL + ); + + mPlayed += mBufTime; + } + +// mOutPlug->flush(0); + mOutPlug->close_audio(); + + //Unload the file + mSoundFile->Destroy(); + delete mArchive; + + if (mBuffer) + { + delete [] mBuffer; + mBuffer = NULL; + } + + mPaused = false; + mStopped = true; + + g_thread_exit(NULL); +} + +void ModplugXMMS::PlayFile(const string& aFilename) +{ + mStopped = true; + mPaused = false; + + //open and mmap the file + mArchive = OpenArchive(aFilename); + if(mArchive->Size() == 0) + { + delete mArchive; + return; + } + + if (mBuffer) + delete [] mBuffer; + + //find buftime to get approx. 512 samples/block + mBufTime = 512000 / mModProps.mFrequency + 1; + + mBufSize = mBufTime; + mBufSize *= mModProps.mFrequency; + mBufSize /= 1000; //milliseconds + mBufSize *= mModProps.mChannels; + mBufSize *= mModProps.mBits / 8; + + mBuffer = new uchar[mBufSize]; + if(!mBuffer) + return; //out of memory! + + CSoundFile::SetWaveConfig + ( + mModProps.mFrequency, + mModProps.mBits, + mModProps.mChannels + ); + CSoundFile::SetWaveConfigEx + ( + mModProps.mSurround, + !mModProps.mOversamp, + mModProps.mReverb, + true, + mModProps.mMegabass, + mModProps.mNoiseReduction, + false + ); + + // [Reverb level 0(quiet)-100(loud)], [delay in ms, usually 40-200ms] + if(mModProps.mReverb) + { + CSoundFile::SetReverbParameters + ( + mModProps.mReverbDepth, + mModProps.mReverbDelay + ); + } + // [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100] + if(mModProps.mMegabass) + { + CSoundFile::SetXBassParameters + ( + mModProps.mBassAmount, + mModProps.mBassRange + ); + } + // [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-40ms] + if(mModProps.mSurround) + { + CSoundFile::SetSurroundParameters + ( + mModProps.mSurroundDepth, + mModProps.mSurroundDelay + ); + } + CSoundFile::SetResamplingMode(mModProps.mResamplingMode); + mSoundFile->SetRepeatCount(mModProps.mLoopCount); + mPreampFactor = exp(mModProps.mPreampLevel); + + mPaused = false; + mStopped = false; + + mSoundFile->Create + ( + (uchar*)mArchive->Map(), + mArchive->Size() + ); + mPlayed = 0; + + bool useFilename = mModProps.mUseFilename; + + if(!useFilename) + { + strncpy(mModName, mSoundFile->GetTitle(), 100); + + for(int i = 0; mModName[i] == ' ' || mModName[i] == 0; i++) + { + if(mModName[i] == 0) + { + useFilename = true; //mod name is blank -- use filename + break; + } + } + } + + if(useFilename) + { + strncpy(mModName, strrchr(aFilename.c_str(), '/') + 1, 100); + char* ext = strrchr(mModName, '.'); + if(ext) *ext = '\0'; + } + + mInPlug->set_info + ( + mModName, + mSoundFile->GetSongTime() * 1000, + mSoundFile->GetNumChannels() * 1000, + mModProps.mFrequency, + mModProps.mChannels + ); + + mStopped = mPaused = false; + + if(mModProps.mBits == 16) + mFormat = FMT_S16_NE; + else + mFormat = FMT_U8; + + mOutPlug->open_audio + ( + mFormat, + mModProps.mFrequency, + mModProps.mChannels + ); + + mDecodeThread = g_thread_create( + (GThreadFunc)PlayThread, + this, + TRUE, + NULL + ); +} + +void ModplugXMMS::Stop(void) +{ + if(mStopped) + return; + + mStopped = true; + mPaused = false; + + g_thread_join(mDecodeThread); +} + +void ModplugXMMS::Pause(bool aPaused) +{ + if(aPaused) + mPaused = true; + else + mPaused = false; + + mOutPlug->pause(aPaused); +} + +void ModplugXMMS::Seek(float32 aTime) +{ + uint32 lMax; + uint32 lMaxtime; + float32 lPostime; + + if(aTime > (lMaxtime = mSoundFile->GetSongTime())) + aTime = lMaxtime; + lMax = mSoundFile->GetMaxPosition(); + lPostime = float(lMax) / lMaxtime; + + mSoundFile->SetCurrentPos(int(aTime * lPostime)); + + mOutPlug->flush(int(aTime * 1000)); + mPlayed = uint32(aTime * 1000); +} + +float32 ModplugXMMS::GetTime(void) +{ + if(mStopped) + return -1; + return (float32)mOutPlug->output_time() / 1000; +} + +void ModplugXMMS::GetSongInfo(const string& aFilename, char*& aTitle, int32& aLength) +{ + aLength = -1; + fstream lTestFile; + string lError; + bool lDone; + + lTestFile.open(aFilename.c_str(), ios::in); + if(!lTestFile) + { + lError = "**no such file: "; + lError += strrchr(aFilename.c_str(), '/') + 1; + aTitle = new char[lError.length() + 1]; + strcpy(aTitle, lError.c_str()); + return; + } + + lTestFile.close(); + + if(mModProps.mFastinfo) + { + if(mModProps.mUseFilename) + { + //Use filename as name + aTitle = new char[aFilename.length() + 1]; + strcpy(aTitle, strrchr(aFilename.c_str(), '/') + 1); + *strrchr(aTitle, '.') = '\0'; + return; + } + + fstream lModFile; + string lExt; + uint32 lPos; + + lDone = true; + + // previously ios::nocreate was used (X Standard C++ Library) + lModFile.open(aFilename.c_str(), ios::in); + + lPos = aFilename.find_last_of('.'); + if((int)lPos == 0) + return; + lExt = aFilename.substr(lPos); + for(uint32 i = 0; i < lExt.length(); i++) + lExt[i] = tolower(lExt[i]); + + if (lExt == ".mod") + { + lModFile.read(mModName, 20); + mModName[20] = 0; + } + else if (lExt == ".s3m") + { + lModFile.read(mModName, 28); + mModName[28] = 0; + } + else if (lExt == ".xm") + { + lModFile.seekg(17); + lModFile.read(mModName, 20); + mModName[20] = 0; + } + else if (lExt == ".it") + { + lModFile.seekg(4); + lModFile.read(mModName, 28); + mModName[28] = 0; + } + else + lDone = false; //fall back to slow info + + lModFile.close(); + + if(lDone) + { + for(int i = 0; mModName[i] != 0; i++) + { + if(mModName[i] != ' ') + { + aTitle = new char[strlen(mModName) + 1]; + strcpy(aTitle, mModName); + + return; + } + } + + //mod name is blank. Use filename instead. + aTitle = new char[aFilename.length() + 1]; + strcpy(aTitle, strrchr(aFilename.c_str(), '/') + 1); + *strrchr(aTitle, '.') = '\0'; + return; + } + } + + Archive* lArchive; + CSoundFile* lSoundFile; + const char* lTitle; + + //open and mmap the file + lArchive = OpenArchive(aFilename); + if(lArchive->Size() == 0) + { + lError = "**bad mod file: "; + lError += strrchr(aFilename.c_str(), '/') + 1; + aTitle = new char[lError.length() + 1]; + strcpy(aTitle, lError.c_str()); + delete lArchive; + return; + } + + lSoundFile = new CSoundFile; + lSoundFile->Create((uchar*)lArchive->Map(), lArchive->Size()); + + if(!mModProps.mUseFilename) + { + lTitle = lSoundFile->GetTitle(); + + for(int i = 0; lTitle[i] != 0; i++) + { + if(lTitle[i] != ' ') + { + aTitle = new char[strlen(lTitle) + 1]; + strcpy(aTitle, lTitle); + goto therest; //sorry + } + } + } + + //mod name is blank, or user wants the filename to be used as the title. + aTitle = new char[aFilename.length() + 1]; + strcpy(aTitle, strrchr(aFilename.c_str(), '/') + 1); + *strrchr(aTitle, '.') = '\0'; + +therest: + aLength = lSoundFile->GetSongTime() * 1000; //It wants milliseconds!?! + + //unload the file + lSoundFile->Destroy(); + delete lSoundFile; + delete lArchive; +} + +void ModplugXMMS::SetInputPlugin(InputPlugin& aInPlugin) +{ + mInPlug = &aInPlugin; +} +void ModplugXMMS::SetOutputPlugin(OutputPlugin& aOutPlugin) +{ + mOutPlug = &aOutPlugin; +} + +const ModplugXMMS::Settings& ModplugXMMS::GetModProps() +{ + return mModProps; +} + +const char* ModplugXMMS::Bool2OnOff(bool aValue) +{ + if(aValue) + return "on"; + else + return "off"; +} + +void ModplugXMMS::SetModProps(const Settings& aModProps) +{ + ConfigDb *db; + mModProps = aModProps; + + // [Reverb level 0(quiet)-100(loud)], [delay in ms, usually 40-200ms] + if(mModProps.mReverb) + { + CSoundFile::SetReverbParameters + ( + mModProps.mReverbDepth, + mModProps.mReverbDelay + ); + } + // [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100] + if(mModProps.mMegabass) + { + CSoundFile::SetXBassParameters + ( + mModProps.mBassAmount, + mModProps.mBassRange + ); + } + else //modplug seems to ignore the SetWaveConfigEx() setting for bass boost + { + CSoundFile::SetXBassParameters + ( + 0, + 0 + ); + } + // [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-40ms] + if(mModProps.mSurround) + { + CSoundFile::SetSurroundParameters + ( + mModProps.mSurroundDepth, + mModProps.mSurroundDelay + ); + } + CSoundFile::SetWaveConfigEx + ( + mModProps.mSurround, + !mModProps.mOversamp, + mModProps.mReverb, + true, + mModProps.mMegabass, + mModProps.mNoiseReduction, + false + ); + CSoundFile::SetResamplingMode(mModProps.mResamplingMode); + mPreampFactor = exp(mModProps.mPreampLevel); + + db = bmp_cfg_db_open(); + + bmp_cfg_db_set_bool(db,"modplug","Surround", mModProps.mSurround); + bmp_cfg_db_set_bool(db,"modplug","Oversampling", mModProps.mOversamp); + bmp_cfg_db_set_bool(db,"modplug","Megabass", mModProps.mMegabass); + bmp_cfg_db_set_bool(db,"modplug","NoiseReduction", mModProps.mNoiseReduction); + bmp_cfg_db_set_bool(db,"modplug","VolumeRamp", mModProps.mVolumeRamp); + bmp_cfg_db_set_bool(db,"modplug","Reverb", mModProps.mReverb); + bmp_cfg_db_set_bool(db,"modplug","FastInfo", mModProps.mFastinfo); + bmp_cfg_db_set_bool(db,"modplug","UseFileName", mModProps.mUseFilename); + bmp_cfg_db_set_bool(db,"modplug","GrabAmigaMOD", mModProps.mGrabAmigaMOD); + bmp_cfg_db_set_bool(db,"modplug","PreAmp", mModProps.mPreamp); + bmp_cfg_db_set_float(db,"modplug","PreAmpLevel", mModProps.mPreampLevel); + bmp_cfg_db_set_int(db,"modplug", "Channels", mModProps.mChannels); + bmp_cfg_db_set_int(db,"modplug", "Bits", mModProps.mBits); + bmp_cfg_db_set_int(db,"modplug", "Frequency", mModProps.mFrequency); + bmp_cfg_db_set_int(db,"modplug", "ResamplineMode", mModProps.mResamplingMode); + bmp_cfg_db_set_int(db,"modplug", "ReverbDepth", mModProps.mReverbDepth); + bmp_cfg_db_set_int(db,"modplug", "ReverbDelay", mModProps.mReverbDelay); + bmp_cfg_db_set_int(db,"modplug", "BassAmount", mModProps.mBassAmount); + bmp_cfg_db_set_int(db,"modplug", "BassRange", mModProps.mBassRange); + bmp_cfg_db_set_int(db,"modplug", "SurroundDepth", mModProps.mSurroundDepth); + bmp_cfg_db_set_int(db,"modplug", "SurroundDelay", mModProps.mSurroundDelay); + bmp_cfg_db_set_int(db,"modplug", "LoopCount", mModProps.mLoopCount); + + bmp_cfg_db_close(db); +} + +ModplugXMMS gModplugXMMS;
--- a/Plugins/Input/modplug/plugin.cpp Sat Sep 16 07:18:18 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* Modplug XMMS Plugin - * Authors: Kenton Varda <temporal@gauge3d.org> - * - * This source code is public domain. - */ - -#include "audacious/plugin.h" -#include <libmodplug/modplug.h> -#include "gui/main.h" - -extern InputPlugin gModPlug; - -static void Init(void) -{ - gModplugXMMS.SetInputPlugin(gModPlug); - gModplugXMMS.Init(); -} - -static int CanPlayFile(char* aFilename) -{ - if(gModplugXMMS.CanPlayFile(aFilename)) - return 1; - return 0; -} - -static void PlayFile(char* aFilename) -{ - gModplugXMMS.SetOutputPlugin(*gModPlug.output); - gModplugXMMS.PlayFile(aFilename); -} - -static void Stop(void) -{ - gModplugXMMS.Stop(); -} - -static void Pause(short aPaused) -{ - gModplugXMMS.Pause((bool)aPaused); -} - -static void Seek(int aTime) -{ - gModplugXMMS.Seek(float32(aTime)); -} -static int GetTime(void) -{ - float32 lTime; - - lTime = gModplugXMMS.GetTime(); - if(lTime == -1) - return -1; - else - return (int)(lTime * 1000); -} - -static void GetSongInfo(char* aFilename, char** aTitle, int* aLength) -{ - gModplugXMMS.GetSongInfo(aFilename, *aTitle, *aLength); -} - -void ShowAboutBox(void) -{ - ShowAboutWindow(); -} - -void ShowConfigureBox(void) -{ - ShowConfigureWindow(gModplugXMMS.GetModProps()); -} - -void ShowFileInfoBox(char* aFilename) -{ - ShowInfoWindow(aFilename); -} - -InputPlugin gModPlug = -{ - NULL, - NULL, - "ModPlug Player", - Init, - ShowAboutBox, - ShowConfigureBox, - CanPlayFile, - NULL, - PlayFile, - Stop, - Pause, - Seek, - NULL, - GetTime, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - GetSongInfo, - ShowFileInfoBox, - NULL -}; - -extern "C" -{ - InputPlugin* get_iplugin_info (void) - { - return &gModPlug; - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/modplug/plugin.cxx Sat Sep 16 07:33:28 2006 -0700 @@ -0,0 +1,111 @@ +/* Modplug XMMS Plugin + * Authors: Kenton Varda <temporal@gauge3d.org> + * + * This source code is public domain. + */ + +#include "audacious/plugin.h" +#include <libmodplug/modplug.h> +#include "gui/main.h" + +extern InputPlugin gModPlug; + +static void Init(void) +{ + gModplugXMMS.SetInputPlugin(gModPlug); + gModplugXMMS.Init(); +} + +static int CanPlayFile(char* aFilename) +{ + if(gModplugXMMS.CanPlayFile(aFilename)) + return 1; + return 0; +} + +static void PlayFile(char* aFilename) +{ + gModplugXMMS.SetOutputPlugin(*gModPlug.output); + gModplugXMMS.PlayFile(aFilename); +} + +static void Stop(void) +{ + gModplugXMMS.Stop(); +} + +static void Pause(short aPaused) +{ + gModplugXMMS.Pause((bool)aPaused); +} + +static void Seek(int aTime) +{ + gModplugXMMS.Seek(float32(aTime)); +} +static int GetTime(void) +{ + float32 lTime; + + lTime = gModplugXMMS.GetTime(); + if(lTime == -1) + return -1; + else + return (int)(lTime * 1000); +} + +static void GetSongInfo(char* aFilename, char** aTitle, int* aLength) +{ + gModplugXMMS.GetSongInfo(aFilename, *aTitle, *aLength); +} + +void ShowAboutBox(void) +{ + ShowAboutWindow(); +} + +void ShowConfigureBox(void) +{ + ShowConfigureWindow(gModplugXMMS.GetModProps()); +} + +void ShowFileInfoBox(char* aFilename) +{ + ShowInfoWindow(aFilename); +} + +InputPlugin gModPlug = +{ + NULL, + NULL, + "ModPlug Player", + Init, + ShowAboutBox, + ShowConfigureBox, + CanPlayFile, + NULL, + PlayFile, + Stop, + Pause, + Seek, + NULL, + GetTime, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + GetSongInfo, + ShowFileInfoBox, + NULL +}; + +extern "C" +{ + InputPlugin* get_iplugin_info (void) + { + return &gModPlug; + } +}