1/* 2 * GUSEMU32 - mixing engine (similar to Interwave GF1 compatibility) 3 * 4 * Copyright (C) 2000-2007 Tibor "TS" Schütz 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25#include "qemu/osdep.h" 26#include "gusemu.h" 27#include "gustate.h" 28 29#define GUSregb(position) (* (gusptr+(position))) 30#define GUSregw(position) (*(uint16_t *) (gusptr+(position))) 31#define GUSregd(position) (*(uint16_t *)(gusptr+(position))) 32 33#define GUSvoice(position) (*(uint16_t *)(voiceptr+(position))) 34 35/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */ 36void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples, 37 int16_t *bufferpos) 38{ 39 /* note that byte registers are stored in the upper half of each voice register! */ 40 uint8_t *gusptr; 41 int Voice; 42 uint16_t *voiceptr; 43 44 unsigned int count; 45 for (count = 0; count < numsamples * 2; count++) 46 *(bufferpos + count) = 0; /* clear */ 47 48 gusptr = state->gusdatapos; 49 voiceptr = (uint16_t *) gusptr; 50 if (!(GUSregb(GUS4cReset) & 0x01)) /* reset flag active? */ 51 return; 52 53 for (Voice = 0; Voice <= (GUSregb(NumVoices) & 31); Voice++) 54 { 55 if (GUSvoice(wVSRControl) & 0x200) 56 GUSvoice(wVSRControl) |= 0x100; /* voice stop request */ 57 if (GUSvoice(wVSRVolRampControl) & 0x200) 58 GUSvoice(wVSRVolRampControl) |= 0x100; /* Volume ramp stop request */ 59 if (!(GUSvoice(wVSRControl) & GUSvoice(wVSRVolRampControl) & 0x100)) /* neither voice nor volume calculation active - save some time here ;) */ 60 { 61 unsigned int sample; 62 63 unsigned int LoopStart = (GUSvoice(wVSRLoopStartHi) << 16) | GUSvoice(wVSRLoopStartLo); /* 23.9 format */ 64 unsigned int LoopEnd = (GUSvoice(wVSRLoopEndHi) << 16) | GUSvoice(wVSRLoopEndLo); /* 23.9 format */ 65 unsigned int CurrPos = (GUSvoice(wVSRCurrPosHi) << 16) | GUSvoice(wVSRCurrPosLo); /* 23.9 format */ 66 int VoiceIncrement = ((((unsigned long) GUSvoice(wVSRFreq) * 44100) / playback_freq) * (14 >> 1)) / 67 ((GUSregb(NumVoices) & 31) + 1); /* 6.10 increment/frame to 23.9 increment/sample */ 68 69 int PanningPos = (GUSvoice(wVSRPanning) >> 8) & 0xf; 70 71 unsigned int Volume32 = 32 * GUSvoice(wVSRCurrVol); /* 32 times larger than original gus for maintaining precision while ramping */ 72 unsigned int StartVol32 = (GUSvoice(wVSRVolRampStartVol) & 0xff00) * 32; 73 unsigned int EndVol32 = (GUSvoice(wVSRVolRampEndVol) & 0xff00) * 32; 74 int VolumeIncrement32 = (32 * 16 * (GUSvoice(wVSRVolRampRate) & 0x3f00) >> 8) >> ((((GUSvoice(wVSRVolRampRate) & 0xc000) >> 8) >> 6) * 3); /* including 1/8/64/512 volume speed divisor */ 75 VolumeIncrement32 = (((VolumeIncrement32 * 44100 / 2) / playback_freq) * 14) / ((GUSregb(NumVoices) & 31) + 1); /* adjust ramping speed to playback speed */ 76 77 if (GUSvoice(wVSRControl) & 0x4000) 78 VoiceIncrement = -VoiceIncrement; /* reverse playback */ 79 if (GUSvoice(wVSRVolRampControl) & 0x4000) 80 VolumeIncrement32 = -VolumeIncrement32; /* reverse ramping */ 81 82 for (sample = 0; sample < numsamples; sample++) 83 { 84 int sample1, sample2, Volume; 85 if (GUSvoice(wVSRControl) & 0x400) /* 16bit */ 86 { 87 int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1); 88 int8_t *adr; 89 adr = (int8_t *) state->himemaddr + offset; 90 sample1 = (*adr & 0xff) + (*(adr + 1) * 256); 91 sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256); 92 } 93 else /* 8bit */ 94 { 95 int offset = (CurrPos >> 9) & 0xfffff; 96 int8_t *adr; 97 adr = (int8_t *) state->himemaddr + offset; 98 sample1 = (*adr) * 256; 99 sample2 = (*(adr + 1)) * 256; 100 } 101 102 Volume = ((((Volume32 >> (4 + 5)) & 0xff) + 256) << (Volume32 >> ((4 + 8) + 5))) / 512; /* semi-logarithmic volume, +5 due to additional precision */ 103 sample1 = (((sample1 * Volume) >> 16) * (512 - (CurrPos % 512))) / 512; 104 sample2 = (((sample2 * Volume) >> 16) * (CurrPos % 512)) / 512; 105 sample1 += sample2; 106 107 if (!(GUSvoice(wVSRVolRampControl) & 0x100)) 108 { 109 Volume32 += VolumeIncrement32; 110 if ((GUSvoice(wVSRVolRampControl) & 0x4000) ? (Volume32 <= StartVol32) : (Volume32 >= EndVol32)) /* ramp up boundary cross */ 111 { 112 if (GUSvoice(wVSRVolRampControl) & 0x2000) 113 GUSvoice(wVSRVolRampControl) |= 0x8000; /* volramp IRQ enabled? -> IRQ wait flag */ 114 if (GUSvoice(wVSRVolRampControl) & 0x800) /* loop enabled */ 115 { 116 if (GUSvoice(wVSRVolRampControl) & 0x1000) /* bidir. loop */ 117 { 118 GUSvoice(wVSRVolRampControl) ^= 0x4000; /* toggle dir */ 119 VolumeIncrement32 = -VolumeIncrement32; 120 } 121 else 122 Volume32 = (GUSvoice(wVSRVolRampControl) & 0x4000) ? EndVol32 : StartVol32; /* unidir. loop ramp */ 123 } 124 else 125 { 126 GUSvoice(wVSRVolRampControl) |= 0x100; 127 Volume32 = 128 (GUSvoice(wVSRVolRampControl) & 0x4000) ? StartVol32 : EndVol32; 129 } 130 } 131 } 132 if ((GUSvoice(wVSRVolRampControl) & 0xa000) == 0xa000) /* volramp IRQ set and enabled? */ 133 { 134 GUSregd(voicevolrampirq) |= 1 << Voice; /* set irq slot */ 135 } 136 else 137 { 138 GUSregd(voicevolrampirq) &= (~(1 << Voice)); /* clear irq slot */ 139 GUSvoice(wVSRVolRampControl) &= 0x7f00; 140 } 141 142 if (!(GUSvoice(wVSRControl) & 0x100)) 143 { 144 CurrPos += VoiceIncrement; 145 if ((GUSvoice(wVSRControl) & 0x4000) ? (CurrPos <= LoopStart) : (CurrPos >= LoopEnd)) /* playback boundary cross */ 146 { 147 if (GUSvoice(wVSRControl) & 0x2000) 148 GUSvoice(wVSRControl) |= 0x8000; /* voice IRQ enabled -> IRQ wait flag */ 149 if (GUSvoice(wVSRControl) & 0x800) /* loop enabled */ 150 { 151 if (GUSvoice(wVSRControl) & 0x1000) /* pingpong loop */ 152 { 153 GUSvoice(wVSRControl) ^= 0x4000; /* toggle dir */ 154 VoiceIncrement = -VoiceIncrement; 155 } 156 else 157 CurrPos = (GUSvoice(wVSRControl) & 0x4000) ? LoopEnd : LoopStart; /* unidir. loop */ 158 } 159 else if (!(GUSvoice(wVSRVolRampControl) & 0x400)) 160 GUSvoice(wVSRControl) |= 0x100; /* loop disabled, rollover check */ 161 } 162 } 163 if ((GUSvoice(wVSRControl) & 0xa000) == 0xa000) /* wavetable IRQ set and enabled? */ 164 { 165 GUSregd(voicewavetableirq) |= 1 << Voice; /* set irq slot */ 166 } 167 else 168 { 169 GUSregd(voicewavetableirq) &= (~(1 << Voice)); /* clear irq slot */ 170 GUSvoice(wVSRControl) &= 0x7f00; 171 } 172 173 /* mix samples into buffer */ 174 *(bufferpos + 2 * sample) += (int16_t) ((sample1 * PanningPos) >> 4); /* right */ 175 *(bufferpos + 2 * sample + 1) += (int16_t) ((sample1 * (15 - PanningPos)) >> 4); /* left */ 176 } 177 /* write back voice and volume */ 178 GUSvoice(wVSRCurrVol) = Volume32 / 32; 179 GUSvoice(wVSRCurrPosHi) = CurrPos >> 16; 180 GUSvoice(wVSRCurrPosLo) = CurrPos & 0xffff; 181 } 182 voiceptr += 16; /* next voice */ 183 } 184} 185 186void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time) 187/* time given in microseconds */ 188{ 189 int requestedIRQs = 0; 190 uint8_t *gusptr; 191 gusptr = state->gusdatapos; 192 if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */ 193 { 194 unsigned int timer1fraction = state->timer1fraction; 195 int newtimerirqs; 196 newtimerirqs = (elapsed_time + timer1fraction) / (80 * (256 - GUSregb(GUS46Counter1))); 197 state->timer1fraction = (elapsed_time + timer1fraction) % (80 * (256 - GUSregb(GUS46Counter1))); 198 if (newtimerirqs) 199 { 200 if (!(GUSregb(TimerDataReg2x9) & 0x40)) 201 GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */ 202 if (GUSregb(GUS45TimerCtrl) & 4) /* timer1 irq enable */ 203 { 204 GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */ 205 GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */ 206 GUSregw(TimerIRQs) += newtimerirqs; 207 requestedIRQs += newtimerirqs; 208 } 209 } 210 } 211 if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */ 212 { 213 unsigned int timer2fraction = state->timer2fraction; 214 int newtimerirqs; 215 newtimerirqs = (elapsed_time + timer2fraction) / (320 * (256 - GUSregb(GUS47Counter2))); 216 state->timer2fraction = (elapsed_time + timer2fraction) % (320 * (256 - GUSregb(GUS47Counter2))); 217 if (newtimerirqs) 218 { 219 if (!(GUSregb(TimerDataReg2x9) & 0x20)) 220 GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */ 221 if (GUSregb(GUS45TimerCtrl) & 8) /* timer2 irq enable */ 222 { 223 GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */ 224 GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */ 225 GUSregw(TimerIRQs) += newtimerirqs; 226 requestedIRQs += newtimerirqs; 227 } 228 } 229 } 230 if (GUSregb(GUS4cReset) & 0x4) /* synth IRQ enable */ 231 { 232 if (GUSregd(voicewavetableirq)) 233 GUSregb(IRQStatReg2x6) |= 0x20; 234 if (GUSregd(voicevolrampirq)) 235 GUSregb(IRQStatReg2x6) |= 0x40; 236 } 237 if ((!requestedIRQs) && GUSregb(IRQStatReg2x6)) 238 requestedIRQs++; 239 if (GUSregb(IRQStatReg2x6)) 240 GUSregw(BusyTimerIRQs) = GUS_irqrequest(state, state->gusirq, requestedIRQs); 241} 242