more 0.98.15-like timing, but sound glitches
[fceu.git] / mappers / vrc7snd.c
CommitLineData
c62d2810 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Ben Parnell
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include "mapinc.h"
24#include "fmopl.h"
25
26static void VRC7_LoadInstrument(uint8 Chan);
27void vrc7translate(uint8 Reg,uint8 V);
28
29FM_OPL *fmob=0;
30uint8 VRC7Chan[3][6];
31static void InitOPL(void);
32
33void OPL2_setreg(uint8 A, uint8 V)
34{
4fdfab07 35 if(fmob)
c62d2810 36 OPLWrite(fmob,A,V);
37}
38
39
40void LoadOPL(void)
41{
42 int x;
43 int y;
44
45 for(x=y=0;x<0x40;x++)
46 y|=MapperExRAM[x];
47 if(y)
4fdfab07 48 {
49 InitOPL();
c62d2810 50 for(x=0;x<6;x++)
51 {
4fdfab07 52 VRC7_LoadInstrument(x);
c62d2810 53 vrc7translate(0x10+x,VRC7Chan[0][x]);
54 }
55 }
56}
57
58static int dwave=0;
59
60void VRC7Update(void)
61{
62 int32 z,a;
63
4fdfab07 64 z=((SOUNDTS<<16)/soundtsinc)>>4;
c62d2810 65 a=z-dwave;
66
67 if(a && fmob)
68 YM3812UpdateOne(fmob, &Wave[dwave], a);
69 dwave+=a;
70}
71
72void UpdateOPL(int Count)
73{
74 int32 z,a;
75
4fdfab07 76 z=((SOUNDTS<<16)/soundtsinc)>>4;
c62d2810 77 a=z-dwave;
78
79 if(fmob && a)
80 YM3812UpdateOne(fmob, &Wave[dwave], a);
81
82 dwave=0;
83}
84
85void KillOPL(void)
86{
87 if(fmob) OPLDestroy(fmob);
88 fmob=0;
89}
90
91static void InitOPL(void)
92{
93 int x;
94
95 if(!fmob)
4fdfab07 96 {
c62d2810 97 if(!( fmob=OPLCreate(OPL_TYPE_WAVESEL,1789772*2,FSettings.SndRate)))
98 return;
99 }
100 GameExpSound.Kill=KillOPL;
101 OPLResetChip(fmob);
102
103 for(x=0x1;x<0xF6;x++)
104 OPL2_setreg(x,0);
105 OPL2_setreg(0xBD,0xC0);
106 OPL2_setreg(1,0x20); /* Enable waveform type manipulation */
107}
108
109/* This following code is in the public domain, but the author, Quietust(see */
110/* the "AUTHORS" file, would appreciate credit to go to him if this code */
111/* is used. */
112
113uint8 VRC7Instrument[16][8] = {
114 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* Custom instrument. */
115 {0x03,0x01,0x14,0x80,0xC2,0x90,0x43,0x14}, /* Currently working on this one */
116 {0x13,0x41,0x10,0x0B,0xFF,0xF2,0x32,0xD6},
117 {0x01,0x01,0x10,0x08,0xF0,0xF4,0x00,0x04}, /* 90% perfect */
118 {0x21,0x41,0x1B,0x08,0x66,0x80,0x30,0x85},
119 {0x22,0x21,0x20,0x03,0x75,0x70,0x24,0x14},
120 {0x02,0x01,0x06,0x00,0xF0,0xF2,0x03,0x95}, /* Do not touch! 98% perfect! */
121 {0x21,0x41,0x18,0x10,0x93,0xE0,0x21,0x15},
122 {0x01,0x22,0x13,0x00,0xF0,0x82,0x00,0x15},
123 {0x05,0x01,0x22,0x00,0x60,0xE3,0xA0,0xF5}, /* 90% perfect */
124 {0x85,0x01,0x20,0x00,0xD7,0xA2,0x22,0xF5}, /* 90% perfect */
125 {0x07,0x81,0x2B,0x05,0xF4,0xF2,0x14,0xF4}, /* 95% perfect */
126 {0x21,0x41,0x20,0x18,0xF3,0x80,0x13,0x95},
127 {0x01,0x02,0x20,0x00,0xF9,0x92,0x41,0x75}, /* Do not touch! 98% perfect! */
128 {0x21,0x62,0x0E,0x00,0x84,0x85,0x45,0x15}, /* 90% perfect */
129 {0x21,0x62,0x0E,0x00,0xA1,0xA0,0x34,0x16} /* Do not touch! 98% perfect! */
130};
131
132static uint8 InstTrans[6] = {0x00,0x01,0x02,0x08,0x09,0x0A};
133
134static void VRC7_LoadInstrument(uint8 Chan)
135{
136 uint8 *i;
137 uint8 x = InstTrans[Chan];
138 uint8 y = (VRC7Chan[2][Chan] >> 4) & 0xF;
4fdfab07 139
c62d2810 140 i=VRC7Instrument[y];
141
142 OPL2_setreg((0x20+x),i[0]);
143 OPL2_setreg((0x23+x),i[1]);
144 OPL2_setreg((0x40+x),i[2]);
4fdfab07 145 OPL2_setreg((0x43+x),((i[3] & 0xC0)
c62d2810 146 | ((VRC7Chan[2][Chan] << 2) & 0x3C))); // quiet
147 OPL2_setreg(0xe0+x,(i[3] >> 3) & 0x01);
148 OPL2_setreg(0xe3+x,(i[3] >> 4) & 0x01);
149 OPL2_setreg(0xC0+Chan,(i[3] << 1) & 0x0E);
150 OPL2_setreg(0x60+x,i[4]);
151 OPL2_setreg(0x63+x,i[5]);
152 OPL2_setreg(0x80+x,i[6]);
153 OPL2_setreg(0x83+x,i[7]);
154}
155
156void vrc7translate(uint8 Reg,uint8 V)
157{
158 uint8 x = Reg & 0x0F, y;
159 if(!fmob) InitOPL();
160
161 MapperExRAM[Reg]=V;
162
163 VRC7Update();
164 switch ((Reg & 0xF0) >> 4)
165 {
166 case 0:
167 if (x & 0x08) break;
168 VRC7Instrument[0][x] = V;
169 for (y = 0; y < 6; y++)
170 if (!(VRC7Chan[2][y]&0xF0))
171 VRC7_LoadInstrument(y);
172 break;
173 case 1:
174 if(x>5) break;
175 VRC7Chan[0][x] = V;
176 OPL2_setreg(0xA0 + x,(VRC7Chan[0][x] << 1) & 0xFE);
177 OPL2_setreg(0xB0 + x,((VRC7Chan[0][x] >> 7) & 0x01) | ((VRC7Chan[1][x] << 1) & 0x3E));
178 break;
179 case 2:
180 if(x>5) break;
181 VRC7Chan[1][x] = V;
182 OPL2_setreg(0xB0 + x,(((VRC7Chan[0][x] >> 7) & 0x01) | ((VRC7Chan[1][x] << 1) & 0x3E)));
183 break;
184 case 3:
185 if(x>5) break;
186 VRC7Chan[2][x] = V;
187 VRC7_LoadInstrument(x);
188 break;
189 }
190}