-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudio_buffer.h
More file actions
105 lines (87 loc) · 3.05 KB
/
audio_buffer.h
File metadata and controls
105 lines (87 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// SPDX-License-Identifier: MIT
#ifndef AUDIO_BUFFER_H
#define AUDIO_BUFFER_H
#include "as_const.h"
#include "audio_format.h"
#include "conditions.h"
#include <atomic>
#include <cstddef>
#include <sys/types.h>
namespace plac {
template <unsigned int N> class AudioBuffer {
public:
float GetFillLevel() const { return static_cast<float>(size_) / static_cast<float>(N); }
bool IsEmpty() const { return size_ == 0; }
ssize_t Write(const AudioFormat format,
const int *const left,
const int *const right,
const size_t count)
{
const size_t result{std::min(count, AsFrames(format, N - size_))};
if (format.bits == 16) {
for (int i{0}; i < result; ++i) {
std::uint32_t interleaved{static_cast<std::uint32_t>(right[i])};
interleaved <<= 16;
interleaved |= static_cast<std::uint32_t>(left[i]) & 0xFFFF;
__builtin_memcpy(&data_[in_], &interleaved, 4);
in_ += 4;
if (in_ == N) {
in_ = 0;
}
}
} else if (format.bits == 24) {
for (int i{0}; i < result; ++i) {
std::uint64_t interleaved{static_cast<std::uint32_t>(right[i])};
interleaved <<= 24;
interleaved |= static_cast<std::uint64_t>(left[i]) & 0xFFFFFF;
__builtin_memcpy(&data_[in_], &interleaved, 6);
in_ += 6;
if (in_ == N) {
in_ = 0;
}
}
}
size_ += AsBytes(format, result);
return result;
}
template<typename T>
ssize_t Read(const AudioFormat format, const size_t count, T &&pipe)
{
if (size_ < AsBytes(format, count)) {
return 0;
}
ssize_t result{0};
if ((out_ + AsBytes(format, count)) <= N) {
result = std::forward<T>(pipe)(format, &AsConst(*this).data_[out_], count);
} else {
const size_t rest{AsFrames(format, (out_ + AsBytes(format, count)) % N)};
result = std::forward<T>(pipe)(format, &AsConst(*this).data_[out_], (count - rest));
}
if (result >= 0) {
out_ = (out_ + AsBytes(format, result)) % N;
size_ -= AsBytes(format, result);
}
return result;
}
template <typename F> ssize_t Drain(const AudioFormat format, F &&Write) {
size_t count{AsFrames(format, size_)};
while (count != 0) {
const ssize_t n{Read(format, count, std::forward<F>(Write))};
if (n < 0) {
LOG_ERROR("dropping {} frames", count);
return n;
}
count -= static_cast<std::size_t>(n);
}
return 0;
}
private:
static_assert((N % 4) == 0, "16bps with channels does not fit evenly into data_.");
static_assert((N % 6) == 0, "24bps with channels does not fit evenly into data_.");
unsigned char data_[N];
std::atomic<unsigned int> size_{0};
unsigned int in_{0};
unsigned int out_{0};
};
} // namespace plac
#endif