2 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
3 * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * realopl.cpp - Real hardware OPL, by Simon Peter <dn.tlp@gmx.net>
22 #ifdef _MSC_VER // Microsoft Visual C++
26 #elif defined(__WATCOMC__) // Watcom C/C++ and OpenWatcom
30 #elif defined(WIN32) && defined(__MSVCRT__) && defined(__MINGW32__) // MinGW32
32 int __cdecl _inp(unsigned short);
33 int __cdecl _outp(unsigned short, int);
38 # define OUTP(reg, val) outb(val, reg)
39 #elif defined(DJGPP) // DJGPP
42 # define OUTP outportb
43 #else // no support on other platforms
45 # define OUTP(reg, val)
50 #define SHORTDELAY 6 // short delay in I/O port-reads after OPL hardware output
51 #define LONGDELAY 35 // long delay in I/O port-reads after OPL hardware output
53 const unsigned char CRealopl::op_table[9] =
54 {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12};
56 #if defined(WIN32) && defined(__MINGW32__)
57 static __inline unsigned char inb(unsigned short int port)
61 __asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (port));
65 static __inline void outb(unsigned char value, unsigned short int port)
67 __asm__ __volatile__ ("outb %b0,%w1": :"a" (value), "Nd" (port));
71 CRealopl::CRealopl(unsigned short initport)
72 : adlport(initport), hardvol(0), bequiet(false), nowrite(false)
74 for(int i=0;i<22;i++) {
75 hardvols[0][i][0] = 0;
76 hardvols[0][i][1] = 0;
77 hardvols[1][i][0] = 0;
78 hardvols[1][i][1] = 0;
84 bool CRealopl::harddetect()
86 unsigned char stat1, stat2, i;
87 unsigned short adp = (currChip == 0 ? adlport : adlport + 2);
89 hardwrite(4,0x60); hardwrite(4,0x80);
91 hardwrite(2,0xff); hardwrite(4,0x21);
92 for(i=0;i<80;i++) // wait for adlib
95 hardwrite(4,0x60); hardwrite(4,0x80);
97 if(((stat1 & 0xe0) == 0) && ((stat2 & 0xe0) == 0xc0))
103 bool CRealopl::detect()
109 // is at least OPL2, check for OPL3
110 currType = TYPE_OPL2;
114 // not OPL3, try dual-OPL2
117 currType = TYPE_DUAL_OPL2;
119 currType = TYPE_OPL3;
127 void CRealopl::setvolume(int volume)
132 for(j = 0; j < 2; j++)
133 for(i = 0; i < 9; i++) {
134 hardwrite(0x43+op_table[i],((hardvols[j][op_table[i]+3][0] & 63) + volume) > 63 ? 63 : hardvols[j][op_table[i]+3][0] + volume);
135 if(hardvols[j][i][1] & 1) // modulator too?
136 hardwrite(0x40+op_table[i],((hardvols[j][op_table[i]][0] & 63) + volume) > 63 ? 63 : hardvols[j][op_table[i]][0] + volume);
140 void CRealopl::setquiet(bool quiet)
151 void CRealopl::hardwrite(int reg, int val)
154 unsigned short adp = (currChip == 0 ? adlport : adlport + 2);
156 OUTP(adp,reg); // set register
157 for(i=0;i<SHORTDELAY;i++) // wait for adlib
159 OUTP(adp+1,val); // set value
160 for(i=0;i<LONGDELAY;i++) // wait for adlib
164 void CRealopl::write(int reg, int val)
171 if(currType == TYPE_OPL2 && currChip > 0)
174 if(bequiet && (reg >= 0xb0 && reg <= 0xb8)) // filter all key-on commands
176 if(reg >= 0x40 && reg <= 0x55) // cache volumes
177 hardvols[currChip][reg-0x40][0] = val;
178 if(reg >= 0xc0 && reg <= 0xc8)
179 hardvols[currChip][reg-0xc0][1] = val;
180 if(hardvol) // reduce volume
182 if(reg == 0x43 + op_table[i])
183 val = ((val & 63) + hardvol) > 63 ? 63 : val + hardvol;
185 if((reg == 0x40 + op_table[i]) && (hardvols[currChip][i][1] & 1))
186 val = ((val & 63) + hardvol) > 63 ? 63 : val + hardvol;
192 void CRealopl::init()
196 for(j = 0; j < 2; j++) {
199 for(i=0;i<9;i++) { // stop instruments
200 hardwrite(0xb0 + i,0); // key off
201 hardwrite(0x80 + op_table[i],0xff); // fastest release
204 hardwrite(0xbd,0); // clear misc. register