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