C# Gameboy Emulator Sound Interference Noise - NaudioC#

Ein Treffpunkt für C#-Programmierer
Anonymous
 C# Gameboy Emulator Sound Interference Noise - Naudio

Post by Anonymous »

Wenn ich den Emulator mit einem ROM starte, spielt ein sehr lautes Interferenzgeräusch und der Emulator stürzt ab. Ich weiß nicht, ob es sich um ein Timing, ein Naudio- oder Spu -Emulationsfehler handelt. />

Code: Select all

public sealed class GameBoyEmulator : NexusConsoleGame
{
private readonly Processor _cpu;
private readonly SoundProcessor _spu;
private readonly MemoryManagement _mmu;
private readonly PixelProcessor _ppu;
private readonly Timer _timer;
private readonly Joypad _joypad;

private double accumulatedTime;
private int cpuCycles;
private int cyclesThisUpdate;

public GameBoyEmulator(string rom)
{
_spu = new SoundProcessor();
_mmu = MemoryManagement.LoadGamePak(rom, _spu);
_cpu = new Processor(_mmu);
_ppu = new PixelProcessor(Graphic, _mmu);
_timer = new Timer(_mmu);
_joypad = new Joypad(_mmu);
}

protected override void Load()
{
Settings.ColorPalette = new GameBoyColorPalette();
Settings.Font = new NexusFont("Consolas", new NexusSize(8));
Settings.Title = "NexusGB";
Settings.StopGameKey = NexusKey.Escape;
}

protected override void Update()
{
accumulatedTime += DeltaTime * 1_000_000_000;

while (accumulatedTime >= 16740000)
{
accumulatedTime -= 16740000;

Input.UpdateGamepads();
Input.Update();
_joypad.HandleInputs(Input.Gamepad1, Input.Keys);

while (cyclesThisUpdate < GameBoySystem.CyclesPerUpdate)
{
cpuCycles = _cpu.Execute();
cyclesThisUpdate += cpuCycles;

_timer.Update(cpuCycles);
_ppu.Update(cpuCycles);
_spu.Update(cpuCycles);
_joypad.Update();
HandleInterrupts();
}

cyclesThisUpdate -= GameBoySystem.CyclesPerUpdate;
}
}

protected override void OnCrash(Exception exception)
=> Utility.ShowAlert("Error", $"An error occured:\n{exception}", NexusAlertIcon.Error);

protected override void CleanUp()
{

}

private void HandleInterrupts()
{
var interruptEnable = _mmu.InterruptEnable;
var interruptFlag = _mmu.InterruptFlag;

for (int i = 0; i < 5; i++)
{
if ((((interruptEnable & interruptFlag) >> i) & 0x01) == 1)
{
_cpu.ExecuteInterrupt(i);
}
}

_cpu.UpdateIme();
}
}
< /code>
Dies ist die Soundprozesssinginit: < /p>
public sealed class SoundProcessor
{
private readonly ImmutableArray _channels;
private readonly WaveSoundChannel _wave;

private byte number50;
private byte number51;
private byte number52;

private byte Sound1Volume => (byte)(number50 & 0x7);

public SoundProcessor()
{
_channels =
[
new SquareSweepChannel(this),
new SquareChannel(this),
_wave = new WaveSoundChannel(this),
new NoiseChannel(this)
];

_channels[0].WriteNumber(0, 0x80);
_channels[0].WriteNumber(1, 0xBF);
_channels[0].WriteNumber(2, 0xF3);
_channels[0].WriteNumber(4, 0xBF);

_channels[1].WriteNumber(1, 0x3F);
_channels[1].WriteNumber(2, 0x00);
_channels[1].WriteNumber(4, 0xBF);

_channels[2].WriteNumber(0, 0x7F);
_channels[2].WriteNumber(1, 0xFF);
_channels[2].WriteNumber(2, 0x9F);
_channels[2].WriteNumber(3, 0xBF);

_channels[3].WriteNumber(1, 0xFF);
_channels[3].WriteNumber(2, 0x00);
_channels[3].WriteNumber(3, 0x00);
_channels[3].WriteNumber(4, 0xBF);

number50 = 0x77;
number51 = 0xF3;
number52 = 0xF1;
}

public void Update(in int cycles)
{
if ((number52 & (1 = 0xFF27 and < 0xFF30: return 0x00;
case >= 0xFF30 and < 0xFF40: return _wave.ReadRam((ushort)(address - 0xFF30));
}

var relativeAddress = address - 0xFF10;
return _channels[relativeAddress / 5].ReadNumber(relativeAddress % 5);
}

public void WriteByte(in ushort address, in byte value)
{
switch (address)
{
case 0xFF24: number50 = value; return;
case 0xFF25: number51 = value; return;
case 0xFF26: number52 = value; return;

case >= 0xFF27 and < 0xFF30: return;
case >= 0xFF30 and < 0xFF40: _wave.WriteRam((ushort)(address - 0xFF30), value); return;
}

var relativeAddress = address - 0xFF10;
_channels[relativeAddress / 5].WriteNumber(relativeAddress % 5, value);
}

public void WriteToSoundBuffer(in int channel, in Span totalBuffer, in int index, float sample)
{
sample *= Sound1Volume / 7f;

if ((number51 & (1 
public abstract class BaseSoundChannel
{
private readonly byte[] _numbers;
protected readonly int _channelNumber;
protected readonly SoundProcessor _spu;
protected readonly WindowsSoundOut _out;

private float volume;

public ref float ChannelVolume => ref volume;

protected BaseSoundChannel(SoundProcessor spu, in int channelNumber)
{
_numbers = new byte[5];
_channelNumber = channelNumber;
_spu = spu;
_out = new WindowsSoundOut();

ChannelVolume = 0.05f;
}

public abstract void Update(in int cycles);

public virtual byte ReadNumber(in int index) => _numbers[index];

public virtual void WriteNumber(in int index, in byte value) => _numbers[index] = value;
}
< /code>
Dies ist die tatsächliche Tonausgabe für ein Windows-Gerät: < /p>
public sealed class WindowsSoundOut
{
private readonly DirectSoundOut soundOut;
private readonly BufferedWaveProvider _provider;
private readonly byte[] _addSampleData;

public int SampleRate => _provider.WaveFormat.SampleRate;

public WindowsSoundOut()
{
_provider = new BufferedWaveProvider(new WaveFormat(44100, 16, 2));
soundOut = new DirectSoundOut(100);
soundOut.Init(_provider);
soundOut.Play();

_addSampleData = new byte[_provider.BufferLength];
}

public void BufferSoundSamples(in Span sampleData, in int length)
{
var index = 0;
foreach (var current in MemoryMarshal.Cast(sampleData))
{
_addSampleData[index++] = current;
}

_provider.AddSamples(_addSampleData, 0, length + sizeof(float)); //The `InvalidOperationException: "Buffer full"` from NAudio occurs here
}
}
Der gesamte Quellcode kann hier gefunden werden>

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post