|
| 1 | +#include "gus.h" |
| 2 | + |
| 3 | +#include <dos.h> |
| 4 | + |
| 5 | +#include <cmath> |
| 6 | + |
| 7 | +static uint32_t Base = 0; |
| 8 | +static uint32_t Divisor = 1; |
| 9 | + |
| 10 | +/* Read a value from GUS memory */ |
| 11 | +uint8_t GUSPeek(uint32_t loc) |
| 12 | +{ |
| 13 | + uint16_t addLo = loc & 0xFFFF; |
| 14 | + uint8_t addHi = loc >> 16; |
| 15 | + outportb(Base + 0x103, 0x43); |
| 16 | + outportw(Base + 0x104, addLo); |
| 17 | + outportb(Base + 0x103, 0x44); |
| 18 | + outportb(Base + 0x105, addHi); |
| 19 | + |
| 20 | + uint8_t b = inportb(Base + 0x107); |
| 21 | + return b; |
| 22 | +} |
| 23 | + |
| 24 | +/* Write a value into GUS memory */ |
| 25 | +void GUSPoke(uint32_t loc, uint8_t b) |
| 26 | +{ |
| 27 | + uint16_t addLo = loc & 0xFFFF; |
| 28 | + uint8_t addHi = loc >> 16; |
| 29 | + outportb(Base + 0x103, 0x43); |
| 30 | + outportw(Base + 0x104, addLo); |
| 31 | + outportb(Base + 0x103, 0x44); |
| 32 | + outportb(Base + 0x105, addHi); |
| 33 | + outportb(Base + 0x107, b); |
| 34 | +} |
| 35 | + |
| 36 | +/* Returns TRUE if there is a GUS at I/O address BASE */ |
| 37 | +bool GUSProbe(void) |
| 38 | +{ |
| 39 | + outportb(Base + 0x103, 0x4C); |
| 40 | + outportb(Base + 0x105, 0); |
| 41 | + delay(1); |
| 42 | + outportb(Base + 0x103, 0x4C); |
| 43 | + outportb(Base + 0x105, 1); |
| 44 | + GUSPoke(0, 0xAA); |
| 45 | + GUSPoke(0x100, 0x55); |
| 46 | + uint8_t b = GUSPeek(0); |
| 47 | + return (b == 0xAA); |
| 48 | +} |
| 49 | + |
| 50 | +/* Search all possible I/O addresses for the GUS */ |
| 51 | +uint32_t GUSFind(void) |
| 52 | +{ |
| 53 | + for (uint16_t i = 1; i <= 8; ++i) |
| 54 | + { |
| 55 | + Base = 0x200 + i * 0x10; |
| 56 | + if (GUSProbe()) |
| 57 | + { |
| 58 | + break; |
| 59 | + } |
| 60 | + } |
| 61 | + if (Base < 0x280) |
| 62 | + { |
| 63 | + return Base; |
| 64 | + } |
| 65 | + return 0; |
| 66 | +} |
| 67 | + |
| 68 | +/* Returns how much RAM is available on the GUS */ |
| 69 | +uint32_t GUSFindMem(void) |
| 70 | +{ |
| 71 | + uint32_t ret; |
| 72 | + GUSPoke(0x40000, 0xAA); |
| 73 | + if (GUSPeek(0x40000) != 0xAA) |
| 74 | + { |
| 75 | + ret = 0x40000; |
| 76 | + } |
| 77 | + else |
| 78 | + { |
| 79 | + GUSPoke(0x80000, 0xAA); |
| 80 | + if (GUSPeek(0x80000) != 0xAA) |
| 81 | + { |
| 82 | + ret = 0x80000; |
| 83 | + } |
| 84 | + else |
| 85 | + { |
| 86 | + GUSPoke(0xC0000, 0xAA); |
| 87 | + if (GUSPeek(0xC0000) != 0xAA) |
| 88 | + { |
| 89 | + ret = 0xC0000; |
| 90 | + } |
| 91 | + else |
| 92 | + { |
| 93 | + ret = 0x100000; |
| 94 | + } |
| 95 | + } |
| 96 | + } |
| 97 | + return ret; |
| 98 | +} |
| 99 | + |
| 100 | +/* An incomplete routine to initialise the GUS for output. */ |
| 101 | +void GUSReset(uint8_t voices) |
| 102 | +{ |
| 103 | + if (voices < 14) |
| 104 | + { |
| 105 | + voices = 14; |
| 106 | + } |
| 107 | + else if (voices > 32) |
| 108 | + { |
| 109 | + voices = 32; |
| 110 | + } |
| 111 | + Divisor = std::floor(1000000.0 / (1.619695497 * voices) + 0.5); |
| 112 | + outportb(Base + 0x103, 0x4C); |
| 113 | + outportb(Base + 0x105, 1); |
| 114 | + delay(1); |
| 115 | + outportb(Base + 0x103, 0x4C); |
| 116 | + outportb(Base + 0x105, 7); |
| 117 | + outportb(Base + 0x103, 0x0E); |
| 118 | + // outportb(Base + 0x105, 14 | 0x0C0); |
| 119 | + outportb(Base + 0x105, (voices - 1) | 0x0C0); |
| 120 | + |
| 121 | + for (int i = 0; i != voices; ++i) |
| 122 | + { |
| 123 | + GUSVoiceControl(i, GUS_VOICE_STOP); |
| 124 | + } |
| 125 | +} |
| 126 | + |
| 127 | +/* Set the volume of channel voi to vol, a 16bit logarithmic scale |
| 128 | + volume value - 0 is off, $ffff is full volume, $e0000 is half volume, etc */ |
| 129 | +void GUSSetVolume(uint8_t voi, uint16_t vol) |
| 130 | +{ |
| 131 | + if (vol > 511) |
| 132 | + vol = 511; |
| 133 | + static const uint16_t volumes[512] = { |
| 134 | + 0x0000, 0x7000, 0x7ff0, 0x8800, 0x8ff0, 0x9400, 0x9800, 0x9c00, 0x9ff0, 0xa200, 0xa400, 0xa600, 0xa800, 0xaa00, |
| 135 | + 0xac00, 0xae00, 0xaff0, 0xb100, 0xb200, 0xb300, 0xb400, 0xb500, 0xb600, 0xb700, 0xb800, 0xb900, 0xba00, 0xbb00, |
| 136 | + 0xbc00, 0xbd00, 0xbe00, 0xbf00, 0xbff0, 0xc080, 0xc100, 0xc180, 0xc200, 0xc280, 0xc300, 0xc380, 0xc400, 0xc480, |
| 137 | + 0xc500, 0xc580, 0xc600, 0xc680, 0xc700, 0xc780, 0xc800, 0xc880, 0xc900, 0xc980, 0xca00, 0xca80, 0xcb00, 0xcb80, |
| 138 | + 0xcc00, 0xcc80, 0xcd00, 0xcd80, 0xce00, 0xce80, 0xcf00, 0xcf80, 0xcff0, 0xd040, 0xd080, 0xd0c0, 0xd100, 0xd140, |
| 139 | + 0xd180, 0xd1c0, 0xd200, 0xd240, 0xd280, 0xd2c0, 0xd300, 0xd340, 0xd380, 0xd3c0, 0xd400, 0xd440, 0xd480, 0xd4c0, |
| 140 | + 0xd500, 0xd540, 0xd580, 0xd5c0, 0xd600, 0xd640, 0xd680, 0xd6c0, 0xd700, 0xd740, 0xd780, 0xd7c0, 0xd800, 0xd840, |
| 141 | + 0xd880, 0xd8c0, 0xd900, 0xd940, 0xd980, 0xd9c0, 0xda00, 0xda40, 0xda80, 0xdac0, 0xdb00, 0xdb40, 0xdb80, 0xdbc0, |
| 142 | + 0xdc00, 0xdc40, 0xdc80, 0xdcc0, 0xdd00, 0xdd40, 0xdd80, 0xddc0, 0xde00, 0xde40, 0xde80, 0xdec0, 0xdf00, 0xdf40, |
| 143 | + 0xdf80, 0xdfc0, 0xdff0, 0xe020, 0xe040, 0xe060, 0xe080, 0xe0a0, 0xe0c0, 0xe0e0, 0xe100, 0xe120, 0xe140, 0xe160, |
| 144 | + 0xe180, 0xe1a0, 0xe1c0, 0xe1e0, 0xe200, 0xe220, 0xe240, 0xe260, 0xe280, 0xe2a0, 0xe2c0, 0xe2e0, 0xe300, 0xe320, |
| 145 | + 0xe340, 0xe360, 0xe380, 0xe3a0, 0xe3c0, 0xe3e0, 0xe400, 0xe420, 0xe440, 0xe460, 0xe480, 0xe4a0, 0xe4c0, 0xe4e0, |
| 146 | + 0xe500, 0xe520, 0xe540, 0xe560, 0xe580, 0xe5a0, 0xe5c0, 0xe5e0, 0xe600, 0xe620, 0xe640, 0xe660, 0xe680, 0xe6a0, |
| 147 | + 0xe6c0, 0xe6e0, 0xe700, 0xe720, 0xe740, 0xe760, 0xe780, 0xe7a0, 0xe7c0, 0xe7e0, 0xe800, 0xe820, 0xe840, 0xe860, |
| 148 | + 0xe880, 0xe8a0, 0xe8c0, 0xe8e0, 0xe900, 0xe920, 0xe940, 0xe960, 0xe980, 0xe9a0, 0xe9c0, 0xe9e0, 0xea00, 0xea20, |
| 149 | + 0xea40, 0xea60, 0xea80, 0xeaa0, 0xeac0, 0xeae0, 0xeb00, 0xeb20, 0xeb40, 0xeb60, 0xeb80, 0xeba0, 0xebc0, 0xebe0, |
| 150 | + 0xec00, 0xec20, 0xec40, 0xec60, 0xec80, 0xeca0, 0xecc0, 0xece0, 0xed00, 0xed20, 0xed40, 0xed60, 0xed80, 0xeda0, |
| 151 | + 0xedc0, 0xede0, 0xee00, 0xee20, 0xee40, 0xee60, 0xee80, 0xeea0, 0xeec0, 0xeee0, 0xef00, 0xef20, 0xef40, 0xef60, |
| 152 | + 0xef80, 0xefa0, 0xefc0, 0xefe0, 0xeff0, 0xf010, 0xf020, 0xf030, 0xf040, 0xf050, 0xf060, 0xf070, 0xf080, 0xf090, |
| 153 | + 0xf0a0, 0xf0b0, 0xf0c0, 0xf0d0, 0xf0e0, 0xf0f0, 0xf100, 0xf110, 0xf120, 0xf130, 0xf140, 0xf150, 0xf160, 0xf170, |
| 154 | + 0xf180, 0xf190, 0xf1a0, 0xf1b0, 0xf1c0, 0xf1d0, 0xf1e0, 0xf1f0, 0xf200, 0xf210, 0xf220, 0xf230, 0xf240, 0xf250, |
| 155 | + 0xf260, 0xf270, 0xf280, 0xf290, 0xf2a0, 0xf2b0, 0xf2c0, 0xf2d0, 0xf2e0, 0xf2f0, 0xf300, 0xf310, 0xf320, 0xf330, |
| 156 | + 0xf340, 0xf350, 0xf360, 0xf370, 0xf380, 0xf390, 0xf3a0, 0xf3b0, 0xf3c0, 0xf3d0, 0xf3e0, 0xf3f0, 0xf400, 0xf410, |
| 157 | + 0xf420, 0xf430, 0xf440, 0xf450, 0xf460, 0xf470, 0xf480, 0xf490, 0xf4a0, 0xf4b0, 0xf4c0, 0xf4d0, 0xf4e0, 0xf4f0, |
| 158 | + 0xf500, 0xf510, 0xf520, 0xf530, 0xf540, 0xf550, 0xf560, 0xf570, 0xf580, 0xf590, 0xf5a0, 0xf5b0, 0xf5c0, 0xf5d0, |
| 159 | + 0xf5e0, 0xf5f0, 0xf600, 0xf610, 0xf620, 0xf630, 0xf640, 0xf650, 0xf660, 0xf670, 0xf680, 0xf690, 0xf6a0, 0xf6b0, |
| 160 | + 0xf6c0, 0xf6d0, 0xf6e0, 0xf6f0, 0xf700, 0xf710, 0xf720, 0xf730, 0xf740, 0xf750, 0xf760, 0xf770, 0xf780, 0xf790, |
| 161 | + 0xf7a0, 0xf7b0, 0xf7c0, 0xf7d0, 0xf7e0, 0xf7f0, 0xf800, 0xf810, 0xf820, 0xf830, 0xf840, 0xf850, 0xf860, 0xf870, |
| 162 | + 0xf880, 0xf890, 0xf8a0, 0xf8b0, 0xf8c0, 0xf8d0, 0xf8e0, 0xf8f0, 0xf900, 0xf910, 0xf920, 0xf930, 0xf940, 0xf950, |
| 163 | + 0xf960, 0xf970, 0xf980, 0xf990, 0xf9a0, 0xf9b0, 0xf9c0, 0xf9d0, 0xf9e0, 0xf9f0, 0xfa00, 0xfa10, 0xfa20, 0xfa30, |
| 164 | + 0xfa40, 0xfa50, 0xfa60, 0xfa70, 0xfa80, 0xfa90, 0xfaa0, 0xfab0, 0xfac0, 0xfad0, 0xfae0, 0xfaf0, 0xfb00, 0xfb10, |
| 165 | + 0xfb20, 0xfb30, 0xfb40, 0xfb50, 0xfb60, 0xfb70, 0xfb80, 0xfb90, 0xfba0, 0xfbb0, 0xfbc0, 0xfbd0, 0xfbe0, 0xfbf0, |
| 166 | + 0xfc00, 0xfc10, 0xfc20, 0xfc30, 0xfc40, 0xfc50, 0xfc60, 0xfc70, 0xfc80, 0xfc90, 0xfca0, 0xfcb0, 0xfcc0, 0xfcd0, |
| 167 | + 0xfce0, 0xfcf0, 0xfd00, 0xfd10, 0xfd20, 0xfd30, 0xfd40, 0xfd50, 0xfd60, 0xfd70, 0xfd80, 0xfd90, 0xfda0, 0xfdb0, |
| 168 | + 0xfdc0, 0xfdd0, 0xfde0, 0xfdf0, 0xfe00, 0xfe10, 0xfe20, 0xfe30, 0xfe40, 0xfe50, 0xfe60, 0xfe70, 0xfe80, 0xfe90, |
| 169 | + 0xfea0, 0xfeb0, 0xfec0, 0xfed0, 0xfee0, 0xfef0, 0xff00, 0xff10, 0xff20, 0xff30, 0xff40, 0xff50, 0xff60, 0xff70, |
| 170 | + 0xff80, 0xff90, 0xffa0, 0xffb0, 0xffc0, 0xffd0, 0xffe0, 0xfff0}; |
| 171 | + |
| 172 | + outportb(Base + 0x102, voi); |
| 173 | + outportb(Base + 0x102, voi); |
| 174 | + outportb(Base + 0x102, voi); |
| 175 | + outportb(Base + 0x103, 9); |
| 176 | + outportw(Base + 0x104, volumes[vol]); /* 0-0ffffh, log scale not linear */ |
| 177 | +} |
| 178 | + |
| 179 | +/* set the pan position (from 0 to 15, 0 being left, 15 right and 7 middle) */ |
| 180 | +void GUSSetBalance(uint8_t v, uint8_t b) |
| 181 | +{ |
| 182 | + outportb(Base + 0x102, v); |
| 183 | + outportb(Base + 0x102, v); |
| 184 | + outportb(Base + 0x102, v); |
| 185 | + outportb(Base + 0x103, 0xC); |
| 186 | + outportb(Base + 0x105, b); |
| 187 | +} |
| 188 | + |
| 189 | +/* frequency at which the sample should be played */ |
| 190 | +void GUSSetFreq(uint8_t v, uint32_t freq) |
| 191 | +{ |
| 192 | + uint32_t fc = (uint32_t)(((freq << 9L) + (Divisor >> 1L)) / Divisor); |
| 193 | + fc = fc << 1; |
| 194 | + if (fc > 65535) |
| 195 | + { |
| 196 | + fc = 65535; |
| 197 | + } |
| 198 | + else if (fc < 16) |
| 199 | + { |
| 200 | + fc = 16; |
| 201 | + } |
| 202 | + outportb(Base + 0x102, v); |
| 203 | + outportb(Base + 0x102, v); |
| 204 | + outportb(Base + 0x102, v); |
| 205 | + outportb(Base + 0x103, 1); |
| 206 | + outportw(Base + 0x104, fc); |
| 207 | +} |
| 208 | + |
| 209 | +/* This routine tells the GUS to play a sample commencing at vBegin, |
| 210 | + starting at location vStart, and stopping at vEnd */ |
| 211 | +void GUSPlayVoice(uint8_t v, uint8_t mode, uint32_t vBegin, uint32_t vStart, uint32_t vEnd) |
| 212 | +{ |
| 213 | + outportb(Base + 0x102, v); |
| 214 | + outportb(Base + 0x102, v); |
| 215 | + outportb(Base + 0x103, 0x0A); |
| 216 | + outportw(Base + 0x104, (vBegin >> 7) & 8191); |
| 217 | + outportb(Base + 0x103, 0x0B); |
| 218 | + outportw(Base + 0x104, (vBegin & 127) << 8); |
| 219 | + outportb(Base + 0x103, 0x02); |
| 220 | + outportw(Base + 0x104, (vStart >> 7) & 8191); |
| 221 | + outportb(Base + 0x103, 0x03); |
| 222 | + outportw(Base + 0x104, (vStart & 127) << 8); |
| 223 | + outportb(Base + 0x103, 0x04); |
| 224 | + outportw(Base + 0x104, ((vEnd) >> 7) & 8191); |
| 225 | + outportb(Base + 0x103, 0x05); |
| 226 | + outportw(Base + 0x104, ((vEnd)&127) << 8); |
| 227 | + outportb(Base + 0x103, 0); |
| 228 | + outportb(Base + 0x105, mode); |
| 229 | + |
| 230 | + /* The below part isn't mentioned as necessary, but the card won't play anything without it! */ |
| 231 | + outportb(Base, 1); |
| 232 | + outportb(Base + 0x103, 0x4C); |
| 233 | + outportb(Base + 0x105, 3); |
| 234 | +} |
| 235 | + |
| 236 | +/* This routine will return the memory location that the channel v is currently playing. If the GUS has reached the end |
| 237 | + * of the sample, then the returned value will be vEnd. If you want to see what BYTE value is currently being played |
| 238 | + * (for visual output of the sample's waveform), then you simply PEEK the location pointed to by this routine. */ |
| 239 | +uint32_t GUSVoicePos(uint8_t v) |
| 240 | +{ |
| 241 | + outportb(Base + 0x102, v); |
| 242 | + outportb(Base + 0x102, v); |
| 243 | + outportb(Base + 0x102, v); |
| 244 | + outportb(Base + 0x103, 0x8A); |
| 245 | + uint16_t temp0 = inportw(Base + 0x104); |
| 246 | + outportb(Base + 0x103, 0x8B); |
| 247 | + uint16_t temp1 = inportw(Base + 0x104); |
| 248 | + return (temp0 << 7) + (temp1 >> 8); |
| 249 | +} |
| 250 | + |
| 251 | +/* stop the playback on channel v */ |
| 252 | +void GUSStopVoice(uint8_t v) |
| 253 | +{ |
| 254 | + outportb(Base + 0x102, v); |
| 255 | + outportb(Base + 0x102, v); |
| 256 | + outportb(Base + 0x102, v); |
| 257 | + outportb(Base + 0x103, 0x80); |
| 258 | + uint8_t temp = inportb(Base + 0x105); |
| 259 | + outportb(Base + 0x103, 0); |
| 260 | + outportb(Base + 0x105, (temp & 0xdf) | 3); |
| 261 | + delay(1); |
| 262 | + outportb(Base + 0x103, 0); |
| 263 | + outportb(Base + 0x105, (temp & 0xdf) | 3); |
| 264 | +} |
| 265 | + |
| 266 | +void GUSVoiceControl(uint8_t v, uint8_t b) |
| 267 | +{ |
| 268 | + outportb(Base + 0x102, v); |
| 269 | + outportb(Base + 0x102, v); |
| 270 | + outportb(Base + 0x103, 0); |
| 271 | + outportb(Base + 0x105, b); |
| 272 | +} |
0 commit comments