Deluge Firmware 1.3.0
Build date: 2026.10.14
Loading...
Searching...
No Matches
cv_engine.h
1/*
2 * Copyright © 2015-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 "model/drum/gate_drum.h"
21#include <cstdint>
22
23struct InterruptsDisabled;
24
25#define WHICH_GATE_OUTPUT_IS_RUN 2
26#define WHICH_GATE_OUTPUT_IS_CLOCK 3
27
28const uint8_t gatePort[] = {2, 2, 2, 4};
29const uint8_t gatePin[] = {7, 8, 9, 0};
30
31class CVChannel {
32public:
33 CVChannel() {
34 noteCurrentlyPlaying = -32768;
35 voltsPerOctave = 100;
36 transpose = 0;
37 cents = 0;
38 pitchBend = 0;
39 }
40 int16_t noteCurrentlyPlaying;
41 uint8_t voltsPerOctave;
42 int8_t transpose;
43 int8_t cents;
44 int32_t
45 pitchBend; // (1 << 23) represents one semitone. So full 32-bit range can be +-256 semitones. This is different
46 // to the equivalent calculation in Voice, which needs to get things into a number of octaves.
47};
48
49class GateChannel {
50public:
51 GateChannel() { on = false; }
52 bool on; // Means either on now, or "awaiting" switch-on
53 GateType mode;
54 uint32_t timeLastSwitchedOff;
55};
56
60 uint8_t mask{0};
61 uint8_t levels{0};
62 uint8_t cvWaitMask{0};
63 bool needsMinOffTime{false};
64};
65
66class CVEngine {
67public:
68 CVEngine();
69 void init();
70 void sendNote(bool on, uint8_t channel, int16_t note = -32768);
71 void setGateType(uint8_t whichGate, GateType value);
72 void setCVVoltsPerOctave(uint8_t channel, uint8_t value);
73 void setCVTranspose(uint8_t channel, int32_t semitones, int32_t cents);
74 void setCVPitchBend(uint8_t channel, int32_t value, bool outputToo = true);
75 int32_t calculateVoltage(int32_t note, uint8_t channel);
76 void physicallySwitchGate(int32_t channel);
77 // release any gates which were held while CV is pending now that it's done
78 void cvOutUpdated(const InterruptsDisabled&);
79
80 void analogOutTick();
81 void playbackBegun();
82 void playbackEnded();
84 void updateClockOutput();
85 void updateRunOutput();
86 bool isTriggerClockOutputEnabled();
88 void updateGateOutputs();
91 GateOutputs takePendingGateOutputs(bool includeAsap);
93 void outputGates(const GateOutputs& outputs, const InterruptsDisabled&);
94
95 bool isAnythingButRunPending() const { return (pendingGates & ~pendingAsapGates) != 0; }
96 bool isAnythingPending() const { return pendingGates != 0; }
97 GateChannel gateChannels[NUM_GATE_CHANNELS];
98
99 CVChannel cvChannels[NUM_PHYSICAL_CV_CHANNELS];
100
101 uint8_t minGateOffTime; // in 100uS's
102
103 bool clockState;
104
105 // When one or more note-on is pending, this is the latest time that one of them last switched off.
106 // But it seems I only use this very coarsely - more to see if we're still in the same audio frame than to measure
107 // time exactly. This could be improved.
108 uint32_t mostRecentSwitchOffTimeOfPendingNoteOn;
109
110 void sendVoltageOut(uint8_t channel, uint16_t voltage);
111
112 inline bool isNoteOn(int32_t channel, int32_t note) {
113 return (gateChannels[channel].on && cvChannels[channel].noteCurrentlyPlaying == note);
114 }
115
116private:
117 void recalculateCVChannelVoltage(uint8_t channel);
118 void switchGateOff(int32_t channel);
119 void switchGateOn(int32_t channel, int32_t doInstantlyIfPossible = false);
121 void switchGateNow(int32_t channel);
122 uint8_t gateLevel(int32_t channel) const {
123 // setOutputState is inverted - sending true turns the gate off
124 return gateChannels[channel].on == (gateChannels[channel].mode == GateType::S_TRIG);
125 }
127 bool cvOutPending{false};
129 uint8_t pendingGates{0};
135 uint8_t gatesAwaitingCV{0};
136 uint8_t levelsAwaitingCV{0};
137};
138
139extern CVEngine cvEngine;
Definition cv_engine.h:31
Definition cv_engine.h:66
void outputGates(const GateOutputs &outputs, const InterruptsDisabled &)
physically output a snapshot of gates
Definition cv_engine.cpp:127
void switchGateNow(int32_t channel)
physically switch a gate right now, superseding any pending or scheduled output for it
Definition cv_engine.cpp:145
void updateGateOutputs()
physically send all pending gate outs right now
Definition cv_engine.cpp:93
bool cvOutPending
signifies there's a gate that can't go until the cv is output
Definition cv_engine.h:127
uint8_t pendingGates
bitmask of gate channels which have changed but haven't been taken for output yet
Definition cv_engine.h:129
void updateClockOutput()
toggles clock, does not physically update until updateGateOutputs called
Definition cv_engine.cpp:367
uint8_t pendingNoteOnGates
subset of pendingGates which are deferred note-ons (must wait for CV and respect minGateOffTime)
Definition cv_engine.h:133
uint8_t pendingAsapGates
subset of pendingGates which should go asap (run signal), respecting minGateOffTime
Definition cv_engine.h:131
GateOutputs takePendingGateOutputs(bool includeAsap)
Definition cv_engine.cpp:104
uint8_t gatesAwaitingCV
gates whose scheduled time has passed but are being held until their cv is output
Definition cv_engine.h:135
Definition cv_engine.h:49
Definition cv_engine.h:59
uint8_t cvWaitMask
channels in mask which can't switch until any pending CV has been sent
Definition cv_engine.h:62
uint8_t levels
pin level for each channel in mask
Definition cv_engine.h:61
bool needsMinOffTime
contains a note-on which must respect minGateOffTime
Definition cv_engine.h:63
uint8_t mask
bitmask of gate channels to physically switch
Definition cv_engine.h:60