Deluge Firmware 1.3.0
Build date: 2026.07.07
Loading...
Searching...
No Matches
voice_sample.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 "definitions_cxx.hpp"
21#include "model/sample/sample_low_level_reader.h"
22
23enum class LateStartAttemptStatus {
24 SUCCESS = 0,
25 FAILURE = 1,
26 WAIT = 2,
27};
28class TimeStretcher;
29class SampleCache;
30class Sample;
31class Voice;
33class Source;
34class SampleControls;
35
36class VoiceSample final : public SampleLowLevelReader {
37public:
38 VoiceSample() = default;
39 explicit VoiceSample(VoiceSample& other) = default;
40 // explicit: an implicit conversion here is a footgun. `*voiceSample = SampleLowLevelReader(...)` would silently
41 // build a temporary VoiceSample (with default-null timeStretcher/cache) and memberwise-move it over the live one,
42 // nulling timeStretcher mid-flight and orphaning it (leaking its reasons -> E078, see TimeStretcher::hopEnd).
43 // Assign through the SampleLowLevelReader base subobject instead when you only mean to replace the reader state.
44 explicit VoiceSample(SampleLowLevelReader&& other) : SampleLowLevelReader{std::move(other)} {}
45 ~VoiceSample() override { endTimeStretching(); }
46 VoiceSample& operator=(const VoiceSample& other) = delete;
47 // Deleted: the defaulted memberwise move-assign would overwrite timeStretcher/cache without endTimeStretching(),
48 // leaking whatever the destination currently owns. VoiceSamples are pool-managed and referenced by pointer, so no
49 // object-level move-assign is needed; if one ever is, give it a body that releases resources first.
50 VoiceSample& operator=(VoiceSample&& other) = delete;
51
52 void noteOn(SamplePlaybackGuide* guide, uint32_t samplesLate, int32_t priorityRating);
53 bool noteOffWhenLoopEndPointExists(Voice* voice, VoiceSamplePlaybackGuide* voiceSource);
54
55 void setupCacheLoopPoints(SamplePlaybackGuide* voiceSource, Sample* sample, LoopType loopingType);
56 LateStartAttemptStatus attemptLateSampleStart(SamplePlaybackGuide* voiceSource, Sample* sample,
57 int64_t rawSamplesLate, int32_t numSamples = 0);
58 void endTimeStretching();
59 bool render(SamplePlaybackGuide* guide, int32_t* oscBuffer, int32_t numSamples, Sample* sample, int32_t numChannels,
60 LoopType loopingType, int32_t phaseIncrement, int32_t timeStretchRatio, int32_t amplitude,
61 int32_t amplitudeIncrement, int32_t bufferSize, InterpolationMode desiredInterpolationMode,
62 int32_t priorityRating);
63 void beenUnassigned(bool wontBeUsedAgain);
64
65 // AudioClips don't obey markers because they "fudge" instead.
66 // Or if fudging can't happen cos no pre-margin, then
67 // AudioClip::doTickForward() manually forces restart.
68 [[nodiscard]] bool shouldObeyMarkers() const override {
69 return (cache == nullptr && timeStretcher == nullptr && !forAudioClip);
70 }
71
72 void readSamplesResampledPossiblyCaching(int32_t** oscBufferPos, int32_t** oscBufferRPos, int32_t numSamples,
73 Sample* sample, int32_t jumpAmount, int32_t numChannels,
74 int32_t numChannelsAfterCondensing, int32_t phaseIncrement,
75 int32_t* sourceAmplitudeNow, int32_t amplitudeIncrement,
76 int32_t bufferSize, int32_t reduceMagnitudeBy = 1);
77
78 bool sampleZoneChanged(SamplePlaybackGuide* voiceSource, Sample* sample, bool reversed, MarkerType markerType,
79 LoopType loopingType, int32_t priorityRating, bool forAudioClip = false);
80 int32_t getPlaySample(Sample* sample, SamplePlaybackGuide* guide);
81 bool stopUsingCache(SamplePlaybackGuide* guide, Sample* sample, int32_t priorityRating, bool loopingAtLowLevel);
82 bool possiblySetUpCache(SampleControls* sampleControls, SamplePlaybackGuide* guide, int32_t phaseIncrement,
83 int32_t timeStretchRatio, int32_t priorityRating, LoopType loopingType);
84 bool fudgeTimeStretchingToAvoidClick(Sample* sample, SamplePlaybackGuide* guide, int32_t phaseIncrement,
85 int32_t numSamplesTilLoop, int32_t playDirection, int32_t priorityRating);
86
87 uint32_t pendingSamplesLate = 0; // This isn't used for AudioClips. And for samples in STRETCH mode, the exact
88 // number isn't relevant - it gets recalculated
89 TimeStretcher* timeStretcher = nullptr;
90
91 SampleCache* cache = nullptr;
92 bool doneFirstRenderYet = false;
93 bool fudging = false;
94 bool forAudioClip = false; // This is a wee bit of a hack - but we need to be able to know this
95 bool writingToCache = false; // Value is only valid if cache assigned
96
97private:
98 bool weShouldBeTimeStretchingNow(Sample* sample, SamplePlaybackGuide* guide, int32_t numSamples,
99 int32_t phaseIncrement, int32_t timeStretchRatio, int32_t playDirection,
100 int32_t priorityRating, LoopType loopingType);
101 void switchToReadingCacheFromWriting();
102 bool stopReadingFromCache();
103
104 int32_t cacheBytePos = 0;
105 uint32_t cacheLoopLengthBytes = 0;
106 int32_t cacheLoopEndPointBytes = 0; // 2147483647 means no looping. Will be set to sample end-point if looping
107 // there. Gets re-set to 2147483647 when note "released"
108 int32_t cacheEndPointBytes = 0; // Will sometimes be the whole length of the sample. Wherever the red marker is. Or
109 // a little further if it's the full length of the sample, to allow for timestretch
110 // / interpolation ring-out
111};
Definition sample_cache.h:25
Definition sample_controls.h:22
Definition sample_playback_guide.h:28
Definition sample.h:50
Definition source.h:31
Definition time_stretcher.h:37
Definition voice_sample_playback_guide.h:28
Definition voice.h:35