-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAudioEngine.h
More file actions
101 lines (80 loc) · 4.19 KB
/
AudioEngine.h
File metadata and controls
101 lines (80 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#pragma once
#include "Config.h"
class NetAudio; // forward decl (remote-record source)
enum MicSource : uint8_t { MIC_INTERNAL, MIC_REMOTE };
// ---------------------------------------------------------------------------
// AudioEngine: owns the per-track sample buffers (in PSRAM), handles recording
// from the mic, mixing all tracks with per-track effects, and looping playback
// through the speaker.
// ---------------------------------------------------------------------------
struct Track {
int16_t* buf = nullptr; // PSRAM sample buffer, MAX_SAMPLES int16
uint32_t length = 0; // recorded length in samples (0 = empty)
Fx fx = FX_NONE;
bool muted = false;
bool hasContent() const { return length > 0; }
};
class AudioEngine {
public:
// Allocates the PSRAM buffers. Returns false if PSRAM is exhausted.
bool begin();
// ---- transport (internal mic, two-phase) -------------------------------
void startRecording(uint8_t track); // switches to mic, overwrites the track
void serviceRecording(); // call every loop() while recording
void stopRecording();
// ---- transport (remote mic / StickS3, true overdub) --------------------
void startRemoteRecording(uint8_t track); // keeps playback running
void serviceRemoteRecording(NetAudio& net); // drain network samples
void stopRemoteRecording(); // finalize + (re)start playback
void startPlayback(); // switches to speaker, mixes + loops
void stopPlayback();
// ---- editing -----------------------------------------------------------
void cycleFx(uint8_t track); // next effect for a track
void toggleMute(uint8_t track);
void clearTrack(uint8_t track);
// ---- editing -----------------------------------------------------------
// Mix src into dst (baking src's effect), replace dst, then clear src.
void mergeTracks(uint8_t dst, uint8_t src);
// ---- settings ----------------------------------------------------------
void setVolume(uint8_t v); // 0..255, applies immediately
uint8_t volume() const { return _volume; }
// ---- queries -----------------------------------------------------------
DeckState state() const { return _state; }
uint8_t recordingTrk() const { return _recTrack; }
MicSource micSource() const { return _micSource; }
const Track& track(uint8_t i) const { return _tracks[i]; }
// Progress 0.0..1.0 of the current operation (rec fill / play position).
float progress() const;
uint32_t masterSamples() const { return _masterLen; }
// Master loop / metronome (the first take defines the tempo grid).
bool hasMaster() const { return _masterLoopLen > 0; }
uint32_t masterLoopSamples() const { return _masterLoopLen; }
uint32_t recElapsedMs() const { return millis() - _recStartMs; }
private:
void render(); // (re)build the mixed master buffer
void refreshPlayback(); // re-render + restart if currently playing
// One track's effect-processed sample at global index i (hold = LOFI state).
int32_t effectedSample(const Track& tr, uint32_t i, int16_t& hold) const;
void finalizeTake(); // onset/quantise/align/fade (shared)
void resetMasterIfTrack(uint8_t t); // drop tempo grid when master is reused
// Loop-matching helpers, run once when a take finishes.
uint32_t findOnset(const int16_t* buf, uint32_t len) const;
void applyFades(int16_t* buf, uint32_t len) const;
int32_t bestAlignShift(const int16_t* buf, uint32_t len) const;
void rotateLeft(int16_t* buf, uint32_t len, uint32_t shift) const;
Track _tracks[NUM_TRACKS];
int16_t* _master = nullptr; // mixed loop fed to the speaker
uint32_t _masterLen = 0;
DeckState _state = STATE_IDLE;
MicSource _micSource = MIC_INTERNAL;
uint8_t _volume = MASTER_VOLUME;
uint8_t _recTrack = 0;
uint32_t _recPos = 0;
uint32_t _playStartMs = 0;
uint32_t _recStartMs = 0;
// Tempo grid: the first recorded loop sets the master length; later takes
// are quantised to integer multiples of it so they stay locked.
uint32_t _masterLoopLen = 0;
int8_t _masterTrack = -1;
};
extern AudioEngine Engine;