OpenShot Audio Library | OpenShotAudio  0.6.0
juce_AbstractFifo.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 AbstractFifo::AbstractFifo (int capacity) noexcept : bufferSize (capacity)
27 {
28  jassert (bufferSize > 0);
29 }
30 
31 int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
32 int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
33 
34 int AbstractFifo::getNumReady() const noexcept
35 {
36  auto vs = validStart.get();
37  auto ve = validEnd.get();
38  return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
39 }
40 
41 void AbstractFifo::reset() noexcept
42 {
43  validEnd = 0;
44  validStart = 0;
45 }
46 
47 void AbstractFifo::setTotalSize (int newSize) noexcept
48 {
49  jassert (newSize > 0);
50  reset();
51  bufferSize = newSize;
52 }
53 
54 //==============================================================================
55 void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1,
56  int& startIndex2, int& blockSize2) const noexcept
57 {
58  auto vs = validStart.get();
59  auto ve = validEnd.get();
60 
61  auto freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
62  numToWrite = jmin (numToWrite, freeSpace - 1);
63 
64  if (numToWrite <= 0)
65  {
66  startIndex1 = 0;
67  startIndex2 = 0;
68  blockSize1 = 0;
69  blockSize2 = 0;
70  }
71  else
72  {
73  startIndex1 = ve;
74  startIndex2 = 0;
75  blockSize1 = jmin (bufferSize - ve, numToWrite);
76  numToWrite -= blockSize1;
77  blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, vs);
78  }
79 }
80 
81 void AbstractFifo::finishedWrite (int numWritten) noexcept
82 {
83  jassert (numWritten >= 0 && numWritten < bufferSize);
84 
85  auto newEnd = validEnd.get() + numWritten;
86 
87  if (newEnd >= bufferSize)
88  newEnd -= bufferSize;
89 
90  validEnd = newEnd;
91 }
92 
93 void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1,
94  int& startIndex2, int& blockSize2) const noexcept
95 {
96  auto vs = validStart.get();
97  auto ve = validEnd.get();
98 
99  auto numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
100  numWanted = jmin (numWanted, numReady);
101 
102  if (numWanted <= 0)
103  {
104  startIndex1 = 0;
105  startIndex2 = 0;
106  blockSize1 = 0;
107  blockSize2 = 0;
108  }
109  else
110  {
111  startIndex1 = vs;
112  startIndex2 = 0;
113  blockSize1 = jmin (bufferSize - vs, numWanted);
114  numWanted -= blockSize1;
115  blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, ve);
116  }
117 }
118 
119 void AbstractFifo::finishedRead (int numRead) noexcept
120 {
121  jassert (numRead >= 0 && numRead <= bufferSize);
122 
123  auto newStart = validStart.get() + numRead;
124 
125  if (newStart >= bufferSize)
126  newStart -= bufferSize;
127 
128  validStart = newStart;
129 }
130 
131 //==============================================================================
132 template <AbstractFifo::ReadOrWrite mode>
133 AbstractFifo::ScopedReadWrite<mode>::ScopedReadWrite (ScopedReadWrite&& other) noexcept
134  : startIndex1 (other.startIndex1),
135  blockSize1 (other.blockSize1),
136  startIndex2 (other.startIndex2),
137  blockSize2 (other.blockSize2)
138 {
139  swap (other);
140 }
141 
142 template <AbstractFifo::ReadOrWrite mode>
143 AbstractFifo::ScopedReadWrite<mode>&
144 AbstractFifo::ScopedReadWrite<mode>::operator= (ScopedReadWrite&& other) noexcept
145 {
146  swap (other);
147  return *this;
148 }
149 
150 template <AbstractFifo::ReadOrWrite mode>
151 void AbstractFifo::ScopedReadWrite<mode>::swap (ScopedReadWrite& other) noexcept
152 {
153  std::swap (other.fifo, fifo);
154  std::swap (other.startIndex1, startIndex1);
155  std::swap (other.blockSize1, blockSize1);
156  std::swap (other.startIndex2, startIndex2);
157  std::swap (other.blockSize2, blockSize2);
158 }
159 
160 template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>;
161 template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>;
162 
163 AbstractFifo::ScopedRead AbstractFifo::read (int numToRead) noexcept { return { *this, numToRead }; }
164 AbstractFifo::ScopedWrite AbstractFifo::write (int numToWrite) noexcept { return { *this, numToWrite }; }
165 
166 
167 //==============================================================================
168 //==============================================================================
169 #if JUCE_UNIT_TESTS
170 
171 class AbstractFifoTests final : public UnitTest
172 {
173 public:
174  AbstractFifoTests()
175  : UnitTest ("Abstract Fifo", UnitTestCategories::containers)
176  {}
177 
178  struct WriteThread final : public Thread
179  {
180  WriteThread (AbstractFifo& f, int* b, Random rng)
181  : Thread ("fifo writer"), fifo (f), buffer (b), random (rng)
182  {
183  startThread();
184  }
185 
186  ~WriteThread() override
187  {
188  stopThread (5000);
189  }
190 
191  void run() override
192  {
193  int n = 0;
194 
195  while (! threadShouldExit())
196  {
197  int num = random.nextInt (2000) + 1;
198 
199  auto writer = fifo.write (num);
200 
201  jassert (writer.blockSize1 >= 0 && writer.blockSize2 >= 0);
202  jassert (writer.blockSize1 == 0
203  || (writer.startIndex1 >= 0 && writer.startIndex1 < fifo.getTotalSize()));
204  jassert (writer.blockSize2 == 0
205  || (writer.startIndex2 >= 0 && writer.startIndex2 < fifo.getTotalSize()));
206 
207  writer.forEach ([this, &n] (int index) { this->buffer[index] = n++; });
208  }
209  }
210 
211  AbstractFifo& fifo;
212  int* buffer;
213  Random random;
214  };
215 
216  JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6262)
217 
218  void runTest() override
219  {
220  beginTest ("AbstractFifo");
221 
222  int buffer[5000];
223  AbstractFifo fifo (numElementsInArray (buffer));
224 
225  WriteThread writer (fifo, buffer, getRandom());
226 
227  int n = 0;
228  Random r = getRandom();
229  r.combineSeed (12345);
230 
231  for (int count = 100000; --count >= 0;)
232  {
233  int num = r.nextInt (6000) + 1;
234 
235  auto reader = fifo.read (num);
236 
237  if (! (reader.blockSize1 >= 0 && reader.blockSize2 >= 0)
238  && (reader.blockSize1 == 0
239  || (reader.startIndex1 >= 0 && reader.startIndex1 < fifo.getTotalSize()))
240  && (reader.blockSize2 == 0
241  || (reader.startIndex2 >= 0 && reader.startIndex2 < fifo.getTotalSize())))
242  {
243  expect (false, "prepareToRead returned -ve values");
244  break;
245  }
246 
247  bool failed = false;
248 
249  reader.forEach ([&failed, &buffer, &n] (int index)
250  {
251  failed = (buffer[index] != n++) || failed;
252  });
253 
254  if (failed)
255  {
256  expect (false, "read values were incorrect");
257  break;
258  }
259  }
260  }
261 
262  JUCE_END_IGNORE_WARNINGS_MSVC
263 };
264 
265 static AbstractFifoTests fifoUnitTests;
266 
267 #endif
268 
269 } // namespace juce
void reset() noexcept
void prepareToWrite(int numToWrite, int &startIndex1, int &blockSize1, int &startIndex2, int &blockSize2) const noexcept
int getTotalSize() const noexcept
ScopedRead read(int numToRead) noexcept
void prepareToRead(int numWanted, int &startIndex1, int &blockSize1, int &startIndex2, int &blockSize2) const noexcept
AbstractFifo(int capacity) noexcept
void finishedRead(int numRead) noexcept
int getFreeSpace() const noexcept
void finishedWrite(int numWritten) noexcept
ScopedWrite write(int numToWrite) noexcept
int getNumReady() const noexcept
void setTotalSize(int newSize) noexcept
Type get() const noexcept
Definition: juce_Atomic.h:64