Synthesizer progress

This commit is contained in:
dexy 2022-01-29 03:52:25 +11:00
parent 1371c0390e
commit 4a00d67658
2 changed files with 128 additions and 36 deletions

View File

@ -748,13 +748,17 @@ namespace CodeWalker.Forms
{
//for (int i = 0; i < buffersCopy.Length; i++)
int i = synthesizer.Synth.OutputsIndices[0];
if (i < SynthBufferChart.Series.Count)
try
{
var series = SynthBufferChart.Series[$"B{i}"];
series.Points.Clear();
foreach (var v in buffersCopy[i])
series.Points.AddY(v);
var series = SynthBufferChart.Series.FindByName($"B{i}");
if (series != null)
{
series.Points.Clear();
foreach (var v in buffersCopy[i])
series.Points.AddY(Math.Max(Math.Min(v, 2.0f), -2.0f));//make sure crazy accidental values don't crash it later
}
}
catch { }
}));
};
}

View File

@ -21,7 +21,7 @@ namespace CodeWalker.Utils
public Dat10Synth Synth { get; private set; }
public float[] Registers { get; private set; }
public float[][] Buffers { get; private set; }
public Vector4[] StateBlocks { get; private set; }
public StateBlock[] StateBlocks { get; private set; }
private Dat10Synth.Instruction[] instructions;
private bool stop;
@ -63,7 +63,7 @@ namespace CodeWalker.Utils
instructions = Dat10Synth.DisassembleGetInstructions(synth.Bytecode, synth.Constants, synth.Variables);
Registers = new float[synth.RegistersCount];
Buffers = new float[synth.BuffersCount][];
StateBlocks = new Vector4[synth.StateBlocksCount];
StateBlocks = new StateBlock[synth.StateBlocksCount];
stop = false;
for (int i = 0; i < synth.BuffersCount; i++)
@ -115,8 +115,9 @@ namespace CodeWalker.Utils
Buffers[i][k] = 0.0f;
bool frameFinished = false;
foreach (var inst in instructions)
for (int insti = 0; insti < instructions.Length; insti++)
{
var inst = instructions[insti];
if (frameFinished)
break;
@ -772,14 +773,18 @@ namespace CodeWalker.Utils
case Dat10Synth.Opcode.GATE_SCALAR_SCALAR:
SetRegister(param[0], Gate(GetScalar(param[1]), GetScalar(param[2])));
break;
//case Dat10Synth.Opcode.SMALL_DELAY_FRAC:
// break;
//case Dat10Synth.Opcode.SMALL_DELAY_NON_INTERP:
// break;
//case Dat10Synth.Opcode.SMALL_DELAY_FRAC_FEEDBACK:
// break;
//case Dat10Synth.Opcode.SMALL_DELAY_NON_INTERP_FEEDBACK:
// break;
case Dat10Synth.Opcode.SMALL_DELAY_FRAC:
SmallDelay(GetBuffer(param[0]), GetScalar(param[1]), 0.0f, ref StateBlocks[param[inst.NumberOfInputs].Value], true);
break;
case Dat10Synth.Opcode.SMALL_DELAY_NON_INTERP:
SmallDelay(GetBuffer(param[0]), GetScalar(param[1]), 0.0f, ref StateBlocks[param[inst.NumberOfInputs].Value], false);
break;
case Dat10Synth.Opcode.SMALL_DELAY_FRAC_FEEDBACK:
SmallDelay(GetBuffer(param[0]), GetScalar(param[1]), GetScalar(param[2]), ref StateBlocks[param[3].Value], true);
break;
case Dat10Synth.Opcode.SMALL_DELAY_NON_INTERP_FEEDBACK:
SmallDelay(GetBuffer(param[0]), GetScalar(param[1]), GetScalar(param[2]), ref StateBlocks[param[3].Value], false);
break;
case Dat10Synth.Opcode.TRIGGER_DIFF:
SetRegister(param[0], TriggerDiff(GetScalar(param[1]), GetScalar(param[2]), ref StateBlocks[param[3].Value]));
break;
@ -913,7 +918,7 @@ namespace CodeWalker.Utils
frameFinished = true;
break;
default:
throw new NotImplementedException(inst.Opcode.ToString());
throw new NotImplementedException(inst.Opcode.ToString() + " (line " + (insti + 1).ToString() + ")");
}
}
@ -1049,7 +1054,7 @@ FINISH =>
return (float)Math.Pow(2.0f, (note + 36.376301f) / 12.0f);
}
private void Decimate(float[] buffer, float scalar1, float deltaPerSample, ref Vector4 stateBlock)
private void Decimate(float[] buffer, float scalar1, float deltaPerSample, ref StateBlock stateBlock)
{
// State block:
// X -> t: samples counter, each sample adds deltaPerSample, once it reaches 1.0 the lastSample value is updated
@ -1082,7 +1087,7 @@ FINISH =>
stateBlock.Y = lastSample;
}
private float Counter(bool returnCounter, float setToZeroTrigger, float incrementTrigger, float decrementTrigger, float maxCounter, ref Vector4 stateBlock)
private float Counter(bool returnCounter, float setToZeroTrigger, float incrementTrigger, float decrementTrigger, float maxCounter, ref StateBlock stateBlock)
{
// State block:
// X -> counter value
@ -1128,7 +1133,7 @@ FINISH =>
return valuePercent * threshold * Math.Sign(value);
}
private void Compress(float[] buffer, float scalar1_threshold, float scalar2_ratio, float scalar3_time1, float scalar4_time2, ref Vector4 stateBlock)
private void Compress(float[] buffer, float scalar1_threshold, float scalar2_ratio, float scalar3_time1, float scalar4_time2, ref StateBlock stateBlock)
{
// State block:
// X -> ...
@ -1331,7 +1336,7 @@ FINISH =>
a1 /= a0; a2 /= a0;
}
private void BiquadFilter2Pole(float[] buffer, float b0, float b1, float b2, float a1, float a2, ref Vector4 stateBlock)
private void BiquadFilter2Pole(float[] buffer, float b0, float b1, float b2, float a1, float a2, ref StateBlock stateBlock)
{
// State block:
// X -> ...
@ -1352,7 +1357,7 @@ FINISH =>
stateBlock.Y = stateY;
}
private void BiquadFilter4Pole(float[] buffer, float b0, float b1, float b2, float a1, float a2, ref Vector4 stateBlock)
private void BiquadFilter4Pole(float[] buffer, float b0, float b1, float b2, float a1, float a2, ref StateBlock stateBlock)
{
// State block:
// X -> ...
@ -1382,7 +1387,7 @@ FINISH =>
stateBlock.W = stateW;
}
private void EnvelopeFollower(float[] buffer, float a2, float a3, ref Vector4 stateBlock)
private void EnvelopeFollower(float[] buffer, float a2, float a3, ref StateBlock stateBlock)
{
// State block:
// X -> previous follower value
@ -1411,7 +1416,7 @@ FINISH =>
stateBlock.X = prevFollower;
}
private float EnvelopeFollower(float scalar, float a2, float a3, ref Vector4 stateBlock)
private float EnvelopeFollower(float scalar, float a2, float a3, ref StateBlock stateBlock)
{
// State block:
// X -> previous follower value
@ -1434,12 +1439,12 @@ FINISH =>
return follower;
}
private float TriggerLatch(float value, float triggerLimit, ref Vector4 stateBlock)
private float TriggerLatch(float value, float triggerLimit, ref StateBlock stateBlock)
{
return TriggerLatch(value >= (triggerLimit - 0.000001f), ref stateBlock);
}
private float TriggerLatch(float[] buffer, float triggerLimit, ref Vector4 stateBlock)
private float TriggerLatch(float[] buffer, float triggerLimit, ref StateBlock stateBlock)
{
bool triggered = false;
for (int i = 0; !triggered && i < BufferSize; i++)
@ -1449,7 +1454,7 @@ FINISH =>
return TriggerLatch(triggered, ref stateBlock);
}
private float TriggerLatch(float[] buffer, float[] triggerLimitBuffer, ref Vector4 stateBlock)
private float TriggerLatch(float[] buffer, float[] triggerLimitBuffer, ref StateBlock stateBlock)
{
bool triggered = false;
for (int i = 0; !triggered && i < BufferSize; i++)
@ -1459,7 +1464,7 @@ FINISH =>
return TriggerLatch(triggered, ref stateBlock);
}
private float TriggerLatch(bool triggered, ref Vector4 stateBlock)
private float TriggerLatch(bool triggered, ref StateBlock stateBlock)
{
// State block:
// X -> latch SET
@ -1477,7 +1482,7 @@ FINISH =>
return latch;
}
private float TriggerDiff(float value, float triggerLimit, ref Vector4 stateBlock)
private float TriggerDiff(float value, float triggerLimit, ref StateBlock stateBlock)
{
// State block:
// X -> previous value
@ -1488,7 +1493,7 @@ FINISH =>
return triggered ? 1.0f : 0.0f;
}
private void OscillatorRamp(float[] buffer, ref Vector4 stateBlock)
private void OscillatorRamp(float[] buffer, ref StateBlock stateBlock)
{
// TODO(alexguirre): better names in OSC_RAMP_BUFFER_BUFFER
var stateX = stateBlock.X;
@ -1503,7 +1508,7 @@ FINISH =>
stateBlock.X = stateX;
}
private void OscillatorRamp(float[] buffer, float frequency, ref Vector4 stateBlock)
private void OscillatorRamp(float[] buffer, float frequency, ref StateBlock stateBlock)
{
// TODO(alexguirre): better names in OSC_RAMP_BUFFER_SCALAR
var v1 = frequency / SampleRate;
@ -1518,7 +1523,7 @@ FINISH =>
stateBlock.X = v3;
}
private float OscillatorRamp(float frequency, ref Vector4 stateBlock)
private float OscillatorRamp(float frequency, ref StateBlock stateBlock)
{
// TODO(alexguirre): better names in OSC_RAMP_SCALAR
var v2 = Math.Max(1.0f, frequency / 187.5f);
@ -1535,7 +1540,7 @@ FINISH =>
private enum EnvelopeReleaseType { Linear, Exponential }
private enum EnvelopeTriggerMode { OneShot, Retrigger, Interruptible }
private float EnvelopeGen(Dat10Synth.Opcode envelopeGenOpcode, float[] buffer, ref Vector4 stateBlock, float predelay, float attack, float decay, float sustain, float hold, float release, float trigger)
private float EnvelopeGen(Dat10Synth.Opcode envelopeGenOpcode, float[] buffer, ref StateBlock stateBlock, float predelay, float attack, float decay, float sustain, float hold, float release, float trigger)
{
EnvelopeReleaseType releaseType;
switch (envelopeGenOpcode)
@ -1576,7 +1581,7 @@ FINISH =>
return EnvelopeGen(releaseType, triggerMode, buffer, ref stateBlock, predelay, attack, decay, sustain, hold, release, trigger);
}
private float EnvelopeGen(EnvelopeReleaseType releaseType, EnvelopeTriggerMode triggerMode, float[] buffer, ref Vector4 stateBlock, float predelay, float attack, float decay, float sustain, float hold, float release, float trigger)
private float EnvelopeGen(EnvelopeReleaseType releaseType, EnvelopeTriggerMode triggerMode, float[] buffer, ref StateBlock stateBlock, float predelay, float attack, float decay, float sustain, float hold, float release, float trigger)
{
// State block:
// X -> envelope state : 8 bits | envelope state remaining samples : 24 bits
@ -1783,7 +1788,7 @@ FINISH =>
public float ReleaseActive;
}
private TimedTriggerResult TimedTrigger(Dat10Synth.Opcode envelopeGenOpcode, ref Vector4 stateBlock, float trigger, float predelay, float attack, float decay, float hold, float release)
private TimedTriggerResult TimedTrigger(Dat10Synth.Opcode envelopeGenOpcode, ref StateBlock stateBlock, float trigger, float predelay, float attack, float decay, float hold, float release)
{
EnvelopeTriggerMode triggerMode;
switch (envelopeGenOpcode)
@ -1821,7 +1826,7 @@ FILL_BUFFER R1 => B1 ; timed trigger finished
FILL_BUFFER 0 => B7
FINISH =>
*/
private TimedTriggerResult TimedTrigger(EnvelopeTriggerMode triggerMode, ref Vector4 stateBlock, float trigger, float predelay, float attack, float decay, float hold, float release)
private TimedTriggerResult TimedTrigger(EnvelopeTriggerMode triggerMode, ref StateBlock stateBlock, float trigger, float predelay, float attack, float decay, float hold, float release)
{
// State block:
// X -> envelope state : 8 bits | envelope state remaining samples : 24 bits
@ -2038,6 +2043,89 @@ FINISH =>
outputBuffer[i] = cos * a[i] + sin * b[i];
}
}
private void SmallDelay(float[] buffer, float delaySamples, float feedback, ref StateBlock stateBlock, bool interpolate)
{
feedback = Math.Max(Math.Min(feedback, 1.0f), -1.0f);//just to stop things getting accidentally out of control...
delaySamples = Math.Abs(delaySamples);//should this be clamped to max 8..?
int delaySamplesInt = (int)delaySamples;
float frac = delaySamples - (float)Math.Floor(delaySamples);
for (int i = 0; i < BufferSize; i++)
{
float currSample = buffer[i];
float delayedSample;
int delayed = i + delaySamplesInt;
float s0 = stateBlock[delayed & 7];
if (interpolate)
{
float s1 = stateBlock[(delayed + 1) & 7];
delayedSample = (s1 - s0) * frac + s0;
}
else
{
delayedSample = s0;
}
buffer[i] = delayedSample;
stateBlock[i & 7] = delayedSample * feedback + currSample;
}
}
public struct StateBlock
{
public float X { get; set; }
public float Y { get; set; }
public float Z { get; set; }
public float W { get; set; }
public float A { get; set; }
public float B { get; set; }
public float C { get; set; }
public float D { get; set; }
public float this[int index]
{
get
{
switch (index)
{
default:
case 0: return X;
case 1: return Y;
case 2: return Z;
case 3: return W;
case 4: return A;
case 5: return B;
case 6: return C;
case 7: return D;
}
}
set
{
switch (index)
{
default:
case 0: X = value; break;
case 1: Y = value; break;
case 2: Z = value; break;
case 3: W = value; break;
case 4: A = value; break;
case 5: B = value; break;
case 6: C = value; break;
case 7: D = value; break;
}
}
}
public float[] Values
{
get
{
return new[] { X, Y, Z, W, A, B, C, D };
}
}
}
}
}