Deluge Firmware 1.3.0
Build date: 2026.10.14
Loading...
Searching...
No Matches
sound.h
1/*
2 * Copyright © 2014-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 "definitions_cxx.hpp"
21#include "model/mod_controllable/mod_controllable_audio.h"
22#include "model/sample/sample_recorder.h"
23#include "model/voiced.h"
24#include "modulation/arpeggiator.h"
25#include "modulation/knob.h"
26#include "modulation/lfo.h"
27#include "modulation/params/param.h"
28#include "modulation/params/param_manager.h"
29#include "modulation/params/param_set.h"
30#include "modulation/patch/patcher.h"
31#include "modulation/sidechain/sidechain.h"
32#include "processing/engines/audio_engine.h"
33#include "processing/source.h"
34#include "util/misc.h"
35#include <bitset>
36#include <memory>
37
38struct CableGroup;
39class StereoSample;
40class Voice;
41class Kit;
43class TimelineCounter;
44class Clip;
49
50#define PARAM_LPF_OFF (-1)
51
52struct ParamLPF {
53 int32_t p; // PARAM_LPF_OFF means none
54 int32_t currentValue;
55};
56
57#define NUM_MOD_SOURCE_SELECTION_BUTTONS 2
58
59/*
60 * Sound can be either an Instrument or a Drum, in the form of SoundInstrument or SoundDrum respectively.
61 * These classes are implemented using “multiple inheritance”, which is sacrilegious to many C++ programmers.
62 * I (Rohan) consider it to be a more or less appropriate solution in this case and a few others in the Deluge codebase
63 * where it’s used. It’s a little while though since I’ve sat and thought about what the alternatives could be and
64 * whether anything else would be appropriate.
65 *
66 * Anyway, Sound (which may be named a bit too broadly) basically means a synth or sample, or any combination of the
67 * two. And, to reiterate the above, it can exist as a “synth” as the melodic Output of one entire Clip(s), or as just a
68 * Drum - one of the many items in a Kit, normally associated with a row of notes.
69 */
70
72constexpr int32_t kDefaultSoundVolumeUserValue = 40;
74constexpr int32_t kSampleDrumVelocityCableUserValue = 50;
75
76class Sound : public ModControllableAudio, public virtual Voiced {
77public:
78 using ActiveVoice = AudioEngine::VoicePool::pointer_type;
79
80 Sound();
81 ~Sound() override { std::erase(AudioEngine::sounds, this); }
82
83 Patcher patcher;
84
85 ParamLPF paramLPF{};
86
87 Source sources[kNumSources];
88
89 // This is for the *global* params only, and begins with FIRST_GLOBAL_PARAM, so subtract that from your p value
90 // before accessing this array!
91 std::array<int32_t, deluge::modulation::params::kNumParams - deluge::modulation::params::FIRST_GLOBAL>
92 paramFinalValues{};
93 std::array<int32_t, util::to_underlying(kFirstLocalSource)> globalSourceValues{};
94
95 uint32_t sourcesChanged{}; // Applies from first source up to FIRST_UNCHANGEABLE_SOURCE
96
97 LFO globalLFO1;
98 LFO globalLFO3;
99 LFOConfig lfoConfig[LFO_COUNT];
100
101 bool invertReversed{}; // Used by the arpeggiator to invert the reverse flag just for the current voice
102
103 // December 3, 2024
104 // @todo
105 // Commit 6534979986d465a0acf01018e066e1d7ca1d170e
106 // From PR #2004 (LFO: cleanups in preparation for LFO2 sync support)
107 // (https://github.com/SynthstromAudible/DelugeFirmware/pull/2004)
108 // Removed four uint8_t lfo variables from this section and replaced them with the LFOConfig
109 // definition above. This unknowingly introduced a "release" bug which changed the sound of the
110 // Deluge synth engine compared to 1.1 as reported in issue #2660:
111 // (https://github.com/SynthstromAudible/DelugeFirmware/issues/2660)
112 // As a solution modKnobs is aligned to 8 bytes. I don't know why this fixes the problem but it seems to work even
113 // with other changes to the class. We think the issue relates to the use of "offsetof" in the
114 // param and patcher system (related to the paramFinalValues / globalSourceValues definitions above)
115
116 alignas(8) ModKnob modKnobs[kNumModButtons][kNumPhysicalModKnobs];
117
118 int32_t sideChainSendLevel = 0;
119
120 PolyphonyMode polyphonic = PolyphonyMode::POLY;
121 uint8_t maxVoiceCount = 8;
122
123 int16_t transpose = 0;
124 int8_t cents = 0;
125 PhaseIncrementFineTuner fineTuner;
126
127 uint8_t numUnison = 1;
128 int8_t unisonDetune = 8;
129 uint8_t unisonStereoSpread = 0;
130
131 // For sending MIDI notes for SoundDrums
132 uint8_t outputMidiChannel = MIDI_CHANNEL_NONE;
133 uint8_t outputMidiNoteForDrum = MIDI_NOTE_NONE;
134
135 int16_t modulatorTranspose[kNumModulators] = {0, -12};
136 int8_t modulatorCents[kNumModulators] = {0, 0};
137
138 PhaseIncrementFineTuner modulatorTransposers[kNumModulators];
139
140 PhaseIncrementFineTuner unisonDetuners[kMaxNumVoicesUnison];
141 int32_t unisonPan[kMaxNumVoicesUnison]{};
142
143 SynthMode synthMode = SynthMode::SUBTRACTIVE;
144 bool modulator1ToModulator0 = false;
145
146 int32_t volumeNeutralValueForUnison{0};
147
148 int32_t lastNoteCode = std::numeric_limits<int32_t>::min();
149
150 bool oscillatorSync = false;
151
152 VoicePriority voicePriority = VoicePriority::MEDIUM;
153
154 bool skippingRendering = true;
155
156 std::bitset<kNumExpressionDimensions> expressionSourcesChangedAtSynthLevel{0};
157
158 // I really didn't want to store these here, since they're stored in the ParamManager, but.... complications! Always
159 // 0 for Drums - that was part of the problem - a Drum's main ParamManager's expression data has been sent to the
160 // "polyphonic" bit, and we don't want it to get referred to twice. These get manually refreshed in setActiveClip().
161 std::array<int32_t, kNumExpressionDimensions> monophonicExpressionValues{};
162
163 std::array<uint32_t, kNumSources> oscRetriggerPhase{}; // 4294967295 means "off"
164 std::array<uint32_t, kNumModulators> modulatorRetriggerPhase{};
165
166 uint32_t timeStartedSkippingRenderingModFX{0};
167 uint32_t timeStartedSkippingRenderingLFO{0};
168 uint32_t timeStartedSkippingRenderingArp{0};
169 uint32_t startSkippingRenderingAtTime = 0; // Valid when not 0. Allows a wait-time before render skipping starts,
170 // for if mod fx are on
171
172 virtual ArpeggiatorSettings* getArpSettings(InstrumentClip* clip = nullptr) = 0;
173 virtual void setSkippingRendering(bool newSkipping);
174
175 ModFXType getModFXType() override;
176 bool setModFXType(ModFXType newType) final;
177
178 void patchedParamPresetValueChanged(uint8_t p, ModelStackWithSoundFlags* modelStack, int32_t oldValue,
179 int32_t newValue);
180 void render(ModelStackWithThreeMainThings* modelStack, std::span<StereoSample> output, int32_t* reverbBuffer,
181 int32_t sideChainHitPending, int32_t reverbAmountAdjust = 134217728,
182 bool shouldLimitDelayFeedback = false, int32_t pitchAdjust = kMaxSampleValue,
183 SampleRecorder* recorder = nullptr);
184
185 void ensureInaccessibleParamPresetValuesWithoutKnobsAreZero(Song* song) final; // Song may be NULL
186 void ensureInaccessibleParamPresetValuesWithoutKnobsAreZero(ModelStackWithThreeMainThings* modelStack);
187 void ensureInaccessibleParamPresetValuesWithoutKnobsAreZeroWithMinimalDetails(ParamManager* paramManager);
188 void ensureParamPresetValueWithoutKnobIsZero(ModelStackWithAutoParam* modelStack);
189 void ensureParamPresetValueWithoutKnobIsZeroWithMinimalDetails(ParamManager* paramManager, int32_t p);
190
191 PatchCableAcceptance maySourcePatchToParam(PatchSource s, uint8_t p, ParamManager* paramManager);
192
193 void resyncGlobalLFOs();
194
195 int8_t getKnobPos(uint8_t p, ParamManagerForTimeline* paramManager, uint32_t timePos, TimelineCounter* counter);
196 int32_t getKnobPosBig(int32_t p, ParamManagerForTimeline* paramManager, uint32_t timePos, TimelineCounter* counter);
197 bool learnKnob(MIDICable* cable, ParamDescriptor paramDescriptor, uint8_t whichKnob, uint8_t modKnobMode,
198 uint8_t midiChannel, Song* song) final;
199
200 bool hasFilters();
201
202 void sampleZoneChanged(MarkerType markerType, int32_t s, ModelStackWithSoundFlags* modelStack);
203 void setNumUnison(int32_t newNum, ModelStackWithSoundFlags* modelStack);
204 void setUnisonDetune(int32_t newAmount, ModelStackWithSoundFlags* modelStack);
205 void setUnisonStereoSpread(int32_t newAmount);
206 void setModulatorTranspose(int32_t m, int32_t value, ModelStackWithSoundFlags* modelStack);
207 void setModulatorCents(int32_t m, int32_t value, ModelStackWithSoundFlags* modelStack);
208 Error readFromFile(Deserializer& reader, ModelStackWithModControllable* modelStack, int32_t readAutomationUpToPos,
209 ArpeggiatorSettings* arpSettings);
210 void writeToFile(Serializer& writer, bool savingSong, ParamManager* paramManager, ArpeggiatorSettings* arpSettings,
211 const char* pathAttribute = NULL);
212
213 void voiceUnassigned(ModelStackWithSoundFlags* modelStack);
214 bool isSourceActiveCurrently(int32_t s, ParamManagerForTimeline* paramManager);
215 bool isSourceActiveEverDisregardingMissingSample(int32_t s, ParamManager* paramManager);
216 bool isSourceActiveEver(int32_t s, ParamManager* paramManager);
217 bool isNoiseActiveEver(ParamManagerForTimeline* paramManager);
218 void noteOn(ModelStackWithThreeMainThings* modelStack, ArpeggiatorBase* arpeggiator, int32_t noteCode,
219 int16_t const* mpeValues, uint32_t sampleSyncLength = 0, int32_t ticksLate = 0,
220 uint32_t samplesLate = 0, int32_t velocity = 64, int32_t fromMIDIChannel = 16);
221 void noteOff(ModelStackWithThreeMainThings* modelStack, ArpeggiatorBase* arpeggiator, int32_t noteCode);
222 void allNotesOff(ModelStackWithThreeMainThings* modelStack, ArpeggiatorBase* arpeggiator);
223
224 void noteOffPostArpeggiator(ModelStackWithSoundFlags* modelStack, int32_t noteCode = -32768);
225 void noteOnPostArpeggiator(ModelStackWithSoundFlags* modelStack, int32_t newNoteCodeBeforeArpeggiation,
226 int32_t newNoteCodeAfterArpeggiation, int32_t velocity, int16_t const* mpeValues,
227 uint32_t sampleSyncLength, int32_t ticksLate, uint32_t samplesLate,
228 int32_t fromMIDIChannel = 16);
229 void polyphonicExpressionEventOnChannelOrNote(int32_t newValue, int32_t expressionDimension,
230 int32_t channelOrNoteNumber,
231 MIDICharacteristic whichCharacteristic) override;
232
233 int16_t getMaxOscTranspose(InstrumentClip* clip);
234 int16_t getMinOscTranspose();
235 void setSynthMode(SynthMode value, Song* song);
236 [[nodiscard]] SynthMode getSynthMode() const { return synthMode; }
237
238 virtual bool isDrum() { return false; }
239 void setupAsSample(ParamManagerForTimeline* paramManager);
240 void recalculateAllVoicePhaseIncrements(ModelStackWithSoundFlags* modelStack);
241 void set_cents(int8_t new_cents);
242 Error loadAllAudioFiles(bool mayActuallyReadFiles);
243 bool envelopeHasSustainCurrently(int32_t e, ParamManagerForTimeline* paramManager);
244 bool envelopeHasSustainEver(int32_t e, ParamManagerForTimeline* paramManager);
245 bool renderingOscillatorSyncCurrently(ParamManagerForTimeline* paramManager);
246 bool renderingOscillatorSyncEver(ParamManager* paramManager);
247 void setupAsBlankSynth(ParamManager* paramManager, bool is_dx = false);
248 void setupAsDefaultSynth(ParamManager* paramManager);
249 void modButtonAction(uint8_t whichModButton, bool on, ParamManagerForTimeline* paramManager) final;
250 bool modEncoderButtonAction(uint8_t whichModEncoder, bool on, ModelStackWithThreeMainThings* modelStack) final;
251 static void writeParamsToFile(Serializer& writer, ParamManager* paramManager, bool writeAutomation);
252 static void readParamsFromFile(Deserializer& reader, ParamManagerForTimeline* paramManager,
253 int32_t readAutomationUpToPos);
254 static bool readParamTagFromFile(Deserializer& reader, char const* tagName, ParamManagerForTimeline* paramManager,
255 int32_t readAutomationUpToPos);
256 static void initParams(ParamManager* paramManager);
257 static Error createParamManagerForLoading(ParamManagerForTimeline* paramManager);
258 int32_t hasAnyTimeStretchSyncing(ParamManagerForTimeline* paramManager, bool getSampleLength = false,
259 int32_t note = 0);
260 int32_t hasCutOrLoopModeSamples(ParamManagerForTimeline* paramManager, int32_t note, bool* anyLooping = nullptr);
261 bool hasCutModeSamples(ParamManagerForTimeline* paramManager);
262 bool allowsVeryLateNoteStart(InstrumentClip* clip, ParamManagerForTimeline* paramManager);
263 void fastReleaseAllVoices(ModelStackWithSoundFlags* modelStack);
264 void recalculatePatchingToParam(uint8_t p, ParamManagerForTimeline* paramManager);
265 void doneReadingFromFile();
266 virtual void setupPatchingForAllParamManagers(Song* song) {}
267 void compensateVolumeForResonance(ModelStackWithThreeMainThings* modelStack);
268 // void channelAftertouchReceivedFromInputMIDIChannel(int32_t newValue);
269 ModelStackWithAutoParam* getParamFromModEncoder(int32_t whichModEncoder, ModelStackWithThreeMainThings* modelStack,
270 bool allowCreation = true) final;
271 void reassessRenderSkippingStatus(ModelStackWithSoundFlags* modelStack, bool shouldJustCutModFX = false);
272 void getThingWithMostReverb(Sound** soundWithMostReverb, ParamManager** paramManagerWithMostReverb,
273 GlobalEffectableForClip** globalEffectableWithMostReverb,
274 int32_t* highestReverbAmountFound, ParamManagerForTimeline* paramManager);
275 virtual bool readTagFromFile(Deserializer& reader, char const* tagName) = 0;
276 void detachSourcesFromAudioFiles();
277
278 // Yup, inlining this helped a tiny bit.
279 [[gnu::always_inline]] int32_t getSmoothedPatchedParamValue(int32_t p, ParamManager& paramManager) const {
280 if (paramLPF.p == p) {
281 return paramLPF.currentValue;
282 }
283 return paramManager.getPatchedParamSet()->getValue(p);
284 }
285
286 void notifyValueChangeViaLPF(int32_t p, bool shouldDoParamLPF, ModelStackWithThreeMainThings const* modelStack,
287 int32_t oldValue, int32_t newValue, bool fromAutomation);
288 void deleteMultiRange(int32_t s, int32_t r);
289 void wontBeRenderedForAWhile() override;
291 virtual ArpeggiatorBase* getArp() = 0;
292 void possiblySetupDefaultExpressionPatching(ParamManager* paramManager);
293
294 int32_t getShiftAmountForSaturation() const { return (clippingAmount >= 2) ? (clippingAmount - 2) : 0; }
295
298 [[gnu::always_inline]] void saturate(int32_t* data, uint32_t* workingValue, int32_t shiftAmount) {
299 // Clipping
300 //*data = getTanHUnknown(*data, 5 + clippingAmount) << (shiftAmount);
301 *data = getTanHAntialiased(*data, workingValue, 5 + clippingAmount) << (shiftAmount);
302 }
303 uint32_t getSyncedLFOPhaseIncrement(const LFOConfig& config);
304
306 [[nodiscard]] bool hasActiveVoices() const override { return !voices_.empty(); }
307
309 [[nodiscard]] size_t numActiveVoices() const { return voices_.size(); }
310
312 void killAllVoices() override;
313
316 [[nodiscard]] const ActiveVoice& getLowestPriorityVoice() const;
317
319 [[nodiscard]] const deluge::fast_vector<ActiveVoice>& voices() const { return voices_; }
320
325 void freeActiveVoice(const ActiveVoice& voice, ModelStackWithSoundFlags* modelStack = nullptr, bool erase = true);
326
327 // Voiced overrides
328 bool anyNoteIsOn() override;
329 bool allowNoteTails(ModelStackWithSoundFlags* modelStack, bool disregardSampleLoop = false) override;
330 void prepareForHibernation() override;
331 void process_postarp_notes(ModelStackWithSoundFlags* modelStackWithSoundFlags, ArpeggiatorSettings* arpSettings,
332 ArpReturnInstruction instruction);
333
334 virtual const char* getName() { return nullptr; }
335
336private:
337 uint32_t getGlobalLFOPhaseIncrement(LFO_ID lfoId, deluge::modulation::params::Global param);
338 void recalculateFineTuner();
339 void recalculateModulatorTransposer(uint8_t m, ModelStackWithSoundFlags* modelStack);
340 void setupUnisonDetuners(ModelStackWithSoundFlags* modelStack);
341 void setupUnisonStereoSpread();
342 void calculateEffectiveVolume();
343 void ensureKnobReferencesCorrectVolume(Knob& knob);
344 Error readTagFromFileOrError(Deserializer& reader, char const* tagName, ParamManagerForTimeline* paramManager,
345 int32_t readAutomationUpToPos, ArpeggiatorSettings* arpSettings, Song* song);
346
347 void writeSourceToFile(Serializer& writer, int32_t s, char const* tagName);
348 Error readSourceFromFile(Deserializer& reader, int32_t s, ParamManagerForTimeline* paramManager,
349 int32_t readAutomationUpToPos);
350 void stopSkippingRendering(ArpeggiatorSettings* arpSettings);
351 void startSkippingRendering(ModelStackWithSoundFlags* modelStack);
352 void getArpBackInTimeAfterSkippingRendering(ArpeggiatorSettings* arpSettings);
353 void doParamLPF(int32_t numSamples, ModelStackWithSoundFlags* modelStack);
354 void stopParamLPF(ModelStackWithSoundFlags* modelStack);
355
356 bool renderingVoicesInStereo(ModelStackWithSoundFlags* modelStack);
357 void setupDefaultExpressionPatching(ParamManager* paramManager);
358 void pushSwitchActionOnEncoderForParam(int32_t p, bool on, ModelStackWithThreeMainThings* modelStack);
359 ModelStackWithAutoParam* getParamFromModEncoderDeeper(int32_t whichModEncoder,
360 ModelStackWithThreeMainThings* modelStack,
361 bool allowCreation = true);
362
364 // O(n) lookup is fine when most of the time we're iterating over all voices anyways.
365 // Went with a vector instead of a list so that we don't need to always allocate if
366 // we're constantly cycling between a minimum and maximum number of voices.
367 deluge::fast_vector<ActiveVoice> voices_;
368
372 const ActiveVoice& acquireVoice() noexcept(false); // throws an exception if no memory is available
373
375 void checkVoiceExists(const ActiveVoice& voice, const char* error) const;
376
379 const ActiveVoice& stealOneActiveVoice();
380
383
386};
Definition arpeggiator.h:190
Definition arpeggiator.h:220
Definition arpeggiator.h:48
Definition clip.h:46
Definition storage_manager.h:185
Definition global_effectable_for_clip.h:33
Definition instrument_clip.h:48
Definition kit.h:34
Definition lfo.h:26
Definition lfo.h:35
A MIDI cable connection. Stores all state specific to a given cable and its contained ports and chann...
Definition midi_device.h:96
Definition knob.h:34
Definition knob.h:46
Definition model_stack.h:269
Definition model_stack.h:225
Definition model_stack.h:287
Definition model_stack.h:231
Definition param_descriptor.h:27
Definition param_manager.h:175
Definition param_manager.h:45
Definition patcher.h:38
Definition phase_increment_fine_tuner.h:21
Definition sample_recorder.h:53
Definition storage_manager.h:119
Definition song.h:103
bool hasActiveVoices() const override
Does this sound have any active voices?
Definition sound.h:306
const ActiveVoice & acquireVoice() noexcept(false)
Acquire a voice for use by a note Internally this will either acquire a new voice or steal an existin...
Definition sound.cpp:4902
void terminateOneActiveVoice()
Force a voice to release very quickly - will be almost instant but click-free.
Definition sound.cpp:4968
ModelStackWithAutoParam * getParamFromMIDIKnob(MIDIKnob &knob, ModelStackWithThreeMainThings *modelStack) final
Check that autoParam isn't NULL, after calling this.
Definition sound.cpp:4866
void saturate(int32_t *data, uint32_t *workingValue, int32_t shiftAmount)
Definition sound.h:298
void freeActiveVoice(const ActiveVoice &voice, ModelStackWithSoundFlags *modelStack=nullptr, bool erase=true)
Releases a given voice from the Sound.
Definition sound.cpp:4927
Error readSourceFromFile(Deserializer &reader, int32_t s, ParamManagerForTimeline *paramManager, int32_t readAutomationUpToPos)
Definition sound.cpp:3353
bool learnKnob(MIDICable *cable, ParamDescriptor paramDescriptor, uint8_t whichKnob, uint8_t modKnobMode, uint8_t midiChannel, Song *song) final
Definition sound.cpp:2836
const deluge::fast_vector< ActiveVoice > & voices() const
Get the voices for this sound.
Definition sound.h:319
void killAllVoices() override
Immediately ends all active voices.
Definition sound.cpp:4934
void forceReleaseOneActiveVoice()
Force a voice to release, or speed up its release if it's already releasing.
Definition sound.cpp:5002
const ActiveVoice & getLowestPriorityVoice() const
Get the voice with the lowest priority.
Definition sound.cpp:4944
const ActiveVoice & stealOneActiveVoice()
Steals a currently-in-use voice for use by another note.
Definition sound.cpp:4953
void checkVoiceExists(const ActiveVoice &voice, const char *error) const
Check if a voice exists in the list of active voices.
Definition sound.cpp:5035
deluge::fast_vector< ActiveVoice > voices_
the list of active voices for this sound
Definition sound.h:367
size_t numActiveVoices() const
Get the number of active voices.
Definition sound.h:309
Definition source.h:31
Definition timeline_counter.h:28
Definition voice.h:35
std::unique_ptr< Voice, decltype(&recycle)> pointer_type
Definition object_pool.h:90
Global
Definition param.h:131
constexpr ParamType kNumParams
None is the last global param, 0 indexed so it's also the number of patched params.
Definition param.h:253
Definition patch_cable_set.h:29
Definition sound.h:52
Definition stereo_sample.h:25
Definition voiced.h:21