Deluge Firmware 1.3.0
Build date: 2026.07.15
Loading...
Searching...
No Matches
encoders.h
1/*
2 * Copyright © 2020-2023 Synthstrom Audible Limited
3 *
4 * This file is part of The Synthstrom Audible Deluge Firmware.
5 *
6 * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software Foundation,
8 * either version 3 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with this program.
15 * If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#pragma once
19
20#include "OSLikeStuff/scheduler_api.h"
21#include <atomic>
22#include <cstddef>
23#include <cstdint>
24
25namespace deluge::hid::encoders {
26
29class DetentedEncoder {
30public:
31 DetentedEncoder() = default;
32 DetentedEncoder(const DetentedEncoder&) = delete;
33 DetentedEncoder& operator=(const DetentedEncoder&) = delete;
34
35 void applyEdges(int8_t edges);
36
38 bool pending() const { return pos.load(std::memory_order_relaxed) != 0; }
39
41 int32_t take();
42
45 void restore(int32_t val) { pos.fetch_add(val, std::memory_order_relaxed); }
46
47private:
48 int32_t edgeAccumulator = 0;
49 std::atomic_int32_t pos = 0;
50};
51
53class ContinuousEncoder {
54public:
55 ContinuousEncoder() = default;
56 ContinuousEncoder(const ContinuousEncoder&) = delete;
57 ContinuousEncoder& operator=(const ContinuousEncoder&) = delete;
58
59 void applyEdges(int8_t edges) { pos.fetch_add(edges, std::memory_order_relaxed); }
60
62 bool pending() const { return pos.load(std::memory_order_relaxed) != 0; }
63
65 int8_t take();
66
68 double calcNextKnobSpeed(int8_t offset);
69
70private:
71 std::atomic_int8_t pos = 0;
72 double currentKnobSpeed{0.0}; // Used for encoder acceleration
73};
74
75// ── Named encoder globals ─────────────────────────────────────────────────
76
77extern DetentedEncoder scrollY;
78extern DetentedEncoder scrollX;
79extern DetentedEncoder tempo;
80extern DetentedEncoder select;
81extern ContinuousEncoder mod0;
82extern ContinuousEncoder mod1;
83
84// ── Array-index access for iteration ─────────────────────────────────────
85
86constexpr size_t kNumFunctionEncoders = 4;
87constexpr size_t kNumModEncoders = 2;
88
89DetentedEncoder& functionEncoderAt(size_t i);
90ContinuousEncoder& modEncoderAt(size_t i);
91
92// ── Shared timestamp ──────────────────────────────────────────────────────
93
96extern uint32_t timeModEncoderLastTurned[];
97
98// ── Lifecycle ─────────────────────────────────────────────────────────────
99
100void init();
101
104extern TaskID EncoderTaskID;
105
106} // namespace deluge::hid::encoders
bool pending() const
True if any ticks are waiting to be consumed.
Definition encoders.h:62
int8_t take()
Returns the accumulated tick count and resets pos to 0.
Definition encoders.cpp:47
std::atomic_int8_t pos
Written by the IRQ (applyEdges), drained by the encoder task.
Definition encoders.h:71
double calcNextKnobSpeed(int8_t offset)
Returns multiplier for encoder offset.
Definition encoders.cpp:51
void restore(int32_t val)
Definition encoders.h:45
bool pending() const
True if any detent steps are waiting to be consumed.
Definition encoders.h:38
int32_t edgeAccumulator
Accumulates A-pin edges until we have a full detent click. IRQ-only.
Definition encoders.h:48
int32_t take()
Returns the accumulated signed detent count and resets pos to 0.
Definition encoders.cpp:41
std::atomic_int32_t pos
Written by the IRQ (applyEdges), drained by the encoder task.
Definition encoders.h:49