From 8d4a7a504576b71dc32c00e5a5b76ce121279f36 Mon Sep 17 00:00:00 2001 From: "5684185+vsariola@users.noreply.github.com" <5684185+vsariola@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:08:12 +0200 Subject: [PATCH] draft a simpler version of the bell eq --- patch.go | 13 +++++++++++++ tracker/presets.go | 1 + vm/go_synth.go | 17 +++++++++++++++++ vm/go_synth_test.go | 1 + vm/opcodes.go | 45 +++++++++++++++++++++++---------------------- 5 files changed, 55 insertions(+), 22 deletions(-) diff --git a/patch.go b/patch.go index b5afee7..d90a85f 100644 --- a/patch.go +++ b/patch.go @@ -206,6 +206,11 @@ var UnitTypes = map[string]([]UnitParameter){ {Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, {Name: "channel", MinValue: 0, MaxValue: 6, CanSet: true, CanModulate: false, DisplayFunc: arrDispFunc(channelNames[:])}}, "sync": []UnitParameter{}, + "eq": []UnitParameter{ + {Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}, + {Name: "frequency", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return filterFrequencyDispFunc(v) }}, + {Name: "bandwidth", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return eqBWdisplayFunc(v) }}, + {Name: "gain", MinValue: 0, Neutral: 64, MaxValue: 128, CanSet: true, CanModulate: true, DisplayFunc: func(v int) (string, string) { return eqGainDisplayFunc(v) }}}, } // compile errors if interface is not implemented. @@ -266,6 +271,13 @@ func filterFrequencyDispFunc(v int) (string, string) { return strconv.FormatFloat(f, 'f', 0, 64), "Hz" } +func eqBWdisplayFunc(v int) (string, string) { + return strconv.FormatFloat(float64(v)/64.*100, 'f', 2, 64), "%" +} +func eqGainDisplayFunc(v int) (string, string) { + + return strconv.FormatFloat(40*(float64(v)/64.-1.), 'f', 2, 64), "dB" +} func compressorTimeDispFunc(v int) (string, string) { alpha := math.Pow(2, -24*float64(v)/128) // alpha is the "smoothing factor" of first order low pass iir sec := -1 / (44100 * math.Log(1-alpha)) // from smoothing factor to time constant, https://en.wikipedia.org/wiki/Exponential_smoothing @@ -435,6 +447,7 @@ var stackUseMonoStereo = map[string][2]StackUse{ {Inputs: [][]int{{0}}, Modifies: []bool{false}, NumOutputs: 1}, {}, }, + "eq": stackUseEffect, } var stackUseSendNoPop = [2]StackUse{ {Inputs: [][]int{{0}}, Modifies: []bool{true}, NumOutputs: 1}, diff --git a/tracker/presets.go b/tracker/presets.go index 11ed1bc..af46c82 100644 --- a/tracker/presets.go +++ b/tracker/presets.go @@ -464,6 +464,7 @@ var defaultUnits = map[string]sointu.Unit{ "compressor": {Type: "compressor", Parameters: map[string]int{"stereo": 0, "attack": 64, "release": 64, "invgain": 64, "threshold": 64, "ratio": 64}}, "send": {Type: "send", Parameters: map[string]int{"stereo": 0, "amount": 64, "voice": 0, "unit": 0, "port": 0, "sendpop": 1}}, "sync": {Type: "sync", Parameters: map[string]int{}}, + "eq": {Type: "eq", Parameters: map[string]int{"stereo": 0, "frequency": 64, "bandwidth": 64, "gain": 64}}, } var defaultInstrument = sointu.Instrument{ diff --git a/vm/go_synth.go b/vm/go_synth.go index 89a3e08..6b87bbb 100644 --- a/vm/go_synth.go +++ b/vm/go_synth.go @@ -594,6 +594,23 @@ func (s *GoSynth) Render(buffer sointu.AudioBuffer, maxtime int) (samples int, r if stereo { stack = append(stack, gain) } + case opEq: + for i := range channels { + inputSample := stack[l-1-i] + w := params[0] * params[0] + alpha := w * params[1] * 2 + A := float32(math.Pow(2, float64(params[2]-.5)*6.643856189774724)) + u := alpha * A + v := alpha / A + + a0, a1, a2 := 1+v, w*w-2, 1-v + b0, b1, b2 := 1+u, a1, 1-u + + output := (b0*inputSample + unit.state[i]) / a0 + unit.state[i] = b1*inputSample - b1*output + unit.state[2+i] + unit.state[2+i] = b2*inputSample - a2*output + stack[l-1-i] = output + } case opSync: break default: diff --git a/vm/go_synth_test.go b/vm/go_synth_test.go index d03b204..60655fc 100644 --- a/vm/go_synth_test.go +++ b/vm/go_synth_test.go @@ -109,6 +109,7 @@ var defaultUnits = map[string]sointu.Unit{ "compressor": {Type: "compressor", Parameters: map[string]int{"stereo": 0, "attack": 64, "release": 64, "invgain": 64, "threshold": 64, "ratio": 64}}, "send": {Type: "send", Parameters: map[string]int{"stereo": 0, "amount": 128, "voice": 0, "unit": 0, "port": 0, "sendpop": 1}}, "sync": {Type: "sync", Parameters: map[string]int{}}, + "eq": {Type: "eq", Parameters: map[string]int{"stereo": 0, "freq": 1000, "q": 10, "gain": 64}}, } var defaultInstrument = sointu.Instrument{ diff --git a/vm/opcodes.go b/vm/opcodes.go index a16263a..a105dea 100644 --- a/vm/opcodes.go +++ b/vm/opcodes.go @@ -12,27 +12,28 @@ const ( opDelay = 8 opDistort = 9 opEnvelope = 10 - opFilter = 11 - opGain = 12 - opHold = 13 - opIn = 14 - opInvgain = 15 - opLoadnote = 16 - opLoadval = 17 - opMul = 18 - opMulp = 19 - opNoise = 20 - opOscillator = 21 - opOut = 22 - opOutaux = 23 - opPan = 24 - opPop = 25 - opPush = 26 - opReceive = 27 - opSend = 28 - opSpeed = 29 - opSync = 30 - opXch = 31 + opEq = 11 + opFilter = 12 + opGain = 13 + opHold = 14 + opIn = 15 + opInvgain = 16 + opLoadnote = 17 + opLoadval = 18 + opMul = 19 + opMulp = 20 + opNoise = 21 + opOscillator = 22 + opOut = 23 + opOutaux = 24 + opPan = 25 + opPop = 26 + opPush = 27 + opReceive = 28 + opSend = 29 + opSpeed = 30 + opSync = 31 + opXch = 32 ) -var transformCounts = [...]int{0, 0, 1, 0, 5, 1, 1, 4, 1, 5, 2, 1, 1, 0, 1, 0, 1, 0, 0, 2, 6, 1, 2, 1, 0, 0, 0, 1, 0, 0, 0} +var transformCounts = [...]int{0, 0, 1, 0, 5, 1, 1, 4, 1, 5, 3, 2, 1, 1, 0, 1, 0, 1, 0, 0, 2, 6, 1, 2, 1, 0, 0, 0, 1, 0, 0, 0}