ym2612: Implement detune. Implement a somewhat better resampler, still not a Good One.

This commit is contained in:
beirich 2012-08-19 04:41:34 +00:00
parent 43518a3a57
commit 4ba8fcf227
3 changed files with 119 additions and 17 deletions

View File

@ -189,7 +189,7 @@ namespace BizHawk.Emulation.Sound
switch (register & 0xF0)
{
case 0x20: WriteLowBlock(register, value); break;
case 0x30: Write_MUL_DT1(chan, oper, value); break;
case 0x30: Write_MUL_DT(chan, oper, value); break;
case 0x40: Write_TL(chan, oper, value); break;
case 0x50: Write_AR_KS(chan, oper, value); break;
case 0x60: Write_DR_AM(chan, oper, value); break;
@ -208,7 +208,7 @@ namespace BizHawk.Emulation.Sound
switch (register & 0xF0)
{
case 0x30: Write_MUL_DT1(chan, oper, value); break;
case 0x30: Write_MUL_DT(chan, oper, value); break;
case 0x40: Write_TL(chan, oper, value); break;
case 0x50: Write_AR_KS(chan, oper, value); break;
case 0x60: Write_DR_AM(chan, oper, value); break;
@ -353,12 +353,12 @@ namespace BizHawk.Emulation.Sound
channel.LeftOutput = (value & 0x80) != 0;
}
void Write_MUL_DT1(int chan, int op, byte value)
void Write_MUL_DT(int chan, int op, byte value)
{
if (chan < 0) return;
var oper = Channels[chan].Operators[op];
oper.MUL_Multiple = value & 15;
oper.DT1_Detune = (value >> 4) & 7;
oper.DT_Detune = (value >> 4) & 7;
}
public void Write_TL(int chan, int op, byte value)
@ -519,7 +519,7 @@ namespace BizHawk.Emulation.Sound
}
// ====================================================================================
// Envelope Generator
// Support Tables
// ====================================================================================
#region tables
@ -616,8 +616,48 @@ namespace BizHawk.Emulation.Sound
0x000, 0x020, 0x040, 0x060, 0x080, 0x0A0, 0x0C0, 0x0E0,
0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x1C0, 0x3FF
};
static readonly int[] detuneTable =
{
0, 0, 1, 2, // Key-Code 0
0, 0, 1, 2, // Key-Code 1
0, 0, 1, 2, // Key-Code 2
0, 0, 1, 2, // Key-Code 3
0, 1, 2, 2, // Key-Code 4
0, 1, 2, 3, // Key-Code 5
0, 1, 2, 3, // Key-Code 6
0, 1, 2, 3, // Key-Code 7
0, 1, 2, 4, // Key-Code 8
0, 1, 3, 4, // Key-Code 9
0, 1, 3, 4, // Key-Code 10
0, 1, 3, 5, // Key-Code 11
0, 2, 4, 5, // Key-Code 12
0, 2, 4, 6, // Key-Code 13
0, 2, 4, 6, // Key-Code 14
0, 2, 5, 7, // Key-Code 15
0, 2, 5, 8, // Key-Code 16
0, 3, 6, 8, // Key-Code 17
0, 3, 6, 9, // Key-Code 18
0, 3, 7, 10, // Key-Code 19
0, 4, 8, 11, // Key-Code 20
0, 4, 8, 12, // Key-Code 21
0, 4, 9, 13, // Key-Code 22
0, 5, 10, 14, // Key-Code 23
0, 5, 11, 16, // Key-Code 24
0, 6, 12, 17, // Key-Code 25
0, 6, 13, 19, // Key-Code 26
0, 7, 14, 20, // Key-Code 27
0, 8, 16, 22, // Key-Code 28
0, 8, 16, 22, // Key-Code 29
0, 8, 16, 22, // Key-Code 30
0, 8, 16, 22 // Key-Code 31
};
#endregion
// ====================================================================================
// Envelope Generator
// ====================================================================================
int egDivisorCounter; // This provides the /3 divisor to run the envelope generator once for every 3 FM sample output ticks.
int egCycleCounter; // This provides a rolling counter of the envelope generator update ticks. (/3 divisor already applied)
@ -755,7 +795,12 @@ namespace BizHawk.Emulation.Sound
default: phaseIncrement <<= op.Block - 1; break;
}
// TODO: Detune
// Apply Detune
int detuneAdjustment = detuneTable[(op.KeyCode * 4) + (op.DT_Detune & 3)];
if ((op.DT_Detune & 4) != 0)
detuneAdjustment = -detuneAdjustment;
phaseIncrement += detuneAdjustment;
phaseIncrement &= 0x1FFFF; // mask to 17-bits, which is the current size of the register at this point in the calculation. This allows proper detune overflow.
// Apply MUL
switch (op.MUL_Multiple)
@ -920,7 +965,7 @@ namespace BizHawk.Emulation.Sound
public int KS_KeyScale; // 2 bits
public int SSG_EG; // 4 bits
public int DT1_Detune; // 3 bits
public int DT_Detune; // 3 bits
public int MUL_Multiple; // 4 bits
public bool AM_AmplitudeModulation; // 1 bit
@ -944,7 +989,7 @@ namespace BizHawk.Emulation.Sound
set
{
egAttenuation = value;
if (egAttenuation < 0) egAttenuation = 0;
if (egAttenuation < 0) egAttenuation = 0;
if (egAttenuation > 1023) egAttenuation = 1023;
}
}
@ -984,13 +1029,65 @@ namespace BizHawk.Emulation.Sound
GetSamplesNative(nativeSamples);
// downsample from native output rate to 44100.
// TODO this is not good resampling code. I'm not rightly sure it's even correct as linear interpolation goes.
//CrappyNaiveResampler(nativeSamples, samples);
MaybeBetterDownsampler(nativeSamples, samples);
}
static void CrappyNaiveResampler(short[] input, short[] output)
{
// this is not good resampling code.
int numStereoSamples = output.Length / 2;
int offset = 0;
for (int i = 0; i < numStereoSamples; i++)
{
int nativeOffset = ((i * ntscOutputRate) / 44100) * 2;
samples[offset++] += nativeSamples[nativeOffset++]; // left
samples[offset++] += nativeSamples[nativeOffset]; // right
output[offset++] += input[nativeOffset++]; // left
output[offset++] += input[nativeOffset]; // right
}
}
static double Fraction(double value)
{
return value - Math.Floor(value);
}
static void MaybeBetterDownsampler(short[] input, short[] output)
{
// This is still not a good resampler. But it's better than the other one. Unsure how much difference it makes.
// The difference with this one is that all source samples will be sampled and weighted, none skipped over.
double nativeSamplesPerOutputSample = (double) input.Length / (double) output.Length;
int outputStereoSamples = output.Length / 2;
int inputStereoSamples = input.Length / 2;
int offset = 0;
for (int i = 0; i < outputStereoSamples; i++)
{
double startSample = nativeSamplesPerOutputSample * i;
double endSample = nativeSamplesPerOutputSample * (i+1);
int iStartSample = (int) Math.Floor(startSample);
int iEndSample = (int) Math.Floor(endSample);
double leftSample = 0;
double rightSample = 0;
for (int j = iStartSample; j <= iEndSample; j++)
{
if (j == inputStereoSamples)
break;
double weight = 1.0;
if (j == iStartSample)
weight = 1.0 - Fraction(startSample);
else if (j == iEndSample)
weight = Fraction(endSample);
leftSample += ((double) input[(j * 2) + 0] * weight);
rightSample += ((double) input[(j * 2) + 1] * weight);
}
output[offset++] = (short) leftSample;
output[offset++] = (short) rightSample;
}
}

View File

@ -836,6 +836,7 @@
<None Include="images\atari_controller.png" />
<Content Include="images\logo.ico" />
<None Include="images\Paste.png" />
<Content Include="output\gamedb_sega_md.txt" />
<Content Include="output\gamedb.txt" />
<Content Include="output\gamedb_neshomebrew.txt" />
<Content Include="output\gamedb_pce_cd.txt" />

View File

@ -1404,7 +1404,7 @@ namespace BizHawk.MultiClient
UpdateStatusSlots();
UpdateDumpIcon();
LastState = Global.Emulator.SaveStateBinary();
CaptureRewindState();
return true;
}
@ -2400,9 +2400,9 @@ namespace BizHawk.MultiClient
private void Render()
{
var video = Global.Emulator.VideoProvider;
if (video.BufferHeight != lastHeight || video.BufferWidth != lastWidth)
if (video.BufferHeight != lastHeight || video.VirtualWidth != lastWidth)
{
lastWidth = video.BufferWidth;
lastWidth = video.VirtualWidth;
lastHeight = video.BufferHeight;
FrameBufferResized();
}
@ -2420,14 +2420,18 @@ namespace BizHawk.MultiClient
int borderHeight = Size.Height - renderTarget.Size.Height;
// start at target zoom and work way down until we find acceptable zoom
for (; zoom >= 1; zoom--)
int videoWidth = video.BufferWidth; // just so its initialized
int videoHeight = video.BufferHeight;
for (; zoom >= 1; zoom--)
{
if ((((video.BufferWidth * zoom) + borderWidth) < area.Width) && (((video.BufferHeight * zoom) + borderHeight) < area.Height))
videoWidth = 320 * zoom;
videoHeight = video.BufferHeight * zoom;
if ((videoWidth + borderWidth < area.Width) && (videoHeight + borderHeight < area.Height))
break;
}
// Change size
Size = new Size((video.BufferWidth * zoom) + borderWidth, (video.BufferHeight * zoom + borderHeight));
Size = new Size(videoWidth + borderWidth, videoHeight + borderHeight);
PerformLayout();
Global.RenderPanel.Resized = true;