| 64 | } // namespace |
| 65 | |
| 66 | StripCompPanel::StripCompPanel(AudioEngine* engine, QWidget* parent) |
| 67 | : QWidget(parent) |
| 68 | , m_audio(engine) |
| 69 | { |
| 70 | setWindowTitle("Aetherial Compressor"); |
| 71 | setStyleSheet(kWindowStyle); |
| 72 | resize(kDefaultWidth, kDefaultHeight); |
| 73 | |
| 74 | auto* root = new QVBoxLayout(this); |
| 75 | root->setContentsMargins(8, 0, 8, 8); |
| 76 | root->setSpacing(6); |
| 77 | |
| 78 | auto* titleBar = new EditorFramelessTitleBar; |
| 79 | m_titleBar = titleBar; |
| 80 | root->addWidget(titleBar); |
| 81 | |
| 82 | // Bypass moved to the CHAIN widget's single-click gesture — nothing |
| 83 | // here in the header. |
| 84 | |
| 85 | // ── Main body: knobs column | canvas | meters | makeup/limiter ── |
| 86 | { |
| 87 | auto* body = new QHBoxLayout; |
| 88 | body->setSpacing(8); |
| 89 | |
| 90 | // Knobs column (Ratio / Attack / Release / Knee). |
| 91 | { |
| 92 | auto* col = new QVBoxLayout; |
| 93 | col->setSpacing(4); |
| 94 | |
| 95 | m_ratio = new ClientCompKnob; |
| 96 | m_ratio->setCenterLabelMode(true); |
| 97 | m_ratio->setLabel("Ratio"); |
| 98 | m_ratio->setRange(1.0f, 20.0f); |
| 99 | m_ratio->setDefault(3.0f); |
| 100 | m_ratio->setValueFromNorm([](float n) { |
| 101 | // Exponential — 1:1 at 0, 20:1 at 1, with a gentle curve |
| 102 | // so the middle of the knob lands near 4:1. |
| 103 | return 1.0f * std::pow(20.0f, n); |
| 104 | }); |
| 105 | m_ratio->setNormFromValue([](float v) { |
| 106 | if (v <= 1.0f) return 0.0f; |
| 107 | return std::log(v) / std::log(20.0f); |
| 108 | }); |
| 109 | m_ratio->setLabelFormat([](float v) { |
| 110 | return QString::number(v, 'f', 2) + " :1"; |
| 111 | }); |
| 112 | m_ratio->setFixedSize(76, 76); |
| 113 | col->addWidget(m_ratio); |
| 114 | |
| 115 | m_attack = new ClientCompKnob; |
| 116 | m_attack->setCenterLabelMode(true); |
| 117 | m_attack->setLabel("Attack"); |
| 118 | m_attack->setRange(0.1f, 300.0f); |
| 119 | m_attack->setDefault(20.0f); |
| 120 | m_attack->setValueFromNorm([](float n) { |
| 121 | return 0.1f * std::pow(3000.0f, n); // 0.1 .. 300 ms |
| 122 | }); |
| 123 | m_attack->setNormFromValue([](float v) { |
nothing calls this directly
no test coverage detected