1 /* OpenCP Module Player
2 * copyright (c) '05-'10 Stian Skjelstad <stian@nixia.no>
3 *
4 * This file is based on AdPlug project, released under GPLv2
5 * with permission from Simon Peter.
6 *
7 * AdPlug - Replayer for many OPL2/OPL3 audio file formats.
8 * Copyright (C) 1999 - 2002 Simon Peter <dn.tlp@gmx.net>, et al.
9 * emuopl.cpp - Emulated OPL, by Simon Peter <dn.tlp@gmx.net>
10 *
11 * File is changed in letting FM_OPL be public
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27 */
28
29 #include "ocpemu.h"
30 #include <string.h>
31 #include <math.h>
32
33 static const int slot_array[32]=
34 {
35 0, 2, 4, 1, 3, 5,-1,-1,
36 6, 8,10, 7, 9,11,-1,-1,
37 12,14,16,13,15,17,-1,-1,
38 -1,-1,-1,-1,-1,-1,-1,-1
39 };
40
41
Cocpopl(int rate)42 Cocpopl::Cocpopl(int rate)
43 {
44 opl = OPLCreate(OPL_TYPE_YM3812, 3579545, rate);
45 }
46
~Cocpopl()47 Cocpopl::~Cocpopl()
48 {
49 OPLDestroy(opl);
50 }
51
update(short * buf,int samples)52 void Cocpopl::update(short *buf, int samples)
53 {
54 int i;
55
56 YM3812UpdateOne(opl,buf,samples);
57
58 for(i=samples-1;i>=0;i--) {
59 buf[i*2] = buf[i];
60 buf[i*2+1] = buf[i];
61 }
62 }
63
write(int reg,int val)64 void Cocpopl::write(int reg, int val)
65 {
66 int slot = slot_array[reg&0x1f];
67
68 switch(reg&0xe0)
69 {
70 case 0xe0:
71 if (slot==-1)
72 goto done;
73 wavesel[slot]=val&3;
74 break;
75 case 0x40:
76 if (slot==-1)
77 goto done;
78 hardvols[slot][0] = val;
79 if (mute[slot])
80 return;
81 break;
82 case 0xc0:
83 if (slot==-1)
84 goto done;
85 if (reg<=0xc8)
86 hardvols[reg-0xc0][1] = val;
87 if (mute[reg-0xc0]&&mute[reg-0xc0+9])
88 return;
89 break;
90 }
91
92 done:
93 OPLWrite(opl,0,reg);
94 OPLWrite(opl,1,val);
95 }
96
97 /* envelope counter lower bits */
98 #define ENV_BITS 16
99 /* envelope output entries */
100 #define EG_ENT 4096
101 static INT32 ENV_CURVE[2*EG_ENT+1];
102 #define EG_OFF ((2*EG_ENT)<<ENV_BITS) /* OFF */
103 #define EG_DED EG_OFF
104 #define EG_DST (EG_ENT<<ENV_BITS) /* DECAY START */
105 #define EG_AED EG_DST
106 #define EG_AST 0 /* ATTACK START */
107
vol(int i)108 int Cocpopl::vol(int i)
109 {
110 OPL_CH *CH = &opl->P_CH[i/2];
111 OPL_SLOT *SLOT = &CH->SLOT[i&1];
112 unsigned int ofs;
113 ofs=SLOT->evc>>ENV_BITS;
114 if (ofs>=sizeof(2*EG_ENT))
115 ofs=2*EG_ENT;
116 return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS];
117 }
118
init()119 void Cocpopl::init()
120 {
121 OPLResetChip(opl);
122 memset(wavesel, 0, sizeof(wavesel));
123 memset(hardvols, 0, sizeof(hardvols));
124 memset(mute, 0, sizeof(mute));
125
126 /* envelope counter -> envelope output table */
127 for (int i=0; i<EG_ENT; i++)
128 {
129 /* ATTACK curve */
130 double pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT;
131 /* if( pom >= EG_ENT ) pom = EG_ENT-1; */
132 ENV_CURVE[i] = (int)pom;
133 /* DECAY ,RELEASE curve */
134 ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i;
135 }
136 /* off */
137 ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
138 }
139
setmute(int chan,int val)140 void Cocpopl::setmute(int chan, int val)
141 {
142 int i;
143 mute[chan]=val;
144 for (i=0;i<32;i++)
145 {
146 int slot = slot_array[i];
147 if (slot<0)
148 continue;
149 OPLWrite(opl, 0, i+0x40);
150 if ((mute[slot]))
151 OPLWrite(opl, 1, 63);
152 else
153 OPLWrite(opl, 1, hardvols[slot][0]);
154 }
155 for (i=0;i<9;i++)
156 {
157 OPLWrite(opl, 0, i+0xc0);
158 if ((mute[i]&&mute[i+9]))
159 OPLWrite(opl, 1, 0);
160 else
161 OPLWrite(opl, 1, hardvols[i][1]);
162 }
163 }
164