Deluge Firmware 1.3.0
Build date: 2025.04.16
Loading...
Searching...
No Matches
sample_recorder.h
1/*
2 * Copyright © 2016-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/envelope_follower/absolute_value.h"
22#include "dsp/stereo_sample.h"
23#include "fatfs/fatfs.hpp"
24#include <cstddef>
25#include <gsl/gsl>
26#include <optional>
27
28enum class MonitoringAction {
29 NONE = 0,
30 REMOVE_RIGHT_CHANNEL = 1,
31 SUBTRACT_RIGHT_CHANNEL = 2,
32};
33
34enum class RecorderStatus {
35 CAPTURING_DATA = 0,
36 CAPTURING_DATA_WAITING_TO_STOP = 1,
37 FINISHED_CAPTURING_BUT_STILL_WRITING = 2,
38 COMPLETE = 3,
39
40 // Means RAM error only. SD errors are noted separately and won't affect operation, as long as RAM lasts
41 ABORTED = 4,
42 AWAITING_DELETION = 5,
43};
44
45class Sample;
46class Cluster;
47class AudioClip;
48class Output;
49class SampleRecorder {
50public:
51 SampleRecorder() = default;
52 ~SampleRecorder();
53 Error setup(int32_t newNumChannels, AudioInputChannel newMode, bool newKeepingReasons,
54 bool shouldRecordExtraMargins, AudioRecordingFolder newFolderID, int32_t buttonPressLatency,
55 Output* outputRecordingFrom);
56 void setRecordingThreshold();
57 void feedAudio(std::span<StereoSample> input, bool applyGain = false, uint8_t gainToApply = 5);
58 Error cardRoutine();
59 void endSyncedRecording(int32_t buttonLatencyForTempolessRecording);
60 bool inputLooksDifferential();
61 bool inputHasNoRightChannel();
62 void removeFromOutput() {
63 if (status < RecorderStatus::FINISHED_CAPTURING_BUT_STILL_WRITING) {
64 abort();
65 }
66 outputRecordingFrom = nullptr;
67 };
68 void abort();
69
70 SampleRecorder* next;
71
72 gsl::owner<Sample*> sample;
73
74 int32_t numSamplesToRunBeforeBeginningCapturing;
75 uint32_t numSamplesBeenRunning;
76 uint32_t numSamplesCaptured;
77
78 uint32_t numSamplesExtraToCaptureAtEndSyncingWise;
79
80 int32_t firstUnwrittenClusterIndex = 0;
81
82 // Put things in valid state so if we get destructed before any recording, it's all ok
83 int32_t currentRecordClusterIndex = -1;
84
85 // Note! If this is NULL, that means that currentRecordClusterIndex refers to a cluster that never got created (cos
86 // some error or max file size reached)
87 Cluster* currentRecordCluster = nullptr;
88
89 uint32_t audioFileNumber;
90 AudioRecordingFolder folderID;
91
92 char* writePos;
93 char* clusterEndPos;
94
95 // When this gets set, we add the Sample to the master list. This is stored here in addition to in the Sample,
96 // so we can delete an aborted file even after the Sample has been detached / destructed.
97 // This will be the temp file path if there is one.
98 String filePathCreated;
99
100 RecorderStatus status = RecorderStatus::CAPTURING_DATA;
101 AudioInputChannel mode;
102 Output* outputRecordingFrom; // for when recording from a specific output
103
104 // Need to keep track of this, so we know whether to remove it. Well I guess we could just look and see if it's
105 // there... but this is nice.
106 bool haveAddedSampleToArray = false;
107
108 bool allowFileAlterationAfter = false;
109 bool allowNormalization = true;
110 bool autoDeleteWhenDone = false;
111 bool keepingReasonsForFirstClusters;
112 uint8_t recordingNumChannels;
113 bool hadCardError = false;
114 bool reachedMaxFileSize = false;
115 bool recordingExtraMargins = false;
116 bool pointerHeldElsewhere = false;
117 bool capturedTooMuch = false;
118 bool thresholdRecording = false;
119
120 // Most of these are not captured in the case of BALANCED input for AudioClips
121 bool recordingClippedRecently;
122 int32_t recordPeakL;
123 int32_t recordPeakR;
124 int32_t recordPeakLMinusR;
125 uint64_t recordSumL;
126 uint64_t recordSumR;
127 uint64_t recordSumLPlusR; // L and R are halved before these two are calculated
128 uint64_t recordSumLMinusR; // --------
129
130 int32_t recordMax;
131 int32_t recordMin;
132
133 uint32_t audioDataLengthBytesAsWrittenToFile;
134 uint32_t loopEndSampleAsWrittenToFile;
135
136 float startValueThreshold;
137
138 int32_t* sourcePos;
139
140 std::optional<FatFS::File> file;
141
142private:
143 void setExtraBytesOnPreviousCluster(Cluster* currentCluster, int32_t currentClusterIndex);
144 Error writeCluster(int32_t clusterIndex, size_t numBytes);
145 Error alterFile(MonitoringAction action, int32_t lshiftAmount, uint32_t idealFileSizeBeforeAction,
146
147 uint64_t dataLengthAfterAction);
148 Error finalizeRecordedFile();
149 Error createNextCluster();
150 Error writeAnyCompletedClusters();
151 void finishCapturing();
152 void updateDataLengthInFirstCluster(Cluster* cluster);
153 void totalSampleLengthNowKnown(uint32_t totalLength, uint32_t loopEndPointSamples = 0);
154 void detachSample();
155 Error truncateFileDownToSize(uint32_t newFileSize);
156 Error writeOneCompletedCluster();
157 AbsValueFollower envelopeFollower{};
158};
Definition absolute_value.h:24
Definition audio_clip.h:35
Definition cluster.h:34
Definition output.h:81
Definition sample.h:50
Definition d_string.h:46