Deluge Firmware 1.3.0
Build date: 2025.04.16
Loading...
Searching...
No Matches
audio_engine.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 "dsp/compressor/rms_feedback.h"
22#include "dsp/envelope_follower/absolute_value.h"
23#include "memory/fast_allocator.h"
24#include "memory/object_pool.h"
25#include "model/output.h"
26#include "util/containers.h"
27#include <cstdint>
28#include <memory>
29
30extern "C" {
31#include "fatfs/ff.h"
32}
33
34class Song;
35class StereoSample;
36class Instrument;
37class Sound;
39class LiveInputBuffer;
40class SampleRecorder;
41class Voice;
42class VoiceSample;
43class TimeStretcher;
44class String;
45class SideChain;
46class VoiceVector;
47class Freeverb;
48class Metronome;
51class SoundDrum;
53
54namespace deluge::dsp {
55class Reverb;
56}
57
58/*
59 * ================== Audio rendering ==================
60 *
61 * The Deluge renders its audio in “windows” (or you could more or less say “buffers”),
62 * a certain number of samples long. In fact, the Deluge’s audio output buffer is a circular,
63 * 128-sample one, whose contents are continuously output to the DAC / codec via I2S
64 * (Renesas calls this SSI) at 44,100hz. That buffer is an array called ssiTxBuffer.
65 *
66 * Each time the audio routine, AudioEngine::routine(), is called, the code checks where the
67 * DMA outputting has gotten up to in ssiTxBuffer, considers where its rendering of the previous
68 * “window” had ended at, and so determines how many new samples it may now render and write into
69 * ssiTxBuffer without “getting ahead of itself”.
70 *
71 * This scheme is primarily useful because it regulates CPU load somewhat, for a slight tradeoff
72 * in audio rendering quality (more on that below) by using longer windows for each render. For instance,
73 * if the CPU load is very light (as in, not many sounds playing), rendering a window will happen very fast,
74 * so when the audio routine is finished and is then called again the next time, only say one or two
75 * samples will have been output via DMA to the DAC. This means the next window length is set at just
76 * one or two samples. I.e. lighter CPU load means shorter windows.
77 *
78 * Often the window length will be rounded to a multiple of 4, because various parts of the rendering code
79 * (e.g. oscillator table lookup / interpolation) use Arm NEON optimizations, which are implemented in
80 * a way that happens to perform best working on chunks of 4 samples. Also, and taking precedence over that,
81 * windows will be shortened to always end at the precise audio sample where an event (e.g. note-on)
82 * is to occur on the Deluge’s sequencer.
83 *
84 * The window length has strictly speaking no effect on the output or quality of oscillators
85 * (including sync, FM, ringmod and wavetable), filters, most effects, sample playback, or timings/jitter
86 * from the Deluge’s sequencer. Where it primarily does have a (barely audible) effect is on envelope shapes.
87 * The current “stage” of the envelope (i.e. A, D, S or R) is only recalculated at the beginning of each window,
88 * so the minimum attack, decay or release time is the length of that window, *unless* that parameter
89 * is in fact set to 0, in which case that stage is skipped. So, you can get a 0ms (well, 1 sample) attack time,
90 * but depending on the window length (which depends on CPU load), your 0.1ms attack time could theoretically
91 * get as long as 2.9ms (128 samples), though it would normally end up quite a bit shorter.
92 *
93 * With envelopes (and LFO position actually) only being recalculated at the start of each “window”,
94 * you might be wondering whether you’ll get an audible “zipper” or stepped effect as the output of these
95 * changes sporadically. The answer is, usually not, because most parameters for which this would be audible
96 * (e.g. definitely anything level/volume related) will linearly interpolate their value change throughout
97 * the window, usually using a variable named something to do with “increment”. This is done per parameter,
98 * rather than per modulation source, essentially for ease / performance. Wavetable position and FM amounts
99 * are other important parameters to do this to.
100 *
101 * But for many parameters, the stepping is not audible in the first place, so there is no interpolation.
102 * This includes filter resonance and oscillator / sample-playback pitch. Especially sample-playback
103 * pitch would be very difficult to interpolate this way because the (unchanging) pitch for the window
104 * is used at the start to calculate how many raw audio-samples (i.e. how many bytes) will need to be
105 * read from memory to render the (repitched) audio-sample window.
106 */
107
108/*
109 * ====================== Audio / CPU performance ======================
110 * A huge number of factors influence the performance of a particular Deluge firmware build.
111 * Subpar performance will usually be noticed in the form of sounds dropping out in songs which
112 * performed better in other firmware versions. As an open source contributer, ensuring optimal performance of any code
113 * modifications you make, and subsequently their builds, will be a big challenge. But don’t sweat it too much - if
114 * you’ve added some cool features which are useful to you or others, maybe lowered audio performance is a reasonable
115 * tradeoff?
116 *
117 * The Deluge codebase, since 2021, has been built with GCC 9.2. I (Rohan) compared this with the other 9.x GCC
118 * versions, some 10.x ones, and the 6.x version(s) that the Deluge had used earlier. Performance differences were
119 * negligible in most cases, and ultimately I settled on GCC 9.2 because it resulted in a built binary which was
120 * smaller by a number of kilobytes compared to other versions. GCC 10.x was particularly bad in this regard.
121 *
122 * The build process includes LTO - this helps performance a fair bit. And normal O2 optimization.
123 * These are both disabled in the HardwareDebug build configuration though, for faster build times and
124 * ease of code debugging. If you’re using live code uploading via a J-link and want to do some tests for
125 * real-world performance, you should enable these for this configuration, at least while doing your tests.
126 *
127 * A few other of the standard compiler optimizations are enabled, like –gc-sections to remove unused code from the
128 * build. Beyond that, I’ve experimented with enabling various of the most advanced GCC optimizations, but haven’t found
129 * any that improve overall performance.
130 */
131
133#define DO_AUDIO_LOG 0
134
135namespace AudioEngine {
136using VoicePool = deluge::memory::ObjectPool<Voice, deluge::memory::fast_allocator>;
137using VoiceSamplePool = deluge::memory::ObjectPool<VoiceSample, deluge::memory::fast_allocator>;
138using TimeStretcherPool = deluge::memory::ObjectPool<TimeStretcher, deluge::memory::fast_allocator>;
139
140void routine();
141void routineWithClusterLoading(bool mayProcessUserActionsBetween = false);
142
143void init();
144void previewSample(String* path, FilePointer* filePointer, bool shouldActuallySound);
145void stopAnyPreviewing();
146
147void songSwapAboutToHappen();
148void killAllVoices(bool deletingSong = false);
149void logAction(char const* string);
150void logAction(int32_t number);
151
152void getReverbParamsFromSong(Song* song);
153
154VoiceSample* solicitVoiceSample();
155void voiceSampleUnassigned(VoiceSample* voiceSample);
156
157TimeStretcher* solicitTimeStretcher();
158void timeStretcherUnassigned(TimeStretcher* timeStretcher);
159
160LiveInputBuffer* getOrCreateLiveInputBuffer(OscType inputType, bool mayCreate);
161void slowRoutine();
162void doRecorderCardRoutines();
163
164int32_t getNumSamplesLeftToOutputFromPreviousRender();
165
166void registerSideChainHit(int32_t strength);
167
168SampleRecorder* getNewRecorder(int32_t numChannels, AudioRecordingFolder folderID, AudioInputChannel mode,
169 bool keepFirstReasons, bool writeLoopPoints, int32_t buttonPressLatency,
170 bool shouldNormalize, Output* outputRecordingFrom);
171void discardRecorder(SampleRecorder* recorder);
172bool isAnyInternalRecordingHappening();
173
174#ifdef FLIGHTDATA
175char log[32][64];
176uint8_t logNextIndex = 0;
177uint32_t logAbsoluteIndex = 0;
178char* getEmptyLogEntry();
179void printLog();
180#endif
181int32_t getNumAudio();
182int32_t getNumVoices();
183
184bool doSomeOutputting();
185void updateReverbParams();
186
187extern bool headphonesPluggedIn;
188extern bool micPluggedIn;
189extern bool lineInPluggedIn;
190extern bool renderInStereo;
191extern uint32_t audioSampleTimer;
192extern bool mustUpdateReverbParamsBeforeNextRender;
193extern bool bypassCulling;
194extern uint32_t i2sTXBufferPos;
195extern uint32_t i2sRXBufferPos;
196extern int32_t cpuDireness;
197extern InputMonitoringMode inputMonitoringMode;
198extern bool audioRoutineLocked;
199extern uint8_t numHopsEndedThisRoutineCall;
200extern SideChain reverbSidechain;
201extern uint32_t timeThereWasLastSomeReverb;
202extern deluge::fast_vector<Sound*> sounds;
203extern deluge::dsp::Reverb reverb;
204extern uint32_t nextVoiceState;
205extern SoundDrum* sampleForPreview;
206extern int32_t reverbSidechainVolume;
207extern int32_t reverbSidechainShape;
208extern int32_t reverbPan;
209extern SampleRecorder* firstRecorder;
210extern Metronome metronome;
211extern RMSFeedbackCompressor mastercompressor;
212extern uint32_t timeLastSideChainHit;
213extern int32_t sizeLastSideChainHit;
214extern StereoFloatSample approxRMSLevel;
215extern AbsValueFollower envelopeFollower;
216void feedReverbBackdoorForGrain(int index, q31_t value);
217
219bool allowedToStartVoice();
220} // namespace AudioEngine
Definition absolute_value.h:24
Definition instrument.h:45
Definition live_input_buffer.h:23
Definition metronome.h:26
Definition model_stack.h:287
Definition param_manager.h:174
Definition rms_feedback.h:26
Definition sample_recorder.h:49
Definition sidechain.h:27
Definition song.h:104
Definition sound_drum.h:28
Definition sound.h:71
Definition d_string.h:46
Definition time_stretcher.h:37
Definition voice_sample.h:36
Definition voice.h:35
Definition reverb.hpp:13
Definition stereo_sample.h:25