Namco163 Audio
This commit is contained in:
parent
ca86a8dff3
commit
8313c103f6
|
@ -302,6 +302,7 @@
|
|||
<Compile Include="Consoles\Nintendo\NES\Boards\Namcot1xx\Mapper112.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Namcot1xx\Mapper154.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Namcot1xx\Mapper206.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Namcot1xx\Namco163Audio.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\Namcot1xx\Namcot1xx.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\NAMCOT_m19_m210.cs">
|
||||
<SubType>Code</SubType>
|
||||
|
|
|
@ -26,12 +26,20 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
int irq_cycles;
|
||||
bool irq_pending;
|
||||
|
||||
Namco163Audio audio;
|
||||
int audio_cycles;
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
prg_banks_8k.Dispose();
|
||||
chr_banks_1k.Dispose();
|
||||
nt_banks_1k.Dispose();
|
||||
if (audio != null)
|
||||
{
|
||||
audio.Dispose();
|
||||
audio = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
|
@ -40,12 +48,18 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
ser.Sync("prg_banks_8k", ref prg_banks_8k);
|
||||
ser.Sync("chr_banks_1k", ref chr_banks_1k);
|
||||
ser.Sync("nt_banks_1k", ref nt_banks_1k);
|
||||
for(int i=0;i<2;i++) ser.Sync("vram_enable_" + i, ref vram_enable[i]);
|
||||
for (int i = 0; i < 2; i++)
|
||||
ser.Sync("vram_enable_" + i, ref vram_enable[i]);
|
||||
ser.Sync("irq_counter", ref irq_counter);
|
||||
ser.Sync("irq_enabled", ref irq_enabled);
|
||||
ser.Sync("irq_cycles", ref irq_cycles);
|
||||
ser.Sync("irq_pending", ref irq_pending);
|
||||
SyncIRQ();
|
||||
if (audio != null)
|
||||
{
|
||||
ser.Sync("audio_cycles", ref audio_cycles);
|
||||
audio.SyncState(ser);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Configure(NES.EDetectionOrigin origin)
|
||||
|
@ -66,6 +80,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
//hydelide 3 *this is a good test of more advanced features
|
||||
Cart.vram_size = 8; //not many test cases of this, but hydelide 3 needs it.
|
||||
AssertPrg(128,256); AssertChr(128,256); AssertVram(8); AssertWram(0,8);
|
||||
audio = new Namco163Audio();
|
||||
break;
|
||||
|
||||
//mapper 210:
|
||||
|
@ -99,6 +114,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
addr &= 0xF800;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x0800:
|
||||
if (audio != null)
|
||||
return audio.ReadData();
|
||||
else
|
||||
break;
|
||||
case 0x1000:
|
||||
return (byte)(irq_counter & 0xFF);
|
||||
case 0x1800:
|
||||
|
@ -113,7 +133,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
switch (addr)
|
||||
{
|
||||
case 0x0800:
|
||||
//sound data port. not used.
|
||||
if (audio != null)
|
||||
audio.WriteData(value);
|
||||
break;
|
||||
case 0x1000:
|
||||
irq_counter = (irq_counter & 0xFF00) | value;
|
||||
|
@ -175,6 +196,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
case 0x7000: //$F000
|
||||
prg_banks_8k[2] = (value & 0x3F) & prg_bank_mask_8k;
|
||||
break;
|
||||
case 0x7800: //$F800
|
||||
if (audio != null)
|
||||
audio.WriteAddr(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,15 +304,30 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
|
||||
public override void ClockPPU()
|
||||
{
|
||||
if (!irq_enabled) return;
|
||||
|
||||
irq_cycles--;
|
||||
if (irq_cycles == 0)
|
||||
if (irq_enabled)
|
||||
{
|
||||
irq_cycles += 3;
|
||||
ClockIRQ();
|
||||
irq_cycles--;
|
||||
if (irq_cycles == 0)
|
||||
{
|
||||
irq_cycles += 3;
|
||||
ClockIRQ();
|
||||
}
|
||||
}
|
||||
if (audio != null)
|
||||
{
|
||||
audio_cycles++;
|
||||
if (audio_cycles == 15 * 3)
|
||||
{
|
||||
audio_cycles = 0;
|
||||
audio.Clock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ApplyCustomAudio(short[] samples)
|
||||
{
|
||||
if (audio != null)
|
||||
audio.ApplyCustomAudio(samples);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
// http://wiki.nesdev.com/w/index.php/Namco_163_audio
|
||||
public class Namco163Audio : IDisposable
|
||||
{
|
||||
//ByteBuffer ram = new ByteBuffer(0x80);
|
||||
byte[] ram = new byte[0x80];
|
||||
int addr;
|
||||
bool autoincrement;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
//ram.Dispose();
|
||||
ram = null;
|
||||
resampler.Dispose();
|
||||
resampler = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// F800:FFFF
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void WriteAddr(byte value)
|
||||
{
|
||||
addr = value & 0x7f;
|
||||
autoincrement = (value & 0x80) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 4800:4FFF
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void WriteData(byte value)
|
||||
{
|
||||
ram[addr] = value;
|
||||
if (autoincrement)
|
||||
{
|
||||
addr++;
|
||||
addr &= 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 4800:4FFF
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public byte ReadData()
|
||||
{
|
||||
byte ret = ram[addr];
|
||||
if (autoincrement)
|
||||
{
|
||||
addr++;
|
||||
addr &= 0x7f;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// last channel clocked
|
||||
/// </summary>
|
||||
int ch;
|
||||
|
||||
// output buffer; not savestated
|
||||
//short[] samplebuff = new short[2048];
|
||||
//int samplebuffpos;
|
||||
|
||||
/// <summary>
|
||||
/// 119318hz (CPU / 15)
|
||||
/// </summary>
|
||||
public void Clock()
|
||||
{
|
||||
ch--;
|
||||
int lastch = 8 - (ram[0x7f] >> 4 & 7);
|
||||
if (ch < lastch)
|
||||
ch = 8;
|
||||
|
||||
byte samp = ClockChannel(ch);
|
||||
|
||||
//samplebuff[samplebuffpos++] = samp;
|
||||
//samplebuffpos &= 2047;
|
||||
short ss = (short)(samp * 50 - 12096);
|
||||
resampler.EnqueueSample(ss, ss);
|
||||
}
|
||||
|
||||
byte ClockChannel(int ch)
|
||||
{
|
||||
// channel regs are at [b..b+7]
|
||||
int b = ch * 8 + 56;
|
||||
|
||||
// not that bad really, and best to do exactly as specified because
|
||||
// the results (phase) can be read back
|
||||
int phase = ram[b + 1] | ram[b + 3] << 8 | ram[b + 5] << 16;
|
||||
int freq = ram[b] | ram[b + 2] << 8 | ram[b + 4] << 16 & 0x030000;
|
||||
int length = 256 - (ram[b + 4] & 0xfc);
|
||||
phase = (phase + freq) % (length << 16);
|
||||
|
||||
int pos = (phase >> 16) + ram[b + 6];
|
||||
pos &= 0xff;
|
||||
int sample = ram[pos / 2] >> (pos & 1) * 4 & 0xf;
|
||||
byte ret = (byte)(sample * (ram[b + 7] & 0x0f));
|
||||
// writeback phase
|
||||
ram[b + 5] = (byte)(phase >> 16);
|
||||
ram[b + 3] = (byte)(phase >> 8);
|
||||
ram[b + 1] = (byte)phase;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("ram", ref ram, false);
|
||||
ser.Sync("addr", ref addr);
|
||||
ser.Sync("autoincrement", ref autoincrement);
|
||||
ser.Sync("ch", ref ch);
|
||||
}
|
||||
|
||||
Sound.Utilities.SpeexResampler resampler;
|
||||
Sound.Utilities.DCFilter dc;
|
||||
Sound.MetaspuAsync metaspu;
|
||||
|
||||
public Namco163Audio()
|
||||
{
|
||||
resampler = new Sound.Utilities.SpeexResampler(2, 119318, 44100, 119318, 44100, null, null);
|
||||
dc = new Sound.Utilities.DCFilter(4096);
|
||||
metaspu = new Sound.MetaspuAsync(resampler, Sound.ESynchMethod.ESynchMethod_V);
|
||||
}
|
||||
|
||||
public void ApplyCustomAudio(short[] samples)
|
||||
{
|
||||
short[] tmp = new short[samples.Length];
|
||||
metaspu.GetSamples(tmp);
|
||||
for (int i = 0; i < samples.Length; i++)
|
||||
{
|
||||
int samp = samples[i] + tmp[i];
|
||||
if (samp > 32767)
|
||||
samples[i] = 32767;
|
||||
else if (samp < -32768)
|
||||
samples[i] = -32768;
|
||||
else
|
||||
samples[i] = (short)samp;
|
||||
}
|
||||
dc.PushThroughSamples(samples, samples.Length);
|
||||
}
|
||||
|
||||
// the same junk used in FDSAudio
|
||||
// the problem here is, the raw 120khz output contains significant amounts of crap that gets
|
||||
// massively garbaged up by this resampling
|
||||
/*
|
||||
public void ApplyCustomAudio(short[] samples)
|
||||
{
|
||||
for (int i = 0; i < samples.Length; i += 2)
|
||||
{
|
||||
// worst imaginable resampling
|
||||
int pos = i * samplebuffpos / samples.Length;
|
||||
int samp = samplebuff[pos] * 50 - 12096;
|
||||
samp += samples[i];
|
||||
if (samp > 32767)
|
||||
samples[i] = 32767;
|
||||
else if (samp < -32768)
|
||||
samples[i] = -32768;
|
||||
else
|
||||
samples[i] = (short)samp;
|
||||
|
||||
// NES audio is mono, so this should be identical anyway
|
||||
samples[i + 1] = samples[i];
|
||||
}
|
||||
samplebuffpos = 0;
|
||||
|
||||
dc.PushThroughSamples(samples, samples.Length);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue