/
AsynchronousValueTreeSynchroniser.h
99 lines (75 loc) · 2.89 KB
/
AsynchronousValueTreeSynchroniser.h
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
/*
==============================================================================
AsynchronousValueTreeSynchroniser.h
Created: 4 Aug 2020 8:58:13am
Author: L.Goodacre
This class can be used to make shadow of a ValueTree in a thread safe way.
ValueTreeSynchroniser is used to pick up the changes made to a ValueTree,
which are then placed into a lock free FiFo. You can then update the shadow
ValueTree from another thread by calling updateShadowValueTree().
It hasn't been rigorously tested and there may be mistakes. Please let me
know if you spot any.
==============================================================================
*/
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include <array>
template <int CAPACITY>
class AsyncValueTreeSynchroniser : public ValueTreeSynchroniser
{
public:
AsyncValueTreeSynchroniser(const ValueTree& vt) :
ValueTreeSynchroniser(vt), fifo(CAPACITY)
{}
inline bool updateShadowValueTree()
{
if (hasOverrun.get())
{
DBG("resetting ValueTree because of buffer overflow.");
fifo.reset();
hasOverrun.set(false);
sendFullSyncCallback();
}
bool hasUpdatedSomething = fifo.getNumReady();
const auto updateShadowVT = [this](const MemoryBlock& block)
{ applyChange(shadowValueTree, block.getData(), block.getSize(), nullptr); };
while (fifo.getNumReady() > 0)
{
int start1, size1, start2, size2;
fifo.prepareToRead(1, start1, size1, start2, size2);
jassert(size1 + size2 <= 1);
if (size1 > 0)
updateShadowVT(arrayOfMemoryBlocks[start1]);
else if (size2 > 0)
updateShadowVT(arrayOfMemoryBlocks[start2]);
fifo.finishedRead(size1 + size2);
}
return hasUpdatedSomething;
}
inline ValueTree getShaddowValueTree() const
{ return shadowValueTree; }
private:
inline void stateChanged(const void* encodedChange, std::size_t sizeOfData) override
{
if (fifo.getFreeSpace() < 1)
{
hasOverrun.set(true);
return;
}
else
{
int start1, size1, start2, size2;
fifo.prepareToWrite(1, start1, size1, start2, size2);
jassert(size1 + size2 <= 1);
if (size1 > 0)
arrayOfMemoryBlocks[start1] = MemoryBlock(encodedChange, sizeOfData);
else if (size2 > 0)
arrayOfMemoryBlocks[start2] = MemoryBlock(encodedChange, sizeOfData);
fifo.finishedWrite(size1 + size2);
}
}
ValueTree shadowValueTree;
std::array<MemoryBlock, CAPACITY> arrayOfMemoryBlocks;
AbstractFifo fifo;
Atomic<bool> hasOverrun = false;
};