Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
forge_sidechain_catalog.hpp
Go to the documentation of this file.
1#pragma once
2
3// Sidechain — Forge-facing bake-layer catalog nodes.
4//
5// Port 0 is the audible signal and port 1 is the external detector/key. The
6// implementation is the shipped Compressor::process_with_sidechain path.
7
8#include <pulp/host/detail/forge_compressor_ballistics.hpp>
13
14#include <algorithm>
15#include <cmath>
16#include <cstddef>
17
19
20inline constexpr const char* kTypeId = "sidechain.compressor";
21inline constexpr PortIndex kSignalPort = 0;
22inline constexpr PortIndex kKeyPort = 1;
23
24inline constexpr state::ParamID kThresholdDb = 1;
25inline constexpr state::ParamID kRatio = 2;
26inline constexpr state::ParamID kAttackMs = 3;
27inline constexpr state::ParamID kReleaseMs = 4;
28inline constexpr state::ParamID kKneeDb = 5;
29inline constexpr state::ParamID kMakeupDb = 6;
30inline constexpr state::ParamID kKeyHpfHz = 7;
31inline constexpr state::ParamID kBallistics = 8;
32
37
40 t.type_id = kTypeId;
41 t.version = 1;
42 t.num_input_ports = 2;
43 t.num_output_ports = 1;
44 t.default_name = "Sidechain Compressor";
45 t.lowerable = true;
46
47 t.create = []() -> void* { return new Instance{}; };
48 t.destroy = [](void* p) { delete static_cast<Instance*>(p); };
49 t.prepare = [](void* p, double sample_rate, int /*max_block*/) {
50 static_cast<Instance*>(p)->compressor.set_sample_rate(static_cast<float>(sample_rate));
51 };
52 t.reset = [](void* p) { static_cast<Instance*>(p)->compressor.reset(); };
53
54 t.baked_params.push_back({kThresholdDb, -60.0f, 0.0f, -18.0f});
55 t.baked_params.push_back({kRatio, 1.0f, 20.0f, 4.0f});
56 t.baked_params.push_back({kAttackMs, 0.1f, 100.0f, 10.0f});
57 t.baked_params.push_back({kReleaseMs, 10.0f, 1000.0f, 150.0f});
58 t.baked_params.push_back({kKneeDb, 0.0f, 24.0f, 6.0f});
59 t.baked_params.push_back({kMakeupDb, -24.0f, 12.0f, 0.0f});
60 t.baked_params.push_back({kKeyHpfHz, 0.0f, 2000.0f, 0.0f});
61 // ballistics: 0 branching (default, as before the control existed), 1 decoupled.
62 t.baked_params.push_back({kBallistics, 0.0f, 1.0f, 0.0f});
63
64 t.process_instance_baked_param = [](void* p, audio::BufferView<float>& out,
65 const audio::BufferView<const float>& in, int n,
66 const BakedParamView& params) {
67 auto* s = static_cast<Instance*>(p);
68 const float* main_input = in.channel_ptr(kSignalPort);
69 const float* key = in.channel_ptr(kKeyPort);
70 float* output = out.channel_ptr(0);
71
72 signal::Compressor::Params cp;
73 cp.threshold_db = params.value_at(kThresholdDb, 0);
74 cp.ratio = std::max(1.0f, params.value_at(kRatio, 0));
75 cp.attack_ms = params.value_at(kAttackMs, 0);
76 cp.release_ms = params.value_at(kReleaseMs, 0);
77 cp.knee_db = params.value_at(kKneeDb, 0);
78 cp.makeup_db = params.value_at(kMakeupDb, 0);
79 s->compressor.set_params(cp);
80 s->compressor.set_ballistics(
81 forge_compressor::ballistics_for(params.value_at(kBallistics, 0)));
82 const float key_hpf_hz = params.value_at(kKeyHpfHz, 0);
83 if (key_hpf_hz != s->key_hpf_hz) {
84 s->key_hpf_hz = key_hpf_hz;
85 s->compressor.set_sidechain_hpf_hz(key_hpf_hz);
86 }
87
88 // Every control above is block-rate, so the block runs through the
89 // compressor's buffer path. That path writes the output in place, so a
90 // key that shares the output buffer falls back to the per-sample path.
91 if (output == key) {
92 for (int k = 0; k < n; ++k) {
93 output[static_cast<std::size_t>(k)] = s->compressor.process_with_sidechain(
94 main_input[static_cast<std::size_t>(k)], key[static_cast<std::size_t>(k)]);
95 }
96 return;
97 }
98 if (output != main_input)
99 std::copy_n(main_input, n, output);
100 s->compressor.process_with_sidechain(output, key, n);
101 };
102 return t;
103}
104
106 return {
107 "sidechain_compressor",
108 "Sidechain Compressor",
109 "A compressor whose gain reduction follows a separate external key signal.",
110 {},
111 {{"default", kTypeId}},
112 {
113 {"threshold_db", kThresholdDb, "Threshold", "dB",
114 "Key-signal level above which gain reduction begins.", ForgeParamKind::continuous,
116 {"ratio", kRatio, "Ratio", ":1", "Gain-reduction ratio above threshold.",
118 {"attack_ms", kAttackMs, "Attack", "ms", "Time for compression to engage.",
120 {"release_ms", kReleaseMs, "Release", "ms", "Time for compression to recover.",
122 {"knee_db", kKneeDb, "Knee", "dB", "Width of the soft-knee transition.",
124 {"makeup_db", kMakeupDb, "Makeup", "dB", "Output gain applied after compression.",
126 {"key_hpf_hz", kKeyHpfHz, "Key HPF", "Hz",
127 "High-pass cutoff that reduces low-frequency key sensitivity; zero disables it.",
129 forge_compressor::ballistics_descriptor(kBallistics),
130 },
131 };
132}
133
134inline float worst_case_gain() {
135 return std::pow(10.0f, 12.0f / 20.0f);
136}
137
138} // namespace pulp::host::sidechain
Non-owning view over multi-channel audio sample data.
Definition buffer.hpp:30
Definition custom_node_type.hpp:51
std::uint32_t PortIndex
Definition graph_types.hpp:8
Definition forge_sidechain_catalog.hpp:18
CustomNodeType make_sidechain_compressor_node()
Definition forge_sidechain_catalog.hpp:38
constexpr PortIndex kKeyPort
Definition forge_sidechain_catalog.hpp:22
constexpr state::ParamID kThresholdDb
Definition forge_sidechain_catalog.hpp:24
constexpr state::ParamID kReleaseMs
Definition forge_sidechain_catalog.hpp:27
ForgeNodeDescriptor descriptor()
Definition forge_sidechain_catalog.hpp:105
constexpr state::ParamID kKneeDb
Definition forge_sidechain_catalog.hpp:28
constexpr PortIndex kSignalPort
Definition forge_sidechain_catalog.hpp:21
constexpr state::ParamID kAttackMs
Definition forge_sidechain_catalog.hpp:26
constexpr const char * kTypeId
Definition forge_sidechain_catalog.hpp:20
constexpr state::ParamID kMakeupDb
Definition forge_sidechain_catalog.hpp:29
float worst_case_gain()
Definition forge_sidechain_catalog.hpp:134
constexpr state::ParamID kKeyHpfHz
Definition forge_sidechain_catalog.hpp:30
constexpr state::ParamID kBallistics
Definition forge_sidechain_catalog.hpp:31
constexpr state::ParamID kRatio
Definition forge_sidechain_catalog.hpp:25
@ continuous
Definition forge_param_descriptor.hpp:25
@ logarithmic
Definition forge_param_descriptor.hpp:29
@ linear
Definition forge_param_descriptor.hpp:29
CompressorT< float > Compressor
Definition compressor.hpp:425
uint32_t ParamID
Unique parameter identifier, stable across plugin versions.
Definition parameter.hpp:55
Definition custom_node_type.hpp:90
Definition forge_param_descriptor.hpp:127
Definition forge_sidechain_catalog.hpp:33
signal::Compressor compressor
Definition forge_sidechain_catalog.hpp:34
float key_hpf_hz
Definition forge_sidechain_catalog.hpp:35