more 0.98.15-like timing, but sound glitches
[fceu.git] / mappers / vrc7snd.c
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
26 static void VRC7_LoadInstrument(uint8 Chan);
27 void vrc7translate(uint8 Reg,uint8 V);
28
29 FM_OPL *fmob=0;
30 uint8 VRC7Chan[3][6];
31 static void InitOPL(void);
32
33 void OPL2_setreg(uint8 A, uint8 V)
34 {
35  if(fmob)
36   OPLWrite(fmob,A,V);
37 }
38
39
40 void 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)
48  {
49   InitOPL();
50   for(x=0;x<6;x++)
51   {
52    VRC7_LoadInstrument(x);
53    vrc7translate(0x10+x,VRC7Chan[0][x]);
54   }
55  }
56 }
57
58 static int dwave=0;
59
60 void VRC7Update(void)
61 {
62  int32 z,a;
63
64  z=((SOUNDTS<<16)/soundtsinc)>>4;
65  a=z-dwave;
66
67  if(a && fmob)
68   YM3812UpdateOne(fmob, &Wave[dwave], a);
69  dwave+=a;
70 }
71
72 void UpdateOPL(int Count)
73 {
74  int32 z,a;
75
76  z=((SOUNDTS<<16)/soundtsinc)>>4;
77  a=z-dwave;
78
79  if(fmob && a)
80   YM3812UpdateOne(fmob, &Wave[dwave], a);
81
82  dwave=0;
83 }
84
85 void KillOPL(void)
86 {
87  if(fmob) OPLDestroy(fmob);
88  fmob=0;
89 }
90
91 static void InitOPL(void)
92 {
93         int x;
94
95         if(!fmob)
96         {
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
113 uint8 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
132 static uint8 InstTrans[6] = {0x00,0x01,0x02,0x08,0x09,0x0A};
133
134 static void VRC7_LoadInstrument(uint8 Chan)
135 {
136         uint8 *i;
137         uint8 x = InstTrans[Chan];
138         uint8 y = (VRC7Chan[2][Chan] >> 4) & 0xF;
139
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]);
145         OPL2_setreg((0x43+x),((i[3] & 0xC0)
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
156 void 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 }