[NES] work on sound, improve square waves muchly, add 6502 IRQ signal, make add some infrastructure to keep from buffering samples while core is silenced.
This commit is contained in:
parent
0a354c2748
commit
c7f0c457ad
|
@ -22,6 +22,10 @@ namespace BizHawk.Emulation.CPUs.M6502
|
||||||
TriggerException(ExceptionType.NMI);
|
TriggerException(ExceptionType.NMI);
|
||||||
NMI = false;
|
NMI = false;
|
||||||
}
|
}
|
||||||
|
if (IRQ && !FlagI)
|
||||||
|
{
|
||||||
|
TriggerException(ExceptionType.IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
if(debug) Console.WriteLine(State());
|
if(debug) Console.WriteLine(State());
|
||||||
|
|
||||||
|
@ -1201,9 +1205,7 @@ FlagT = true;// this seems wrong
|
||||||
PendingCycles -= 7; TotalExecutedCycles += 7;
|
PendingCycles -= 7; TotalExecutedCycles += 7;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//throw new Exception(String.Format("Unhandled opcode: {0:X2}", opcode));
|
throw new Exception(String.Format("Unhandled opcode: {0:X2}", opcode));
|
||||||
//Console.WriteLine(String.Format("Unhandled opcode: {0:X2}", opcode));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,10 +64,11 @@ namespace BizHawk.Emulation.CPUs.M6502
|
||||||
private const ushort NMIVector = 0xFFFA;
|
private const ushort NMIVector = 0xFFFA;
|
||||||
private const ushort ResetVector = 0xFFFC;
|
private const ushort ResetVector = 0xFFFC;
|
||||||
private const ushort BRKVector = 0xFFFE;
|
private const ushort BRKVector = 0xFFFE;
|
||||||
|
private const ushort IRQVector = 0xFFFE;
|
||||||
|
|
||||||
enum ExceptionType
|
enum ExceptionType
|
||||||
{
|
{
|
||||||
BRK, NMI
|
BRK, NMI, IRQ
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriggerException(ExceptionType type)
|
void TriggerException(ExceptionType type)
|
||||||
|
@ -80,10 +81,19 @@ namespace BizHawk.Emulation.CPUs.M6502
|
||||||
WriteMemory((ushort)(S-- + 0x100), P);
|
WriteMemory((ushort)(S-- + 0x100), P);
|
||||||
P = oldP;
|
P = oldP;
|
||||||
FlagI = true;
|
FlagI = true;
|
||||||
if (type == ExceptionType.NMI)
|
switch (type)
|
||||||
PC = ReadWord(NMIVector);
|
{
|
||||||
else
|
case ExceptionType.NMI:
|
||||||
PC = ReadWord(BRKVector);
|
PC = ReadWord(NMIVector);
|
||||||
|
break;
|
||||||
|
case ExceptionType.IRQ:
|
||||||
|
PC = ReadWord(IRQVector);
|
||||||
|
break;
|
||||||
|
case ExceptionType.BRK:
|
||||||
|
PC = ReadWord(BRKVector);
|
||||||
|
break;
|
||||||
|
default: throw new Exception();
|
||||||
|
}
|
||||||
PendingCycles -= 7;
|
PendingCycles -= 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,8 +106,7 @@ namespace BizHawk.Emulation.CPUs.M6502
|
||||||
public ushort PC;
|
public ushort PC;
|
||||||
public byte S;
|
public byte S;
|
||||||
|
|
||||||
// TODO IRQ, NMI functions
|
public bool IRQ;
|
||||||
public bool Interrupt;
|
|
||||||
public bool NMI;
|
public bool NMI;
|
||||||
|
|
||||||
public void SaveStateText(TextWriter writer)
|
public void SaveStateText(TextWriter writer)
|
||||||
|
@ -110,7 +119,7 @@ namespace BizHawk.Emulation.CPUs.M6502
|
||||||
writer.WriteLine("PC {0:X4}", PC);
|
writer.WriteLine("PC {0:X4}", PC);
|
||||||
writer.WriteLine("S {0:X2}", S);
|
writer.WriteLine("S {0:X2}", S);
|
||||||
writer.WriteLine("NMI {0}", NMI);
|
writer.WriteLine("NMI {0}", NMI);
|
||||||
writer.WriteLine("Interrupt {0}", Interrupt);
|
writer.WriteLine("IRQ {0}", IRQ);
|
||||||
writer.WriteLine("TotalExecutedCycles {0}", TotalExecutedCycles);
|
writer.WriteLine("TotalExecutedCycles {0}", TotalExecutedCycles);
|
||||||
writer.WriteLine("PendingCycles {0}", PendingCycles);
|
writer.WriteLine("PendingCycles {0}", PendingCycles);
|
||||||
writer.WriteLine("[/MOS6502]\n");
|
writer.WriteLine("[/MOS6502]\n");
|
||||||
|
@ -137,8 +146,8 @@ namespace BizHawk.Emulation.CPUs.M6502
|
||||||
S = byte.Parse(args[1], NumberStyles.HexNumber);
|
S = byte.Parse(args[1], NumberStyles.HexNumber);
|
||||||
else if (args[0] == "NMI")
|
else if (args[0] == "NMI")
|
||||||
NMI = bool.Parse(args[1]);
|
NMI = bool.Parse(args[1]);
|
||||||
else if (args[0] == "Interrupt")
|
else if (args[0] == "IRQ")
|
||||||
Interrupt = bool.Parse(args[1]);
|
IRQ = bool.Parse(args[1]);
|
||||||
else if (args[0] == "TotalExecutedCycles")
|
else if (args[0] == "TotalExecutedCycles")
|
||||||
TotalExecutedCycles = int.Parse(args[1]);
|
TotalExecutedCycles = int.Parse(args[1]);
|
||||||
else if (args[0] == "PendingCycles")
|
else if (args[0] == "PendingCycles")
|
||||||
|
|
|
@ -47,13 +47,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
//reg0
|
//reg0
|
||||||
int duty_cnt, env_loop, env_constant, env_cnt_value;
|
int duty_cnt, env_loop, env_constant, env_cnt_value;
|
||||||
//reg1
|
//reg1
|
||||||
int sweep_en, sweep_period, negate, shiftcount;
|
int sweep_en, sweep_divider_cnt, sweep_negate, sweep_shiftcount;
|
||||||
|
bool sweep_reload;
|
||||||
//reg2/3
|
//reg2/3
|
||||||
int len_cnt;
|
int len_cnt;
|
||||||
int timer_raw_reload_value, timer_reload_value;
|
int timer_raw_reload_value, timer_reload_value;
|
||||||
|
|
||||||
//from other apu regs
|
//misc..
|
||||||
public int lenctr_en;
|
int lenctr_en;
|
||||||
|
|
||||||
|
public bool IsLenCntNonZero() { return len_cnt > 0; }
|
||||||
|
|
||||||
public void WriteReg(int addr, byte val)
|
public void WriteReg(int addr, byte val)
|
||||||
{
|
{
|
||||||
|
@ -67,30 +70,42 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
duty_cnt = (val >> 6) & 3;
|
duty_cnt = (val >> 6) & 3;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
shiftcount = val & 7;
|
sweep_shiftcount = val & 7;
|
||||||
negate = (val >> 3) & 1;
|
sweep_negate = (val >> 3) & 1;
|
||||||
sweep_period = (val >> 4) & 7;
|
sweep_divider_cnt = (val >> 4) & 7;
|
||||||
sweep_en = (val >> 7) & 1;
|
sweep_en = (val >> 7) & 1;
|
||||||
|
sweep_reload = true;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
timer_reload_value = (timer_reload_value & ~0xFF) | val;
|
timer_reload_value = (timer_reload_value & ~0xFF) | val;
|
||||||
calc_sweep_unit();
|
timer_raw_reload_value = timer_reload_value * 2 + 2;
|
||||||
|
//if (unit == 1) Console.WriteLine("{0} timer_reload_value: {1}", unit, timer_reload_value);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F];
|
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F];
|
||||||
timer_reload_value = (timer_reload_value & 0xFF) | ((val & 0x07) << 8);
|
timer_reload_value = (timer_reload_value & 0xFF) | ((val & 0x07) << 8);
|
||||||
timer_raw_reload_value = timer_reload_value * 2;
|
timer_raw_reload_value = timer_reload_value * 2 + 2;
|
||||||
duty_step = 0;
|
//duty_step = 0; //?just a guess?
|
||||||
timer_counter = timer_raw_reload_value;
|
timer_counter = timer_raw_reload_value;
|
||||||
calc_sweep_unit();
|
|
||||||
env_start_flag = 1;
|
env_start_flag = 1;
|
||||||
|
|
||||||
|
//allow the lenctr_en to kill the len_cnt
|
||||||
|
set_lenctr_en(lenctr_en);
|
||||||
|
|
||||||
//serves as a useful note-on diagnostic
|
//serves as a useful note-on diagnostic
|
||||||
//Console.WriteLine("{0} timer_reload_value: {1}", unit, timer_reload_value);
|
//if(unit==1) Console.WriteLine("{0} timer_reload_value: {1}", unit, timer_reload_value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int swp_val_result;
|
public void set_lenctr_en(int value)
|
||||||
|
{
|
||||||
|
lenctr_en = value;
|
||||||
|
//if the length counter is not enabled, then we must disable the length system in this way
|
||||||
|
if (lenctr_en == 0) len_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int swp_divider_counter;
|
||||||
bool swp_silence;
|
bool swp_silence;
|
||||||
int duty_step;
|
int duty_step;
|
||||||
int timer_counter;
|
int timer_counter;
|
||||||
|
@ -98,27 +113,51 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
|
|
||||||
int env_start_flag, env_divider, env_counter, env_output;
|
int env_start_flag, env_divider, env_counter, env_output;
|
||||||
|
|
||||||
void calc_sweep_unit()
|
|
||||||
{
|
|
||||||
//1's complement for chan 0, 2's complement if chan 1
|
|
||||||
if (negate == 1) //check to see if negate is on
|
|
||||||
swp_val_result = ~swp_val_result + unit;
|
|
||||||
//add with the shifter chan
|
|
||||||
swp_val_result += timer_reload_value;
|
|
||||||
|
|
||||||
if ((timer_reload_value < 8) ||
|
|
||||||
((swp_val_result > 0x7FF) && (negate==0)))
|
|
||||||
swp_silence = true; //silence
|
|
||||||
else
|
|
||||||
swp_silence = false; //don't silence
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clock_length_and_sweep()
|
public void clock_length_and_sweep()
|
||||||
{
|
{
|
||||||
//(as well as length counter)
|
//this should be optimized to update only when `timer_reload_value` changes
|
||||||
if(sweep_en==1)
|
int sweep_shifter = timer_reload_value >> sweep_shiftcount;
|
||||||
timer_raw_reload_value = swp_val_result & 0x7FF;
|
if (sweep_negate == 1)
|
||||||
|
sweep_shifter = ~sweep_shifter + unit;
|
||||||
|
sweep_shifter += timer_reload_value;
|
||||||
|
|
||||||
|
//this sweep logic is always enabled:
|
||||||
|
swp_silence = (timer_reload_value < 8 || (sweep_shifter > 0x7FF && sweep_negate == 0));
|
||||||
|
|
||||||
|
//does enable only block the pitch bend? does the clocking proceed?
|
||||||
|
if (sweep_en == 1)
|
||||||
|
{
|
||||||
|
//clock divider
|
||||||
|
if (swp_divider_counter != 0) swp_divider_counter--;
|
||||||
|
if (swp_divider_counter == 0)
|
||||||
|
{
|
||||||
|
swp_divider_counter = sweep_divider_cnt + 1;
|
||||||
|
|
||||||
|
//divider was clocked: process sweep pitch bend
|
||||||
|
if (sweep_shiftcount != 0 && !swp_silence)
|
||||||
|
{
|
||||||
|
timer_reload_value = sweep_shifter;
|
||||||
|
timer_raw_reload_value = timer_reload_value * 2 + 2;
|
||||||
|
}
|
||||||
|
//TODO - does this change the user's reload value or the latched reload value?
|
||||||
|
}
|
||||||
|
|
||||||
|
//handle divider reload, after clocking happens
|
||||||
|
if (sweep_reload)
|
||||||
|
{
|
||||||
|
swp_divider_counter = sweep_divider_cnt + 1;
|
||||||
|
sweep_reload = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//env_loopdoubles as "halt length counter"
|
||||||
|
if (env_loop == 0 && len_cnt > 0)
|
||||||
|
len_cnt--;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clock_env()
|
public void clock_env()
|
||||||
|
@ -131,7 +170,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
env_divider--;
|
if(env_divider != 0) env_divider--;
|
||||||
if (env_divider == 0)
|
if (env_divider == 0)
|
||||||
{
|
{
|
||||||
env_divider = (env_cnt_value + 1);
|
env_divider = (env_cnt_value + 1);
|
||||||
|
@ -162,7 +201,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
duty_step = (duty_step + 1) & 7;
|
duty_step = (duty_step + 1) & 7;
|
||||||
//reload timer
|
//reload timer
|
||||||
timer_counter = timer_raw_reload_value + 2;
|
timer_counter = timer_raw_reload_value;
|
||||||
}
|
}
|
||||||
if (PULSE_DUTY[duty_cnt, duty_step] == 1) //we are outputting something
|
if (PULSE_DUTY[duty_cnt, duty_step] == 1) //we are outputting something
|
||||||
{
|
{
|
||||||
|
@ -171,8 +210,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
if (swp_silence)
|
if (swp_silence)
|
||||||
sample = 0;
|
sample = 0;
|
||||||
|
|
||||||
//if (len_cnt==0) //length counter is 0
|
if (len_cnt==0) //length counter is 0
|
||||||
// sample = 0; //silenced
|
sample = 0; //silenced
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sample = 0; //duty cycle is 0, silenced.
|
sample = 0; //duty cycle is 0, silenced.
|
||||||
|
@ -269,7 +308,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
PulseUnit[] pulse = { new PulseUnit(0), new PulseUnit(1) };
|
PulseUnit[] pulse = { new PulseUnit(0), new PulseUnit(1) };
|
||||||
TriangleUnit triangle = new TriangleUnit();
|
TriangleUnit triangle = new TriangleUnit();
|
||||||
|
|
||||||
int sequencer_counter, sequencer_step, sequencer_mode, sequencer_irq_inhibit, sequencer_irq_flag;
|
int sequencer_counter, sequencer_step, sequencer_mode, sequencer_irq_inhibit;
|
||||||
void sequencer_reset()
|
void sequencer_reset()
|
||||||
{
|
{
|
||||||
sequencer_counter = 0;
|
sequencer_counter = 0;
|
||||||
|
@ -308,9 +347,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
if (sequencer_irq_inhibit == 0)
|
if (sequencer_irq_inhibit == 0)
|
||||||
{
|
{
|
||||||
sequencer_irq_flag = 1;
|
nes.irq_apu = true;
|
||||||
//nes.cpu.Interrupt = true;
|
|
||||||
//Console.WriteLine("APU trigger IRQ (cpu needs implementation)");
|
|
||||||
}
|
}
|
||||||
sequencer_step = 0;
|
sequencer_step = 0;
|
||||||
}
|
}
|
||||||
|
@ -349,13 +386,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
triangle.WriteReg(addr - 0x4008, val);
|
triangle.WriteReg(addr - 0x4008, val);
|
||||||
break;
|
break;
|
||||||
case 0x4015:
|
case 0x4015:
|
||||||
pulse[0].lenctr_en = (val & 1);
|
pulse[0].set_lenctr_en(val & 1);
|
||||||
pulse[1].lenctr_en = ((val>>1) & 1);
|
pulse[1].set_lenctr_en((val >> 1) & 1);
|
||||||
break;
|
break;
|
||||||
case 0x4017:
|
case 0x4017:
|
||||||
sequencer_mode = (val>>7)&1;
|
sequencer_mode = (val>>7)&1;
|
||||||
if(((val>>6)&1)==1)
|
sequencer_irq_inhibit = (val >> 6) & 1;
|
||||||
sequencer_irq_inhibit = 0;
|
if (sequencer_irq_inhibit == 1)
|
||||||
|
nes.irq_apu = false;
|
||||||
sequencer_reset();
|
sequencer_reset();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -365,8 +403,22 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
switch (addr)
|
switch (addr)
|
||||||
{
|
{
|
||||||
|
case 0x4015:
|
||||||
|
{
|
||||||
|
//notice a missing bit here. should properly emulate with empty bus
|
||||||
|
//if an interrupt flag was set at the same moment of the read, it will read back as 1 but it will not be cleared.
|
||||||
|
int dmc_irq_flag = 0; //todo
|
||||||
|
int dmc_nonzero = 0; //todo
|
||||||
|
int noise_nonzero = 0; //todo
|
||||||
|
int tri_nonzero = 0; //todo
|
||||||
|
int pulse1_nonzero = pulse[1].IsLenCntNonZero() ? 1 : 0;
|
||||||
|
int pulse0_nonzero = pulse[0].IsLenCntNonZero() ? 1 : 0;
|
||||||
|
int ret = (dmc_irq_flag << 7) | ((nes.irq_apu?1:0) << 6) | (dmc_nonzero << 4) | (noise_nonzero << 3) | (tri_nonzero<<2) | (pulse1_nonzero<<1) | (pulse0_nonzero);
|
||||||
|
nes.irq_apu = false;
|
||||||
|
return (byte)ret;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return 0x00;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,6 +428,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
RunOne();
|
RunOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DiscardSamples()
|
||||||
|
{
|
||||||
|
metaspu.buffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void RunOne()
|
void RunOne()
|
||||||
{
|
{
|
||||||
pulse[0].Run();
|
pulse[0].Run();
|
||||||
|
|
|
@ -23,6 +23,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
CartInfo cart; //the current cart prototype. should be moved into the board, perhaps
|
CartInfo cart; //the current cart prototype. should be moved into the board, perhaps
|
||||||
INESBoard board; //the board hardware that is currently driving things
|
INESBoard board; //the board hardware that is currently driving things
|
||||||
|
|
||||||
|
bool _irq_apu;
|
||||||
|
public bool irq_apu { get { return _irq_apu; } set { _irq_apu = value; sync_irq(); } }
|
||||||
|
void sync_irq()
|
||||||
|
{
|
||||||
|
cpu.IRQ = _irq_apu;
|
||||||
|
}
|
||||||
|
|
||||||
//user configuration
|
//user configuration
|
||||||
int[,] palette = new int[64,3];
|
int[,] palette = new int[64,3];
|
||||||
int[] palette_compiled = new int[64];
|
int[] palette_compiled = new int[64];
|
||||||
|
|
|
@ -46,6 +46,7 @@ namespace BizHawk
|
||||||
public int BufferHeight { get { return 192; } }
|
public int BufferHeight { get { return 192; } }
|
||||||
public int BackgroundColor { get { return 0; } }
|
public int BackgroundColor { get { return 0; } }
|
||||||
public void GetSamples(short[] samples) { }
|
public void GetSamples(short[] samples) { }
|
||||||
|
public void DiscardSamples() { }
|
||||||
private IList<MemoryDomain> memoryDomains;
|
private IList<MemoryDomain> memoryDomains;
|
||||||
public IList<MemoryDomain> MemoryDomains { get { return memoryDomains; } }
|
public IList<MemoryDomain> MemoryDomains { get { return memoryDomains; } }
|
||||||
public MemoryDomain MainMemory { get { return memoryDomains[0]; } }
|
public MemoryDomain MainMemory { get { return memoryDomains[0]; } }
|
||||||
|
|
|
@ -3,5 +3,6 @@
|
||||||
public interface ISoundProvider
|
public interface ISoundProvider
|
||||||
{
|
{
|
||||||
void GetSamples(short[] samples);
|
void GetSamples(short[] samples);
|
||||||
|
void DiscardSamples();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,7 @@ namespace BizHawk.Emulation.Sound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DiscardSamples() { /*TBD*/ }
|
||||||
public void GetSamples(short[] samples)
|
public void GetSamples(short[] samples)
|
||||||
{
|
{
|
||||||
int elapsedCycles = frameStopTime - frameStartTime;
|
int elapsedCycles = frameStopTime - frameStartTime;
|
||||||
|
|
|
@ -416,6 +416,7 @@ namespace BizHawk.Emulation.Sound
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public void DiscardSamples() { /* todo */ }
|
||||||
public void GetSamples(short[] samples)
|
public void GetSamples(short[] samples)
|
||||||
{
|
{
|
||||||
int elapsedCycles = frameStopTime - frameStartTime;
|
int elapsedCycles = frameStopTime - frameStartTime;
|
||||||
|
|
|
@ -23,6 +23,12 @@ namespace BizHawk.Emulation.Sound
|
||||||
private const int TargetExtraSamples = 882;
|
private const int TargetExtraSamples = 882;
|
||||||
private const int MaxExcessSamples = 4096;
|
private const int MaxExcessSamples = 4096;
|
||||||
|
|
||||||
|
public void DiscardSamples()
|
||||||
|
{
|
||||||
|
if(BaseSoundProvider != null)
|
||||||
|
BaseSoundProvider.DiscardSamples();
|
||||||
|
}
|
||||||
|
|
||||||
public void GetSamples(short[] samples)
|
public void GetSamples(short[] samples)
|
||||||
{
|
{
|
||||||
int samplesToGenerate = SamplesInOneFrame;
|
int samplesToGenerate = SamplesInOneFrame;
|
||||||
|
|
|
@ -19,12 +19,17 @@ namespace BizHawk.Emulation.Sound
|
||||||
{
|
{
|
||||||
buffer.output_samples(samples, samples.Length / 2);
|
buffer.output_samples(samples, samples.Length / 2);
|
||||||
}
|
}
|
||||||
|
public void DiscardSamples()
|
||||||
|
{
|
||||||
|
buffer.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
//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
|
||||||
int output_samples(short[] buf, int samples_requested);
|
int output_samples(short[] buf, int samples_requested);
|
||||||
|
@ -69,6 +74,11 @@ namespace BizHawk.Emulation.Sound
|
||||||
//adjustobuf(200,1000)
|
//adjustobuf(200,1000)
|
||||||
bool mixqueue_go = false;
|
bool mixqueue_go = false;
|
||||||
|
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
adjustobuf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
public void enqueue_sample(short left, short right)
|
public void enqueue_sample(short left, short right)
|
||||||
{
|
{
|
||||||
adjustobuf.enqueue(left, right);
|
adjustobuf.enqueue(left, right);
|
||||||
|
@ -122,12 +132,7 @@ namespace BizHawk.Emulation.Sound
|
||||||
{
|
{
|
||||||
minLatency = _minLatency;
|
minLatency = _minLatency;
|
||||||
maxLatency = _maxLatency;
|
maxLatency = _maxLatency;
|
||||||
rollingTotalSize = 0;
|
clear();
|
||||||
targetLatency = (maxLatency + minLatency)/2;
|
|
||||||
rate = 1.0f;
|
|
||||||
cursor = 0.0f;
|
|
||||||
curr[0] = curr[1] = 0;
|
|
||||||
kAverageSize = 80000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float rate, cursor;
|
float rate, cursor;
|
||||||
|
@ -137,6 +142,19 @@ namespace BizHawk.Emulation.Sound
|
||||||
public int size = 0;
|
public int size = 0;
|
||||||
short[] curr = new short[2];
|
short[] curr = new short[2];
|
||||||
|
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
buffer.Clear();
|
||||||
|
statsHistory.Clear();
|
||||||
|
rollingTotalSize = 0;
|
||||||
|
targetLatency = (maxLatency + minLatency) / 2;
|
||||||
|
rate = 1.0f;
|
||||||
|
cursor = 0.0f;
|
||||||
|
curr[0] = curr[1] = 0;
|
||||||
|
kAverageSize = 80000;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void enqueue(short left, short right)
|
public void enqueue(short left, short right)
|
||||||
{
|
{
|
||||||
buffer.Enqueue(left);
|
buffer.Enqueue(left);
|
||||||
|
@ -244,6 +262,11 @@ namespace BizHawk.Emulation.Sound
|
||||||
return new ssamp((short)lrv,(short)rrv);
|
return new ssamp((short)lrv,(short)rrv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
sampleQueue.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
static void emit_sample(short[] outbuf, ref int cursor, ssamp sample)
|
static void emit_sample(short[] outbuf, ref int cursor, ssamp sample)
|
||||||
{
|
{
|
||||||
outbuf[cursor++] = sample.l;
|
outbuf[cursor++] = sample.l;
|
||||||
|
|
|
@ -24,6 +24,12 @@ namespace BizHawk.Emulation.Sound
|
||||||
SoundProviders.Remove(source);
|
SoundProviders.Remove(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DiscardSamples()
|
||||||
|
{
|
||||||
|
foreach (var soundSource in SoundProviders)
|
||||||
|
soundSource.DiscardSamples();
|
||||||
|
}
|
||||||
|
|
||||||
public void GetSamples(short[] samples)
|
public void GetSamples(short[] samples)
|
||||||
{
|
{
|
||||||
foreach (var soundSource in SoundProviders)
|
foreach (var soundSource in SoundProviders)
|
||||||
|
|
|
@ -38,6 +38,7 @@ namespace BizHawk.Emulation.Sound
|
||||||
OPLL_writeReg(opll, register, value);
|
OPLL_writeReg(opll, register, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DiscardSamples() { }
|
||||||
public void GetSamples(short[] samples)
|
public void GetSamples(short[] samples)
|
||||||
{
|
{
|
||||||
for (int i=0; i<samples.Length;)
|
for (int i=0; i<samples.Length;)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DiscardSamples() { }
|
||||||
public void GetSamples(short[] samples)
|
public void GetSamples(short[] samples)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
@ -125,12 +125,19 @@ namespace BizHawk.MultiClient
|
||||||
cmdRom = arg;
|
cmdRom = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdRom != null) //Commandline should always override auto-load
|
if (cmdRom != null)
|
||||||
|
{
|
||||||
|
//Commandline should always override auto-load
|
||||||
LoadRom(cmdRom);
|
LoadRom(cmdRom);
|
||||||
|
if (Global.Game == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Failed to load rom specified on commandline");
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (Global.Config.AutoLoadMostRecentRom && !Global.Config.RecentRoms.IsEmpty())
|
else if (Global.Config.AutoLoadMostRecentRom && !Global.Config.RecentRoms.IsEmpty())
|
||||||
LoadRomFromRecent(Global.Config.RecentRoms.GetRecentFileByPosition(0));
|
LoadRomFromRecent(Global.Config.RecentRoms.GetRecentFileByPosition(0));
|
||||||
|
|
||||||
if (cmdLoadState != null)
|
if (cmdLoadState != null && Global.Game != null)
|
||||||
LoadState("QuickSave" + cmdLoadState);
|
LoadState("QuickSave" + cmdLoadState);
|
||||||
|
|
||||||
if (Global.Config.AutoLoadRamWatch)
|
if (Global.Config.AutoLoadRamWatch)
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace BizHawk.MultiClient
|
||||||
private byte[] SoundBuffer;
|
private byte[] SoundBuffer;
|
||||||
private const int BufferSize = 4410 * 2 * 2; // 1/10th of a second, 2 bytes per sample, 2 channels;
|
private const int BufferSize = 4410 * 2 * 2; // 1/10th of a second, 2 bytes per sample, 2 channels;
|
||||||
//private int SoundBufferPosition; //TODO: use this
|
//private int SoundBufferPosition; //TODO: use this
|
||||||
|
bool needDiscard;
|
||||||
|
|
||||||
private BufferedAsync semisync = new BufferedAsync();
|
private BufferedAsync semisync = new BufferedAsync();
|
||||||
|
|
||||||
|
@ -48,6 +49,8 @@ namespace BizHawk.MultiClient
|
||||||
if(IsPlaying)
|
if(IsPlaying)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
needDiscard = true;
|
||||||
|
|
||||||
DSoundBuffer.Write(SoundBuffer, 0, LockFlags.EntireBuffer);
|
DSoundBuffer.Write(SoundBuffer, 0, LockFlags.EntireBuffer);
|
||||||
|
|
||||||
DSoundBuffer.CurrentPlayPosition = 0;
|
DSoundBuffer.CurrentPlayPosition = 0;
|
||||||
|
@ -112,7 +115,10 @@ namespace BizHawk.MultiClient
|
||||||
public void UpdateSound(ISoundProvider soundProvider)
|
public void UpdateSound(ISoundProvider soundProvider)
|
||||||
{
|
{
|
||||||
if (Global.Config.SoundEnabled == false || disposed)
|
if (Global.Config.SoundEnabled == false || disposed)
|
||||||
return;
|
{
|
||||||
|
soundProvider.DiscardSamples();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int samplesNeeded = SNDDXGetAudioSpace()*2;
|
int samplesNeeded = SNDDXGetAudioSpace()*2;
|
||||||
if (samplesNeeded == 0)
|
if (samplesNeeded == 0)
|
||||||
|
@ -121,11 +127,12 @@ namespace BizHawk.MultiClient
|
||||||
short[] samples = new short[samplesNeeded];
|
short[] samples = new short[samplesNeeded];
|
||||||
//Console.WriteLine(samplesNeeded/2);
|
//Console.WriteLine(samplesNeeded/2);
|
||||||
|
|
||||||
if (soundProvider != null && Muted == false)
|
if (soundProvider != null && Muted == false)
|
||||||
{
|
{
|
||||||
semisync.BaseSoundProvider = soundProvider;
|
semisync.BaseSoundProvider = soundProvider;
|
||||||
semisync.GetSamples(samples);
|
semisync.GetSamples(samples);
|
||||||
}
|
}
|
||||||
|
else soundProvider.DiscardSamples();
|
||||||
|
|
||||||
int cursor = soundoffset;
|
int cursor = soundoffset;
|
||||||
for (int i = 0; i < samples.Length; i++)
|
for (int i = 0; i < samples.Length; i++)
|
||||||
|
|
|
@ -364,6 +364,10 @@ namespace M6502
|
||||||
w.WriteLine(" TriggerException(ExceptionType.NMI);");
|
w.WriteLine(" TriggerException(ExceptionType.NMI);");
|
||||||
w.WriteLine(" NMI = false;");
|
w.WriteLine(" NMI = false;");
|
||||||
w.WriteLine(" }");
|
w.WriteLine(" }");
|
||||||
|
w.WriteLine(" if (IRQ && !FlagI)");
|
||||||
|
w.WriteLine(" {");
|
||||||
|
w.WriteLine(" TriggerException(ExceptionType.IRQ);");
|
||||||
|
w.WriteLine(" }");
|
||||||
w.WriteLine("");
|
w.WriteLine("");
|
||||||
|
|
||||||
w.WriteLine(" if(debug) Console.WriteLine(State());");
|
w.WriteLine(" if(debug) Console.WriteLine(State());");
|
||||||
|
|
Loading…
Reference in New Issue