33 const unsigned int numChannels_,
34 const unsigned int bitsPerSample_)
36 numChannels (numChannels_),
37 bitsPerSample (bitsPerSample_),
38 usesFloatingPointData (false),
39 channelLayout (
AudioChannelSet::canonicalChannelSet(static_cast<int> (numChannels_))),
41 formatName (formatName_)
49 const unsigned int bitsPerSample_)
51 numChannels (static_cast<unsigned int> (channelLayout_.size())),
52 bitsPerSample (bitsPerSample_),
53 usesFloatingPointData (false),
54 channelLayout (channelLayout_),
56 formatName (formatName_)
65static void convertFloatsToInts (
int* dest,
const float* src,
int numSamples)
noexcept
67 while (--numSamples >= 0)
69 const double samp = *src++;
72 *dest = std::numeric_limits<int>::min();
74 *dest = std::numeric_limits<int>::max();
76 *dest = roundToInt (std::numeric_limits<int>::max() * samp);
84 int64 numSamplesToRead)
86 const int bufferSize = 16384;
89 int* buffers[128] = {
nullptr };
92 buffers[i] =
reinterpret_cast<int*
> (tempBuffer.
getWritePointer (i, 0));
94 if (numSamplesToRead < 0)
97 while (numSamplesToRead > 0)
99 const int numToDo = (int) jmin (numSamplesToRead, (int64) bufferSize);
101 if (! reader.
read (buffers, (
int)
numChannels, startSample, numToDo,
false))
106 int** bufferChan = buffers;
108 while (*bufferChan !=
nullptr)
110 void*
const b = *bufferChan++;
115 convertFloatsToInts ((
int*) b, (
float*) b, numToDo);
119 if (!
write (
const_cast<const int**
> (buffers), numToDo))
122 numSamplesToRead -= numToDo;
123 startSample += numToDo;
133 while (numSamplesToRead > 0)
135 auto numToDo = jmin (numSamplesToRead, samplesPerBlock);
145 numSamplesToRead -= numToDo;
157 return write ((
const int**) channels, numSamples);
162 jassert (numSourceChannels < numElementsInArray (chans));
163 const int maxSamples = (int) (numElementsInArray (scratch) / numSourceChannels);
165 for (
int i = 0; i < numSourceChannels; ++i)
166 chans[i] = scratch + (i * maxSamples);
168 chans[numSourceChannels] =
nullptr;
171 while (numSamples > 0)
173 auto numToDo = jmin (numSamples, maxSamples);
175 for (
int i = 0; i < numSourceChannels; ++i)
176 convertFloatsToInts (chans[i], channels[i] + startSample, numToDo);
178 if (!
write ((
const int**) chans, numToDo))
181 startSample += numToDo;
182 numSamples -= numToDo;
191 jassert (startSample >= 0 && startSample + numSamples <= source.
getNumSamples() && numSourceChannels > 0);
193 if (startSample == 0)
196 const float* chans[256];
197 jassert ((
int)
numChannels < numElementsInArray (chans));
199 for (
int i = 0; i < numSourceChannels; ++i)
202 chans[numSourceChannels] =
nullptr;
213class AudioFormatWriter::ThreadedWriter::Buffer :
private TimeSliceClient
218 buffer (channels, numSamples),
219 timeSliceThread (tst),
222 timeSliceThread.addTimeSliceClient (
this);
228 timeSliceThread.removeTimeSliceClient (
this);
230 while (writePendingData() == 0)
234 bool write (
const float*
const* data,
int numSamples)
236 if (numSamples <= 0 || ! isRunning)
239 jassert (timeSliceThread.isThreadRunning());
241 int start1, size1, start2, size2;
242 fifo.prepareToWrite (numSamples, start1, size1, start2, size2);
244 if (size1 + size2 < numSamples)
247 for (
int i = buffer.getNumChannels(); --i >= 0;)
249 buffer.copyFrom (i, start1, data[i], size1);
250 buffer.copyFrom (i, start2, data[i] + size1, size2);
253 fifo.finishedWrite (size1 + size2);
254 timeSliceThread.notify();
258 int useTimeSlice()
override
260 return writePendingData();
263 int writePendingData()
265 auto numToDo = fifo.getTotalSize() / 4;
267 int start1, size1, start2, size2;
268 fifo.prepareToRead (numToDo, start1, size1, start2, size2);
273 writer->writeFromAudioSampleBuffer (buffer, start1, size1);
275 const ScopedLock sl (thumbnailLock);
277 if (receiver !=
nullptr)
278 receiver->addBlock (samplesWritten, buffer, start1, size1);
280 samplesWritten += size1;
284 writer->writeFromAudioSampleBuffer (buffer, start2, size2);
286 if (receiver !=
nullptr)
287 receiver->addBlock (samplesWritten, buffer, start2, size2);
289 samplesWritten += size2;
292 fifo.finishedRead (size1 + size2);
294 if (samplesPerFlush > 0)
296 flushSampleCounter -= size1 + size2;
298 if (flushSampleCounter <= 0)
300 flushSampleCounter = samplesPerFlush;
308 void setDataReceiver (IncomingDataReceiver* newReceiver)
310 if (newReceiver !=
nullptr)
311 newReceiver->reset (buffer.getNumChannels(), writer->getSampleRate(), 0);
313 const ScopedLock sl (thumbnailLock);
314 receiver = newReceiver;
318 void setFlushInterval (
int numSamples)
noexcept
320 samplesPerFlush = numSamples;
325 AudioBuffer<float> buffer;
326 TimeSliceThread& timeSliceThread;
327 std::unique_ptr<AudioFormatWriter> writer;
328 CriticalSection thumbnailLock;
329 IncomingDataReceiver* receiver = {};
330 int64 samplesWritten = 0;
331 int samplesPerFlush = 0, flushSampleCounter = 0;
332 std::atomic<bool> isRunning {
true };
334 JUCE_DECLARE_NON_COPYABLE (Buffer)
348 return buffer->write (data, numSamples);
353 buffer->setDataReceiver (receiver);
358 buffer->setFlushInterval (numSamplesPerFlush);
Type * getWritePointer(int channelNumber) noexcept
int getNumChannels() const noexcept
int getNumSamples() const noexcept
const Type * getReadPointer(int channelNumber) const noexcept
const Type ** getArrayOfReadPointers() const noexcept
virtual void getNextAudioBlock(const AudioSourceChannelInfo &bufferToFill)=0
static void JUCE_CALLTYPE convertFixedToFloat(float *dest, const int *src, float multiplier, int numValues) noexcept
void clearActiveBufferRegion() const