Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
transport_source.hpp
Go to the documentation of this file.
1#pragma once
2
6
8
9#include <algorithm>
10#include <cstdint>
11
12namespace pulp::audio {
13
26public:
28
31 source_ = source;
32 playing_ = false;
33 current_gain_ = target_gain_;
34 }
35
36 PositionableAudioSource* source() const { return source_; }
37
38 // ── Transport ──────────────────────────────────────────────────────────
39
40 void start() { playing_ = (source_ != nullptr); }
41 void stop() { playing_ = false; }
42 bool is_playing() const { return playing_; }
43
47 void set_gain(float new_gain) { target_gain_ = new_gain; }
48 float gain() const { return target_gain_; }
49 float current_gain() const { return current_gain_; }
50
51 // ── AudioSource ────────────────────────────────────────────────────────
52
53 void prepare_to_play(int samples_per_block, double sample_rate) override {
54 samples_per_block_ = samples_per_block;
55 sample_rate_ = sample_rate;
56 if (source_) source_->prepare_to_play(samples_per_block, sample_rate);
57 current_gain_ = target_gain_;
58 }
59
60 void release_resources() override {
61 if (source_) source_->release_resources();
62 }
63
65 int start_sample,
66 int num_samples) override {
67 if (num_samples <= 0 || out.num_channels() == 0) return;
68
69 // Stopped or no source → silence + still advance the gain
70 // ramp toward target so resuming doesn't snap.
71 if (!playing_ || !source_) {
72 fill_silence(out, start_sample, num_samples);
73 current_gain_ = target_gain_;
74 return;
75 }
76
77 source_->get_next_audio_block(out, start_sample, num_samples);
78
79 // Apply per-sample ramp from current_gain_ → target_gain_.
80 const float total_step = target_gain_ - current_gain_;
81 if (total_step == 0.0f) {
82 // Constant scale — fast path.
83 if (current_gain_ != 1.0f) {
84 scale_block(out, start_sample, num_samples, current_gain_);
85 }
86 return;
87 }
88 const float step = total_step / static_cast<float>(num_samples);
89 float g = current_gain_;
90 for (std::size_t ch = 0; ch < out.num_channels(); ++ch) {
91 float* ptr = out.channel_ptr(ch) + start_sample;
92 float local_g = g;
93 for (int i = 0; i < num_samples; ++i) {
94 ptr[i] *= local_g;
95 local_g += step;
96 }
97 }
98 current_gain_ = target_gain_;
99 }
100
101 // ── PositionableAudioSource pass-through ───────────────────────────────
102
103 void set_next_read_position(uint64_t new_position) override {
104 if (source_) source_->set_next_read_position(new_position);
105 }
106 uint64_t get_next_read_position() const override {
107 return source_ ? source_->get_next_read_position() : 0;
108 }
109 uint64_t get_total_length() const override {
110 return source_ ? source_->get_total_length() : 0;
111 }
112 bool is_looping() const override {
113 return source_ ? source_->is_looping() : false;
114 }
115 void set_looping(bool should_loop) override {
116 if (source_) source_->set_looping(should_loop);
117 }
118
119private:
120 static void fill_silence(BufferView<float> out, int start, int count) {
121 for (std::size_t ch = 0; ch < out.num_channels(); ++ch) {
122 float* ptr = out.channel_ptr(ch) + start;
123 for (int i = 0; i < count; ++i) ptr[i] = 0.0f;
124 }
125 }
126 static void scale_block(BufferView<float> out, int start, int count, float g) {
127 for (std::size_t ch = 0; ch < out.num_channels(); ++ch) {
128 float* ptr = out.channel_ptr(ch) + start;
129 for (int i = 0; i < count; ++i) ptr[i] *= g;
130 }
131 }
132
133 PositionableAudioSource* source_ = nullptr;
134 bool playing_ = false;
135 float current_gain_ = 1.0f;
136 float target_gain_ = 1.0f;
137 int samples_per_block_ = 0;
138 double sample_rate_ = 0.0;
139};
140
141} // namespace pulp::audio
float gain() const
Definition transport_source.hpp:48
void get_next_audio_block(BufferView< float > out, int start_sample, int num_samples) override
Fill num_samples of out, starting at start_sample within out.
Definition transport_source.hpp:64
void release_resources() override
Called when playback is finished.
Definition transport_source.hpp:60
float current_gain() const
Definition transport_source.hpp:49
bool is_playing() const
Definition transport_source.hpp:42
void set_next_read_position(uint64_t new_position) override
Move the read head to new_position (frames from the start of the source).
Definition transport_source.hpp:103
void set_source(PositionableAudioSource *source)
Bind a source (or nullptr to detach). Resets gain ramp state.
Definition transport_source.hpp:30
void stop()
Definition transport_source.hpp:41
void set_gain(float new_gain)
Set the target gain.
Definition transport_source.hpp:47
void start()
Definition transport_source.hpp:40
void prepare_to_play(int samples_per_block, double sample_rate) override
Called before playback begins.
Definition transport_source.hpp:53
PositionableAudioSource * source() const
Definition transport_source.hpp:36
void set_looping(bool should_loop) override
Enable / disable looping.
Definition transport_source.hpp:115
uint64_t get_next_read_position() const override
Current frame position the next get_next_audio_block call will read from.
Definition transport_source.hpp:106
uint64_t get_total_length() const override
Total length in frames. 0 means "unknown" or "infinite".
Definition transport_source.hpp:109
bool is_looping() const override
True if the source should wrap back to 0 when it reaches the end.
Definition transport_source.hpp:112
Non-owning view over multi-channel audio sample data.
Definition buffer.hpp:30
std::size_t num_channels() const
Definition buffer.hpp:83
SampleType * channel_ptr(std::size_t index)
Raw pointer to one channel's sample data.
Definition buffer.hpp:68
AudioSource with a notion of position.
Definition source.hpp:60
Definition analyzer_provider.hpp:12
Audio source hierarchy — abstract bases for streaming audio playback graphs.