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"
26 // --------------------------------------------------------------------------------------------------------------------
28 class Lv2AtomRingBuffer
: public CarlaRingBufferControl
<HeapBuffer
>
31 Lv2AtomRingBuffer() noexcept
33 fHeapBuffer
{0, 0, 0, 0, false, nullptr},
34 fNeedsDataDelete(true)
38 Lv2AtomRingBuffer(Lv2AtomRingBuffer
& ringBuf
, uint8_t buf
[]) noexcept
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
);
52 setRingBuffer(&fHeapBuffer
, false);
55 ~Lv2AtomRingBuffer() noexcept
57 if (fHeapBuffer
.buf
== nullptr || ! fNeedsDataDelete
)
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
);
75 fHeapBuffer
.buf
= new uint8_t[p2size
];
76 } CARLA_SAFE_EXCEPTION_RETURN("Lv2AtomRingBuffer::createBuffer",);
78 fHeapBuffer
.size
= p2size
;
79 setRingBuffer(&fHeapBuffer
, true);
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;
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
117 // ----------------------------------------------------------------------------------------------------------------
119 // NOTE: must have been locked before
120 bool get(uint32_t& portIndex
, LV2_Atom
* const retAtom
) noexcept
122 if (readAtom(portIndex
, retAtom
))
125 retAtom
->size
= retAtom
->type
= 0;
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
));
151 // ----------------------------------------------------------------------------------------------------------------
153 bool readAtom(uint32_t& portIndex
, LV2_Atom
* const retAtom
) noexcept
155 const uint32_t maxAtomSize
= retAtom
->size
- sizeof(LV2_Atom
);
159 if (! tryRead(&atom
, sizeof(LV2_Atom
)))
161 if (atom
.size
== 0 || atom
.type
== 0)
164 CARLA_SAFE_ASSERT_UINT2_RETURN(atom
.size
< maxAtomSize
, atom
.size
, maxAtomSize
, false);
167 if (! tryRead(&index
, sizeof(int32_t)))
172 if (! tryRead(retAtom
+ 1, atom
.size
))
175 portIndex
= static_cast<uint32_t>(index
);
176 retAtom
->size
= atom
.size
;
177 retAtom
->type
= atom
.type
;
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 // ----------------------------------------------------------------------------------------------------------------
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