Added AY38912 support
This commit is contained in:
69
Core/Audio/Ay38912.cs
Normal file
69
Core/Audio/Ay38912.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
|
||||
namespace Core.Audio
|
||||
{
|
||||
public class Ay38912
|
||||
{
|
||||
private readonly byte[] _registers = new byte[16];
|
||||
private byte _selectedRegister = 0;
|
||||
|
||||
// The AY-3-8912 uses logarithmic volume, not linear!
|
||||
// This table converts the 0-15 register value into a precise float multiplier.
|
||||
private readonly float[] _volumeTable = {
|
||||
0.0000f, 0.0137f, 0.0205f, 0.0291f, 0.0423f, 0.0618f, 0.0847f, 0.1369f,
|
||||
0.1691f, 0.2647f, 0.3527f, 0.4499f, 0.5704f, 0.6873f, 0.8482f, 1.0000f
|
||||
};
|
||||
|
||||
// --- Hardware Port Intercepts ---
|
||||
public void SelectRegister(byte register)
|
||||
{
|
||||
_selectedRegister = (byte)(register & 0x0F); // Only 16 registers exist
|
||||
}
|
||||
|
||||
public void WriteRegister(byte value)
|
||||
{
|
||||
_registers[_selectedRegister] = value;
|
||||
}
|
||||
|
||||
public byte ReadRegister()
|
||||
{
|
||||
return _registers[_selectedRegister];
|
||||
}
|
||||
|
||||
// --- Audio Math Generators ---
|
||||
|
||||
// The AY clock on a Spectrum 128 is 1.7734 MHz.
|
||||
// The chip divides this by 16 internally, giving a base clock of ~110,837 Hz.
|
||||
private float GetFrequency(int registerLow, int registerHigh)
|
||||
{
|
||||
int period = _registers[registerLow] | ((_registers[registerHigh] & 0x0F) << 8);
|
||||
if (period == 0) return 0f; // Prevent divide-by-zero
|
||||
return 110837.5f / period;
|
||||
}
|
||||
|
||||
private float GetVolume(int volumeRegister)
|
||||
{
|
||||
byte vol = _registers[volumeRegister];
|
||||
|
||||
// Bit 4 indicates if the channel is using the hardware Envelope generator.
|
||||
// For Version 1 of our chip, if the envelope is active, we will just
|
||||
// output half volume so the game doesn't go silent!
|
||||
if ((vol & 0x10) != 0)
|
||||
{
|
||||
return 0.5f;
|
||||
}
|
||||
|
||||
return _volumeTable[vol & 0x0F];
|
||||
}
|
||||
|
||||
// --- Public Data for your Audio Engine ---
|
||||
public float FreqA => GetFrequency(0, 1);
|
||||
public float FreqB => GetFrequency(2, 3);
|
||||
public float FreqC => GetFrequency(4, 5);
|
||||
|
||||
// Register 7 is the Mixer. Bit 0, 1, and 2 turn the tone channels OFF when set to 1.
|
||||
public float VolA => (_registers[7] & 0x01) == 0 ? GetVolume(8) : 0f;
|
||||
public float VolB => (_registers[7] & 0x02) == 0 ? GetVolume(9) : 0f;
|
||||
public float VolC => (_registers[7] & 0x04) == 0 ? GetVolume(10) : 0f;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user