Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
sample_resource.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <atomic>
7#include <cstdint>
8#include <functional>
9#include <list>
10#include <memory>
11#include <mutex>
12#include <optional>
13#include <string>
14#include <unordered_map>
15#include <utility>
16#include <vector>
17
18namespace pulp::audio {
19
26
29 uint64_t generation = 0;
30 uint64_t frame_count = 0;
31 uint32_t channel_count = 0;
32 uint32_t sample_rate = 0;
33 uint64_t byte_size = 0;
34 uint64_t memory_budget_bytes = 0;
35 std::shared_ptr<const AudioFileData> data;
36
37 bool ready() const noexcept {
38 return status == SampleResourceStatus::Loaded && data && !data->empty();
39 }
40};
41
44 uint64_t generation = 0;
45 std::string path;
46 std::string reason;
47 uint64_t frame_count = 0;
48 uint32_t channel_count = 0;
49 uint32_t sample_rate = 0;
50 uint64_t byte_size = 0;
51 uint64_t memory_budget_bytes = 0;
52};
53
55public:
57 auto current = std::atomic_load_explicit(&snapshot_, std::memory_order_acquire);
58 return current ? *current : SampleResourceSnapshot{};
59 }
61 std::lock_guard lock(diagnostics_mutex_);
62 return diagnostics_;
63 }
64
65 void clear() {
66 publish_snapshot({});
67 std::lock_guard lock(diagnostics_mutex_);
68 diagnostics_ = {};
69 }
70
71 void publish_missing(std::string path, std::string reason) {
72 const auto next_generation = snapshot().generation + 1;
73 publish_snapshot({
75 .generation = next_generation,
76 });
77 std::lock_guard lock(diagnostics_mutex_);
78 diagnostics_ = {
80 .generation = next_generation,
81 .path = std::move(path),
82 .reason = std::move(reason),
83 };
84 }
85
87 std::string path,
88 uint64_t memory_budget_bytes = 0) {
89 const auto byte_size = decoded_byte_size(data);
90 const auto next_generation = snapshot().generation + 1;
91 if (memory_budget_bytes != 0 && byte_size > memory_budget_bytes) {
92 publish_snapshot({
94 .generation = next_generation,
95 .frame_count = data.num_frames(),
96 .channel_count = data.num_channels(),
97 .sample_rate = data.sample_rate,
98 .byte_size = byte_size,
99 .memory_budget_bytes = memory_budget_bytes,
100 });
101 std::lock_guard lock(diagnostics_mutex_);
102 diagnostics_ = {
104 .generation = next_generation,
105 .path = std::move(path),
106 .reason = "decoded sample exceeds memory budget",
107 .frame_count = data.num_frames(),
108 .channel_count = data.num_channels(),
109 .sample_rate = data.sample_rate,
110 .byte_size = byte_size,
111 .memory_budget_bytes = memory_budget_bytes,
112 };
113 return false;
114 }
115
116 auto shared = std::make_shared<AudioFileData>(std::move(data));
117 return publish_loaded(std::move(shared), std::move(path), memory_budget_bytes);
118 }
119
120 bool publish_loaded(std::shared_ptr<const AudioFileData> data,
121 std::string path,
122 uint64_t memory_budget_bytes = 0) {
123 if (!data) {
124 publish_missing(std::move(path), "sample data unavailable");
125 return false;
126 }
127
128 const auto byte_size = decoded_byte_size(*data);
129 const auto next_generation = snapshot().generation + 1;
130 if (memory_budget_bytes != 0 && byte_size > memory_budget_bytes) {
131 publish_snapshot({
133 .generation = next_generation,
134 .frame_count = data->num_frames(),
135 .channel_count = data->num_channels(),
136 .sample_rate = data->sample_rate,
137 .byte_size = byte_size,
138 .memory_budget_bytes = memory_budget_bytes,
139 });
140 std::lock_guard lock(diagnostics_mutex_);
141 diagnostics_ = {
143 .generation = next_generation,
144 .path = std::move(path),
145 .reason = "decoded sample exceeds memory budget",
146 .frame_count = data->num_frames(),
147 .channel_count = data->num_channels(),
148 .sample_rate = data->sample_rate,
149 .byte_size = byte_size,
150 .memory_budget_bytes = memory_budget_bytes,
151 };
152 return false;
153 }
154
157 .generation = next_generation,
158 .frame_count = data->num_frames(),
159 .channel_count = data->num_channels(),
160 .sample_rate = data->sample_rate,
161 .byte_size = byte_size,
162 .memory_budget_bytes = memory_budget_bytes,
163 .data = std::move(data),
164 };
165 publish_snapshot(next);
166 std::lock_guard lock(diagnostics_mutex_);
167 diagnostics_ = {
169 .generation = next_generation,
170 .path = std::move(path),
171 .frame_count = next.frame_count,
172 .channel_count = next.channel_count,
173 .sample_rate = next.sample_rate,
174 .byte_size = next.byte_size,
175 .memory_budget_bytes = memory_budget_bytes,
176 };
177 return true;
178 }
179
180 static uint64_t decoded_byte_size(const AudioFileData& data) noexcept {
181 uint64_t total = 0;
182 for (const auto& channel : data.channels) {
183 total += static_cast<uint64_t>(channel.size() * sizeof(float));
184 }
185 return total;
186 }
187
188private:
189 void publish_snapshot(SampleResourceSnapshot snapshot) {
190 std::shared_ptr<const SampleResourceSnapshot> next =
191 std::make_shared<SampleResourceSnapshot>(std::move(snapshot));
192 std::atomic_store_explicit(&snapshot_, std::move(next), std::memory_order_release);
193 }
194
195 std::shared_ptr<const SampleResourceSnapshot> snapshot_ =
196 std::make_shared<SampleResourceSnapshot>();
197 mutable std::mutex diagnostics_mutex_;
198 SampleResourceDiagnostics diagnostics_{};
199};
200
202 std::size_t max_entries = 16;
203 uint64_t max_decoded_bytes = 0;
204};
205
207 std::size_t entries = 0;
208 uint64_t decoded_bytes = 0;
209 uint64_t hits = 0;
210 uint64_t misses = 0;
211 uint64_t puts = 0;
212 uint64_t evictions = 0;
213 uint64_t rejections = 0;
214};
215
222public:
224 : limits_(normalize_limits(limits)) {}
225
226 std::shared_ptr<const AudioFileData> get(const std::string& path) {
227 auto it = entries_.find(path);
228 if (it == entries_.end()) {
229 ++stats_.misses;
230 return {};
231 }
232
233 lru_.splice(lru_.begin(), lru_, it->second.lru);
234 ++stats_.hits;
235 return it->second.data;
236 }
237
238 bool put(std::string path, AudioFileData data) {
239 return put(std::move(path),
240 std::make_shared<AudioFileData>(std::move(data)));
241 }
242
243 bool put(std::string path, std::shared_ptr<const AudioFileData> data) {
244 if (path.empty() || !data) {
245 ++stats_.rejections;
246 return false;
247 }
248
249 const auto bytes = SampleResourceHandle::decoded_byte_size(*data);
250 if (limits_.max_decoded_bytes != 0 && bytes > limits_.max_decoded_bytes) {
251 ++stats_.rejections;
252 return false;
253 }
254
255 erase(path);
256 lru_.push_front(path);
257 entries_.emplace(path, Entry{
258 .data = std::move(data),
259 .decoded_bytes = bytes,
260 .lru = lru_.begin(),
261 });
262 stats_.decoded_bytes += bytes;
263 ++stats_.puts;
264 evict_to_limits();
265 return entries_.find(path) != entries_.end();
266 }
267
268 bool erase(const std::string& path) {
269 auto it = entries_.find(path);
270 if (it == entries_.end()) return false;
271 stats_.decoded_bytes -= it->second.decoded_bytes;
272 lru_.erase(it->second.lru);
273 entries_.erase(it);
274 return true;
275 }
276
277 void clear() {
278 entries_.clear();
279 lru_.clear();
280 stats_.entries = 0;
281 stats_.decoded_bytes = 0;
282 }
283
285 auto out = stats_;
286 out.entries = entries_.size();
287 return out;
288 }
289
290 SampleResourceCacheLimits limits() const noexcept { return limits_; }
291
292private:
293 struct Entry {
294 std::shared_ptr<const AudioFileData> data;
295 uint64_t decoded_bytes = 0;
296 std::list<std::string>::iterator lru;
297 };
298
299 static SampleResourceCacheLimits normalize_limits(SampleResourceCacheLimits limits) {
300 if (limits.max_entries == 0) limits.max_entries = 1;
301 return limits;
302 }
303
304 void evict_to_limits() {
305 while (entries_.size() > limits_.max_entries
306 || (limits_.max_decoded_bytes != 0
307 && stats_.decoded_bytes > limits_.max_decoded_bytes)) {
308 const auto victim = lru_.back();
309 erase(victim);
310 ++stats_.evictions;
311 }
312 }
313
314 SampleResourceCacheLimits limits_;
315 std::list<std::string> lru_;
316 std::unordered_map<std::string, Entry> entries_;
317 SampleResourceCacheStats stats_{};
318};
319
321 uint64_t start_frame = 0;
323
324 uint64_t end_frame() const noexcept { return start_frame + data.num_frames(); }
325
326 bool contains(uint64_t frame) const noexcept {
327 return frame >= start_frame && frame < end_frame();
328 }
329
330 float sample(uint32_t channel, uint64_t frame) const noexcept {
331 if (!contains(frame) || channel >= data.channels.size()) return 0.0f;
332 const auto& samples = data.channels[channel];
333 const auto local = frame - start_frame;
334 if (local >= samples.size()) return 0.0f;
335 return samples[static_cast<std::size_t>(local)];
336 }
337};
338
340 uint32_t sample_rate = 0;
341 uint32_t channel_count = 0;
342 uint64_t generation = 0;
343 std::vector<SampleResourcePage> pages;
344
345 uint64_t covered_frame_count() const noexcept {
346 uint64_t covered = 0;
347 for (const auto& page : pages) {
348 covered += page.data.num_frames();
349 }
350 return covered;
351 }
352
353 const SampleResourcePage* find_page(uint64_t frame) const noexcept {
354 for (const auto& page : pages) {
355 if (page.contains(frame)) return &page;
356 }
357 return nullptr;
358 }
359
360 float sample(uint32_t channel, uint64_t frame) const noexcept {
361 const auto* page = find_page(frame);
362 return page ? page->sample(channel, frame) : 0.0f;
363 }
364};
365
367 uint64_t generation = 0;
368 std::size_t page_count = 0;
370 uint64_t page_misses = 0;
371 uint64_t last_miss_frame = 0;
372};
373
381public:
383 auto shared = std::make_shared<SampleResourcePageWindow>(std::move(window));
384 publish(std::move(shared));
385 }
386
387 void publish(std::shared_ptr<const SampleResourcePageWindow> window) {
388 std::atomic_store_explicit(&window_, std::move(window), std::memory_order_release);
389 page_misses_.store(0, std::memory_order_relaxed);
390 last_miss_frame_.store(0, std::memory_order_relaxed);
391 }
392
393 void clear() {
394 std::shared_ptr<const SampleResourcePageWindow> empty;
395 std::atomic_store_explicit(&window_, std::move(empty), std::memory_order_release);
396 page_misses_.store(0, std::memory_order_relaxed);
397 last_miss_frame_.store(0, std::memory_order_relaxed);
398 }
399
400 std::shared_ptr<const SampleResourcePageWindow> snapshot() const {
401 return std::atomic_load_explicit(&window_, std::memory_order_acquire);
402 }
403
404 float sample_or_zero(uint32_t channel, uint64_t frame) const noexcept {
405 const auto window = snapshot();
406 if (!window) {
407 record_miss(frame);
408 return 0.0f;
409 }
410
411 const auto* page = window->find_page(frame);
412 if (!page) {
413 record_miss(frame);
414 return 0.0f;
415 }
416
417 return page->sample(channel, frame);
418 }
419
420 void read_channel(float* dest,
421 uint32_t channel,
422 uint64_t start_frame,
423 uint64_t frame_count) const noexcept {
424 if (!dest) return;
425 for (uint64_t i = 0; i < frame_count; ++i) {
426 dest[i] = sample_or_zero(channel, start_frame + i);
427 }
428 }
429
431 const auto window = snapshot();
432 return {
433 .generation = window ? window->generation : 0,
434 .page_count = window ? window->pages.size() : 0,
435 .covered_frame_count = window ? window->covered_frame_count() : 0,
436 .page_misses = page_misses_.load(std::memory_order_relaxed),
437 .last_miss_frame = last_miss_frame_.load(std::memory_order_relaxed),
438 };
439 }
440
441private:
442 void record_miss(uint64_t frame) const noexcept {
443 page_misses_.fetch_add(1, std::memory_order_relaxed);
444 last_miss_frame_.store(frame, std::memory_order_relaxed);
445 }
446
447 std::shared_ptr<const SampleResourcePageWindow> window_;
448 mutable std::atomic<uint64_t> page_misses_{0};
449 mutable std::atomic<uint64_t> last_miss_frame_{0};
450};
451
456
458 uint64_t submitted_loads = 0;
460 uint64_t cache_hits = 0;
461 uint64_t decode_successes = 0;
462 uint64_t decode_failures = 0;
463 uint64_t cancelled = 0;
465};
466
467using SampleResourceDecodeFunction = std::function<std::optional<AudioFileData>(
468 const std::string& path,
470
477public:
479 SampleResourceCacheLimits limits = {},
481 : cache_(limits)
482 , decode_(std::move(decode)) {
483 if (!decode_) decode_ = default_decode;
484 }
485
487 jobs_.cancel_all();
488 jobs_.wait_all();
490 }
491
494
496 SampleResourceHandle& target,
497 SampleResourceLoadOptions options = {}) {
498 {
499 std::lock_guard lock(mutex_);
500 ++stats_.submitted_loads;
501 if (auto cached = cache_.get(path)) {
502 ++stats_.cache_hits;
503 target.publish_loaded(std::move(cached),
504 std::move(path),
505 options.memory_budget_bytes);
506 return {};
507 }
508 }
509
510 return submit_decode(std::move(path), &target, options);
511 }
512
514 SampleResourceLoadOptions options = {}) {
515 {
516 std::lock_guard lock(mutex_);
517 ++stats_.submitted_prefetches;
518 if (cache_.get(path)) {
519 ++stats_.cache_hits;
520 return {};
521 }
522 }
523
524 return submit_decode(std::move(path), nullptr, options);
525 }
526
527 std::size_t drain_completions() {
528 std::vector<Completion> completions;
529 {
530 std::lock_guard lock(mutex_);
531 completions.swap(completions_);
532
533 for (auto& completion : completions) {
534 if (completion.cancelled) {
535 ++stats_.cancelled;
536 } else if (completion.data) {
537 auto shared = std::make_shared<AudioFileData>(std::move(*completion.data));
538 const auto cached = shared;
539 cache_.put(completion.path, std::move(shared));
540 if (completion.target) {
541 completion.target->publish_loaded(std::move(cached),
542 completion.path,
543 completion.memory_budget_bytes);
544 }
545 ++stats_.decode_successes;
546 } else {
547 if (completion.target) {
548 completion.target->publish_missing(completion.path, completion.reason);
549 }
550 ++stats_.decode_failures;
551 }
552 ++stats_.drained_completions;
553 }
554 }
555
556 return completions.size();
557 }
558
559 bool publish_cached(const std::string& path,
560 SampleResourceHandle& target,
561 uint64_t memory_budget_bytes = 0) {
562 std::lock_guard lock(mutex_);
563 if (auto cached = cache_.get(path)) {
564 ++stats_.cache_hits;
565 target.publish_loaded(std::move(cached), path, memory_budget_bytes);
566 return true;
567 }
568 return false;
569 }
570
571 bool publish_cached(const std::string& path,
572 SampleResourceHandle& target,
574 return publish_cached(path, target, options.memory_budget_bytes);
575 }
576
578 std::lock_guard lock(mutex_);
579 return cache_.stats();
580 }
581
583 std::lock_guard lock(mutex_);
584 return stats_;
585 }
586
587 std::size_t pending_count() const {
588 return jobs_.pending_count();
589 }
590
591 static std::optional<AudioFileData> default_decode(
592 const std::string& path,
594 return read_audio_file(path);
595 }
596
597private:
598 struct Completion {
599 std::string path;
600 SampleResourceHandle* target = nullptr;
601 uint64_t memory_budget_bytes = 0;
602 std::optional<AudioFileData> data;
603 std::string reason;
604 bool cancelled = false;
605 };
606
607 runtime::BackgroundJobHandle submit_decode(std::string path,
608 SampleResourceHandle* target,
609 SampleResourceLoadOptions options) {
610 auto job_path = path;
611 return jobs_.submit(
612 {
613 .name = "sample-resource-decode:" + path,
614 .priority = options.priority,
615 },
616 [this,
617 path = std::move(job_path),
618 target,
619 memory_budget_bytes = options.memory_budget_bytes](
620 runtime::BackgroundJobContext& context) mutable {
621 if (context.is_cancelled()) {
622 queue_completion({
623 .path = std::move(path),
624 .target = target,
625 .memory_budget_bytes = memory_budget_bytes,
626 .cancelled = true,
627 });
628 return;
629 }
630
631 auto decoded = decode_(path, context);
632 if (context.is_cancelled()) {
633 queue_completion({
634 .path = std::move(path),
635 .target = target,
636 .memory_budget_bytes = memory_budget_bytes,
637 .cancelled = true,
638 });
639 return;
640 }
641
642 queue_completion({
643 .path = std::move(path),
644 .target = target,
645 .memory_budget_bytes = memory_budget_bytes,
646 .data = std::move(decoded),
647 .reason = decoded ? std::string{} : "decode failed",
648 });
649 });
650 }
651
652 void queue_completion(Completion completion) {
653 std::lock_guard lock(mutex_);
654 completions_.push_back(std::move(completion));
655 }
656
657 mutable std::mutex mutex_;
658 runtime::BackgroundJobService jobs_;
659 SampleResourceCache cache_;
661 std::vector<Completion> completions_;
662 SampleResourceServiceStats stats_{};
663};
664
665} // namespace pulp::audio
void clear()
Definition sample_resource.hpp:277
bool put(std::string path, AudioFileData data)
Definition sample_resource.hpp:238
bool erase(const std::string &path)
Definition sample_resource.hpp:268
bool put(std::string path, std::shared_ptr< const AudioFileData > data)
Definition sample_resource.hpp:243
SampleResourceCache(SampleResourceCacheLimits limits={})
Definition sample_resource.hpp:223
SampleResourceCacheStats stats() const
Definition sample_resource.hpp:284
std::shared_ptr< const AudioFileData > get(const std::string &path)
Definition sample_resource.hpp:226
SampleResourceCacheLimits limits() const noexcept
Definition sample_resource.hpp:290
Definition sample_resource.hpp:54
SampleResourceSnapshot snapshot() const
Definition sample_resource.hpp:56
SampleResourceDiagnostics diagnostics() const
Definition sample_resource.hpp:60
void clear()
Definition sample_resource.hpp:65
void publish_missing(std::string path, std::string reason)
Definition sample_resource.hpp:71
static uint64_t decoded_byte_size(const AudioFileData &data) noexcept
Definition sample_resource.hpp:180
bool publish_loaded(std::shared_ptr< const AudioFileData > data, std::string path, uint64_t memory_budget_bytes=0)
Definition sample_resource.hpp:120
bool publish_loaded(AudioFileData data, std::string path, uint64_t memory_budget_bytes=0)
Definition sample_resource.hpp:86
Render-thread view of immutable decoded sample pages.
Definition sample_resource.hpp:380
float sample_or_zero(uint32_t channel, uint64_t frame) const noexcept
Definition sample_resource.hpp:404
void read_channel(float *dest, uint32_t channel, uint64_t start_frame, uint64_t frame_count) const noexcept
Definition sample_resource.hpp:420
void publish(SampleResourcePageWindow window)
Definition sample_resource.hpp:382
std::shared_ptr< const SampleResourcePageWindow > snapshot() const
Definition sample_resource.hpp:400
void publish(std::shared_ptr< const SampleResourcePageWindow > window)
Definition sample_resource.hpp:387
SampleResourcePageHandoffDiagnostics diagnostics() const
Definition sample_resource.hpp:430
void clear()
Definition sample_resource.hpp:393
SampleResourceService & operator=(const SampleResourceService &)=delete
~SampleResourceService()
Definition sample_resource.hpp:486
bool publish_cached(const std::string &path, SampleResourceHandle &target, SampleResourceLoadOptions options)
Definition sample_resource.hpp:571
SampleResourceCacheStats cache_stats() const
Definition sample_resource.hpp:577
std::size_t drain_completions()
Definition sample_resource.hpp:527
std::size_t pending_count() const
Definition sample_resource.hpp:587
runtime::BackgroundJobHandle load_async(std::string path, SampleResourceHandle &target, SampleResourceLoadOptions options={})
Definition sample_resource.hpp:495
SampleResourceService(SampleResourceCacheLimits limits={}, SampleResourceDecodeFunction decode={})
Definition sample_resource.hpp:478
SampleResourceService(const SampleResourceService &)=delete
SampleResourceServiceStats stats() const
Definition sample_resource.hpp:582
bool publish_cached(const std::string &path, SampleResourceHandle &target, uint64_t memory_budget_bytes=0)
Definition sample_resource.hpp:559
static std::optional< AudioFileData > default_decode(const std::string &path, runtime::BackgroundJobContext &)
Definition sample_resource.hpp:591
runtime::BackgroundJobHandle prefetch_async(std::string path, SampleResourceLoadOptions options={})
Definition sample_resource.hpp:513
Definition background_job.hpp:33
Definition background_job.hpp:51
BackgroundJobHandle submit(BackgroundJobOptions options, BackgroundJobFunction job)
Definition analyzer_provider.hpp:12
std::optional< AudioFileData > read_audio_file(const std::string &path)
SampleResourceStatus
Definition sample_resource.hpp:20
@ Missing
Definition sample_resource.hpp:23
@ Oversized
Definition sample_resource.hpp:24
@ Loaded
Definition sample_resource.hpp:22
@ Empty
Definition sample_resource.hpp:21
std::function< std::optional< AudioFileData >( const std::string &path, runtime::BackgroundJobContext &context)> SampleResourceDecodeFunction
Definition sample_resource.hpp:467
@ shared
Definition device.hpp:32
BackgroundJobPriority
Definition background_job.hpp:21
@ normal
Definition background_job.hpp:23
STL namespace.
Definition audio_file.hpp:24
uint64_t num_frames() const
Definition audio_file.hpp:29
uint32_t num_channels() const
Definition audio_file.hpp:28
uint32_t sample_rate
Definition audio_file.hpp:26
Definition sample_resource.hpp:201
std::size_t max_entries
Definition sample_resource.hpp:202
uint64_t max_decoded_bytes
Definition sample_resource.hpp:203
Definition sample_resource.hpp:206
uint64_t misses
Definition sample_resource.hpp:210
uint64_t decoded_bytes
Definition sample_resource.hpp:208
uint64_t puts
Definition sample_resource.hpp:211
std::size_t entries
Definition sample_resource.hpp:207
uint64_t evictions
Definition sample_resource.hpp:212
uint64_t hits
Definition sample_resource.hpp:209
uint64_t rejections
Definition sample_resource.hpp:213
Definition sample_resource.hpp:42
std::string path
Definition sample_resource.hpp:45
uint64_t frame_count
Definition sample_resource.hpp:47
uint64_t byte_size
Definition sample_resource.hpp:50
std::string reason
Definition sample_resource.hpp:46
uint32_t channel_count
Definition sample_resource.hpp:48
uint64_t memory_budget_bytes
Definition sample_resource.hpp:51
uint64_t generation
Definition sample_resource.hpp:44
uint32_t sample_rate
Definition sample_resource.hpp:49
SampleResourceStatus status
Definition sample_resource.hpp:43
Definition sample_resource.hpp:452
runtime::BackgroundJobPriority priority
Definition sample_resource.hpp:454
uint64_t memory_budget_bytes
Definition sample_resource.hpp:453
Definition sample_resource.hpp:366
uint64_t covered_frame_count
Definition sample_resource.hpp:369
std::size_t page_count
Definition sample_resource.hpp:368
uint64_t generation
Definition sample_resource.hpp:367
uint64_t page_misses
Definition sample_resource.hpp:370
uint64_t last_miss_frame
Definition sample_resource.hpp:371
Definition sample_resource.hpp:339
uint32_t channel_count
Definition sample_resource.hpp:341
std::vector< SampleResourcePage > pages
Definition sample_resource.hpp:343
float sample(uint32_t channel, uint64_t frame) const noexcept
Definition sample_resource.hpp:360
const SampleResourcePage * find_page(uint64_t frame) const noexcept
Definition sample_resource.hpp:353
uint64_t covered_frame_count() const noexcept
Definition sample_resource.hpp:345
uint32_t sample_rate
Definition sample_resource.hpp:340
uint64_t generation
Definition sample_resource.hpp:342
Definition sample_resource.hpp:320
bool contains(uint64_t frame) const noexcept
Definition sample_resource.hpp:326
uint64_t end_frame() const noexcept
Definition sample_resource.hpp:324
AudioFileData data
Definition sample_resource.hpp:322
uint64_t start_frame
Definition sample_resource.hpp:321
float sample(uint32_t channel, uint64_t frame) const noexcept
Definition sample_resource.hpp:330
Definition sample_resource.hpp:457
uint64_t submitted_prefetches
Definition sample_resource.hpp:459
uint64_t cache_hits
Definition sample_resource.hpp:460
uint64_t drained_completions
Definition sample_resource.hpp:464
uint64_t submitted_loads
Definition sample_resource.hpp:458
uint64_t cancelled
Definition sample_resource.hpp:463
uint64_t decode_failures
Definition sample_resource.hpp:462
uint64_t decode_successes
Definition sample_resource.hpp:461
Definition sample_resource.hpp:27
uint64_t generation
Definition sample_resource.hpp:29
uint32_t sample_rate
Definition sample_resource.hpp:32
uint64_t frame_count
Definition sample_resource.hpp:30
std::shared_ptr< const AudioFileData > data
Definition sample_resource.hpp:35
SampleResourceStatus status
Definition sample_resource.hpp:28
bool ready() const noexcept
Definition sample_resource.hpp:37
uint32_t channel_count
Definition sample_resource.hpp:31
uint64_t byte_size
Definition sample_resource.hpp:33
uint64_t memory_budget_bytes
Definition sample_resource.hpp:34