Clean up namespaces for BizHawk.Emulation sound files

This commit is contained in:
adelikat 2013-11-14 19:33:13 +00:00
parent 906c0316a6
commit 25b242ade4
40 changed files with 1442 additions and 1426 deletions

View File

@ -998,7 +998,7 @@ namespace BizHawk.Client.EmuHawk
//avi/wav state
private IVideoWriter CurrAviWriter;
private ISoundProvider AviSoundInput;
private Emulation.Sound.MetaspuSoundProvider DumpProxy; //an audio proxy used for dumping
private MetaspuSoundProvider DumpProxy; //an audio proxy used for dumping
private long SoundRemainder; //audio timekeeping for video dumping
private int avwriter_resizew;
private int avwriter_resizeh;
@ -1412,7 +1412,7 @@ namespace BizHawk.Client.EmuHawk
if (!Global.Emulator.StartAsyncSound())
{
// if the core doesn't support async mode, use a standard vecna wrapper
GlobalWin.Sound.SetAsyncInputPin(new Emulation.Sound.MetaspuAsync(Global.Emulator.SyncSoundProvider, Emulation.Sound.ESynchMethod.ESynchMethod_V));
GlobalWin.Sound.SetAsyncInputPin(new MetaspuAsync(Global.Emulator.SyncSoundProvider, ESynchMethod.ESynchMethod_V));
}
else
{
@ -2854,10 +2854,10 @@ namespace BizHawk.Client.EmuHawk
// do sound rewire. the plan is to eventually have AVI writing support syncsound input, but it doesn't for the moment
if (!Global.Emulator.StartAsyncSound())
AviSoundInput = new Emulation.Sound.MetaspuAsync(Global.Emulator.SyncSoundProvider, Emulation.Sound.ESynchMethod.ESynchMethod_V);
AviSoundInput = new MetaspuAsync(Global.Emulator.SyncSoundProvider, ESynchMethod.ESynchMethod_V);
else
AviSoundInput = Global.Emulator.SoundProvider;
DumpProxy = new Emulation.Sound.MetaspuSoundProvider(Emulation.Sound.ESynchMethod.ESynchMethod_V);
DumpProxy = new MetaspuSoundProvider(ESynchMethod.ESynchMethod_V);
SoundRemainder = 0;
RewireSound();
}

View File

@ -1,13 +1,13 @@
using System;
using BizHawk.Emulation.Sound;
using System.Collections.Generic;
#if WINDOWS
using SlimDX.DirectSound;
using SlimDX.Multimedia;
#endif
using BizHawk.Client.Common;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
using System;
using BizHawk.Common;
using BizHawk.Emulation.Common;
#pragma warning disable 649 //adelikat: Disable dumb warnings until this file is complete
#pragma warning disable 169 //adelikat: Disable dumb warnings until this file is complete
@ -14,12 +16,12 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
// ------------------------------------
public Sound.Utilities.SpeexResampler resampler;
public SpeexResampler resampler;
static int[] syncNextTable = new int[] { 1, 2, 0 };
static int[] syncPrevTable = new int[] { 2, 0, 1 };
int cachedCycles;
int cachedCycles;
bool disableVoice3;
int[] envelopeOutput;
Envelope[] envelopes;
@ -29,12 +31,12 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
bool filterSelectBandPass;
bool filterSelectLoPass;
bool filterSelectHiPass;
int mixer;
int potCounter;
int mixer;
int potCounter;
int potX;
int potY;
short sample;
int[] voiceOutput;
int potY;
short sample;
int[] voiceOutput;
Voice[] voices;
int volume;
int[][] waveformTable;
@ -45,15 +47,15 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
public Sid(int[][] newWaveformTable, int newSampleRate, Region newRegion)
{
uint cyclesPerSec = 0;
uint cyclesNum;
uint cyclesDen;
uint sampleRate = 44100;
uint cyclesNum;
uint cyclesDen;
uint sampleRate = 44100;
switch (newRegion)
{
case Region.NTSC: cyclesNum = 14318181; cyclesDen = 14; break;
case Region.NTSC: cyclesNum = 14318181; cyclesDen = 14; break;
case Region.PAL: cyclesNum = 17734472; cyclesDen = 18; break;
default: return;
default: return;
}
waveformTable = newWaveformTable;
@ -72,7 +74,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
for (int i = 0; i < 3; i++)
filterEnable[i] = false;
resampler = new Sound.Utilities.SpeexResampler(0, cyclesNum, sampleRate * cyclesDen, cyclesNum, sampleRate * cyclesDen, null, null);
resampler = new SpeexResampler(0, cyclesNum, sampleRate * cyclesDen, cyclesNum, sampleRate * cyclesDen, null, null);
}
public void Dispose()
@ -100,55 +102,55 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
// ------------------------------------
public void ExecutePhase2()
public void ExecutePhase2()
{
cachedCycles++;
cachedCycles++;
// potentiometer values refresh every 512 cycles
if (potCounter == 0)
{
potCounter = 512;
potX = ReadPotX();
potY = ReadPotY();
Flush(); //this is here unrelated to the pots, just to keep the buffer somewhat loaded
}
potCounter--;
}
// potentiometer values refresh every 512 cycles
if (potCounter == 0)
{
potCounter = 512;
potX = ReadPotX();
potY = ReadPotY();
Flush(); //this is here unrelated to the pots, just to keep the buffer somewhat loaded
}
potCounter--;
}
public void Flush()
{
while (cachedCycles > 0)
{
// process voices and envelopes
voices[0].ExecutePhase2();
voices[1].ExecutePhase2();
voices[2].ExecutePhase2();
envelopes[0].ExecutePhase2();
envelopes[1].ExecutePhase2();
envelopes[2].ExecutePhase2();
public void Flush()
{
while (cachedCycles > 0)
{
// process voices and envelopes
voices[0].ExecutePhase2();
voices[1].ExecutePhase2();
voices[2].ExecutePhase2();
envelopes[0].ExecutePhase2();
envelopes[1].ExecutePhase2();
envelopes[2].ExecutePhase2();
// process sync
for (int i = 0; i < 3; i++)
voices[i].Synchronize(voices[syncNextTable[i]], voices[syncPrevTable[i]]);
// process sync
for (int i = 0; i < 3; i++)
voices[i].Synchronize(voices[syncNextTable[i]], voices[syncPrevTable[i]]);
// get output
voiceOutput[0] = voices[0].Output(voices[2]);
voiceOutput[1] = voices[1].Output(voices[0]);
voiceOutput[2] = voices[2].Output(voices[1]);
envelopeOutput[0] = envelopes[0].Level;
envelopeOutput[1] = envelopes[1].Level;
envelopeOutput[2] = envelopes[2].Level;
// get output
voiceOutput[0] = voices[0].Output(voices[2]);
voiceOutput[1] = voices[1].Output(voices[0]);
voiceOutput[2] = voices[2].Output(voices[1]);
envelopeOutput[0] = envelopes[0].Level;
envelopeOutput[1] = envelopes[1].Level;
envelopeOutput[2] = envelopes[2].Level;
mixer = ((voiceOutput[0] * envelopeOutput[0]) >> 7);
mixer += ((voiceOutput[1] * envelopeOutput[1]) >> 7);
mixer += ((voiceOutput[2] * envelopeOutput[2]) >> 7);
mixer = (mixer * volume) >> 4;
mixer = ((voiceOutput[0] * envelopeOutput[0]) >> 7);
mixer += ((voiceOutput[1] * envelopeOutput[1]) >> 7);
mixer += ((voiceOutput[2] * envelopeOutput[2]) >> 7);
mixer = (mixer * volume) >> 4;
sample = (short)mixer;
resampler.EnqueueSample(sample, sample);
cachedCycles--;
}
}
sample = (short)mixer;
resampler.EnqueueSample(sample, sample);
cachedCycles--;
}
}
// ------------------------------------
@ -172,7 +174,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
case 0x1A:
case 0x1B:
case 0x1C:
Flush();
Flush();
result = ReadRegister(addr);
break;
}
@ -204,7 +206,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
(envelopes[0].Decay)
);
break;
case 0x06:
case 0x06:
result = (byte)(
(envelopes[0].Sustain << 4) |
(envelopes[0].Release)
@ -280,7 +282,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
);
break;
case 0x19: result = (byte)potX; break;
case 0x1A: result = (byte)potY; break;
case 0x1A: result = (byte)potY; break;
case 0x1B: result = (byte)(voiceOutput[2] >> 4); break;
case 0x1C: result = (byte)(envelopeOutput[2]); break;
}
@ -303,7 +305,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
// can't write to these
break;
default:
Flush();
Flush();
WriteRegister(addr, val);
break;
}
@ -360,10 +362,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
// ----------------------------------
public void SyncState(Serializer ser)
public void SyncState(Serializer ser)
{
SaveState.SyncObject(ser, this);
ser.BeginSection("env0");
SaveState.SyncObject(ser, this);
ser.BeginSection("env0");
envelopes[0].SyncState(ser);
ser.EndSection();
ser.BeginSection("wav0");

View File

@ -1,6 +1,7 @@
using System;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.Components.M6502;
@ -12,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public MOS6502X cpu;
public M6532 m6532;
public TIA tia;
public Emulation.Sound.Utilities.DCFilter dcfilter;
public DCFilter dcfilter;
public byte[] ram = new byte[128];
public MapperBase mapper;
@ -183,7 +184,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
//tia = new TIA(this, frameBuffer);
tia = new TIA(this);
// dcfilter coefficent is from real observed hardware behavior: a latched "1" will fully decay by ~170 or so tia sound cycles
dcfilter = Emulation.Sound.Utilities.DCFilter.AsISoundProvider(tia, 256);
dcfilter = DCFilter.AsISoundProvider(tia, 256);
// Setup 6532
m6532 = new M6532(this);

View File

@ -344,16 +344,16 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800
// really shouldn't happen (after init), but if it does, we're ready
if (resampler != null)
resampler.Dispose();
resampler = new Emulation.Sound.Utilities.SpeexResampler(3, newsamplerate, 44100, newsamplerate, 44100, null, null);
resampler = new SpeexResampler(3, newsamplerate, 44100, newsamplerate, 44100, null, null);
samplerate = newsamplerate;
dcfilter = Emulation.Sound.Utilities.DCFilter.DetatchedMode(256);
dcfilter = DCFilter.DetatchedMode(256);
}
}
uint samplerate;
int[] vidbuffer;
Emulation.Sound.Utilities.SpeexResampler resampler;
Emulation.Sound.Utilities.DCFilter dcfilter;
SpeexResampler resampler;
DCFilter dcfilter;
public void FillFrameBuffer()
{

View File

@ -4,8 +4,8 @@ using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.Components;
using BizHawk.Emulation.Common.Components.Z80;
using BizHawk.Emulation.Sound;
namespace BizHawk.Emulation.Cores.ColecoVision
{

View File

@ -826,10 +826,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
int latchaudio = 0;
//Sound.Utilities.SpeexResampler resampler;
//Sound.Utilities.DCFilter dcfilter;
//SpeexResampler resampler;
//DCFilter dcfilter;
Sound.Utilities.BlipBuffer blip;
BlipBuffer blip;
void ProcessSound()
{
@ -862,7 +862,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
//dcfilter = Sound.Utilities.DCFilter.AsISyncSoundProvider(resampler, 65536);
// lowpass filtering on an actual GB was probably pretty aggressive?
//dcfilter = Sound.Utilities.DCFilter.AsISyncSoundProvider(resampler, 2048);
blip = new Sound.Utilities.BlipBuffer(1024);
blip = new BlipBuffer(1024);
blip.SetRates(2097152, 44100);
}

View File

@ -60,8 +60,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
LagCount = 0;
IsLagFrame = false;
blip_left = new Sound.Utilities.BlipBuffer(1024);
blip_right = new Sound.Utilities.BlipBuffer(1024);
blip_left = new BlipBuffer(1024);
blip_right = new BlipBuffer(1024);
blip_left.SetRates(2097152 * 2, 44100);
blip_right.SetRates(2097152 * 2, 44100);
@ -357,9 +357,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
// i tried using the left and right buffers and then mixing them together... it was kind of a mess of code, and slow
Sound.Utilities.BlipBuffer blip_left;
Sound.Utilities.BlipBuffer blip_right;
BlipBuffer blip_left;
BlipBuffer blip_right;
short[] LeftBuffer = new short[(35112 + 2064) * 2];
short[] RightBuffer = new short[(35112 + 2064) * 2];

View File

@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
public int BackgroundColor { get { return 0; } }
public Sound.Utilities.SpeexResampler resampler;
public SpeexResampler resampler;
public ISoundProvider SoundProvider { get { return null; } }
public ISyncSoundProvider SyncSoundProvider { get { return resampler; } }

View File

@ -5,6 +5,8 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.N64
{
public class mupen64plusApi : IDisposable
@ -515,7 +517,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
// Set up the resampler
m64pSamplingRate = (uint)AudGetAudioRate();
bizhawkCore.resampler = new Sound.Utilities.SpeexResampler(6, m64pSamplingRate, 44100, m64pSamplingRate, 44100, null, null);
bizhawkCore.resampler = new SpeexResampler(6, m64pSamplingRate, 44100, m64pSamplingRate, 44100, null, null);
AttachedCore = this;
}

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Sound;
//http://wiki.nesdev.com/w/index.php/APU_Mixer_Emulation
//http://wiki.nesdev.com/w/index.php/APU

View File

@ -2,6 +2,7 @@
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.Components;
//simplifications/approximations:
//* "Note that no commercial games rely on this mirroring -- therefore you can take the easy way out and simply give all MMC5 games 64k PRG-RAM."
@ -38,7 +39,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
int wram_bank;
byte[] EXRAM = new byte[1024];
byte multiplicand, multiplier;
Sound.MMC5Audio audio;
MMC5Audio audio;
//regeneratable state
IntBuffer a_banks_1k = new IntBuffer(8);
IntBuffer b_banks_1k = new IntBuffer(8);
@ -119,7 +120,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
PoweronState();
if (NES.apu != null)
audio = new Sound.MMC5Audio(NES.apu.ExternalQueue, (e) => { irq_audio = e; SyncIRQ(); });
audio = new MMC5Audio(NES.apu.ExternalQueue, (e) => { irq_audio = e; SyncIRQ(); });
return true;
}

View File

@ -1,4 +1,5 @@
using BizHawk.Common;
using BizHawk.Emulation.Common.Components;
namespace BizHawk.Emulation.Cores.Nintendo.NES
{
@ -7,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public sealed class Sunsoft_5 : Sunsoft_FME7
{
Sound.Sunsoft5BAudio audio;
Sunsoft5BAudio audio;
public override bool Configure(NES.EDetectionOrigin origin)
{
@ -23,7 +24,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
BaseConfigure();
if (NES.apu != null)
audio = new Sound.Sunsoft5BAudio(NES.apu.ExternalQueue);
audio = new Sunsoft5BAudio(NES.apu.ExternalQueue);
return true;
}

View File

@ -1,5 +1,7 @@
using System;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.NES
{
@ -116,15 +118,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
ser.Sync("ch", ref ch);
}
Sound.Utilities.SpeexResampler resampler;
Sound.Utilities.DCFilter dc;
Sound.MetaspuAsync metaspu;
SpeexResampler resampler;
DCFilter dc;
MetaspuAsync metaspu;
public Namco163Audio()
{
resampler = new Sound.Utilities.SpeexResampler(2, 119318, 44100, 119318, 44100, null, null);
dc = Sound.Utilities.DCFilter.DetatchedMode(4096);
metaspu = new Sound.MetaspuAsync(resampler, Sound.ESynchMethod.ESynchMethod_V);
resampler = new SpeexResampler(2, 119318, 44100, 119318, 44100, null, null);
dc = DCFilter.DetatchedMode(4096);
metaspu = new MetaspuAsync(resampler, ESynchMethod.ESynchMethod_V);
}
public void ApplyCustomAudio(short[] samples)

View File

@ -1,5 +1,7 @@
using System;
using BizHawk.Common;
using BizHawk.Emulation.Common.Components;
namespace BizHawk.Emulation.Cores.Nintendo.NES
{
@ -12,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
bool newer_variant;
//Sound.VRC6 VRC6Sound = new Sound.VRC6();
Sound.VRC6Alt VRC6Sound;
VRC6Alt VRC6Sound;
//state
int prg_bank_16k, prg_bank_8k;
@ -96,7 +98,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
SetMirrorType(EMirrorType.Vertical);
if (NES.apu != null) // don't start up sound when in configurator
VRC6Sound = new Sound.VRC6Alt((uint)NES.cpuclockrate, NES.apu.ExternalQueue);
VRC6Sound = new VRC6Alt((uint)NES.cpuclockrate, NES.apu.ExternalQueue);
return true;
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using BizHawk.Common;
using BizHawk.Emulation.Common.Components;
namespace BizHawk.Emulation.Cores.Nintendo.NES
{
@ -14,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
Func<int, int> remap;
//state
BizHawk.Emulation.Sound.YM2413 fm; //= new Sound.YM2413(Sound.YM2413.ChipType.VRC7);
YM2413 fm; //= new Sound.YM2413(Sound.YM2413.ChipType.VRC7);
ByteBuffer prg_banks_8k = new ByteBuffer(4);
ByteBuffer chr_banks_1k = new ByteBuffer(8);
@ -94,7 +95,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
// presumably the only reason a homebrew would use mapper085 is for the sound?
// so initialize like lagrange point
remap = (addr) => ((addr & 0xF000) | ((addr & 0x30) >> 4));
fm = new Sound.YM2413(Sound.YM2413.ChipType.VRC7);
fm = new YM2413(YM2413.ChipType.VRC7);
break;
case "KONAMI-VRC-7":
AssertPrg(128, 512); AssertChr(0, 128); AssertVram(0, 8); AssertWram(0, 8);
@ -109,7 +110,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
{
//lagrange point
remap = (addr) => ((addr & 0xF000) | ((addr & 0x30) >> 4));
fm = new Sound.YM2413(Sound.YM2413.ChipType.VRC7);
fm = new YM2413(YM2413.ChipType.VRC7);
}
else
throw new Exception("Unknown PCB type for VRC7");

View File

@ -66,7 +66,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
class MagicSoundProvider : ISoundProvider, ISyncSoundProvider, IDisposable
{
Sound.Utilities.BlipBuffer blip;
BlipBuffer blip;
NES nes;
const int blipbuffsize = 4096;
@ -75,7 +75,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
{
this.nes = nes;
blip = new Sound.Utilities.BlipBuffer(blipbuffsize);
blip = new BlipBuffer(blipbuffsize);
blip.SetRates(infreq, 44100);
//var actualMetaspu = new Sound.MetaspuSoundProvider(Sound.ESynchMethod.ESynchMethod_V);

View File

@ -975,11 +975,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
#region audio stuff
Sound.Utilities.SpeexResampler resampler;
SpeexResampler resampler;
void InitAudio()
{
resampler = new Sound.Utilities.SpeexResampler(6, 64081, 88200, 32041, 44100);
resampler = new SpeexResampler(6, 64081, 88200, 32041, 44100);
}
void snes_audio_sample(ushort left, ushort right)

View File

@ -1,5 +1,4 @@
using System;
using BizHawk.Emulation.Sound;
using System.IO;
using System.Globalization;

View File

@ -5,9 +5,9 @@ using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.Components;
using BizHawk.Emulation.Common.Components.H6280;
using BizHawk.Emulation.DiscSystem;
using BizHawk.Emulation.Sound;
namespace BizHawk.Emulation.Cores.PCEngine
{

View File

@ -3,8 +3,8 @@ using System.IO;
using System.Globalization;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.DiscSystem;
using BizHawk.Emulation.Sound;
namespace BizHawk.Emulation.Cores.PCEngine
{

View File

@ -7,12 +7,11 @@ using System.Runtime.InteropServices;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.Components;
using BizHawk.Emulation.Common.Components.M68000;
using BizHawk.Emulation.Common.Components.Z80;
using BizHawk.Emulation.Sound;
using Native68000;
namespace BizHawk.Emulation.Cores.Sega.Genesis
{
public sealed partial class Genesis : IEmulator

View File

@ -5,8 +5,8 @@ using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.Components;
using BizHawk.Emulation.Common.Components.Z80;
using BizHawk.Emulation.Sound;
/*****************************************************

View File

@ -9,7 +9,7 @@ using BizHawk.Emulation.DiscSystem;
// I decided not to let the perfect be the enemy of the good.
// It can always be refactored. It's at least deterministic.
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common
{
public sealed class CDAudio : ISoundProvider
{

View File

@ -6,7 +6,7 @@ using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common.Components
{
// Emulates PSG audio unit of a PC Engine / Turbografx-16 / SuperGrafx.
// It is embedded on the CPU and doesn't have its own part number. None the less, it is emulated separately from the 6280 CPU.

View File

@ -5,7 +5,7 @@ using System.Text;
using BizHawk.Common;
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common.Components
{
public class MMC5Audio
{

View File

@ -5,11 +5,13 @@ using System.IO;
using BizHawk.Emulation.Common;
// Emulates a Texas Instruments SN76489
// TODO the freq->note translation should be moved to a separate utility class.
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common.Components
{
/// <summary>
/// Emulates a Texas Instruments SN76489
/// </summary>
public sealed class SN76489 : ISoundProvider
{
public sealed class Channel

View File

@ -5,11 +5,13 @@ using System.Text;
using BizHawk.Common;
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common.Components
{
// YM2149F variant
// this implementation is quite incomplete
// http://wiki.nesdev.com/w/index.php/Sunsoft_5B_audio
/// <summary>
/// YM2149F variant
/// this implementation is quite incomplete
/// http://wiki.nesdev.com/w/index.php/Sunsoft_5B_audio
/// </summary>
public class Sunsoft5BAudio
{
class Pulse

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace BizHawk.Emulation.Sound.Utilities
namespace BizHawk.Emulation.Common
{
/// <summary>
/// wrapper around blargg's unmanaged blip_buf
@ -16,18 +16,18 @@ namespace BizHawk.Emulation.Sound.Utilities
static class BlipBufDll
{
/** Creates new buffer that can hold at most sample_count samples. Sets rates
so that there are blip_max_ratio clocks per sample. Returns pointer to new
/** Creates new buffer that can hold at most sample_count samples. Sets rates
so that there are blip_max_ratio clocks per sample. Returns pointer to new
buffer, or NULL if insufficient memory. */
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr blip_new(int sample_count);
/** Sets approximate input clock rate and output sample rate. For every
/** Sets approximate input clock rate and output sample rate. For every
clock_rate input clocks, approximately sample_rate samples are generated. */
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void blip_set_rates(IntPtr context, double clock_rate, double sample_rate);
/** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
/** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
clock_rate must not be greater than sample_rate*blip_max_ratio. */
public const int blip_max_ratio = 1 << 20;
@ -43,7 +43,7 @@ namespace BizHawk.Emulation.Sound.Utilities
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void blip_add_delta_fast(IntPtr context, uint clock_time, int delta);
/** Length of time frame, in clocks, needed to make sample_count additional
/** Length of time frame, in clocks, needed to make sample_count additional
samples available. */
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int blip_clocks_needed(IntPtr context, int sample_count);
@ -51,10 +51,10 @@ namespace BizHawk.Emulation.Sound.Utilities
/** Maximum number of samples that can be generated from one time frame. */
public const int blip_max_frame = 4000;
/** Makes input clocks before clock_duration available for reading as output
samples. Also begins new time frame at clock_duration, so that clock time 0 in
the new time frame specifies the same clock as clock_duration in the old time
frame specified. Deltas can have been added slightly past clock_duration (up to
/** Makes input clocks before clock_duration available for reading as output
samples. Also begins new time frame at clock_duration, so that clock time 0 in
the new time frame specifies the same clock as clock_duration in the old time
frame specified. Deltas can have been added slightly past clock_duration (up to
however many clocks there are in two output samples). */
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void blip_end_frame(IntPtr context, uint clock_duration);
@ -63,9 +63,9 @@ namespace BizHawk.Emulation.Sound.Utilities
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int blip_samples_avail(IntPtr context);
/** Reads and removes at most 'count' samples and writes them to 'out'. If
'stereo' is true, writes output to every other element of 'out', allowing easy
interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
/** Reads and removes at most 'count' samples and writes them to 'out'. If
'stereo' is true, writes output to every other element of 'out', allowing easy
interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
samples. Returns number of samples actually read. */
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int blip_read_samples(IntPtr context, short[] @out, int count, int stereo);

View File

@ -2,18 +2,18 @@
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common
{
// Generates SEMI-synchronous sound, or "buffered asynchronous" sound.
// Generates SEMI-synchronous sound, or "buffered asynchronous" sound.
// This class will try as hard as it can to request the correct number of samples on each frame and then
// send them out to the sound card as it needs them.
// This class will try as hard as it can to request the correct number of samples on each frame and then
// send them out to the sound card as it needs them.
// However, it has minimum/maximum buffer targets and will request smaller or larger frames if it has to.
// The ultimate goal of this strategy is to make MOST frames 100% correct, and if errors must occur,
// concentrate it on a single frame, rather than distribute small errors across most frames, as
// distributing error to most frames tends to result in persistently distorted audio, especially when
// sample playback is involved.
// However, it has minimum/maximum buffer targets and will request smaller or larger frames if it has to.
// The ultimate goal of this strategy is to make MOST frames 100% correct, and if errors must occur,
// concentrate it on a single frame, rather than distribute small errors across most frames, as
// distributing error to most frames tends to result in persistently distorted audio, especially when
// sample playback is involved.
/*
@ -30,15 +30,15 @@ namespace BizHawk.Emulation.Sound
* that and then bypass the BufferedAsync.
*/
public sealed class BufferedAsync : ISoundProvider
{
public ISoundProvider BaseSoundProvider;
public sealed class BufferedAsync : ISoundProvider
{
public ISoundProvider BaseSoundProvider;
Queue<short> buffer = new Queue<short>(4096);
Queue<short> buffer = new Queue<short>(4096);
int SamplesInOneFrame = 1470;
int TargetExtraSamples = 882;
const int MaxExcessSamples = 4096;
int SamplesInOneFrame = 1470;
int TargetExtraSamples = 882;
const int MaxExcessSamples = 4096;
/// <summary>
/// recalculates some internal parameters based on the IEmulator's framerate
@ -52,31 +52,31 @@ namespace BizHawk.Emulation.Sound
public void DiscardSamples()
{
if(BaseSoundProvider != null)
if (BaseSoundProvider != null)
BaseSoundProvider.DiscardSamples();
}
public int MaxVolume { get; set; }
public int MaxVolume { get; set; }
public void GetSamples(short[] samples)
{
int samplesToGenerate = SamplesInOneFrame;
if (buffer.Count > samples.Length + MaxExcessSamples)
samplesToGenerate = 0;
if (buffer.Count - samples.Length < TargetExtraSamples)
samplesToGenerate += SamplesInOneFrame;
if (samplesToGenerate + buffer.Count < samples.Length)
samplesToGenerate = samples.Length - buffer.Count;
public void GetSamples(short[] samples)
{
int samplesToGenerate = SamplesInOneFrame;
if (buffer.Count > samples.Length + MaxExcessSamples)
samplesToGenerate = 0;
if (buffer.Count - samples.Length < TargetExtraSamples)
samplesToGenerate += SamplesInOneFrame;
if (samplesToGenerate + buffer.Count < samples.Length)
samplesToGenerate = samples.Length - buffer.Count;
var mySamples = new short[samplesToGenerate];
var mySamples = new short[samplesToGenerate];
BaseSoundProvider.GetSamples(mySamples);
BaseSoundProvider.GetSamples(mySamples);
for (int i = 0; i < mySamples.Length; i++)
buffer.Enqueue(mySamples[i]);
for (int i = 0; i < mySamples.Length; i++)
buffer.Enqueue(mySamples[i]);
for (int i = 0; i < samples.Length; i++)
samples[i] = buffer.Dequeue();
}
}
for (int i = 0; i < samples.Length; i++)
samples[i] = buffer.Dequeue();
}
}
}

View File

@ -5,7 +5,7 @@ using System.Text;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Sound.Utilities
namespace BizHawk.Emulation.Common
{
/// <summary>
/// implements a DC block filter on top of an ISoundProvider. rather simple.
@ -39,7 +39,7 @@ namespace BizHawk.Emulation.Sound.Utilities
}
int depth;
public static DCFilter AsISoundProvider(ISoundProvider input, int filterwidth)
{
if (input == null)
@ -59,7 +59,7 @@ namespace BizHawk.Emulation.Sound.Utilities
return new DCFilter(null, null, filterwidth);
}
DCFilter(ISoundProvider input, ISyncSoundProvider syncinput, int filterwidth)
DCFilter(ISoundProvider input, ISyncSoundProvider syncinput, int filterwidth)
{
if (filterwidth < 8 || filterwidth > 65536)
throw new ArgumentOutOfRangeException();
@ -67,7 +67,7 @@ namespace BizHawk.Emulation.Sound.Utilities
this.syncinput = syncinput;
depth = DepthFromFilterwidth(filterwidth);
}
/// <summary>
/// pass a set of samples through the filter. should only be used in detached mode
/// </summary>

View File

@ -5,94 +5,94 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common
{
public sealed class Equalizer
{
double lowFilter;
double lowFilterPole0;
double lowFilterPole1;
double lowFilterPole2;
double lowFilterPole3;
public sealed class Equalizer
{
double lowFilter;
double lowFilterPole0;
double lowFilterPole1;
double lowFilterPole2;
double lowFilterPole3;
double highFilter;
double highFilterPole0;
double highFilterPole1;
double highFilterPole2;
double highFilterPole3;
double highFilter;
double highFilterPole0;
double highFilterPole1;
double highFilterPole2;
double highFilterPole3;
double sampleDataMinus1;
double sampleDataMinus2;
double sampleDataMinus3;
double sampleDataMinus1;
double sampleDataMinus2;
double sampleDataMinus3;
double lowGain;
double midGain;
double highGain;
const double sampleRate = 44100.0;
const double verySmallAmount = (1.0 / 4294967295.0);
double lowGain;
double midGain;
double highGain;
double lowfreq;
public double LowFreqCutoff
{
get { return lowfreq; }
set
{
lowfreq = value;
lowFilter = 2 * Math.Sin(Math.PI * (lowfreq / sampleRate));
}
}
const double sampleRate = 44100.0;
const double verySmallAmount = (1.0 / 4294967295.0);
double highfreq;
public double HighFreqCutoff
{
get { return highfreq; }
set
{
highfreq = value;
highFilter = 2 * Math.Sin(Math.PI * (highfreq / sampleRate));
}
}
double lowfreq;
public double LowFreqCutoff
{
get { return lowfreq; }
set
{
lowfreq = value;
lowFilter = 2 * Math.Sin(Math.PI * (lowfreq / sampleRate));
}
}
public Equalizer(double lowFreq=880, double highFreq=5000)
{
lowGain = 1.3;
midGain = 0.9;
highGain = 1.3;
LowFreqCutoff = lowFreq;
HighFreqCutoff = highFreq;
}
double highfreq;
public double HighFreqCutoff
{
get { return highfreq; }
set
{
highfreq = value;
highFilter = 2 * Math.Sin(Math.PI * (highfreq / sampleRate));
}
}
public short EqualizeSample(short sample)
{
lowFilterPole0 += (lowFilter * (sample - lowFilterPole0)) + verySmallAmount;
lowFilterPole1 += lowFilter * (lowFilterPole0 - lowFilterPole1);
lowFilterPole2 += lowFilter * (lowFilterPole1 - lowFilterPole2);
lowFilterPole3 += lowFilter * (lowFilterPole2 - lowFilterPole3);
double l = lowFilterPole3;
public Equalizer(double lowFreq = 880, double highFreq = 5000)
{
lowGain = 1.3;
midGain = 0.9;
highGain = 1.3;
LowFreqCutoff = lowFreq;
HighFreqCutoff = highFreq;
}
highFilterPole0 += (highFilter * (sample - highFilterPole0)) + verySmallAmount;
highFilterPole1 += highFilter * (highFilterPole0 - highFilterPole1);
highFilterPole2 += highFilter * (highFilterPole1 - highFilterPole2);
highFilterPole3 += highFilter * (highFilterPole2 - highFilterPole3);
double h = sampleDataMinus3 - highFilterPole3;
public short EqualizeSample(short sample)
{
lowFilterPole0 += (lowFilter * (sample - lowFilterPole0)) + verySmallAmount;
lowFilterPole1 += lowFilter * (lowFilterPole0 - lowFilterPole1);
lowFilterPole2 += lowFilter * (lowFilterPole1 - lowFilterPole2);
lowFilterPole3 += lowFilter * (lowFilterPole2 - lowFilterPole3);
double l = lowFilterPole3;
double m = sample - (h + l);
l *= lowGain;
m *= midGain;
h *= highGain;
highFilterPole0 += (highFilter * (sample - highFilterPole0)) + verySmallAmount;
highFilterPole1 += highFilter * (highFilterPole0 - highFilterPole1);
highFilterPole2 += highFilter * (highFilterPole1 - highFilterPole2);
highFilterPole3 += highFilter * (highFilterPole2 - highFilterPole3);
double h = sampleDataMinus3 - highFilterPole3;
sampleDataMinus3 = sampleDataMinus2;
sampleDataMinus2 = sampleDataMinus1;
sampleDataMinus1 = sample;
double m = sample - (h + l);
l *= lowGain;
m *= midGain;
h *= highGain;
return (short) (l + m + h);
}
sampleDataMinus3 = sampleDataMinus2;
sampleDataMinus2 = sampleDataMinus1;
sampleDataMinus1 = sample;
public void Equalize(short[] samples)
{
for (int i = 0; i < samples.Length; i++)
samples[i] = EqualizeSample(samples[i]);
}
}
return (short)(l + m + h);
}
public void Equalize(short[] samples)
{
for (int i = 0; i < samples.Length; i++)
samples[i] = EqualizeSample(samples[i]);
}
}
}

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common
{
/// <summary>
/// uses Metaspu to have an ISyncSoundProvider input to a ISoundProvider
@ -36,8 +36,6 @@ namespace BizHawk.Emulation.Sound
public int MaxVolume { get; set; }
}
public class MetaspuSoundProvider : ISoundProvider
{
public ISynchronizingAudioBuffer buffer;
@ -46,17 +44,18 @@ namespace BizHawk.Emulation.Sound
buffer = Metaspu.metaspu_construct(method);
}
public MetaspuSoundProvider() : this(ESynchMethod.ESynchMethod_V)
public MetaspuSoundProvider()
: this(ESynchMethod.ESynchMethod_V)
{
}
short[] pullBuffer = new short[1470];
public void PullSamples(ISoundProvider source)
{
Array.Clear(pullBuffer, 0, 1470);
source.GetSamples(pullBuffer);
buffer.enqueue_samples(pullBuffer, 735);
}
short[] pullBuffer = new short[1470];
public void PullSamples(ISoundProvider source)
{
Array.Clear(pullBuffer, 0, 1470);
source.GetSamples(pullBuffer);
buffer.enqueue_samples(pullBuffer, 735);
}
public void GetSamples(short[] samples)
{
@ -68,15 +67,15 @@ namespace BizHawk.Emulation.Sound
buffer.clear();
}
public int MaxVolume { get; set; }
}
public int MaxVolume { get; set; }
}
public interface ISynchronizingAudioBuffer
{
void enqueue_samples(short[] buf, int samples_provided);
void enqueue_sample(short left, short right);
void clear();
//returns the number of samples actually supplied, which may not match the number requested
// ^^ what the hell is that supposed to mean.
// the entire point of an ISynchronzingAudioBuffer
@ -90,9 +89,9 @@ namespace BizHawk.Emulation.Sound
ESynchMethod_N, //nitsuja's
ESynchMethod_Z, //zero's
//ESynchMethod_P, //PCSX2 spu2-x //ohno! not available yet in c#
ESynchMethod_V // vecna
ESynchMethod_V // vecna
};
public static class Metaspu
{
public static ISynchronizingAudioBuffer metaspu_construct(ESynchMethod method)
@ -103,15 +102,15 @@ namespace BizHawk.Emulation.Sound
return new ZeromusSynchronizer();
case ESynchMethod.ESynchMethod_N:
return new NitsujaSynchronizer();
case ESynchMethod.ESynchMethod_V:
return new VecnaSynchronizer();
case ESynchMethod.ESynchMethod_V:
return new VecnaSynchronizer();
default:
return new NitsujaSynchronizer();
}
}
}
class ZeromusSynchronizer : ISynchronizingAudioBuffer
{
public ZeromusSynchronizer()
@ -121,7 +120,7 @@ namespace BizHawk.Emulation.Sound
//#else
//adjustobuf = new Adjustobuf(22000, 44000);
//#endif
}
//adjustobuf(200,1000)
@ -151,7 +150,7 @@ namespace BizHawk.Emulation.Sound
//returns the number of samples actually supplied, which may not match the number requested
public int output_samples(short[] buf, int samples_requested)
{
int ctr=0;
int ctr = 0;
int done = 0;
if (!mixqueue_go)
{
@ -208,7 +207,7 @@ namespace BizHawk.Emulation.Sound
size = 0;
}
public void enqueue(short left, short right)
public void enqueue(short left, short right)
{
buffer.Enqueue(left);
buffer.Enqueue(right);
@ -232,14 +231,16 @@ namespace BizHawk.Emulation.Sound
//static int ctr=0; ctr++; if((ctr&127)==0) printf("avg size: %f curr size: %d rate: %f\n",averageSize,size,rate);
{
float targetRate;
if(averageSize < targetLatency)
if (averageSize < targetLatency)
{
targetRate = 1.0f - (targetLatency-averageSize)/kAverageSize;
targetRate = 1.0f - (targetLatency - averageSize) / kAverageSize;
}
else if(averageSize > targetLatency) {
targetRate = 1.0f + (averageSize-targetLatency)/kAverageSize;
} else targetRate = 1.0f;
else if (averageSize > targetLatency)
{
targetRate = 1.0f + (averageSize - targetLatency) / kAverageSize;
}
else targetRate = 1.0f;
//rate = moveValueTowards(rate,targetRate,0.001f);
rate = targetRate;
}
@ -251,19 +252,21 @@ namespace BizHawk.Emulation.Sound
public void dequeue(out short left, out short right)
{
left = right = 0;
left = right = 0;
addStatistic();
if(size==0) { return; }
if (size == 0) { return; }
cursor += rate;
while(cursor>1.0f) {
while (cursor > 1.0f)
{
cursor -= 1.0f;
if(size>0) {
if (size > 0)
{
curr[0] = buffer.Dequeue();
curr[1] = buffer.Dequeue();
size--;
}
}
left = curr[0];
left = curr[0];
right = curr[1];
}
}
@ -282,9 +285,9 @@ namespace BizHawk.Emulation.Sound
// returns values going between 0 and y-1 in a saw wave pattern, based on x
static int pingpong(int x, int y)
{
x %= 2*y;
if(x >= y)
x = 2*y - x - 1;
x %= 2 * y;
if (x >= y)
x = 2 * y - x - 1;
return x;
// in case we want to switch to odd buffer sizes for more sharpness
@ -294,11 +297,11 @@ namespace BizHawk.Emulation.Sound
//return x;
}
static ssamp crossfade (ssamp lhs, ssamp rhs, int cur, int start, int end)
static ssamp crossfade(ssamp lhs, ssamp rhs, int cur, int start, int end)
{
if(cur <= start)
if (cur <= start)
return lhs;
if(cur >= end)
if (cur >= end)
return rhs;
// in case we want sine wave interpolation instead of linear here
@ -312,7 +315,7 @@ namespace BizHawk.Emulation.Sound
int lrv = ((int)lhs.l * outNum + (int)rhs.l * inNum) / denom;
int rrv = ((int)lhs.r * outNum + (int)rhs.r * inNum) / denom;
return new ssamp((short)lrv,(short)rrv);
return new ssamp((short)lrv, (short)rrv);
}
public void clear()
@ -328,8 +331,8 @@ namespace BizHawk.Emulation.Sound
static void emit_samples(short[] outbuf, ref int outcursor, ssamp[] samplebuf, int incursor, int samples)
{
for(int i=0;i<samples;i++)
emit_sample(outbuf,ref outcursor, samplebuf[i+incursor]);
for (int i = 0; i < samples; i++)
emit_sample(outbuf, ref outcursor, samplebuf[i + incursor]);
}
static short abs(short value)
@ -347,345 +350,347 @@ namespace BizHawk.Emulation.Sound
public void enqueue_samples(short[] buf, int samples_provided)
{
int cursor = 0;
for(int i=0;i<samples_provided;i++)
for (int i = 0; i < samples_provided; i++)
{
sampleQueue.Add(new ssamp(buf[cursor+0],buf[cursor+1]));
sampleQueue.Add(new ssamp(buf[cursor + 0], buf[cursor + 1]));
cursor += 2;
}
}
public void enqueue_sample(short left, short right)
{
sampleQueue.Add(new ssamp(left,right));
sampleQueue.Add(new ssamp(left, right));
}
public int output_samples(short[] buf, int samples_requested)
{
Console.WriteLine("{0} {1}", samples_requested, sampleQueue.Count); //add this line
Console.WriteLine("{0} {1}", samples_requested, sampleQueue.Count); //add this line
int bufcursor = 0;
int audiosize = samples_requested;
int queued = sampleQueue.Count;
int audiosize = samples_requested;
int queued = sampleQueue.Count;
// I am too lazy to deal with odd numbers
audiosize &= ~1;
queued &= ~1;
// I am too lazy to deal with odd numbers
audiosize &= ~1;
queued &= ~1;
if(queued > 0x200 && audiosize > 0) // is there any work to do?
{
// are we going at normal speed?
// or more precisely, are the input and output queues/buffers of similar size?
if(queued > 900 || audiosize > queued * 2)
if (queued > 0x200 && audiosize > 0) // is there any work to do?
{
// not normal speed. we have to resample it somehow in this case.
if(audiosize <= queued)
// are we going at normal speed?
// or more precisely, are the input and output queues/buffers of similar size?
if (queued > 900 || audiosize > queued * 2)
{
// fast forward speed
// this is the easy case, just crossfade it and it sounds ok
for(int i = 0; i < audiosize; i++)
// not normal speed. we have to resample it somehow in this case.
if (audiosize <= queued)
{
int j = i + queued - audiosize;
ssamp outsamp = crossfade(sampleQueue[i],sampleQueue[j], i,0,audiosize);
emit_sample(buf,ref bufcursor,outsamp);
}
}
else
{
// slow motion speed
// here we take a very different approach,
// instead of crossfading it, we select a single sample from the queue
// and make sure that the index we use to select a sample is constantly moving
// and that it starts at the first sample in the queue and ends on the last one.
//
// hopefully the index doesn't move discontinuously or we'll get slight crackling
// (there might still be a minor bug here that causes this occasionally)
//
// here's a diagram of how the index we sample from moves:
//
// queued (this axis represents the index we sample from. the top means the end of the queue)
// ^
// | --> audiosize (this axis represents the output index we write to, right meaning forward in output time/position)
// | A C C end
// A A B C C C
// A A A B C C C
// A A A B C C
// A A C
// start
//
// yes, this means we are spending some stretches of time playing the sound backwards,
// but the stretches are short enough that this doesn't sound weird.
// this lets us avoid most crackling problems due to the endpoints matching up.
// first calculate a shorter-than-full window
// that has minimal slope at the endpoints
// (to further reduce crackling, especially in sine waves)
int beststart = 0, extraAtEnd = 0;
{
int bestend = queued;
const int worstdiff = 99999999;
int beststartdiff = worstdiff;
int bestenddiff = worstdiff;
for(int i = 0; i < 128; i+=2)
// fast forward speed
// this is the easy case, just crossfade it and it sounds ok
for (int i = 0; i < audiosize; i++)
{
int diff = abs(sampleQueue[i].l - sampleQueue[i+1].l) + abs(sampleQueue[i].r - sampleQueue[i+1].r);
if(diff < beststartdiff)
{
beststartdiff = diff;
beststart = i;
}
int j = i + queued - audiosize;
ssamp outsamp = crossfade(sampleQueue[i], sampleQueue[j], i, 0, audiosize);
emit_sample(buf, ref bufcursor, outsamp);
}
for(int i = queued-3; i > queued-3-128; i-=2)
}
else
{
// slow motion speed
// here we take a very different approach,
// instead of crossfading it, we select a single sample from the queue
// and make sure that the index we use to select a sample is constantly moving
// and that it starts at the first sample in the queue and ends on the last one.
//
// hopefully the index doesn't move discontinuously or we'll get slight crackling
// (there might still be a minor bug here that causes this occasionally)
//
// here's a diagram of how the index we sample from moves:
//
// queued (this axis represents the index we sample from. the top means the end of the queue)
// ^
// | --> audiosize (this axis represents the output index we write to, right meaning forward in output time/position)
// | A C C end
// A A B C C C
// A A A B C C C
// A A A B C C
// A A C
// start
//
// yes, this means we are spending some stretches of time playing the sound backwards,
// but the stretches are short enough that this doesn't sound weird.
// this lets us avoid most crackling problems due to the endpoints matching up.
// first calculate a shorter-than-full window
// that has minimal slope at the endpoints
// (to further reduce crackling, especially in sine waves)
int beststart = 0, extraAtEnd = 0;
{
int diff = abs(sampleQueue[i].l - sampleQueue[i+1].l) + abs(sampleQueue[i].r - sampleQueue[i+1].r);
if(diff < bestenddiff)
int bestend = queued;
const int worstdiff = 99999999;
int beststartdiff = worstdiff;
int bestenddiff = worstdiff;
for (int i = 0; i < 128; i += 2)
{
bestenddiff = diff;
bestend = i+1;
int diff = abs(sampleQueue[i].l - sampleQueue[i + 1].l) + abs(sampleQueue[i].r - sampleQueue[i + 1].r);
if (diff < beststartdiff)
{
beststartdiff = diff;
beststart = i;
}
}
for (int i = queued - 3; i > queued - 3 - 128; i -= 2)
{
int diff = abs(sampleQueue[i].l - sampleQueue[i + 1].l) + abs(sampleQueue[i].r - sampleQueue[i + 1].r);
if (diff < bestenddiff)
{
bestenddiff = diff;
bestend = i + 1;
}
}
extraAtEnd = queued - bestend;
queued = bestend - beststart;
int oksize = queued;
while (oksize + queued * 2 + beststart + extraAtEnd <= samples_requested)
oksize += queued * 2;
audiosize = oksize;
for (int x = 0; x < beststart; x++)
{
emit_sample(buf, ref bufcursor, sampleQueue[x]);
}
//sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin() + beststart);
sampleQueue.RemoveRange(0, beststart);
//zero 08-nov-2010: did i do this right?
}
int midpointX = audiosize >> 1;
int midpointY = queued >> 1;
// all we need to do here is calculate the X position of the leftmost "B" in the above diagram.
// TODO: we should calculate it with a simple equation like
// midpointXOffset = min(something,somethingElse);
// but it's a little difficult to work it out exactly
// so here's a stupid search for the value for now:
int prevA = 999999;
int midpointXOffset = queued / 2;
while (true)
{
int a = abs(pingpong(midpointX - midpointXOffset, queued) - midpointY) - midpointXOffset;
if (((a > 0) != (prevA > 0) || (a < 0) != (prevA < 0)) && prevA != 999999)
{
if (((a + prevA) & 1) != 0) // there's some sort of off-by-one problem with this search since we're moving diagonally...
midpointXOffset++; // but this fixes it most of the time...
break; // found it
}
prevA = a;
midpointXOffset--;
if (midpointXOffset < 0)
{
midpointXOffset = 0;
break; // failed to find it. the two sides probably meet exactly in the center.
}
}
extraAtEnd = queued - bestend;
queued = bestend - beststart;
int leftMidpointX = midpointX - midpointXOffset;
int rightMidpointX = midpointX + midpointXOffset;
int leftMidpointY = pingpong(leftMidpointX, queued);
int rightMidpointY = (queued - 1) - pingpong((int)audiosize - 1 - rightMidpointX + queued * 2, queued);
int oksize = queued;
while(oksize + queued*2 + beststart + extraAtEnd <= samples_requested)
oksize += queued*2;
audiosize = oksize;
for(int x = 0; x < beststart; x++)
// output the left almost-half of the sound (section "A")
for (int x = 0; x < leftMidpointX; x++)
{
emit_sample(buf,ref bufcursor,sampleQueue[x]);
int i = pingpong(x, queued);
emit_sample(buf, ref bufcursor, sampleQueue[i]);
}
//sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin() + beststart);
sampleQueue.RemoveRange(0, beststart);
//zero 08-nov-2010: did i do this right?
}
// output the middle stretch (section "B")
int y = leftMidpointY;
int dyMidLeft = (leftMidpointY < midpointY) ? 1 : -1;
int dyMidRight = (rightMidpointY > midpointY) ? 1 : -1;
for (int x = leftMidpointX; x < midpointX; x++, y += dyMidLeft)
emit_sample(buf, ref bufcursor, sampleQueue[y]);
for (int x = midpointX; x < rightMidpointX; x++, y += dyMidRight)
emit_sample(buf, ref bufcursor, sampleQueue[y]);
int midpointX = audiosize >> 1;
int midpointY = queued >> 1;
// all we need to do here is calculate the X position of the leftmost "B" in the above diagram.
// TODO: we should calculate it with a simple equation like
// midpointXOffset = min(something,somethingElse);
// but it's a little difficult to work it out exactly
// so here's a stupid search for the value for now:
int prevA = 999999;
int midpointXOffset = queued/2;
while(true)
{
int a = abs(pingpong(midpointX - midpointXOffset, queued) - midpointY) - midpointXOffset;
if(((a > 0) != (prevA > 0) || (a < 0) != (prevA < 0)) && prevA != 999999)
// output the end of the queued sound (section "C")
for (int x = rightMidpointX; x < audiosize; x++)
{
if(((a + prevA)&1)!=0) // there's some sort of off-by-one problem with this search since we're moving diagonally...
midpointXOffset++; // but this fixes it most of the time...
break; // found it
int i = (queued - 1) - pingpong((int)audiosize - 1 - x + queued * 2, queued);
emit_sample(buf, ref bufcursor, sampleQueue[i]);
}
prevA = a;
midpointXOffset--;
if(midpointXOffset < 0)
for (int x = 0; x < extraAtEnd; x++)
{
midpointXOffset = 0;
break; // failed to find it. the two sides probably meet exactly in the center.
int i = queued + x;
emit_sample(buf, ref bufcursor, sampleQueue[i]);
}
}
queued += extraAtEnd;
audiosize += beststart + extraAtEnd;
} //end else
int leftMidpointX = midpointX - midpointXOffset;
int rightMidpointX = midpointX + midpointXOffset;
int leftMidpointY = pingpong(leftMidpointX, queued);
int rightMidpointY = (queued-1) - pingpong((int)audiosize-1 - rightMidpointX + queued*2, queued);
// output the left almost-half of the sound (section "A")
for(int x = 0; x < leftMidpointX; x++)
{
int i = pingpong(x, queued);
emit_sample(buf,ref bufcursor,sampleQueue[i]);
}
// output the middle stretch (section "B")
int y = leftMidpointY;
int dyMidLeft = (leftMidpointY < midpointY) ? 1 : -1;
int dyMidRight = (rightMidpointY > midpointY) ? 1 : -1;
for(int x = leftMidpointX; x < midpointX; x++, y+=dyMidLeft)
emit_sample(buf,ref bufcursor,sampleQueue[y]);
for(int x = midpointX; x < rightMidpointX; x++, y+=dyMidRight)
emit_sample(buf, ref bufcursor, sampleQueue[y]);
// output the end of the queued sound (section "C")
for(int x = rightMidpointX; x < audiosize; x++)
{
int i = (queued-1) - pingpong((int)audiosize-1 - x + queued*2, queued);
emit_sample(buf,ref bufcursor,sampleQueue[i]);
}
for(int x = 0; x < extraAtEnd; x++)
{
int i = queued + x;
emit_sample(buf,ref bufcursor,sampleQueue[i]);
}
queued += extraAtEnd;
audiosize += beststart + extraAtEnd;
} //end else
//sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin() + queued);
sampleQueue.RemoveRange(0, queued);
//zero 08-nov-2010: did i do this right?
return audiosize;
}
else
{
// normal speed
// just output the samples straightforwardly.
//
// at almost-full speeds (like 50/60 FPS)
// what will happen is that we rapidly fluctuate between entering this branch
// and entering the "slow motion speed" branch above.
// but that's ok! because all of these branches sound similar enough that we can get away with it.
// so the two cases actually complement each other.
if(audiosize >= queued)
{
emit_samples(buf,ref bufcursor, sampleQueue.ToArray(),0,queued);
//sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin() + queued);
sampleQueue.RemoveRange(0, queued);
//zero 08-nov-2010: did i do this right?
return queued;
return audiosize;
}
else
{
emit_samples(buf,ref bufcursor, sampleQueue.ToArray(),0,audiosize);
//sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin()+audiosize);
sampleQueue.RemoveRange(0, audiosize);
//zero 08-nov-2010: did i do this right?
return audiosize;
}
// normal speed
// just output the samples straightforwardly.
//
// at almost-full speeds (like 50/60 FPS)
// what will happen is that we rapidly fluctuate between entering this branch
// and entering the "slow motion speed" branch above.
// but that's ok! because all of these branches sound similar enough that we can get away with it.
// so the two cases actually complement each other.
} //end normal speed
if (audiosize >= queued)
{
emit_samples(buf, ref bufcursor, sampleQueue.ToArray(), 0, queued);
//sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin() + queued);
sampleQueue.RemoveRange(0, queued);
//zero 08-nov-2010: did i do this right?
return queued;
}
else
{
emit_samples(buf, ref bufcursor, sampleQueue.ToArray(), 0, audiosize);
//sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin()+audiosize);
sampleQueue.RemoveRange(0, audiosize);
//zero 08-nov-2010: did i do this right?
return audiosize;
}
} //end if there is any work to do
else
} //end normal speed
} //end if there is any work to do
else
{
return 0;
}
} //output_samples
}; //NitsujaSynchronizer
class VecnaSynchronizer : ISynchronizingAudioBuffer
{
// vecna's attempt at a fully synchronous sound provider.
// It's similar in philosophy to my "BufferedAsync" provider, but BufferedAsync is not
// fully synchronous.
// Like BufferedAsync, it tries to make most frames 100% correct and just suck it up
// periodically and have a big bad-sounding mistake frame if it has to.
// It is significantly less ambitious and elaborate than the other methods.
// We'll see if it works better or not!
// It has a min and maximum amount of excess buffer to deal with minor overflows.
// When fastforwarding, it will discard samples above the maximum excess buffer.
// When underflowing, it will attempt to resample to a certain threshhold.
// If it underflows beyond that threshhold, it will give up and output silence.
// Since it has done this, it will go ahead and generate some excess silence in order
// to restock its excess buffer.
struct Sample
{
return 0;
public short left, right;
public Sample(short l, short r)
{
left = l;
right = r;
}
}
} //output_samples
Queue<Sample> buffer;
Sample[] resampleBuffer;
const int SamplesInOneFrame = 735;
const int MaxExcessSamples = 2048;
}; //NitsujaSynchronizer
public VecnaSynchronizer()
{
buffer = new Queue<Sample>(2048);
resampleBuffer = new Sample[2730]; // 2048 * 1.25
class VecnaSynchronizer : ISynchronizingAudioBuffer
{
// vecna's attempt at a fully synchronous sound provider.
// It's similar in philosophy to my "BufferedAsync" provider, but BufferedAsync is not
// fully synchronous.
// Give us a little buffer wiggle-room
for (int i = 0; i < 367; i++)
buffer.Enqueue(new Sample(0, 0));
}
// Like BufferedAsync, it tries to make most frames 100% correct and just suck it up
// periodically and have a big bad-sounding mistake frame if it has to.
// It is significantly less ambitious and elaborate than the other methods.
// We'll see if it works better or not!
public void enqueue_samples(short[] buf, int samples_provided)
{
int ctr = 0;
for (int i = 0; i < samples_provided; i++)
{
short left = buf[ctr++];
short right = buf[ctr++];
enqueue_sample(left, right);
}
}
// It has a min and maximum amount of excess buffer to deal with minor overflows.
// When fastforwarding, it will discard samples above the maximum excess buffer.
// When underflowing, it will attempt to resample to a certain threshhold.
// If it underflows beyond that threshhold, it will give up and output silence.
// Since it has done this, it will go ahead and generate some excess silence in order
// to restock its excess buffer.
public void enqueue_sample(short left, short right)
{
if (buffer.Count >= MaxExcessSamples - 1)
{
// if buffer is overfull, dequeue old samples to make room for new samples.
buffer.Dequeue();
}
buffer.Enqueue(new Sample(left, right));
}
struct Sample
{
public short left, right;
public Sample(short l, short r)
{
left = l;
right = r;
}
}
public void clear()
{
buffer.Clear();
}
Queue<Sample> buffer;
Sample[] resampleBuffer;
public int output_samples(short[] buf, int samples_requested)
{
if (samples_requested > buffer.Count)
{
// underflow!
if (buffer.Count > samples_requested * 3 / 4)
{
// if we're within 75% of target, then I guess we suck it up and resample.
// we sample in a goofy way, we could probably do it a bit smarter, if we cared more.
const int SamplesInOneFrame = 735;
const int MaxExcessSamples = 2048;
int samples_available = buffer.Count;
for (int i = 0; buffer.Count > 0; i++)
resampleBuffer[i] = buffer.Dequeue();
public VecnaSynchronizer()
{
buffer = new Queue<Sample>(2048);
resampleBuffer = new Sample[2730]; // 2048 * 1.25
// Give us a little buffer wiggle-room
for (int i=0; i<367; i++)
buffer.Enqueue(new Sample(0,0));
}
public void enqueue_samples(short[] buf, int samples_provided)
{
int ctr = 0;
for (int i = 0; i < samples_provided; i++)
{
short left = buf[ctr++];
short right = buf[ctr++];
enqueue_sample(left, right);
}
}
public void enqueue_sample(short left, short right)
{
if (buffer.Count >= MaxExcessSamples - 1)
{
// if buffer is overfull, dequeue old samples to make room for new samples.
buffer.Dequeue();
}
buffer.Enqueue(new Sample(left, right));
}
public void clear()
{
buffer.Clear();
}
public int output_samples(short[] buf, int samples_requested)
{
if (samples_requested > buffer.Count)
{
// underflow!
if (buffer.Count > samples_requested * 3 / 4)
{
// if we're within 75% of target, then I guess we suck it up and resample.
// we sample in a goofy way, we could probably do it a bit smarter, if we cared more.
int samples_available = buffer.Count;
for (int i = 0; buffer.Count > 0; i++)
resampleBuffer[i] = buffer.Dequeue();
int index = 0;
for (int i = 0; i<samples_requested; i++)
{
Sample sample = resampleBuffer[i*samples_available/samples_requested];
buf[index++] += sample.left;
buf[index++] += sample.right;
}
} else {
// we're outside of a "reasonable" underflow. Give up and output silence.
// Do nothing. The whole frame will be excess buffer.
}
}
else
{
// normal operation
//Console.WriteLine("samples in buffer {0}, requested {1}", buffer.Count, samples_requested);
int index = 0;
for (int i = 0; i < samples_requested && buffer.Count > 0; i++)
{
Sample sample = buffer.Dequeue();
buf[index++] += sample.left;
buf[index++] += sample.right;
}
}
return samples_requested;
}
}
int index = 0;
for (int i = 0; i < samples_requested; i++)
{
Sample sample = resampleBuffer[i * samples_available / samples_requested];
buf[index++] += sample.left;
buf[index++] += sample.right;
}
}
else
{
// we're outside of a "reasonable" underflow. Give up and output silence.
// Do nothing. The whole frame will be excess buffer.
}
}
else
{
// normal operation
//Console.WriteLine("samples in buffer {0}, requested {1}", buffer.Count, samples_requested);
int index = 0;
for (int i = 0; i < samples_requested && buffer.Count > 0; i++)
{
Sample sample = buffer.Dequeue();
buf[index++] += sample.left;
buf[index++] += sample.right;
}
}
return samples_requested;
}
}
}

View File

@ -1,7 +1,7 @@
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common
{
// This is a straightforward class to mix/chain multiple ISoundProvider sources.

View File

@ -6,7 +6,7 @@ using System.Runtime.InteropServices;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Sound.Utilities
namespace BizHawk.Emulation.Common
{
/// <summary>
/// junk wrapper around LibSpeexDSP. quite inefficient. will be replaced

View File

@ -1,53 +1,53 @@
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common
{
public static class Waves
{
public static short[] SquareWave;
public static short[] ImperfectSquareWave;
public static short[] NoiseWave;
public static short[] PeriodicWave16;
public static class Waves
{
public static short[] SquareWave;
public static short[] ImperfectSquareWave;
public static short[] NoiseWave;
public static short[] PeriodicWave16;
public static void InitWaves()
{
SquareWave = new short[]
{
-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767
};
public static void InitWaves()
{
SquareWave = new short[]
{
-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767
};
ImperfectSquareWave = new short[]
{
-32768,-30145,-27852,-26213,-24902,-23592,-22282,-20971,-19988,-19005,-18350,-17694,-17366,-17039,-16711,-16711,
32767, 30145, 27852, 26213, 24902, 23592, 22282, 20971, 19988, 19005, 18350, 17694, 17366, 17039, 16711, 16711
};
ImperfectSquareWave = new short[]
{
-32768,-30145,-27852,-26213,-24902,-23592,-22282,-20971,-19988,-19005,-18350,-17694,-17366,-17039,-16711,-16711,
32767, 30145, 27852, 26213, 24902, 23592, 22282, 20971, 19988, 19005, 18350, 17694, 17366, 17039, 16711, 16711
};
PeriodicWave16 = new short[] { 32767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
PeriodicWave16 = new short[] { 32767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
NoiseWave = new short[0x1000];
var rnd = new System.Random(unchecked((int)0xDEADBEEF));
for (int i = 0; i < NoiseWave.Length; i++)
{
int r = rnd.Next();
if ((r & 1) > 0)
NoiseWave[i] = short.MaxValue;
}
NoiseWave = new short[0x1000];
var rnd = new System.Random(unchecked((int)0xDEADBEEF));
for (int i = 0; i < NoiseWave.Length; i++)
{
int r = rnd.Next();
if ((r & 1) > 0)
NoiseWave[i] = short.MaxValue;
}
/*TriangleWave = new short[512];
for (int i = 0; i < 256; i++)
TriangleWave[i] = (short)((ushort.MaxValue*i/256)-short.MinValue);
for (int i = 0; i < 256; i++)
TriangleWave[256+i] = TriangleWave[256-i];
TriangleWave[256] = short.MaxValue;
/*TriangleWave = new short[512];
for (int i = 0; i < 256; i++)
TriangleWave[i] = (short)((ushort.MaxValue*i/256)-short.MinValue);
for (int i = 0; i < 256; i++)
TriangleWave[256+i] = TriangleWave[256-i];
TriangleWave[256] = short.MaxValue;
SawWave = new short[512];
for (int i = 0; i < 512; i++)
SawWave[i] = (short)((ushort.MaxValue * i / 512) - short.MinValue);
SawWave = new short[512];
for (int i = 0; i < 512; i++)
SawWave[i] = (short)((ushort.MaxValue * i / 512) - short.MinValue);
SineWave = new short[1024];
for (int i=0; i<1024; i++)
{
SineWave[i] = (short) (Math.Sin(i*Math.PI*2/1024d)*32767);
}*/
}
}
SineWave = new short[1024];
for (int i=0; i<1024; i++)
{
SineWave[i] = (short) (Math.Sin(i*Math.PI*2/1024d)*32767);
}*/
}
}
}

View File

@ -5,7 +5,7 @@ using System.Text;
using BizHawk.Common;
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common.Components
{
public class VRC6Alt
{

View File

@ -1,16 +1,15 @@
using System;
// Credits:
// Credits:
// Original emulator written by Mitsutaka Okazaki 2001.
// Original conversion to C# by Ben Ryves.
// TODO The savestate support here is very simplistic and incomplete. However, this does not result in desyncs as the YM2413 is write-only.
// TODO This should eventually be replaced, due to 1) uncertain licensing terms 2) This is not a native C# implementation, but a naive port.
using System;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common.Components
{
public sealed class YM2413 : ISoundProvider
{

View File

@ -5,7 +5,7 @@ using System.IO;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Sound
namespace BizHawk.Emulation.Common.Components
{
// ======================================================================
// Yamaha YM2612 Emulation Core