OpenShot Audio Library | OpenShotAudio  0.3.1
juce_AbstractFifo.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
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 
32 
33 int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
34 int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
35 
36 int AbstractFifo::getNumReady() const noexcept
37 {
38  auto vs = validStart.get();
39  auto ve = validEnd.get();
40  return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
41 }
42 
43 void AbstractFifo::reset() noexcept
44 {
45  validEnd = 0;
46  validStart = 0;
47 }
48 
49 void AbstractFifo::setTotalSize (int newSize) noexcept
50 {
51  jassert (newSize > 0);
52  reset();
53  bufferSize = newSize;
54 }
55 
56 //==============================================================================
57 void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1,
58  int& startIndex2, int& blockSize2) const noexcept
59 {
60  auto vs = validStart.get();
61  auto ve = validEnd.get();
62 
63  auto freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
64  numToWrite = jmin (numToWrite, freeSpace - 1);
65 
66  if (numToWrite <= 0)
67  {
68  startIndex1 = 0;
69  startIndex2 = 0;
70  blockSize1 = 0;
71  blockSize2 = 0;
72  }
73  else
74  {
75  startIndex1 = ve;
76  startIndex2 = 0;
77  blockSize1 = jmin (bufferSize - ve, numToWrite);
78  numToWrite -= blockSize1;
79  blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, vs);
80  }
81 }
82 
83 void AbstractFifo::finishedWrite (int numWritten) noexcept
84 {
85  jassert (numWritten >= 0 && numWritten < bufferSize);
86 
87  auto newEnd = validEnd.get() + numWritten;
88 
89  if (newEnd >= bufferSize)
90  newEnd -= bufferSize;
91 
92  validEnd = newEnd;
93 }
94 
95 void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1,
96  int& startIndex2, int& blockSize2) const noexcept
97 {
98  auto vs = validStart.get();
99  auto ve = validEnd.get();
100 
101  auto numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
102  numWanted = jmin (numWanted, numReady);
103 
104  if (numWanted <= 0)
105  {
106  startIndex1 = 0;
107  startIndex2 = 0;
108  blockSize1 = 0;
109  blockSize2 = 0;
110  }
111  else
112  {
113  startIndex1 = vs;
114  startIndex2 = 0;
115  blockSize1 = jmin (bufferSize - vs, numWanted);
116  numWanted -= blockSize1;
117  blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, ve);
118  }
119 }
120 
121 void AbstractFifo::finishedRead (int numRead) noexcept
122 {
123  jassert (numRead >= 0 && numRead <= bufferSize);
124 
125  auto newStart = validStart.get() + numRead;
126 
127  if (newStart >= bufferSize)
128  newStart -= bufferSize;
129 
130  validStart = newStart;
131 }
132 
133 //==============================================================================
134 template <AbstractFifo::ReadOrWrite mode>
136  : startIndex1 (other.startIndex1),
137  blockSize1 (other.blockSize1),
138  startIndex2 (other.startIndex2),
139  blockSize2 (other.blockSize2)
140 {
141  swap (other);
142 }
143 
144 template <AbstractFifo::ReadOrWrite mode>
147 {
148  swap (other);
149  return *this;
150 }
151 
152 template <AbstractFifo::ReadOrWrite mode>
154 {
155  std::swap (other.fifo, fifo);
156  std::swap (other.startIndex1, startIndex1);
157  std::swap (other.blockSize1, blockSize1);
158  std::swap (other.startIndex2, startIndex2);
159  std::swap (other.blockSize2, blockSize2);
160 }
161 
164 
165 AbstractFifo::ScopedRead AbstractFifo::read (int numToRead) noexcept { return { *this, numToRead }; }
166 AbstractFifo::ScopedWrite AbstractFifo::write (int numToWrite) noexcept { return { *this, numToWrite }; }
167 
168 
169 //==============================================================================
170 //==============================================================================
171 #if JUCE_UNIT_TESTS
172 
173 class AbstractFifoTests : public UnitTest
174 {
175 public:
176  AbstractFifoTests()
177  : UnitTest ("Abstract Fifo", UnitTestCategories::containers)
178  {}
179 
180  struct WriteThread : public Thread
181  {
182  WriteThread (AbstractFifo& f, int* b, Random rng)
183  : Thread ("fifo writer"), fifo (f), buffer (b), random (rng)
184  {
185  startThread();
186  }
187 
188  ~WriteThread()
189  {
190  stopThread (5000);
191  }
192 
193  void run()
194  {
195  int n = 0;
196 
197  while (! threadShouldExit())
198  {
199  int num = random.nextInt (2000) + 1;
200 
201  auto writer = fifo.write (num);
202 
203  jassert (writer.blockSize1 >= 0 && writer.blockSize2 >= 0);
204  jassert (writer.blockSize1 == 0
205  || (writer.startIndex1 >= 0 && writer.startIndex1 < fifo.getTotalSize()));
206  jassert (writer.blockSize2 == 0
207  || (writer.startIndex2 >= 0 && writer.startIndex2 < fifo.getTotalSize()));
208 
209  writer.forEach ([this, &n] (int index) { this->buffer[index] = n++; });
210  }
211  }
212 
213  AbstractFifo& fifo;
214  int* buffer;
215  Random random;
216  };
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 
263 static AbstractFifoTests fifoUnitTests;
264 
265 #endif
266 
267 } // namespace juce
AbstractFifo(int capacity) noexcept
void finishedRead(int numRead) noexcept
void combineSeed(int64 seedValue) noexcept
Definition: juce_Random.cpp:54
int nextInt() noexcept
Definition: juce_Random.cpp:78
int getTotalSize() const noexcept
void reset() noexcept
void setTotalSize(int newSize) noexcept
int getNumReady() const noexcept
void prepareToWrite(int numToWrite, int &startIndex1, int &blockSize1, int &startIndex2, int &blockSize2) const noexcept
ScopedWrite write(int numToWrite) noexcept
void finishedWrite(int numWritten) noexcept
Type get() const noexcept
Definition: juce_Atomic.h:64
void prepareToRead(int numWanted, int &startIndex1, int &blockSize1, int &startIndex2, int &blockSize2) const noexcept
ScopedRead read(int numToRead) noexcept
int getFreeSpace() const noexcept