feat: the frequency shifter, a ring modulator at sideband zero, over a Hilbert pair #148
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
bcox/tymbal!148
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "shifter"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds a frequency shifter, with the ring modulator as one setting of it, as the twelfth layer kind: the next effect from #105. It does not close that issue.
What it is
dsp/hilbert.h: a Hilbert pair, two chains of eight one-multiply allpass sections whose outputs sit a quarter turn apart across the band. Its coefficient table,dsp/hilbert_coeffs.h, is generated:materials/hilbert.hholds the elliptic design indouble,bazel run //tools:hilbert_gen > dsp/hilbert_coeffs.hrewrites it, and//materials:hilbert_testfails when the two disagree. It is a primitive of its own because the mono-to-stereo widener and barber-pole phasing both wait on one.dsp/shifter_layer.h: a stereo single-sideband shifter over that pair.sidebandruns from -1 (shift down) through 0 (both sidebands, which is ring modulation) to +1 (shift up). The carrier is linear in hertz and signed, so it sweeps through zero; it can follow the key, bend and glide included. It has its own dry path, as the phaser does, and the dry is the raw input, so a small shift at half mix gives notches that travel.mirrorsends the two sides to opposite sidebands andstereo_phaseoffsets the right side's carrier.Also in the branch: the resolver, format (
SHFT, minor 2.9), patch-diff walker, editor page, and one factory patch,shifter-return(bank 62 to 63).Where it departs from the design
The spec is brought to what was built; the ledger has the measurements.
Coeffstep a sample, 64,881 samples. With the gain at zero the pair has no loop around it, so a released voice freeing is a property of the arithmetic. Held notes render bit-identically to before the change. The cost is a shorter release tail at high feedback: at 0.99 the last audible sample comes at 0.22 to 0.42 of the held tail's length over the three carriers tried; at 0.5 nothing changes. Nobody has heard this.Measured
sizeof(VoiceType)unchanged at 794,528; the layer is 952 bytes.--config=opt,//plugin:instrument_bench, three runs on the laptop, ns per voice per sample: chorus 58.0–60.7, phaser at 12 stages 131.4–137.3, shifter 135.8–140.6, shifter with a tracked carrier 137.3–139.1. No fabric price is stated.What it does not touch
dsp/va_*.h,dsp/layer_strip.h,dsp/mod_ops.h,dsp/mod_matrix.h,dsp/voice_allocator.h,dsp/svf.h,dsp/phase.h,dsp/lfo.h,dsp/sine.h,dsp/phaser_layer.h,dsp/layer.h,resolve/va*.h,patches/poly800_strings.h, or anything underfabric/,rtl/,hps/.plugin/render_golden_test.ccandfabric/master_pin_test.ccare unmoved.Verification
On the branch's final tree:
bazel test //...: 322 of 322 pass.bazel test --config=opt //...: 322 of 322 pass.Before the review's last two commits, which change tests, comments and docs only (not re-run after them):
--config=asan //...and--config=ubsan //...: 322 of 322 each.--config=tsanon the five scoped targets: 5 of 5.An independent review found no defect in the code. It re-ran fourteen injections, two of which failed nothing or failed only the medium target; both now fail a named test in the small one, along with the four rounding sites and a legato note-on taking an edited field. It traced two anomalies the builders had left: the returned lines sitting 3.01 dB under what mix alone gives is the center pan law, and the lower sideband rising at feedback 0.9 is the loop clipping.
Known, and left
shifter-return(0.5 Hz up, mix one half, feedback +0.25, a quarter turn of stereo phase) are starting values.format/project_test.cc's fixture puts every factory patch on a channel and asserts the bank fits in 64; the 65th patch trips that test's build, not the product.//patches:auditionwrites a silent wav for every return, this one included.Spec, plan and ledger:
docs/superpowers/{specs,plans,ledgers}/2026-10-05-frequency-shifter*.md.🤖 Generated with Claude Code