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 | |
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=((timestamp<<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=((timestamp<<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 | } |