Clean up namespaces for BizHawk.Emulation sound files
This commit is contained in:
parent
906c0316a6
commit
25b242ade4
|
@ -998,7 +998,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
//avi/wav state
|
//avi/wav state
|
||||||
private IVideoWriter CurrAviWriter;
|
private IVideoWriter CurrAviWriter;
|
||||||
private ISoundProvider AviSoundInput;
|
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 long SoundRemainder; //audio timekeeping for video dumping
|
||||||
private int avwriter_resizew;
|
private int avwriter_resizew;
|
||||||
private int avwriter_resizeh;
|
private int avwriter_resizeh;
|
||||||
|
@ -1412,7 +1412,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
if (!Global.Emulator.StartAsyncSound())
|
if (!Global.Emulator.StartAsyncSound())
|
||||||
{
|
{
|
||||||
// if the core doesn't support async mode, use a standard vecna wrapper
|
// 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
|
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
|
// 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())
|
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
|
else
|
||||||
AviSoundInput = Global.Emulator.SoundProvider;
|
AviSoundInput = Global.Emulator.SoundProvider;
|
||||||
DumpProxy = new Emulation.Sound.MetaspuSoundProvider(Emulation.Sound.ESynchMethod.ESynchMethod_V);
|
DumpProxy = new MetaspuSoundProvider(ESynchMethod.ESynchMethod_V);
|
||||||
SoundRemainder = 0;
|
SoundRemainder = 0;
|
||||||
RewireSound();
|
RewireSound();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using BizHawk.Emulation.Sound;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
#if WINDOWS
|
#if WINDOWS
|
||||||
using SlimDX.DirectSound;
|
using SlimDX.DirectSound;
|
||||||
using SlimDX.Multimedia;
|
using SlimDX.Multimedia;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using BizHawk.Client.Common;
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
using BizHawk.Client.Common;
|
||||||
|
|
||||||
namespace BizHawk.Client.EmuHawk
|
namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
#pragma warning disable 649 //adelikat: Disable dumb warnings until this file is complete
|
#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
|
#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[] syncNextTable = new int[] { 1, 2, 0 };
|
||||||
static int[] syncPrevTable = new int[] { 2, 0, 1 };
|
static int[] syncPrevTable = new int[] { 2, 0, 1 };
|
||||||
|
|
||||||
int cachedCycles;
|
int cachedCycles;
|
||||||
bool disableVoice3;
|
bool disableVoice3;
|
||||||
int[] envelopeOutput;
|
int[] envelopeOutput;
|
||||||
Envelope[] envelopes;
|
Envelope[] envelopes;
|
||||||
|
@ -29,12 +31,12 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
||||||
bool filterSelectBandPass;
|
bool filterSelectBandPass;
|
||||||
bool filterSelectLoPass;
|
bool filterSelectLoPass;
|
||||||
bool filterSelectHiPass;
|
bool filterSelectHiPass;
|
||||||
int mixer;
|
int mixer;
|
||||||
int potCounter;
|
int potCounter;
|
||||||
int potX;
|
int potX;
|
||||||
int potY;
|
int potY;
|
||||||
short sample;
|
short sample;
|
||||||
int[] voiceOutput;
|
int[] voiceOutput;
|
||||||
Voice[] voices;
|
Voice[] voices;
|
||||||
int volume;
|
int volume;
|
||||||
int[][] waveformTable;
|
int[][] waveformTable;
|
||||||
|
@ -45,15 +47,15 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
||||||
public Sid(int[][] newWaveformTable, int newSampleRate, Region newRegion)
|
public Sid(int[][] newWaveformTable, int newSampleRate, Region newRegion)
|
||||||
{
|
{
|
||||||
uint cyclesPerSec = 0;
|
uint cyclesPerSec = 0;
|
||||||
uint cyclesNum;
|
uint cyclesNum;
|
||||||
uint cyclesDen;
|
uint cyclesDen;
|
||||||
uint sampleRate = 44100;
|
uint sampleRate = 44100;
|
||||||
|
|
||||||
switch (newRegion)
|
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;
|
case Region.PAL: cyclesNum = 17734472; cyclesDen = 18; break;
|
||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
|
|
||||||
waveformTable = newWaveformTable;
|
waveformTable = newWaveformTable;
|
||||||
|
@ -72,7 +74,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
filterEnable[i] = false;
|
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()
|
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
|
// potentiometer values refresh every 512 cycles
|
||||||
if (potCounter == 0)
|
if (potCounter == 0)
|
||||||
{
|
{
|
||||||
potCounter = 512;
|
potCounter = 512;
|
||||||
potX = ReadPotX();
|
potX = ReadPotX();
|
||||||
potY = ReadPotY();
|
potY = ReadPotY();
|
||||||
Flush(); //this is here unrelated to the pots, just to keep the buffer somewhat loaded
|
Flush(); //this is here unrelated to the pots, just to keep the buffer somewhat loaded
|
||||||
}
|
}
|
||||||
potCounter--;
|
potCounter--;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Flush()
|
public void Flush()
|
||||||
{
|
{
|
||||||
while (cachedCycles > 0)
|
while (cachedCycles > 0)
|
||||||
{
|
{
|
||||||
// process voices and envelopes
|
// process voices and envelopes
|
||||||
voices[0].ExecutePhase2();
|
voices[0].ExecutePhase2();
|
||||||
voices[1].ExecutePhase2();
|
voices[1].ExecutePhase2();
|
||||||
voices[2].ExecutePhase2();
|
voices[2].ExecutePhase2();
|
||||||
envelopes[0].ExecutePhase2();
|
envelopes[0].ExecutePhase2();
|
||||||
envelopes[1].ExecutePhase2();
|
envelopes[1].ExecutePhase2();
|
||||||
envelopes[2].ExecutePhase2();
|
envelopes[2].ExecutePhase2();
|
||||||
|
|
||||||
// process sync
|
// process sync
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
voices[i].Synchronize(voices[syncNextTable[i]], voices[syncPrevTable[i]]);
|
voices[i].Synchronize(voices[syncNextTable[i]], voices[syncPrevTable[i]]);
|
||||||
|
|
||||||
// get output
|
// get output
|
||||||
voiceOutput[0] = voices[0].Output(voices[2]);
|
voiceOutput[0] = voices[0].Output(voices[2]);
|
||||||
voiceOutput[1] = voices[1].Output(voices[0]);
|
voiceOutput[1] = voices[1].Output(voices[0]);
|
||||||
voiceOutput[2] = voices[2].Output(voices[1]);
|
voiceOutput[2] = voices[2].Output(voices[1]);
|
||||||
envelopeOutput[0] = envelopes[0].Level;
|
envelopeOutput[0] = envelopes[0].Level;
|
||||||
envelopeOutput[1] = envelopes[1].Level;
|
envelopeOutput[1] = envelopes[1].Level;
|
||||||
envelopeOutput[2] = envelopes[2].Level;
|
envelopeOutput[2] = envelopes[2].Level;
|
||||||
|
|
||||||
mixer = ((voiceOutput[0] * envelopeOutput[0]) >> 7);
|
mixer = ((voiceOutput[0] * envelopeOutput[0]) >> 7);
|
||||||
mixer += ((voiceOutput[1] * envelopeOutput[1]) >> 7);
|
mixer += ((voiceOutput[1] * envelopeOutput[1]) >> 7);
|
||||||
mixer += ((voiceOutput[2] * envelopeOutput[2]) >> 7);
|
mixer += ((voiceOutput[2] * envelopeOutput[2]) >> 7);
|
||||||
mixer = (mixer * volume) >> 4;
|
mixer = (mixer * volume) >> 4;
|
||||||
|
|
||||||
sample = (short)mixer;
|
sample = (short)mixer;
|
||||||
resampler.EnqueueSample(sample, sample);
|
resampler.EnqueueSample(sample, sample);
|
||||||
cachedCycles--;
|
cachedCycles--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
|
|
||||||
|
@ -172,7 +174,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
||||||
case 0x1A:
|
case 0x1A:
|
||||||
case 0x1B:
|
case 0x1B:
|
||||||
case 0x1C:
|
case 0x1C:
|
||||||
Flush();
|
Flush();
|
||||||
result = ReadRegister(addr);
|
result = ReadRegister(addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -204,7 +206,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
||||||
(envelopes[0].Decay)
|
(envelopes[0].Decay)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
result = (byte)(
|
result = (byte)(
|
||||||
(envelopes[0].Sustain << 4) |
|
(envelopes[0].Sustain << 4) |
|
||||||
(envelopes[0].Release)
|
(envelopes[0].Release)
|
||||||
|
@ -280,7 +282,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 0x19: result = (byte)potX; 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 0x1B: result = (byte)(voiceOutput[2] >> 4); break;
|
||||||
case 0x1C: result = (byte)(envelopeOutput[2]); break;
|
case 0x1C: result = (byte)(envelopeOutput[2]); break;
|
||||||
}
|
}
|
||||||
|
@ -303,7 +305,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
||||||
// can't write to these
|
// can't write to these
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Flush();
|
Flush();
|
||||||
WriteRegister(addr, val);
|
WriteRegister(addr, val);
|
||||||
break;
|
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);
|
SaveState.SyncObject(ser, this);
|
||||||
ser.BeginSection("env0");
|
ser.BeginSection("env0");
|
||||||
envelopes[0].SyncState(ser);
|
envelopes[0].SyncState(ser);
|
||||||
ser.EndSection();
|
ser.EndSection();
|
||||||
ser.BeginSection("wav0");
|
ser.BeginSection("wav0");
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Emulation.Common.Components.M6502;
|
using BizHawk.Emulation.Common.Components.M6502;
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
||||||
public MOS6502X cpu;
|
public MOS6502X cpu;
|
||||||
public M6532 m6532;
|
public M6532 m6532;
|
||||||
public TIA tia;
|
public TIA tia;
|
||||||
public Emulation.Sound.Utilities.DCFilter dcfilter;
|
public DCFilter dcfilter;
|
||||||
public byte[] ram = new byte[128];
|
public byte[] ram = new byte[128];
|
||||||
public MapperBase mapper;
|
public MapperBase mapper;
|
||||||
|
|
||||||
|
@ -183,7 +184,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
||||||
//tia = new TIA(this, frameBuffer);
|
//tia = new TIA(this, frameBuffer);
|
||||||
tia = new TIA(this);
|
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 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
|
// Setup 6532
|
||||||
m6532 = new M6532(this);
|
m6532 = new M6532(this);
|
||||||
|
|
||||||
|
|
|
@ -344,16 +344,16 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800
|
||||||
// really shouldn't happen (after init), but if it does, we're ready
|
// really shouldn't happen (after init), but if it does, we're ready
|
||||||
if (resampler != null)
|
if (resampler != null)
|
||||||
resampler.Dispose();
|
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;
|
samplerate = newsamplerate;
|
||||||
dcfilter = Emulation.Sound.Utilities.DCFilter.DetatchedMode(256);
|
dcfilter = DCFilter.DetatchedMode(256);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint samplerate;
|
uint samplerate;
|
||||||
int[] vidbuffer;
|
int[] vidbuffer;
|
||||||
Emulation.Sound.Utilities.SpeexResampler resampler;
|
SpeexResampler resampler;
|
||||||
Emulation.Sound.Utilities.DCFilter dcfilter;
|
DCFilter dcfilter;
|
||||||
|
|
||||||
public void FillFrameBuffer()
|
public void FillFrameBuffer()
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,8 +4,8 @@ using System.IO;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
using BizHawk.Emulation.Common.Components;
|
||||||
using BizHawk.Emulation.Common.Components.Z80;
|
using BizHawk.Emulation.Common.Components.Z80;
|
||||||
using BizHawk.Emulation.Sound;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.ColecoVision
|
namespace BizHawk.Emulation.Cores.ColecoVision
|
||||||
{
|
{
|
||||||
|
|
|
@ -826,10 +826,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
|
||||||
int latchaudio = 0;
|
int latchaudio = 0;
|
||||||
|
|
||||||
//Sound.Utilities.SpeexResampler resampler;
|
//SpeexResampler resampler;
|
||||||
//Sound.Utilities.DCFilter dcfilter;
|
//DCFilter dcfilter;
|
||||||
|
|
||||||
Sound.Utilities.BlipBuffer blip;
|
BlipBuffer blip;
|
||||||
|
|
||||||
void ProcessSound()
|
void ProcessSound()
|
||||||
{
|
{
|
||||||
|
@ -862,7 +862,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
//dcfilter = Sound.Utilities.DCFilter.AsISyncSoundProvider(resampler, 65536);
|
//dcfilter = Sound.Utilities.DCFilter.AsISyncSoundProvider(resampler, 65536);
|
||||||
// lowpass filtering on an actual GB was probably pretty aggressive?
|
// lowpass filtering on an actual GB was probably pretty aggressive?
|
||||||
//dcfilter = Sound.Utilities.DCFilter.AsISyncSoundProvider(resampler, 2048);
|
//dcfilter = Sound.Utilities.DCFilter.AsISyncSoundProvider(resampler, 2048);
|
||||||
blip = new Sound.Utilities.BlipBuffer(1024);
|
blip = new BlipBuffer(1024);
|
||||||
blip.SetRates(2097152, 44100);
|
blip.SetRates(2097152, 44100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
LagCount = 0;
|
LagCount = 0;
|
||||||
IsLagFrame = false;
|
IsLagFrame = false;
|
||||||
|
|
||||||
blip_left = new Sound.Utilities.BlipBuffer(1024);
|
blip_left = new BlipBuffer(1024);
|
||||||
blip_right = new Sound.Utilities.BlipBuffer(1024);
|
blip_right = new BlipBuffer(1024);
|
||||||
blip_left.SetRates(2097152 * 2, 44100);
|
blip_left.SetRates(2097152 * 2, 44100);
|
||||||
blip_right.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
|
// 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;
|
BlipBuffer blip_left;
|
||||||
Sound.Utilities.BlipBuffer blip_right;
|
BlipBuffer blip_right;
|
||||||
|
|
||||||
|
|
||||||
short[] LeftBuffer = new short[(35112 + 2064) * 2];
|
short[] LeftBuffer = new short[(35112 + 2064) * 2];
|
||||||
short[] RightBuffer = new short[(35112 + 2064) * 2];
|
short[] RightBuffer = new short[(35112 + 2064) * 2];
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
|
||||||
public int BackgroundColor { get { return 0; } }
|
public int BackgroundColor { get { return 0; } }
|
||||||
|
|
||||||
|
|
||||||
public Sound.Utilities.SpeexResampler resampler;
|
public SpeexResampler resampler;
|
||||||
|
|
||||||
public ISoundProvider SoundProvider { get { return null; } }
|
public ISoundProvider SoundProvider { get { return null; } }
|
||||||
public ISyncSoundProvider SyncSoundProvider { get { return resampler; } }
|
public ISyncSoundProvider SyncSoundProvider { get { return resampler; } }
|
||||||
|
|
|
@ -5,6 +5,8 @@ using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.N64
|
namespace BizHawk.Emulation.Cores.Nintendo.N64
|
||||||
{
|
{
|
||||||
public class mupen64plusApi : IDisposable
|
public class mupen64plusApi : IDisposable
|
||||||
|
@ -515,7 +517,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
|
||||||
|
|
||||||
// Set up the resampler
|
// Set up the resampler
|
||||||
m64pSamplingRate = (uint)AudGetAudioRate();
|
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;
|
AttachedCore = this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Emulation.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_Mixer_Emulation
|
||||||
//http://wiki.nesdev.com/w/index.php/APU
|
//http://wiki.nesdev.com/w/index.php/APU
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
using BizHawk.Emulation.Common.Components;
|
||||||
|
|
||||||
//simplifications/approximations:
|
//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."
|
//* "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;
|
int wram_bank;
|
||||||
byte[] EXRAM = new byte[1024];
|
byte[] EXRAM = new byte[1024];
|
||||||
byte multiplicand, multiplier;
|
byte multiplicand, multiplier;
|
||||||
Sound.MMC5Audio audio;
|
MMC5Audio audio;
|
||||||
//regeneratable state
|
//regeneratable state
|
||||||
IntBuffer a_banks_1k = new IntBuffer(8);
|
IntBuffer a_banks_1k = new IntBuffer(8);
|
||||||
IntBuffer b_banks_1k = new IntBuffer(8);
|
IntBuffer b_banks_1k = new IntBuffer(8);
|
||||||
|
@ -119,7 +120,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
PoweronState();
|
PoweronState();
|
||||||
|
|
||||||
if (NES.apu != null)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
using BizHawk.Emulation.Common.Components;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
{
|
{
|
||||||
|
@ -7,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
|
|
||||||
public sealed class Sunsoft_5 : Sunsoft_FME7
|
public sealed class Sunsoft_5 : Sunsoft_FME7
|
||||||
{
|
{
|
||||||
Sound.Sunsoft5BAudio audio;
|
Sunsoft5BAudio audio;
|
||||||
|
|
||||||
public override bool Configure(NES.EDetectionOrigin origin)
|
public override bool Configure(NES.EDetectionOrigin origin)
|
||||||
{
|
{
|
||||||
|
@ -23,7 +24,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
|
|
||||||
BaseConfigure();
|
BaseConfigure();
|
||||||
if (NES.apu != null)
|
if (NES.apu != null)
|
||||||
audio = new Sound.Sunsoft5BAudio(NES.apu.ExternalQueue);
|
audio = new Sunsoft5BAudio(NES.apu.ExternalQueue);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
{
|
{
|
||||||
|
@ -116,15 +118,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
ser.Sync("ch", ref ch);
|
ser.Sync("ch", ref ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sound.Utilities.SpeexResampler resampler;
|
SpeexResampler resampler;
|
||||||
Sound.Utilities.DCFilter dc;
|
DCFilter dc;
|
||||||
Sound.MetaspuAsync metaspu;
|
MetaspuAsync metaspu;
|
||||||
|
|
||||||
public Namco163Audio()
|
public Namco163Audio()
|
||||||
{
|
{
|
||||||
resampler = new Sound.Utilities.SpeexResampler(2, 119318, 44100, 119318, 44100, null, null);
|
resampler = new SpeexResampler(2, 119318, 44100, 119318, 44100, null, null);
|
||||||
dc = Sound.Utilities.DCFilter.DetatchedMode(4096);
|
dc = DCFilter.DetatchedMode(4096);
|
||||||
metaspu = new Sound.MetaspuAsync(resampler, Sound.ESynchMethod.ESynchMethod_V);
|
metaspu = new MetaspuAsync(resampler, ESynchMethod.ESynchMethod_V);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyCustomAudio(short[] samples)
|
public void ApplyCustomAudio(short[] samples)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
using BizHawk.Emulation.Common.Components;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
{
|
{
|
||||||
|
@ -12,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
bool newer_variant;
|
bool newer_variant;
|
||||||
|
|
||||||
//Sound.VRC6 VRC6Sound = new Sound.VRC6();
|
//Sound.VRC6 VRC6Sound = new Sound.VRC6();
|
||||||
Sound.VRC6Alt VRC6Sound;
|
VRC6Alt VRC6Sound;
|
||||||
|
|
||||||
//state
|
//state
|
||||||
int prg_bank_16k, prg_bank_8k;
|
int prg_bank_16k, prg_bank_8k;
|
||||||
|
@ -96,7 +98,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
SetMirrorType(EMirrorType.Vertical);
|
SetMirrorType(EMirrorType.Vertical);
|
||||||
|
|
||||||
if (NES.apu != null) // don't start up sound when in configurator
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
using BizHawk.Emulation.Common.Components;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
{
|
{
|
||||||
|
@ -14,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
Func<int, int> remap;
|
Func<int, int> remap;
|
||||||
|
|
||||||
//state
|
//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 prg_banks_8k = new ByteBuffer(4);
|
||||||
ByteBuffer chr_banks_1k = new ByteBuffer(8);
|
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?
|
// presumably the only reason a homebrew would use mapper085 is for the sound?
|
||||||
// so initialize like lagrange point
|
// so initialize like lagrange point
|
||||||
remap = (addr) => ((addr & 0xF000) | ((addr & 0x30) >> 4));
|
remap = (addr) => ((addr & 0xF000) | ((addr & 0x30) >> 4));
|
||||||
fm = new Sound.YM2413(Sound.YM2413.ChipType.VRC7);
|
fm = new YM2413(YM2413.ChipType.VRC7);
|
||||||
break;
|
break;
|
||||||
case "KONAMI-VRC-7":
|
case "KONAMI-VRC-7":
|
||||||
AssertPrg(128, 512); AssertChr(0, 128); AssertVram(0, 8); AssertWram(0, 8);
|
AssertPrg(128, 512); AssertChr(0, 128); AssertVram(0, 8); AssertWram(0, 8);
|
||||||
|
@ -109,7 +110,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
{
|
{
|
||||||
//lagrange point
|
//lagrange point
|
||||||
remap = (addr) => ((addr & 0xF000) | ((addr & 0x30) >> 4));
|
remap = (addr) => ((addr & 0xF000) | ((addr & 0x30) >> 4));
|
||||||
fm = new Sound.YM2413(Sound.YM2413.ChipType.VRC7);
|
fm = new YM2413(YM2413.ChipType.VRC7);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new Exception("Unknown PCB type for VRC7");
|
throw new Exception("Unknown PCB type for VRC7");
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
|
|
||||||
class MagicSoundProvider : ISoundProvider, ISyncSoundProvider, IDisposable
|
class MagicSoundProvider : ISoundProvider, ISyncSoundProvider, IDisposable
|
||||||
{
|
{
|
||||||
Sound.Utilities.BlipBuffer blip;
|
BlipBuffer blip;
|
||||||
NES nes;
|
NES nes;
|
||||||
|
|
||||||
const int blipbuffsize = 4096;
|
const int blipbuffsize = 4096;
|
||||||
|
@ -75,7 +75,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
{
|
{
|
||||||
this.nes = nes;
|
this.nes = nes;
|
||||||
|
|
||||||
blip = new Sound.Utilities.BlipBuffer(blipbuffsize);
|
blip = new BlipBuffer(blipbuffsize);
|
||||||
blip.SetRates(infreq, 44100);
|
blip.SetRates(infreq, 44100);
|
||||||
|
|
||||||
//var actualMetaspu = new Sound.MetaspuSoundProvider(Sound.ESynchMethod.ESynchMethod_V);
|
//var actualMetaspu = new Sound.MetaspuSoundProvider(Sound.ESynchMethod.ESynchMethod_V);
|
||||||
|
|
|
@ -975,11 +975,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
|
|
||||||
#region audio stuff
|
#region audio stuff
|
||||||
|
|
||||||
Sound.Utilities.SpeexResampler resampler;
|
SpeexResampler resampler;
|
||||||
|
|
||||||
void InitAudio()
|
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)
|
void snes_audio_sample(ushort left, ushort right)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using BizHawk.Emulation.Sound;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ using System.IO;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
using BizHawk.Emulation.Common.Components;
|
||||||
using BizHawk.Emulation.Common.Components.H6280;
|
using BizHawk.Emulation.Common.Components.H6280;
|
||||||
using BizHawk.Emulation.DiscSystem;
|
using BizHawk.Emulation.DiscSystem;
|
||||||
using BizHawk.Emulation.Sound;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.PCEngine
|
namespace BizHawk.Emulation.Cores.PCEngine
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,8 +3,8 @@ using System.IO;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Emulation.DiscSystem;
|
using BizHawk.Emulation.DiscSystem;
|
||||||
using BizHawk.Emulation.Sound;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.PCEngine
|
namespace BizHawk.Emulation.Cores.PCEngine
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,12 +7,11 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
using BizHawk.Emulation.Common.Components;
|
||||||
using BizHawk.Emulation.Common.Components.M68000;
|
using BizHawk.Emulation.Common.Components.M68000;
|
||||||
using BizHawk.Emulation.Common.Components.Z80;
|
using BizHawk.Emulation.Common.Components.Z80;
|
||||||
using BizHawk.Emulation.Sound;
|
|
||||||
using Native68000;
|
using Native68000;
|
||||||
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Sega.Genesis
|
namespace BizHawk.Emulation.Cores.Sega.Genesis
|
||||||
{
|
{
|
||||||
public sealed partial class Genesis : IEmulator
|
public sealed partial class Genesis : IEmulator
|
||||||
|
|
|
@ -5,8 +5,8 @@ using System.IO;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
using BizHawk.Emulation.Common.Components;
|
||||||
using BizHawk.Emulation.Common.Components.Z80;
|
using BizHawk.Emulation.Common.Components.Z80;
|
||||||
using BizHawk.Emulation.Sound;
|
|
||||||
|
|
||||||
/*****************************************************
|
/*****************************************************
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ using BizHawk.Emulation.DiscSystem;
|
||||||
// I decided not to let the perfect be the enemy of the good.
|
// I decided not to let the perfect be the enemy of the good.
|
||||||
// It can always be refactored. It's at least deterministic.
|
// It can always be refactored. It's at least deterministic.
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound
|
namespace BizHawk.Emulation.Common
|
||||||
{
|
{
|
||||||
public sealed class CDAudio : ISoundProvider
|
public sealed class CDAudio : ISoundProvider
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.IO;
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Emulation.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.
|
// 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.
|
// 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.
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Text;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound
|
namespace BizHawk.Emulation.Common.Components
|
||||||
{
|
{
|
||||||
public class MMC5Audio
|
public class MMC5Audio
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,11 +5,13 @@ using System.IO;
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
// Emulates a Texas Instruments SN76489
|
|
||||||
// TODO the freq->note translation should be moved to a separate utility class.
|
// 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 SN76489 : ISoundProvider
|
||||||
{
|
{
|
||||||
public sealed class Channel
|
public sealed class Channel
|
||||||
|
|
|
@ -5,11 +5,13 @@ using System.Text;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound
|
namespace BizHawk.Emulation.Common.Components
|
||||||
{
|
{
|
||||||
// YM2149F variant
|
/// <summary>
|
||||||
// this implementation is quite incomplete
|
/// YM2149F variant
|
||||||
// http://wiki.nesdev.com/w/index.php/Sunsoft_5B_audio
|
/// this implementation is quite incomplete
|
||||||
|
/// http://wiki.nesdev.com/w/index.php/Sunsoft_5B_audio
|
||||||
|
/// </summary>
|
||||||
public class Sunsoft5BAudio
|
public class Sunsoft5BAudio
|
||||||
{
|
{
|
||||||
class Pulse
|
class Pulse
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound.Utilities
|
namespace BizHawk.Emulation.Common
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// wrapper around blargg's unmanaged blip_buf
|
/// wrapper around blargg's unmanaged blip_buf
|
||||||
|
@ -16,18 +16,18 @@ namespace BizHawk.Emulation.Sound.Utilities
|
||||||
|
|
||||||
static class BlipBufDll
|
static class BlipBufDll
|
||||||
{
|
{
|
||||||
/** Creates new buffer that can hold at most sample_count samples. Sets rates
|
/** 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
|
so that there are blip_max_ratio clocks per sample. Returns pointer to new
|
||||||
buffer, or NULL if insufficient memory. */
|
buffer, or NULL if insufficient memory. */
|
||||||
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern IntPtr blip_new(int sample_count);
|
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. */
|
clock_rate input clocks, approximately sample_rate samples are generated. */
|
||||||
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern void blip_set_rates(IntPtr context, double clock_rate, double sample_rate);
|
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. */
|
clock_rate must not be greater than sample_rate*blip_max_ratio. */
|
||||||
public const int blip_max_ratio = 1 << 20;
|
public const int blip_max_ratio = 1 << 20;
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ namespace BizHawk.Emulation.Sound.Utilities
|
||||||
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern void blip_add_delta_fast(IntPtr context, uint clock_time, int delta);
|
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. */
|
samples available. */
|
||||||
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern int blip_clocks_needed(IntPtr context, int sample_count);
|
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. */
|
/** Maximum number of samples that can be generated from one time frame. */
|
||||||
public const int blip_max_frame = 4000;
|
public const int blip_max_frame = 4000;
|
||||||
|
|
||||||
/** Makes input clocks before clock_duration available for reading as output
|
/** 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
|
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
|
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
|
frame specified. Deltas can have been added slightly past clock_duration (up to
|
||||||
however many clocks there are in two output samples). */
|
however many clocks there are in two output samples). */
|
||||||
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern void blip_end_frame(IntPtr context, uint clock_duration);
|
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)]
|
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern int blip_samples_avail(IntPtr context);
|
public static extern int blip_samples_avail(IntPtr context);
|
||||||
|
|
||||||
/** Reads and removes at most 'count' samples and writes them to 'out'. If
|
/** 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
|
'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
|
interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
|
||||||
samples. Returns number of samples actually read. */
|
samples. Returns number of samples actually read. */
|
||||||
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern int blip_read_samples(IntPtr context, short[] @out, int count, int stereo);
|
public static extern int blip_read_samples(IntPtr context, short[] @out, int count, int stereo);
|
||||||
|
|
|
@ -2,18 +2,18 @@
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
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
|
// 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.
|
// 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.
|
// 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,
|
// 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
|
// 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
|
// distributing error to most frames tends to result in persistently distorted audio, especially when
|
||||||
// sample playback is involved.
|
// sample playback is involved.
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -30,15 +30,15 @@ namespace BizHawk.Emulation.Sound
|
||||||
* that and then bypass the BufferedAsync.
|
* that and then bypass the BufferedAsync.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public sealed class BufferedAsync : ISoundProvider
|
public sealed class BufferedAsync : ISoundProvider
|
||||||
{
|
{
|
||||||
public ISoundProvider BaseSoundProvider;
|
public ISoundProvider BaseSoundProvider;
|
||||||
|
|
||||||
Queue<short> buffer = new Queue<short>(4096);
|
Queue<short> buffer = new Queue<short>(4096);
|
||||||
|
|
||||||
int SamplesInOneFrame = 1470;
|
int SamplesInOneFrame = 1470;
|
||||||
int TargetExtraSamples = 882;
|
int TargetExtraSamples = 882;
|
||||||
const int MaxExcessSamples = 4096;
|
const int MaxExcessSamples = 4096;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// recalculates some internal parameters based on the IEmulator's framerate
|
/// recalculates some internal parameters based on the IEmulator's framerate
|
||||||
|
@ -52,31 +52,31 @@ namespace BizHawk.Emulation.Sound
|
||||||
|
|
||||||
public void DiscardSamples()
|
public void DiscardSamples()
|
||||||
{
|
{
|
||||||
if(BaseSoundProvider != null)
|
if (BaseSoundProvider != null)
|
||||||
BaseSoundProvider.DiscardSamples();
|
BaseSoundProvider.DiscardSamples();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int MaxVolume { get; set; }
|
public int MaxVolume { get; set; }
|
||||||
|
|
||||||
public void GetSamples(short[] samples)
|
public void GetSamples(short[] samples)
|
||||||
{
|
{
|
||||||
int samplesToGenerate = SamplesInOneFrame;
|
int samplesToGenerate = SamplesInOneFrame;
|
||||||
if (buffer.Count > samples.Length + MaxExcessSamples)
|
if (buffer.Count > samples.Length + MaxExcessSamples)
|
||||||
samplesToGenerate = 0;
|
samplesToGenerate = 0;
|
||||||
if (buffer.Count - samples.Length < TargetExtraSamples)
|
if (buffer.Count - samples.Length < TargetExtraSamples)
|
||||||
samplesToGenerate += SamplesInOneFrame;
|
samplesToGenerate += SamplesInOneFrame;
|
||||||
if (samplesToGenerate + buffer.Count < samples.Length)
|
if (samplesToGenerate + buffer.Count < samples.Length)
|
||||||
samplesToGenerate = samples.Length - buffer.Count;
|
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++)
|
for (int i = 0; i < mySamples.Length; i++)
|
||||||
buffer.Enqueue(mySamples[i]);
|
buffer.Enqueue(mySamples[i]);
|
||||||
|
|
||||||
for (int i = 0; i < samples.Length; i++)
|
for (int i = 0; i < samples.Length; i++)
|
||||||
samples[i] = buffer.Dequeue();
|
samples[i] = buffer.Dequeue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@ using System.Text;
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound.Utilities
|
namespace BizHawk.Emulation.Common
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// implements a DC block filter on top of an ISoundProvider. rather simple.
|
/// implements a DC block filter on top of an ISoundProvider. rather simple.
|
||||||
|
@ -39,7 +39,7 @@ namespace BizHawk.Emulation.Sound.Utilities
|
||||||
}
|
}
|
||||||
|
|
||||||
int depth;
|
int depth;
|
||||||
|
|
||||||
public static DCFilter AsISoundProvider(ISoundProvider input, int filterwidth)
|
public static DCFilter AsISoundProvider(ISoundProvider input, int filterwidth)
|
||||||
{
|
{
|
||||||
if (input == null)
|
if (input == null)
|
||||||
|
@ -59,7 +59,7 @@ namespace BizHawk.Emulation.Sound.Utilities
|
||||||
return new DCFilter(null, null, filterwidth);
|
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)
|
if (filterwidth < 8 || filterwidth > 65536)
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
|
@ -67,7 +67,7 @@ namespace BizHawk.Emulation.Sound.Utilities
|
||||||
this.syncinput = syncinput;
|
this.syncinput = syncinput;
|
||||||
depth = DepthFromFilterwidth(filterwidth);
|
depth = DepthFromFilterwidth(filterwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// pass a set of samples through the filter. should only be used in detached mode
|
/// pass a set of samples through the filter. should only be used in detached mode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -5,94 +5,94 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound
|
namespace BizHawk.Emulation.Common
|
||||||
{
|
{
|
||||||
public sealed class Equalizer
|
public sealed class Equalizer
|
||||||
{
|
{
|
||||||
double lowFilter;
|
double lowFilter;
|
||||||
double lowFilterPole0;
|
double lowFilterPole0;
|
||||||
double lowFilterPole1;
|
double lowFilterPole1;
|
||||||
double lowFilterPole2;
|
double lowFilterPole2;
|
||||||
double lowFilterPole3;
|
double lowFilterPole3;
|
||||||
|
|
||||||
double highFilter;
|
double highFilter;
|
||||||
double highFilterPole0;
|
double highFilterPole0;
|
||||||
double highFilterPole1;
|
double highFilterPole1;
|
||||||
double highFilterPole2;
|
double highFilterPole2;
|
||||||
double highFilterPole3;
|
double highFilterPole3;
|
||||||
|
|
||||||
double sampleDataMinus1;
|
double sampleDataMinus1;
|
||||||
double sampleDataMinus2;
|
double sampleDataMinus2;
|
||||||
double sampleDataMinus3;
|
double sampleDataMinus3;
|
||||||
|
|
||||||
double lowGain;
|
double lowGain;
|
||||||
double midGain;
|
double midGain;
|
||||||
double highGain;
|
double highGain;
|
||||||
|
|
||||||
const double sampleRate = 44100.0;
|
|
||||||
const double verySmallAmount = (1.0 / 4294967295.0);
|
|
||||||
|
|
||||||
double lowfreq;
|
const double sampleRate = 44100.0;
|
||||||
public double LowFreqCutoff
|
const double verySmallAmount = (1.0 / 4294967295.0);
|
||||||
{
|
|
||||||
get { return lowfreq; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
lowfreq = value;
|
|
||||||
lowFilter = 2 * Math.Sin(Math.PI * (lowfreq / sampleRate));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double highfreq;
|
double lowfreq;
|
||||||
public double HighFreqCutoff
|
public double LowFreqCutoff
|
||||||
{
|
{
|
||||||
get { return highfreq; }
|
get { return lowfreq; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
highfreq = value;
|
lowfreq = value;
|
||||||
highFilter = 2 * Math.Sin(Math.PI * (highfreq / sampleRate));
|
lowFilter = 2 * Math.Sin(Math.PI * (lowfreq / sampleRate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Equalizer(double lowFreq=880, double highFreq=5000)
|
double highfreq;
|
||||||
{
|
public double HighFreqCutoff
|
||||||
lowGain = 1.3;
|
{
|
||||||
midGain = 0.9;
|
get { return highfreq; }
|
||||||
highGain = 1.3;
|
set
|
||||||
LowFreqCutoff = lowFreq;
|
{
|
||||||
HighFreqCutoff = highFreq;
|
highfreq = value;
|
||||||
}
|
highFilter = 2 * Math.Sin(Math.PI * (highfreq / sampleRate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public short EqualizeSample(short sample)
|
public Equalizer(double lowFreq = 880, double highFreq = 5000)
|
||||||
{
|
{
|
||||||
lowFilterPole0 += (lowFilter * (sample - lowFilterPole0)) + verySmallAmount;
|
lowGain = 1.3;
|
||||||
lowFilterPole1 += lowFilter * (lowFilterPole0 - lowFilterPole1);
|
midGain = 0.9;
|
||||||
lowFilterPole2 += lowFilter * (lowFilterPole1 - lowFilterPole2);
|
highGain = 1.3;
|
||||||
lowFilterPole3 += lowFilter * (lowFilterPole2 - lowFilterPole3);
|
LowFreqCutoff = lowFreq;
|
||||||
double l = lowFilterPole3;
|
HighFreqCutoff = highFreq;
|
||||||
|
}
|
||||||
|
|
||||||
highFilterPole0 += (highFilter * (sample - highFilterPole0)) + verySmallAmount;
|
public short EqualizeSample(short sample)
|
||||||
highFilterPole1 += highFilter * (highFilterPole0 - highFilterPole1);
|
{
|
||||||
highFilterPole2 += highFilter * (highFilterPole1 - highFilterPole2);
|
lowFilterPole0 += (lowFilter * (sample - lowFilterPole0)) + verySmallAmount;
|
||||||
highFilterPole3 += highFilter * (highFilterPole2 - highFilterPole3);
|
lowFilterPole1 += lowFilter * (lowFilterPole0 - lowFilterPole1);
|
||||||
double h = sampleDataMinus3 - highFilterPole3;
|
lowFilterPole2 += lowFilter * (lowFilterPole1 - lowFilterPole2);
|
||||||
|
lowFilterPole3 += lowFilter * (lowFilterPole2 - lowFilterPole3);
|
||||||
|
double l = lowFilterPole3;
|
||||||
|
|
||||||
double m = sample - (h + l);
|
highFilterPole0 += (highFilter * (sample - highFilterPole0)) + verySmallAmount;
|
||||||
l *= lowGain;
|
highFilterPole1 += highFilter * (highFilterPole0 - highFilterPole1);
|
||||||
m *= midGain;
|
highFilterPole2 += highFilter * (highFilterPole1 - highFilterPole2);
|
||||||
h *= highGain;
|
highFilterPole3 += highFilter * (highFilterPole2 - highFilterPole3);
|
||||||
|
double h = sampleDataMinus3 - highFilterPole3;
|
||||||
|
|
||||||
sampleDataMinus3 = sampleDataMinus2;
|
double m = sample - (h + l);
|
||||||
sampleDataMinus2 = sampleDataMinus1;
|
l *= lowGain;
|
||||||
sampleDataMinus1 = sample;
|
m *= midGain;
|
||||||
|
h *= highGain;
|
||||||
|
|
||||||
return (short) (l + m + h);
|
sampleDataMinus3 = sampleDataMinus2;
|
||||||
}
|
sampleDataMinus2 = sampleDataMinus1;
|
||||||
|
sampleDataMinus1 = sample;
|
||||||
|
|
||||||
public void Equalize(short[] samples)
|
return (short)(l + m + h);
|
||||||
{
|
}
|
||||||
for (int i = 0; i < samples.Length; i++)
|
|
||||||
samples[i] = EqualizeSample(samples[i]);
|
public void Equalize(short[] samples)
|
||||||
}
|
{
|
||||||
}
|
for (int i = 0; i < samples.Length; i++)
|
||||||
|
samples[i] = EqualizeSample(samples[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound
|
namespace BizHawk.Emulation.Common
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// uses Metaspu to have an ISyncSoundProvider input to a ISoundProvider
|
/// uses Metaspu to have an ISyncSoundProvider input to a ISoundProvider
|
||||||
|
@ -36,8 +36,6 @@ namespace BizHawk.Emulation.Sound
|
||||||
public int MaxVolume { get; set; }
|
public int MaxVolume { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class MetaspuSoundProvider : ISoundProvider
|
public class MetaspuSoundProvider : ISoundProvider
|
||||||
{
|
{
|
||||||
public ISynchronizingAudioBuffer buffer;
|
public ISynchronizingAudioBuffer buffer;
|
||||||
|
@ -46,17 +44,18 @@ namespace BizHawk.Emulation.Sound
|
||||||
buffer = Metaspu.metaspu_construct(method);
|
buffer = Metaspu.metaspu_construct(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetaspuSoundProvider() : this(ESynchMethod.ESynchMethod_V)
|
public MetaspuSoundProvider()
|
||||||
|
: this(ESynchMethod.ESynchMethod_V)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
short[] pullBuffer = new short[1470];
|
short[] pullBuffer = new short[1470];
|
||||||
public void PullSamples(ISoundProvider source)
|
public void PullSamples(ISoundProvider source)
|
||||||
{
|
{
|
||||||
Array.Clear(pullBuffer, 0, 1470);
|
Array.Clear(pullBuffer, 0, 1470);
|
||||||
source.GetSamples(pullBuffer);
|
source.GetSamples(pullBuffer);
|
||||||
buffer.enqueue_samples(pullBuffer, 735);
|
buffer.enqueue_samples(pullBuffer, 735);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetSamples(short[] samples)
|
public void GetSamples(short[] samples)
|
||||||
{
|
{
|
||||||
|
@ -68,15 +67,15 @@ namespace BizHawk.Emulation.Sound
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int MaxVolume { get; set; }
|
public int MaxVolume { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ISynchronizingAudioBuffer
|
public interface ISynchronizingAudioBuffer
|
||||||
{
|
{
|
||||||
void enqueue_samples(short[] buf, int samples_provided);
|
void enqueue_samples(short[] buf, int samples_provided);
|
||||||
void enqueue_sample(short left, short right);
|
void enqueue_sample(short left, short right);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
//returns the number of samples actually supplied, which may not match the number requested
|
//returns the number of samples actually supplied, which may not match the number requested
|
||||||
// ^^ what the hell is that supposed to mean.
|
// ^^ what the hell is that supposed to mean.
|
||||||
// the entire point of an ISynchronzingAudioBuffer
|
// the entire point of an ISynchronzingAudioBuffer
|
||||||
|
@ -90,9 +89,9 @@ namespace BizHawk.Emulation.Sound
|
||||||
ESynchMethod_N, //nitsuja's
|
ESynchMethod_N, //nitsuja's
|
||||||
ESynchMethod_Z, //zero's
|
ESynchMethod_Z, //zero's
|
||||||
//ESynchMethod_P, //PCSX2 spu2-x //ohno! not available yet in c#
|
//ESynchMethod_P, //PCSX2 spu2-x //ohno! not available yet in c#
|
||||||
ESynchMethod_V // vecna
|
ESynchMethod_V // vecna
|
||||||
};
|
};
|
||||||
|
|
||||||
public static class Metaspu
|
public static class Metaspu
|
||||||
{
|
{
|
||||||
public static ISynchronizingAudioBuffer metaspu_construct(ESynchMethod method)
|
public static ISynchronizingAudioBuffer metaspu_construct(ESynchMethod method)
|
||||||
|
@ -103,15 +102,15 @@ namespace BizHawk.Emulation.Sound
|
||||||
return new ZeromusSynchronizer();
|
return new ZeromusSynchronizer();
|
||||||
case ESynchMethod.ESynchMethod_N:
|
case ESynchMethod.ESynchMethod_N:
|
||||||
return new NitsujaSynchronizer();
|
return new NitsujaSynchronizer();
|
||||||
case ESynchMethod.ESynchMethod_V:
|
case ESynchMethod.ESynchMethod_V:
|
||||||
return new VecnaSynchronizer();
|
return new VecnaSynchronizer();
|
||||||
default:
|
default:
|
||||||
return new NitsujaSynchronizer();
|
return new NitsujaSynchronizer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ZeromusSynchronizer : ISynchronizingAudioBuffer
|
class ZeromusSynchronizer : ISynchronizingAudioBuffer
|
||||||
{
|
{
|
||||||
public ZeromusSynchronizer()
|
public ZeromusSynchronizer()
|
||||||
|
@ -121,7 +120,7 @@ namespace BizHawk.Emulation.Sound
|
||||||
//#else
|
//#else
|
||||||
//adjustobuf = new Adjustobuf(22000, 44000);
|
//adjustobuf = new Adjustobuf(22000, 44000);
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//adjustobuf(200,1000)
|
//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
|
//returns the number of samples actually supplied, which may not match the number requested
|
||||||
public int output_samples(short[] buf, int samples_requested)
|
public int output_samples(short[] buf, int samples_requested)
|
||||||
{
|
{
|
||||||
int ctr=0;
|
int ctr = 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
if (!mixqueue_go)
|
if (!mixqueue_go)
|
||||||
{
|
{
|
||||||
|
@ -208,7 +207,7 @@ namespace BizHawk.Emulation.Sound
|
||||||
size = 0;
|
size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enqueue(short left, short right)
|
public void enqueue(short left, short right)
|
||||||
{
|
{
|
||||||
buffer.Enqueue(left);
|
buffer.Enqueue(left);
|
||||||
buffer.Enqueue(right);
|
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);
|
//static int ctr=0; ctr++; if((ctr&127)==0) printf("avg size: %f curr size: %d rate: %f\n",averageSize,size,rate);
|
||||||
{
|
{
|
||||||
float targetRate;
|
float targetRate;
|
||||||
if(averageSize < targetLatency)
|
if (averageSize < targetLatency)
|
||||||
{
|
{
|
||||||
targetRate = 1.0f - (targetLatency-averageSize)/kAverageSize;
|
targetRate = 1.0f - (targetLatency - averageSize) / kAverageSize;
|
||||||
}
|
}
|
||||||
else if(averageSize > targetLatency) {
|
else if (averageSize > targetLatency)
|
||||||
targetRate = 1.0f + (averageSize-targetLatency)/kAverageSize;
|
{
|
||||||
} else targetRate = 1.0f;
|
targetRate = 1.0f + (averageSize - targetLatency) / kAverageSize;
|
||||||
|
}
|
||||||
|
else targetRate = 1.0f;
|
||||||
|
|
||||||
//rate = moveValueTowards(rate,targetRate,0.001f);
|
//rate = moveValueTowards(rate,targetRate,0.001f);
|
||||||
rate = targetRate;
|
rate = targetRate;
|
||||||
}
|
}
|
||||||
|
@ -251,19 +252,21 @@ namespace BizHawk.Emulation.Sound
|
||||||
|
|
||||||
public void dequeue(out short left, out short right)
|
public void dequeue(out short left, out short right)
|
||||||
{
|
{
|
||||||
left = right = 0;
|
left = right = 0;
|
||||||
addStatistic();
|
addStatistic();
|
||||||
if(size==0) { return; }
|
if (size == 0) { return; }
|
||||||
cursor += rate;
|
cursor += rate;
|
||||||
while(cursor>1.0f) {
|
while (cursor > 1.0f)
|
||||||
|
{
|
||||||
cursor -= 1.0f;
|
cursor -= 1.0f;
|
||||||
if(size>0) {
|
if (size > 0)
|
||||||
|
{
|
||||||
curr[0] = buffer.Dequeue();
|
curr[0] = buffer.Dequeue();
|
||||||
curr[1] = buffer.Dequeue();
|
curr[1] = buffer.Dequeue();
|
||||||
size--;
|
size--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
left = curr[0];
|
left = curr[0];
|
||||||
right = curr[1];
|
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
|
// returns values going between 0 and y-1 in a saw wave pattern, based on x
|
||||||
static int pingpong(int x, int y)
|
static int pingpong(int x, int y)
|
||||||
{
|
{
|
||||||
x %= 2*y;
|
x %= 2 * y;
|
||||||
if(x >= y)
|
if (x >= y)
|
||||||
x = 2*y - x - 1;
|
x = 2 * y - x - 1;
|
||||||
return x;
|
return x;
|
||||||
|
|
||||||
// in case we want to switch to odd buffer sizes for more sharpness
|
// in case we want to switch to odd buffer sizes for more sharpness
|
||||||
|
@ -294,11 +297,11 @@ namespace BizHawk.Emulation.Sound
|
||||||
//return x;
|
//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;
|
return lhs;
|
||||||
if(cur >= end)
|
if (cur >= end)
|
||||||
return rhs;
|
return rhs;
|
||||||
|
|
||||||
// in case we want sine wave interpolation instead of linear here
|
// 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 lrv = ((int)lhs.l * outNum + (int)rhs.l * inNum) / denom;
|
||||||
int rrv = ((int)lhs.r * outNum + (int)rhs.r * 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()
|
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)
|
static void emit_samples(short[] outbuf, ref int outcursor, ssamp[] samplebuf, int incursor, int samples)
|
||||||
{
|
{
|
||||||
for(int i=0;i<samples;i++)
|
for (int i = 0; i < samples; i++)
|
||||||
emit_sample(outbuf,ref outcursor, samplebuf[i+incursor]);
|
emit_sample(outbuf, ref outcursor, samplebuf[i + incursor]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static short abs(short value)
|
static short abs(short value)
|
||||||
|
@ -347,345 +350,347 @@ namespace BizHawk.Emulation.Sound
|
||||||
public void enqueue_samples(short[] buf, int samples_provided)
|
public void enqueue_samples(short[] buf, int samples_provided)
|
||||||
{
|
{
|
||||||
int cursor = 0;
|
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;
|
cursor += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enqueue_sample(short left, short right)
|
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)
|
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 bufcursor = 0;
|
||||||
int audiosize = samples_requested;
|
int audiosize = samples_requested;
|
||||||
int queued = sampleQueue.Count;
|
int queued = sampleQueue.Count;
|
||||||
|
|
||||||
// I am too lazy to deal with odd numbers
|
// I am too lazy to deal with odd numbers
|
||||||
audiosize &= ~1;
|
audiosize &= ~1;
|
||||||
queued &= ~1;
|
queued &= ~1;
|
||||||
|
|
||||||
if(queued > 0x200 && audiosize > 0) // is there any work to do?
|
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)
|
|
||||||
{
|
{
|
||||||
// not normal speed. we have to resample it somehow in this case.
|
// are we going at normal speed?
|
||||||
if(audiosize <= queued)
|
// or more precisely, are the input and output queues/buffers of similar size?
|
||||||
|
if (queued > 900 || audiosize > queued * 2)
|
||||||
{
|
{
|
||||||
// fast forward speed
|
// not normal speed. we have to resample it somehow in this case.
|
||||||
// this is the easy case, just crossfade it and it sounds ok
|
if (audiosize <= queued)
|
||||||
for(int i = 0; i < audiosize; i++)
|
|
||||||
{
|
{
|
||||||
int j = i + queued - audiosize;
|
// fast forward speed
|
||||||
ssamp outsamp = crossfade(sampleQueue[i],sampleQueue[j], i,0,audiosize);
|
// this is the easy case, just crossfade it and it sounds ok
|
||||||
emit_sample(buf,ref bufcursor,outsamp);
|
for (int i = 0; i < audiosize; i++)
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
int diff = abs(sampleQueue[i].l - sampleQueue[i+1].l) + abs(sampleQueue[i].r - sampleQueue[i+1].r);
|
int j = i + queued - audiosize;
|
||||||
if(diff < beststartdiff)
|
ssamp outsamp = crossfade(sampleQueue[i], sampleQueue[j], i, 0, audiosize);
|
||||||
{
|
emit_sample(buf, ref bufcursor, outsamp);
|
||||||
beststartdiff = diff;
|
|
||||||
beststart = i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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);
|
int bestend = queued;
|
||||||
if(diff < bestenddiff)
|
const int worstdiff = 99999999;
|
||||||
|
int beststartdiff = worstdiff;
|
||||||
|
int bestenddiff = worstdiff;
|
||||||
|
for (int i = 0; i < 128; i += 2)
|
||||||
{
|
{
|
||||||
bestenddiff = diff;
|
int diff = abs(sampleQueue[i].l - sampleQueue[i + 1].l) + abs(sampleQueue[i].r - sampleQueue[i + 1].r);
|
||||||
bestend = i+1;
|
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;
|
int leftMidpointX = midpointX - midpointXOffset;
|
||||||
queued = bestend - beststart;
|
int rightMidpointX = midpointX + midpointXOffset;
|
||||||
|
int leftMidpointY = pingpong(leftMidpointX, queued);
|
||||||
|
int rightMidpointY = (queued - 1) - pingpong((int)audiosize - 1 - rightMidpointX + queued * 2, queued);
|
||||||
|
|
||||||
int oksize = queued;
|
// output the left almost-half of the sound (section "A")
|
||||||
while(oksize + queued*2 + beststart + extraAtEnd <= samples_requested)
|
for (int x = 0; x < leftMidpointX; x++)
|
||||||
oksize += queued*2;
|
|
||||||
audiosize = oksize;
|
|
||||||
|
|
||||||
for(int x = 0; x < beststart; 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;
|
// output the end of the queued sound (section "C")
|
||||||
int midpointY = queued >> 1;
|
for (int x = rightMidpointX; x < audiosize; x++)
|
||||||
|
|
||||||
// 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...
|
int i = (queued - 1) - pingpong((int)audiosize - 1 - x + queued * 2, queued);
|
||||||
midpointXOffset++; // but this fixes it most of the time...
|
emit_sample(buf, ref bufcursor, sampleQueue[i]);
|
||||||
break; // found it
|
|
||||||
}
|
}
|
||||||
prevA = a;
|
|
||||||
midpointXOffset--;
|
for (int x = 0; x < extraAtEnd; x++)
|
||||||
if(midpointXOffset < 0)
|
|
||||||
{
|
{
|
||||||
midpointXOffset = 0;
|
int i = queued + x;
|
||||||
break; // failed to find it. the two sides probably meet exactly in the center.
|
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.erase(sampleQueue.begin(), sampleQueue.begin() + queued);
|
||||||
sampleQueue.RemoveRange(0, queued);
|
sampleQueue.RemoveRange(0, queued);
|
||||||
//zero 08-nov-2010: did i do this right?
|
//zero 08-nov-2010: did i do this right?
|
||||||
return queued;
|
return audiosize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
emit_samples(buf,ref bufcursor, sampleQueue.ToArray(),0,audiosize);
|
// normal speed
|
||||||
//sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin()+audiosize);
|
// just output the samples straightforwardly.
|
||||||
sampleQueue.RemoveRange(0, audiosize);
|
//
|
||||||
//zero 08-nov-2010: did i do this right?
|
// at almost-full speeds (like 50/60 FPS)
|
||||||
return audiosize;
|
// 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
|
} //end normal speed
|
||||||
else
|
|
||||||
|
} //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
|
// Give us a little buffer wiggle-room
|
||||||
{
|
for (int i = 0; i < 367; i++)
|
||||||
// vecna's attempt at a fully synchronous sound provider.
|
buffer.Enqueue(new Sample(0, 0));
|
||||||
// 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
|
public void enqueue_samples(short[] buf, int samples_provided)
|
||||||
// periodically and have a big bad-sounding mistake frame if it has to.
|
{
|
||||||
|
int ctr = 0;
|
||||||
// It is significantly less ambitious and elaborate than the other methods.
|
for (int i = 0; i < samples_provided; i++)
|
||||||
// We'll see if it works better or not!
|
{
|
||||||
|
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.
|
public void enqueue_sample(short left, short right)
|
||||||
// When fastforwarding, it will discard samples above the maximum excess buffer.
|
{
|
||||||
|
if (buffer.Count >= MaxExcessSamples - 1)
|
||||||
// When underflowing, it will attempt to resample to a certain threshhold.
|
{
|
||||||
// If it underflows beyond that threshhold, it will give up and output silence.
|
// if buffer is overfull, dequeue old samples to make room for new samples.
|
||||||
// Since it has done this, it will go ahead and generate some excess silence in order
|
buffer.Dequeue();
|
||||||
// to restock its excess buffer.
|
}
|
||||||
|
buffer.Enqueue(new Sample(left, right));
|
||||||
|
}
|
||||||
|
|
||||||
struct Sample
|
public void clear()
|
||||||
{
|
{
|
||||||
public short left, right;
|
buffer.Clear();
|
||||||
public Sample(short l, short r)
|
}
|
||||||
{
|
|
||||||
left = l;
|
|
||||||
right = r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Queue<Sample> buffer;
|
public int output_samples(short[] buf, int samples_requested)
|
||||||
Sample[] resampleBuffer;
|
{
|
||||||
|
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;
|
int samples_available = buffer.Count;
|
||||||
const int MaxExcessSamples = 2048;
|
for (int i = 0; buffer.Count > 0; i++)
|
||||||
|
resampleBuffer[i] = buffer.Dequeue();
|
||||||
|
|
||||||
public VecnaSynchronizer()
|
int index = 0;
|
||||||
{
|
for (int i = 0; i < samples_requested; i++)
|
||||||
buffer = new Queue<Sample>(2048);
|
{
|
||||||
resampleBuffer = new Sample[2730]; // 2048 * 1.25
|
Sample sample = resampleBuffer[i * samples_available / samples_requested];
|
||||||
|
buf[index++] += sample.left;
|
||||||
// Give us a little buffer wiggle-room
|
buf[index++] += sample.right;
|
||||||
for (int i=0; i<367; i++)
|
}
|
||||||
buffer.Enqueue(new Sample(0,0));
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
public void enqueue_samples(short[] buf, int samples_provided)
|
// we're outside of a "reasonable" underflow. Give up and output silence.
|
||||||
{
|
// Do nothing. The whole frame will be excess buffer.
|
||||||
int ctr = 0;
|
}
|
||||||
for (int i = 0; i < samples_provided; i++)
|
}
|
||||||
{
|
else
|
||||||
short left = buf[ctr++];
|
{
|
||||||
short right = buf[ctr++];
|
// normal operation
|
||||||
enqueue_sample(left, right);
|
//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++)
|
||||||
|
{
|
||||||
public void enqueue_sample(short left, short right)
|
Sample sample = buffer.Dequeue();
|
||||||
{
|
buf[index++] += sample.left;
|
||||||
if (buffer.Count >= MaxExcessSamples - 1)
|
buf[index++] += sample.right;
|
||||||
{
|
}
|
||||||
// if buffer is overfull, dequeue old samples to make room for new samples.
|
}
|
||||||
buffer.Dequeue();
|
return samples_requested;
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound
|
namespace BizHawk.Emulation.Common
|
||||||
{
|
{
|
||||||
// This is a straightforward class to mix/chain multiple ISoundProvider sources.
|
// This is a straightforward class to mix/chain multiple ISoundProvider sources.
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound.Utilities
|
namespace BizHawk.Emulation.Common
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// junk wrapper around LibSpeexDSP. quite inefficient. will be replaced
|
/// junk wrapper around LibSpeexDSP. quite inefficient. will be replaced
|
||||||
|
|
|
@ -1,53 +1,53 @@
|
||||||
namespace BizHawk.Emulation.Sound
|
namespace BizHawk.Emulation.Common
|
||||||
{
|
{
|
||||||
public static class Waves
|
public static class Waves
|
||||||
{
|
{
|
||||||
public static short[] SquareWave;
|
public static short[] SquareWave;
|
||||||
public static short[] ImperfectSquareWave;
|
public static short[] ImperfectSquareWave;
|
||||||
public static short[] NoiseWave;
|
public static short[] NoiseWave;
|
||||||
public static short[] PeriodicWave16;
|
public static short[] PeriodicWave16;
|
||||||
|
|
||||||
public static void InitWaves()
|
public static void InitWaves()
|
||||||
{
|
{
|
||||||
SquareWave = new short[]
|
SquareWave = new short[]
|
||||||
{
|
{
|
||||||
-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
|
-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
|
32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767
|
||||||
};
|
};
|
||||||
|
|
||||||
ImperfectSquareWave = new short[]
|
ImperfectSquareWave = new short[]
|
||||||
{
|
{
|
||||||
-32768,-30145,-27852,-26213,-24902,-23592,-22282,-20971,-19988,-19005,-18350,-17694,-17366,-17039,-16711,-16711,
|
-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
|
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];
|
NoiseWave = new short[0x1000];
|
||||||
var rnd = new System.Random(unchecked((int)0xDEADBEEF));
|
var rnd = new System.Random(unchecked((int)0xDEADBEEF));
|
||||||
for (int i = 0; i < NoiseWave.Length; i++)
|
for (int i = 0; i < NoiseWave.Length; i++)
|
||||||
{
|
{
|
||||||
int r = rnd.Next();
|
int r = rnd.Next();
|
||||||
if ((r & 1) > 0)
|
if ((r & 1) > 0)
|
||||||
NoiseWave[i] = short.MaxValue;
|
NoiseWave[i] = short.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*TriangleWave = new short[512];
|
/*TriangleWave = new short[512];
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; i++)
|
||||||
TriangleWave[i] = (short)((ushort.MaxValue*i/256)-short.MinValue);
|
TriangleWave[i] = (short)((ushort.MaxValue*i/256)-short.MinValue);
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; i++)
|
||||||
TriangleWave[256+i] = TriangleWave[256-i];
|
TriangleWave[256+i] = TriangleWave[256-i];
|
||||||
TriangleWave[256] = short.MaxValue;
|
TriangleWave[256] = short.MaxValue;
|
||||||
|
|
||||||
SawWave = new short[512];
|
SawWave = new short[512];
|
||||||
for (int i = 0; i < 512; i++)
|
for (int i = 0; i < 512; i++)
|
||||||
SawWave[i] = (short)((ushort.MaxValue * i / 512) - short.MinValue);
|
SawWave[i] = (short)((ushort.MaxValue * i / 512) - short.MinValue);
|
||||||
|
|
||||||
SineWave = new short[1024];
|
SineWave = new short[1024];
|
||||||
for (int i=0; i<1024; i++)
|
for (int i=0; i<1024; i++)
|
||||||
{
|
{
|
||||||
SineWave[i] = (short) (Math.Sin(i*Math.PI*2/1024d)*32767);
|
SineWave[i] = (short) (Math.Sin(i*Math.PI*2/1024d)*32767);
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@ using System.Text;
|
||||||
|
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound
|
namespace BizHawk.Emulation.Common.Components
|
||||||
{
|
{
|
||||||
public class VRC6Alt
|
public class VRC6Alt
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
using System;
|
// Credits:
|
||||||
|
|
||||||
// Credits:
|
|
||||||
// Original emulator written by Mitsutaka Okazaki 2001.
|
// Original emulator written by Mitsutaka Okazaki 2001.
|
||||||
// Original conversion to C# by Ben Ryves.
|
// 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 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.
|
// 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.Common;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound
|
namespace BizHawk.Emulation.Common.Components
|
||||||
{
|
{
|
||||||
public sealed class YM2413 : ISoundProvider
|
public sealed class YM2413 : ISoundProvider
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.IO;
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Sound
|
namespace BizHawk.Emulation.Common.Components
|
||||||
{
|
{
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
// Yamaha YM2612 Emulation Core
|
// Yamaha YM2612 Emulation Core
|
||||||
|
|
Loading…
Reference in New Issue