]> git.sesse.net Git - nageru/blob - nageru/audio_clip.cpp
ec97e6b0f04543920ead2028b5f08cabeb788aae
[nageru] / nageru / audio_clip.cpp
1 #include "audio_clip.h"
2
3 #include <assert.h>
4 #include <math.h>
5
6 using namespace std;
7 using namespace std::chrono;
8
9 void AudioClip::clear()
10 {
11         lock_guard<mutex> lock(mu);
12         vals.clear();
13 }
14
15 void AudioClip::add_audio(const float *samples, size_t num_samples, double sample_rate, std::chrono::steady_clock::time_point frame_time)
16 {
17         lock_guard<mutex> lock(mu);
18         if (!vals.empty() && sample_rate != this->sample_rate) {
19                 vals.clear();
20         }
21         if (vals.empty()) {
22                 first_sample = frame_time;
23         }
24         this->sample_rate = sample_rate;
25         vals.insert(vals.end(), samples, samples + num_samples);
26 }
27
28 double AudioClip::get_length_seconds() const
29 {
30         lock_guard<mutex> lock(mu);
31         if (vals.empty()) {
32                 return 0.0;
33         }
34
35         return double(vals.size()) / sample_rate;
36 }
37
38 double AudioClip::get_length_seconds_after_base(std::chrono::steady_clock::time_point base) const
39 {
40         lock_guard<mutex> lock(mu);
41         if (vals.empty() || base < first_sample) {
42                 // NOTE: base < first_sample can happen only during race conditions.
43                 return 0.0;
44         }
45
46         return double(vals.size()) / sample_rate - duration<double>(base - first_sample).count();
47 }
48
49 bool AudioClip::empty() const
50 {
51         lock_guard<mutex> lock(mu);
52         return vals.empty();
53 }
54
55 steady_clock::time_point AudioClip::get_first_sample() const
56 {
57         lock_guard<mutex> lock(mu);
58         assert(!vals.empty());
59         return first_sample;
60 }
61
62 unique_ptr<pair<float, float>[]> AudioClip::get_min_max_peaks(unsigned width, steady_clock::time_point base) const
63 {
64         unique_ptr<pair<float, float>[]> min_max(new pair<float, float>[width]);
65         for (unsigned x = 0; x < width; ++x) {
66                 min_max[x].first = min_max[x].second = 0.0 / 0.0;  // NaN.
67         }
68
69         lock_guard<mutex> lock(mu);
70         double skip_samples = duration<double>(base - first_sample).count() * sample_rate;
71         for (size_t i = int(floor(skip_samples)); i < vals.size(); ++i) {
72                 // We display one second.
73                 int x = lrint((i - skip_samples) * (double(width) / sample_rate));
74                 if (x < 0 || x >= int(width)) continue;
75                 if (isnan(min_max[x].first)) {
76                         min_max[x].first = min_max[x].second = 0.0;
77                 }
78                 min_max[x].first = min(min_max[x].first, vals[i]);
79                 min_max[x].second = max(min_max[x].second, vals[i]);
80         }
81
82         return min_max;
83 }