public void Update() { if (mute || turbo) { for (int updateCycle = lastUpdateCycle; updateCycle < currentTime; updateCycle++) { sampleRateDivider--; if (sampleRateDivider <= 0) { output[outputPtr] = 0; outputPtr++; sampleRateDivider += sampleDivider; } } lastUpdateCycle = currentTime; return; } for (int updateCycle = lastUpdateCycle; updateCycle < currentTime; updateCycle++) { byte square1Volume = square1.Cycle(); byte square2Volume = square2.Cycle(); byte triangleVolume = triangle.Cycle(); byte noiseVolume = noise.Cycle(); byte dmcVolume = dmc.buffer[dmcOutputPtr++]; byte externalVolume = external.Cycle();//treating external volume as 0-255 #if DEBUGGER nes.debug.APUCycle(square1Volume, square2Volume, triangleVolume, noiseVolume, dmcVolume, externalVolume); #endif square1Volume = (byte)(square1Volume * volume.square1); square2Volume = (byte)(square2Volume * volume.square2); triangleVolume = (byte)(triangleVolume * volume.triangle); noiseVolume = (byte)(noiseVolume * volume.noise); dmcVolume = (byte)(dmcVolume * volume.dmc); externalVolume = (byte)(externalVolume * volume.external); sampleTotal += (short)((tndTableShort[(3 * triangleVolume) + (2 * noiseVolume) + dmcVolume] + pulseTableShort[square1Volume + square2Volume] + (externalVolume << 7)) ^ 0x8000);//just inserting external sound linearly. sampleCount++; sampleRateDivider--; if (sampleRateDivider <= 0) //&& outputPtr < output.Length) { double sample = sampleTotal / (sampleCount * 1.0); sampleRateDivider += sampleDivider; rollingAveTotal += sample; rollingAve.Enqueue(sample); if (rollingAveCount == rollingAveWindow) { rollingAveTotal -= rollingAve.Dequeue(); } else { rollingAveCount++; } aveSample = rollingAveTotal / (rollingAveCount * 1.0); //aveSample reduces clicks by keeping waveform centered around 0, size of window can be adjusted with rollingAveWindow. output[outputPtr++] = (short)(Math.Max(Math.Min(sample - aveSample, short.MaxValue), short.MinValue)); //I can't imagine clamping the audio could possibly sound worse then an overflow so this is how I shall do things (even though this will rarely even have an effect). sampleTotal = 0; sampleCount = 0; } } lastUpdateCycle = currentTime; }
public override byte Cycle() { int volume = 0; volume += VRC6.Cycle(); volume += VRC7.Cycle(); volume += FDS.Cycle(); volume += MMC5.Cycle(); volume += N163.Cycle(); volume += FME7.Cycle(); volume = (byte)(volume / (chipCount * 1.0)); if (hasMMC5) { nes.mapper.interruptMapper = ((Channels.MMC5)MMC5).interrupt; } return((byte)volume); }