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