Files
es5-clap/src/plugin.h
T
sub 6a117a9ba9 Initial CLAP plugin scaffold for ES-5 encoder
Implements the full encoding pipeline for Expert Sleepers ES-5 with
ESX-8GT (gate) and ESX-8CV (CV) expanders as a native CLAP plugin.

Encoder logic ported from Expert Sleepers' MIT-licensed Pure Data
externals (https://github.com/expertsleepersltd/externals).

- ES-5 encoder: packs 6 × 8-bit header values into stereo 24-bit audio
- ESX-8GT encoder: 8 boolean gates → 1 byte
- ESX-8CV encoder: 8 × 12-bit CV values via 64-phase state machine
- 54 automatable parameters (6 header types + 48 gate/CV values)
- State save/load for preset support
- Builds on Linux (tested), macOS, and Windows
2026-03-21 01:43:32 +01:00

77 lines
2.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ES-5 CLAP Plugin — Bitwig-native encoder for Expert Sleepers ES-5 + ESX expanders
// Copyright (c) 2026 Sub-Net e.U. — MIT License
#pragma once
#include <clap/helpers/plugin.hh>
#include <clap/helpers/plugin.hxx>
#include <clap/helpers/host-proxy.hh>
#include <clap/helpers/host-proxy.hxx>
#include <array>
#include "encoders.h"
// Header type enum (matches parameter stepped values)
enum class HeaderType : int { Off = 0, GT = 1, CV = 2 };
// Parameter ID scheme:
// 16: Header type (Off/GT/CV)
// 101108: Header 1 values
// 201208: Header 2 values
// ...
// 601608: Header 6 values
constexpr uint32_t NUM_HEADERS = 6;
constexpr uint32_t CHANNELS_PER_HEADER = 8;
constexpr uint32_t TOTAL_PARAMS = NUM_HEADERS + NUM_HEADERS * CHANNELS_PER_HEADER; // 54
constexpr clap_id headerTypeParamId(uint32_t header) { return header + 1; }
constexpr clap_id headerValueParamId(uint32_t header, uint32_t ch) {
return (header + 1) * 100 + ch + 1;
}
class ES5Plugin : public clap::helpers::Plugin<
clap::helpers::MisbehaviourHandler::Terminate,
clap::helpers::CheckingLevel::Maximal>
{
public:
ES5Plugin(const clap_plugin_descriptor *desc, const clap_host *host);
// --- Audio Ports ---
bool implementsAudioPorts() const noexcept override { return true; }
uint32_t audioPortsCount(bool isInput) const noexcept override;
bool audioPortsInfo(uint32_t index, bool isInput,
clap_audio_port_info *info) const noexcept override;
// --- Parameters ---
bool implementsParams() const noexcept override { return true; }
uint32_t paramsCount() const noexcept override;
bool paramsInfo(uint32_t paramIndex, clap_param_info *info) const noexcept override;
bool paramsValue(clap_id paramId, double *value) noexcept override;
bool paramsValueToText(clap_id paramId, double value,
char *display, uint32_t size) noexcept override;
bool paramsTextToValue(clap_id paramId, const char *display,
double *value) noexcept override;
void paramsFlush(const clap_input_events *in,
const clap_output_events *out) noexcept override;
// --- State ---
bool implementsState() const noexcept override { return true; }
bool stateSave(const clap_ostream *stream) noexcept override;
bool stateLoad(const clap_istream *stream) noexcept override;
// --- Process ---
clap_process_status process(const clap_process *process) noexcept override;
private:
void handleEvent(const clap_event_header *hdr);
// Parameter storage
std::array<double, NUM_HEADERS> headerTypes_{}; // 0=off, 1=gt, 2=cv
std::array<std::array<double, CHANNELS_PER_HEADER>, NUM_HEADERS> values_{}; // 0.01.0
// Encoder instances
es5::ES5Encoder es5Encoder_;
std::array<es5::ESX8GTEncoder, NUM_HEADERS> gtEncoders_;
std::array<es5::ESX8CVEncoder, NUM_HEADERS> cvEncoders_;
};