Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2025 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #pragma once
23 :
24 : #include <vector>
25 : #include <cassert>
26 :
27 : namespace muse::audio {
28 : //! NOTE This is a ring buffer, not thread-safe.
29 : //! Designed to align processed audio blocks
30 : //! For example, we expect block 512, but the driver requests 470
31 : class AlignmentBuffer
32 : {
33 : public:
34 1 : AlignmentBuffer(size_t capacity)
35 3 : : m_buf(capacity) {}
36 :
37 0 : inline size_t capacity() const
38 : {
39 0 : return m_buf.size();
40 : }
41 :
42 40 : inline size_t availableRead() const
43 : {
44 40 : return m_availableRead;
45 : }
46 :
47 74 : inline size_t availableWrite() const
48 : {
49 74 : return m_buf.size() - m_availableRead;
50 : }
51 :
52 37 : bool write(const float* data, size_t size)
53 : {
54 37 : assert(size <= availableWrite());
55 37 : if (!(size <= availableWrite())) {
56 0 : return false;
57 : }
58 :
59 37 : if (m_tail + size <= m_buf.size()) {
60 19 : std::copy(data, data + size, m_buf.begin() + m_tail);
61 19 : m_tail += size;
62 : } else {
63 18 : size_t firstPart = m_buf.size() - m_tail;
64 18 : std::copy(data, data + firstPart, m_buf.begin() + m_tail);
65 18 : std::copy(data + firstPart, data + size, m_buf.begin());
66 18 : m_tail = size - firstPart;
67 : }
68 :
69 37 : m_availableRead += size;
70 37 : return true;
71 : }
72 :
73 40 : bool read(float* dest, size_t size)
74 : {
75 40 : if (size == 0) {
76 0 : return true;
77 : }
78 :
79 40 : assert(size <= m_availableRead);
80 40 : if (!(size <= m_availableRead)) {
81 0 : return false;
82 : }
83 :
84 40 : if (m_head + size <= m_buf.size()) {
85 23 : std::copy(m_buf.begin() + m_head, m_buf.begin() + m_head + size, dest);
86 23 : m_head += size;
87 : } else {
88 17 : size_t firstPart = m_buf.size() - m_head;
89 17 : std::copy(m_buf.begin() + m_head, m_buf.begin() + m_buf.size(), dest);
90 17 : std::copy(m_buf.begin(), m_buf.begin() + (size - firstPart), dest + firstPart);
91 17 : m_head = size - firstPart;
92 : }
93 :
94 40 : m_availableRead -= size;
95 40 : return true;
96 : }
97 :
98 : private:
99 : std::vector<float> m_buf;
100 : size_t m_availableRead = 0;
101 : size_t m_head = 0;
102 : size_t m_tail = 0;
103 : };
104 : }
|