annotate foosdk/sdk/foobar2000/helpers/duration_counter.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
1 #pragma once
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
2
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
3 #include <SDK/dsp.h>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
4 #include <pfc/map.h>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
5
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
6 //! Duration counter class - accumulates duration using sample values, without any kind of rounding error accumulation.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
7 class duration_counter {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
8 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
9 duration_counter() {}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
10 void set(double v) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
11 m_sampleCounts.remove_all();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
12 m_offset = v;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
13 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
14 void reset() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
15 set(0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
16 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
17
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
18 void add(double v) { m_offset += v; }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
19 void subtract(double v) { m_offset -= v; }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
20
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
21 double query() const {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
22 double acc = m_offset;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
23 for (auto& walk : m_sampleCounts) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
24 acc += audio_math::samples_to_time(walk.m_value, walk.m_key);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
25 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
26 return acc;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
27 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
28
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
29 uint64_t queryAsAnySampleCount() const {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
30 if (m_sampleCounts.get_count() == 1) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
31 return m_sampleCounts.first()->m_value;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
32 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
33 return 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
34 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
35
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
36 uint64_t queryAsSampleCount(uint32_t rate) const {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
37 uint64_t samples = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
38 double acc = m_offset;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
39 for (auto& walk : m_sampleCounts) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
40 if (walk.m_key == rate) samples += walk.m_value;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
41 else acc += audio_math::samples_to_time(walk.m_value, walk.m_key);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
42 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
43 return samples + audio_math::time_to_samples(acc, rate);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
44 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
45
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
46 void add(const audio_chunk & c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
47 add(c.get_sample_count(), c.get_sample_rate());
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
48 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
49 #ifdef FOOBAR2000_HAVE_DSP
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
50 void add(dsp_chunk_list const & c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
51 const size_t num = c.get_count();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
52 for (size_t walk = 0; walk < num; ++walk) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
53 add(*c.get_item(walk));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
54 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
55 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
56 #endif
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
57 void add(t_uint64 sampleCount, t_uint32 sampleRate) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
58 PFC_ASSERT(sampleRate > 0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
59 if (sampleRate > 0 && sampleCount > 0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
60 m_sampleCounts.find_or_add(sampleRate) += sampleCount;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
61 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
62 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
63 void add(const duration_counter & other) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
64 add(other.m_offset);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
65 for (auto& walk : other.m_sampleCounts) add(walk.m_value, walk.m_key);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
66 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
67 void subtract(const duration_counter & other) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
68 subtract(other.m_offset);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
69 for (auto& walk : other.m_sampleCounts) subtract(walk.m_value, walk.m_key);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
70 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
71 void subtract(t_uint64 sampleCount, t_uint32 sampleRate) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
72 PFC_ASSERT(sampleRate > 0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
73 if (sampleRate > 0 && sampleCount > 0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
74 t_uint64 * val = m_sampleCounts.query_ptr(sampleRate);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
75 if (val == NULL) throw pfc::exception_invalid_params();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
76 if (*val < sampleCount) throw pfc::exception_invalid_params();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
77 else if (*val == sampleCount) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
78 m_sampleCounts.remove(sampleRate);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
79 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
80 *val -= sampleCount;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
81 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
82
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
83 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
84 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
85 void subtract(const audio_chunk & c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
86 subtract(c.get_sample_count(), c.get_sample_rate());
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
87 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
88 template<typename t_source> duration_counter & operator+=(const t_source & source) { add(source); return *this; }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
89 template<typename t_source> duration_counter & operator-=(const t_source & source) { subtract(source); return *this; }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
90 template<typename t_source> duration_counter & operator=(const t_source & source) { reset(); add(source); return *this; }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
91 private:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
92 double m_offset = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
93 typedef pfc::map_t<t_uint32, t_uint64> t_map;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
94 t_map m_sampleCounts;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
95 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
96