VST3: fetch midi mappings all at once, use it for note/sound-off
[carla.git] / source / utils / Lv2AtomRingBuffer.hpp
blobc45790cabca6b9996092afd5ace03ea7da6a2cda
1 /*
2 * LV2 Atom Ring Buffer
3 * Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #ifndef LV2_ATOM_RING_BUFFER_HPP_INCLUDED
19 #define LV2_ATOM_RING_BUFFER_HPP_INCLUDED
21 #include "CarlaMutex.hpp"
22 #include "CarlaRingBuffer.hpp"
24 #include "lv2/atom.h"
26 // --------------------------------------------------------------------------------------------------------------------
28 class Lv2AtomRingBuffer : public CarlaRingBufferControl<HeapBuffer>
30 public:
31 Lv2AtomRingBuffer() noexcept
32 : fMutex(),
33 fHeapBuffer{0, 0, 0, 0, false, nullptr},
34 fNeedsDataDelete(true)
38 Lv2AtomRingBuffer(Lv2AtomRingBuffer& ringBuf, uint8_t buf[]) noexcept
39 : fMutex(),
40 fHeapBuffer{0, 0, 0, 0, false, nullptr},
41 fNeedsDataDelete(false)
43 fHeapBuffer.buf = buf;
44 fHeapBuffer.size = ringBuf.fHeapBuffer.size;
47 const CarlaMutexLocker cml(ringBuf.fMutex);
48 fHeapBuffer.copyDataFrom(ringBuf.fHeapBuffer);
49 ringBuf.clearData();
52 setRingBuffer(&fHeapBuffer, false);
55 ~Lv2AtomRingBuffer() noexcept
57 if (fHeapBuffer.buf == nullptr || ! fNeedsDataDelete)
58 return;
60 delete[] fHeapBuffer.buf;
61 fHeapBuffer.buf = nullptr;
64 // ----------------------------------------------------------------------------------------------------------------
66 void createBuffer(const uint32_t size, const bool mlock) noexcept
68 CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf == nullptr,);
69 CARLA_SAFE_ASSERT_RETURN(fNeedsDataDelete,);
70 CARLA_SAFE_ASSERT_RETURN(size > 0,);
72 const uint32_t p2size = carla_nextPowerOf2(size);
74 try {
75 fHeapBuffer.buf = new uint8_t[p2size];
76 } CARLA_SAFE_EXCEPTION_RETURN("Lv2AtomRingBuffer::createBuffer",);
78 fHeapBuffer.size = p2size;
79 setRingBuffer(&fHeapBuffer, true);
81 if (mlock)
83 carla_mlock(&fHeapBuffer, sizeof(fHeapBuffer));
84 carla_mlock(fHeapBuffer.buf, p2size);
88 void deleteBuffer() noexcept
90 CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf != nullptr,);
91 CARLA_SAFE_ASSERT_RETURN(fNeedsDataDelete,);
93 setRingBuffer(nullptr, false);
95 delete[] fHeapBuffer.buf;
96 fHeapBuffer.buf = nullptr;
97 fHeapBuffer.size = 0;
100 uint32_t getSize() const noexcept
102 return fHeapBuffer.size;
105 // ----------------------------------------------------------------------------------------------------------------
107 bool tryLock() const noexcept
109 return fMutex.tryLock();
112 void unlock() const noexcept
114 fMutex.unlock();
117 // ----------------------------------------------------------------------------------------------------------------
119 // NOTE: must have been locked before
120 bool get(uint32_t& portIndex, LV2_Atom* const retAtom) noexcept
122 if (readAtom(portIndex, retAtom))
123 return true;
125 retAtom->size = retAtom->type = 0;
126 return false;
129 // NOTE: must NOT been locked, we do that here
130 bool put(const LV2_Atom* const atom, const uint32_t portIndex) noexcept
132 CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
134 const CarlaMutexLocker cml(fMutex);
136 return writeAtom(atom, static_cast<int32_t>(portIndex));
139 // NOTE: must NOT been locked, we do that here
140 bool putChunk(const LV2_Atom* const atom, const void* const data, const uint32_t portIndex) noexcept
142 CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
143 CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);
145 const CarlaMutexLocker cml(fMutex);
147 return writeAtomChunk(atom, data, static_cast<int32_t>(portIndex));
150 protected:
151 // ----------------------------------------------------------------------------------------------------------------
153 bool readAtom(uint32_t& portIndex, LV2_Atom* const retAtom) noexcept
155 const uint32_t maxAtomSize = retAtom->size - sizeof(LV2_Atom);
157 LV2_Atom atom = {};
159 if (! tryRead(&atom, sizeof(LV2_Atom)))
160 return false;
161 if (atom.size == 0 || atom.type == 0)
162 return false;
164 CARLA_SAFE_ASSERT_UINT2_RETURN(atom.size < maxAtomSize, atom.size, maxAtomSize, false);
166 int32_t index = -1;
167 if (! tryRead(&index, sizeof(int32_t)))
168 return false;
169 if (index < 0)
170 return false;
172 if (! tryRead(retAtom + 1, atom.size))
173 return false;
175 portIndex = static_cast<uint32_t>(index);
176 retAtom->size = atom.size;
177 retAtom->type = atom.type;
178 return true;
181 // ----------------------------------------------------------------------------------------------------------------
183 bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) noexcept
185 if (tryWrite(atom, sizeof(LV2_Atom)) && tryWrite(&portIndex, sizeof(int32_t)))
186 tryWrite(LV2_ATOM_BODY_CONST(atom), atom->size);
187 return commitWrite();
190 bool writeAtomChunk(const LV2_Atom* const atom, const void* const data, const int32_t portIndex) noexcept
192 if (tryWrite(atom, sizeof(LV2_Atom)) && tryWrite(&portIndex, sizeof(int32_t)))
193 tryWrite(data, atom->size);
194 return commitWrite();
197 // ----------------------------------------------------------------------------------------------------------------
199 private:
200 CarlaMutex fMutex;
201 HeapBuffer fHeapBuffer;
202 const bool fNeedsDataDelete;
204 friend class Lv2AtomQueue;
206 CARLA_PREVENT_VIRTUAL_HEAP_ALLOCATION
207 CARLA_DECLARE_NON_COPYABLE(Lv2AtomRingBuffer)
210 // --------------------------------------------------------------------------------------------------------------------
212 #endif // LV2_ATOM_RING_BUFFER_HPP_INCLUDED