Torch
Loading...
Searching...
No Matches
SequenceSynth.h
1#pragma once
2
3#ifdef BUILD_UI
4
5#include <cstdint>
6#include <memory>
7#include <vector>
8
9// Game-agnostic offline sequence synthesizer. Drivers interpret their own
10// sequence format into SynthNotes referencing decoded samples, plus per-channel
11// gain automation; Synthesize mixes them into stereo PCM.
12namespace UI {
13
14constexpr int kSynthRate = 32000;
15constexpr double kSynthMaxSeconds = 330.0;
16
17struct SynthSample {
18 std::vector<int16_t> pcm; // decoded, 1:1 with the source sample units
19 uint32_t loopStart = 0;
20 uint32_t loopEnd = 0;
21 bool looped = false;
22};
23
24struct SynthNote {
25 double startSec = 0.0;
26 double soundSec = 0.0; // sounding time before the release begins
27 float freqScale = 1.0f;
28 float gain = 1.0f; // velocity term; channel gain comes from automation
29 float pan = 0.5f; // 0..1
30 int chan = 0;
31 std::shared_ptr<SynthSample> sample;
32 float reverb = 0.0f;
33
34 // Envelope as (time sec, level 0..1) breakpoints; loopStartT >= 0 cycles
35 // the tail. Empty = default fast attack + hold.
36 std::vector<std::pair<float, float>> envPoints;
37 float envLoopStartT = -1.0f;
38
39 // Release is the game's linear fade: full scale to zero in releaseSec.
40 // sustainLevel (0..1) floors the fade at that fraction of the gate-end
41 // level, holds ~0.53s, then resumes.
42 float releaseSec = 0.1f;
43 float sustainLevel = 0.0f;
44 float sustainHoldSec = 128.0f / 240.0f;
45 float vibDelaySec = 0.0f;
46 float vibRampSec = 0.0f;
47 float vibDepthStart = 0.0f;
48 float vibDepthEnd = 0.0f; // semitones
49 float vibRateStartHz = 0.0f;
50 float vibRateEndHz = 0.0f;
51 float vibRateRampSec = 0.0f;
52 float portaRatio = 1.0f; // end/start pitch ratio (1 = none)
53 float portaSec = 0.0f;
54
55 // Legato continuations: pitch/velocity switches without retriggering.
56 struct Seg {
57 float t;
58 float freq;
59 float gainMul;
60 };
61 std::vector<Seg> segs;
62};
63
64// Per-channel (time sec, value) points; applied to notes while they sound.
65// Gain tracks channel/master volume, pitch tracks the channel freq multiplier.
66using GainAutomation = std::vector<std::pair<float, float>>;
67using PitchAutomation = std::vector<std::pair<float, float>>;
68
69struct RenderedAudio {
70 std::vector<int16_t> pcm; // interleaved stereo at kSynthRate
71 size_t noteCount = 0;
72 double seconds = 0.0;
73};
74
75std::vector<int16_t> Synthesize(const std::vector<SynthNote>& notes, const GainAutomation (&gainAuto)[16],
76 const PitchAutomation (&pitchAuto)[16], double lengthSec);
77
78} // namespace UI
79
80#endif // BUILD_UI