| 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 | } |