]> 4ch.mooo.com Git - 16.git/blob - 16/adplug/adplug/src/realopl.cpp
wwww~
[16.git] / 16 / adplug / adplug / src / realopl.cpp
1 /*
2  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
3  * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al.
4  * 
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.
9  * 
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.
14  * 
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
18  *
19  * realopl.cpp - Real hardware OPL, by Simon Peter <dn.tlp@gmx.net>
20  */
21
22 #ifdef _MSC_VER                 // Microsoft Visual C++
23 #       include <conio.h>
24 #       define INP      _inp
25 #       define OUTP     _outp
26 #elif defined(__WATCOMC__)      // Watcom C/C++ and OpenWatcom
27 #       include <conio.h>
28 #       define INP      inp
29 #       define OUTP     outp
30 #elif defined(WIN32) && defined(__MSVCRT__) && defined(__MINGW32__)     // MinGW32
31 /*
32 int __cdecl _inp(unsigned short);
33 int __cdecl _outp(unsigned short, int);
34 #       define INP      _inp
35 #       define OUTP     _outp
36 */
37 #       define INP              inb
38 #       define OUTP(reg, val)   outb(val, reg)
39 #elif defined(DJGPP)            // DJGPP
40 #       include <pc.h>
41 #       define INP      inportb
42 #       define OUTP     outportb
43 #else                           // no support on other platforms
44 #       define INP(reg)         0
45 #       define OUTP(reg, val)
46 #endif
47
48 #include "realopl.h"
49
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
52
53 const unsigned char CRealopl::op_table[9] =
54   {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12};
55
56 #if defined(WIN32) && defined(__MINGW32__)
57 static __inline unsigned char inb(unsigned short int port)
58 {
59   unsigned char _v;
60
61   __asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (port));
62   return _v;
63 }
64
65 static __inline void outb(unsigned char value, unsigned short int port)
66 {
67   __asm__ __volatile__ ("outb %b0,%w1": :"a" (value), "Nd" (port));
68 }
69 #endif
70
71 CRealopl::CRealopl(unsigned short initport)
72   : adlport(initport), hardvol(0), bequiet(false), nowrite(false)
73 {
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;
79   }
80
81   currType = TYPE_OPL3;
82 }
83
84 bool CRealopl::harddetect()
85 {
86   unsigned char         stat1, stat2, i;
87   unsigned short        adp = (currChip == 0 ? adlport : adlport + 2);
88
89   hardwrite(4,0x60); hardwrite(4,0x80);
90   stat1 = INP(adp);
91   hardwrite(2,0xff); hardwrite(4,0x21);
92   for(i=0;i<80;i++)                     // wait for adlib
93     INP(adp);
94   stat2 = INP(adp);
95   hardwrite(4,0x60); hardwrite(4,0x80);
96
97   if(((stat1 & 0xe0) == 0) && ((stat2 & 0xe0) == 0xc0))
98     return true;
99   else
100     return false;
101 }
102
103 bool CRealopl::detect()
104 {
105   unsigned char stat;
106
107   setchip(0);
108   if(harddetect()) {
109     // is at least OPL2, check for OPL3
110     currType = TYPE_OPL2;
111
112     stat = INP(adlport);
113     if(stat & 6) {
114       // not OPL3, try dual-OPL2
115       setchip(1);
116       if(harddetect())
117         currType = TYPE_DUAL_OPL2;
118     } else
119       currType = TYPE_OPL3;
120
121     setchip(0);
122     return true;
123   } else
124     return false;
125 }
126
127 void CRealopl::setvolume(int volume)
128 {
129   int i, j;
130
131   hardvol = 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);
137     }
138 }
139
140 void CRealopl::setquiet(bool quiet)
141 {
142   bequiet = quiet;
143
144   if(quiet) {
145     oldvol = hardvol;
146     setvolume(63);
147   } else
148     setvolume(oldvol);
149 }
150
151 void CRealopl::hardwrite(int reg, int val)
152 {
153   int                   i;
154   unsigned short        adp = (currChip == 0 ? adlport : adlport + 2);
155
156   OUTP(adp,reg);                // set register
157   for(i=0;i<SHORTDELAY;i++)     // wait for adlib
158     INP(adp);
159   OUTP(adp+1,val);              // set value
160   for(i=0;i<LONGDELAY;i++)      // wait for adlib
161     INP(adp);
162 }
163
164 void CRealopl::write(int reg, int val)
165 {
166   int i;
167
168   if(nowrite)
169     return;
170
171   if(currType == TYPE_OPL2 && currChip > 0)
172     return;
173
174   if(bequiet && (reg >= 0xb0 && reg <= 0xb8))   // filter all key-on commands
175     val &= ~32;
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
181     for(i=0;i<9;i++) {
182       if(reg == 0x43 + op_table[i])
183         val = ((val & 63) + hardvol) > 63 ? 63 : val + hardvol;
184       else
185         if((reg == 0x40 + op_table[i]) && (hardvols[currChip][i][1] & 1))
186           val = ((val & 63) + hardvol) > 63 ? 63 : val + hardvol;
187     }
188
189   hardwrite(reg,val);
190 }
191
192 void CRealopl::init()
193 {
194   int i, j;
195
196   for(j = 0; j < 2; j++) {
197     setchip(j);
198
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
202     }
203
204     hardwrite(0xbd,0);  // clear misc. register
205   }
206
207   setchip(0);
208 }