OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
juce_AudioFormatWriter.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 By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11 Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12 27th April 2017).
13
14 End User License Agreement: www.juce.com/juce-5-licence
15 Privacy Policy: www.juce.com/juce-5-privacy-policy
16
17 Or: You may also use this code under the terms of the GPL v3 (see
18 www.gnu.org/licenses).
19
20 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22 DISCLAIMED.
23
24 ==============================================================================
25*/
26
27namespace juce
28{
29
31 const String& formatName_,
32 const double rate,
33 const unsigned int numChannels_,
34 const unsigned int bitsPerSample_)
35 : sampleRate (rate),
36 numChannels (numChannels_),
37 bitsPerSample (bitsPerSample_),
38 usesFloatingPointData (false),
39 channelLayout (AudioChannelSet::canonicalChannelSet(static_cast<int> (numChannels_))),
40 output (out),
41 formatName (formatName_)
42{
43}
44
46 const String& formatName_,
47 const double rate,
49 const unsigned int bitsPerSample_)
50 : sampleRate (rate),
51 numChannels (static_cast<unsigned int> (channelLayout_.size())),
52 bitsPerSample (bitsPerSample_),
53 usesFloatingPointData (false),
54 channelLayout (channelLayout_),
55 output (out),
56 formatName (formatName_)
57{
58}
59
64
65static void convertFloatsToInts (int* dest, const float* src, int numSamples) noexcept
66{
67 while (--numSamples >= 0)
68 {
69 const double samp = *src++;
70
71 if (samp <= -1.0)
72 *dest = std::numeric_limits<int>::min();
73 else if (samp >= 1.0)
74 *dest = std::numeric_limits<int>::max();
75 else
76 *dest = roundToInt (std::numeric_limits<int>::max() * samp);
77
78 ++dest;
79 }
80}
81
83 int64 startSample,
84 int64 numSamplesToRead)
85{
86 const int bufferSize = 16384;
87 AudioBuffer<float> tempBuffer ((int) numChannels, bufferSize);
88
89 int* buffers[128] = { nullptr };
90
91 for (int i = tempBuffer.getNumChannels(); --i >= 0;)
92 buffers[i] = reinterpret_cast<int*> (tempBuffer.getWritePointer (i, 0));
93
94 if (numSamplesToRead < 0)
96
97 while (numSamplesToRead > 0)
98 {
99 const int numToDo = (int) jmin (numSamplesToRead, (int64) bufferSize);
100
101 if (! reader.read (buffers, (int) numChannels, startSample, numToDo, false))
102 return false;
103
105 {
106 int** bufferChan = buffers;
107
108 while (*bufferChan != nullptr)
109 {
110 void* const b = *bufferChan++;
111
112 if (isFloatingPoint())
113 FloatVectorOperations::convertFixedToFloat ((float*) b, (int*) b, 1.0f / 0x7fffffff, numToDo);
114 else
115 convertFloatsToInts ((int*) b, (float*) b, numToDo);
116 }
117 }
118
119 if (! write (const_cast<const int**> (buffers), numToDo))
120 return false;
121
123 startSample += numToDo;
124 }
125
126 return true;
127}
128
129bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, int numSamplesToRead, const int samplesPerBlock)
130{
131 AudioBuffer<float> tempBuffer (getNumChannels(), samplesPerBlock);
132
133 while (numSamplesToRead > 0)
134 {
135 auto numToDo = jmin (numSamplesToRead, samplesPerBlock);
136
137 AudioSourceChannelInfo info (&tempBuffer, 0, numToDo);
138 info.clearActiveBufferRegion();
139
140 source.getNextAudioBlock (info);
141
142 if (! writeFromAudioSampleBuffer (tempBuffer, 0, numToDo))
143 return false;
144
146 }
147
148 return true;
149}
150
151bool AudioFormatWriter::writeFromFloatArrays (const float* const* channels, int numSourceChannels, int numSamples)
152{
153 if (numSamples <= 0)
154 return true;
155
156 if (isFloatingPoint())
157 return write ((const int**) channels, numSamples);
158
159 int* chans[256];
160 int scratch[4096];
161
162 jassert (numSourceChannels < numElementsInArray (chans));
163 const int maxSamples = (int) (numElementsInArray (scratch) / numSourceChannels);
164
165 for (int i = 0; i < numSourceChannels; ++i)
166 chans[i] = scratch + (i * maxSamples);
167
168 chans[numSourceChannels] = nullptr;
169 int startSample = 0;
170
171 while (numSamples > 0)
172 {
173 auto numToDo = jmin (numSamples, maxSamples);
174
175 for (int i = 0; i < numSourceChannels; ++i)
176 convertFloatsToInts (chans[i], channels[i] + startSample, numToDo);
177
178 if (! write ((const int**) chans, numToDo))
179 return false;
180
181 startSample += numToDo;
182 numSamples -= numToDo;
183 }
184
185 return true;
186}
187
188bool AudioFormatWriter::writeFromAudioSampleBuffer (const AudioBuffer<float>& source, int startSample, int numSamples)
189{
190 auto numSourceChannels = source.getNumChannels();
191 jassert (startSample >= 0 && startSample + numSamples <= source.getNumSamples() && numSourceChannels > 0);
192
193 if (startSample == 0)
194 return writeFromFloatArrays (source.getArrayOfReadPointers(), numSourceChannels, numSamples);
195
196 const float* chans[256];
197 jassert ((int) numChannels < numElementsInArray (chans));
198
199 for (int i = 0; i < numSourceChannels; ++i)
200 chans[i] = source.getReadPointer (i, startSample);
201
202 chans[numSourceChannels] = nullptr;
203
204 return writeFromFloatArrays (chans, numSourceChannels, numSamples);
205}
206
208{
209 return false;
210}
211
212//==============================================================================
213class AudioFormatWriter::ThreadedWriter::Buffer : private TimeSliceClient
214{
215public:
216 Buffer (TimeSliceThread& tst, AudioFormatWriter* w, int channels, int numSamples)
217 : fifo (numSamples),
218 buffer (channels, numSamples),
219 timeSliceThread (tst),
220 writer (w)
221 {
222 timeSliceThread.addTimeSliceClient (this);
223 }
224
225 ~Buffer() override
226 {
227 isRunning = false;
228 timeSliceThread.removeTimeSliceClient (this);
229
230 while (writePendingData() == 0)
231 {}
232 }
233
234 bool write (const float* const* data, int numSamples)
235 {
236 if (numSamples <= 0 || ! isRunning)
237 return true;
238
239 jassert (timeSliceThread.isThreadRunning()); // you need to get your thread running before pumping data into this!
240
241 int start1, size1, start2, size2;
242 fifo.prepareToWrite (numSamples, start1, size1, start2, size2);
243
244 if (size1 + size2 < numSamples)
245 return false;
246
247 for (int i = buffer.getNumChannels(); --i >= 0;)
248 {
249 buffer.copyFrom (i, start1, data[i], size1);
250 buffer.copyFrom (i, start2, data[i] + size1, size2);
251 }
252
253 fifo.finishedWrite (size1 + size2);
254 timeSliceThread.notify();
255 return true;
256 }
257
258 int useTimeSlice() override
259 {
260 return writePendingData();
261 }
262
263 int writePendingData()
264 {
265 auto numToDo = fifo.getTotalSize() / 4;
266
267 int start1, size1, start2, size2;
268 fifo.prepareToRead (numToDo, start1, size1, start2, size2);
269
270 if (size1 <= 0)
271 return 10;
272
273 writer->writeFromAudioSampleBuffer (buffer, start1, size1);
274
275 const ScopedLock sl (thumbnailLock);
276
277 if (receiver != nullptr)
278 receiver->addBlock (samplesWritten, buffer, start1, size1);
279
280 samplesWritten += size1;
281
282 if (size2 > 0)
283 {
284 writer->writeFromAudioSampleBuffer (buffer, start2, size2);
285
286 if (receiver != nullptr)
287 receiver->addBlock (samplesWritten, buffer, start2, size2);
288
289 samplesWritten += size2;
290 }
291
292 fifo.finishedRead (size1 + size2);
293
294 if (samplesPerFlush > 0)
295 {
296 flushSampleCounter -= size1 + size2;
297
298 if (flushSampleCounter <= 0)
299 {
300 flushSampleCounter = samplesPerFlush;
301 writer->flush();
302 }
303 }
304
305 return 0;
306 }
307
308 void setDataReceiver (IncomingDataReceiver* newReceiver)
309 {
310 if (newReceiver != nullptr)
311 newReceiver->reset (buffer.getNumChannels(), writer->getSampleRate(), 0);
312
313 const ScopedLock sl (thumbnailLock);
314 receiver = newReceiver;
315 samplesWritten = 0;
316 }
317
318 void setFlushInterval (int numSamples) noexcept
319 {
320 samplesPerFlush = numSamples;
321 }
322
323private:
324 AbstractFifo fifo;
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 };
333
334 JUCE_DECLARE_NON_COPYABLE (Buffer)
335};
336
338 : buffer (new AudioFormatWriter::ThreadedWriter::Buffer (backgroundThread, writer, (int) writer->numChannels, numSamplesToBuffer))
339{
340}
341
345
346bool AudioFormatWriter::ThreadedWriter::write (const float* const* data, int numSamples)
347{
348 return buffer->write (data, numSamples);
349}
350
355
357{
358 buffer->setFlushInterval (numSamplesPerFlush);
359}
360
361} // namespace juce
bool read(float *const *destChannels, int numDestChannels, int64 startSampleInSource, int numSamplesToRead)
bool write(const float *const *data, int numSamples)
ThreadedWriter(AudioFormatWriter *writer, TimeSliceThread &backgroundThread, int numSamplesToBuffer)
void setFlushInterval(int numSamplesPerFlush) noexcept
bool writeFromAudioReader(AudioFormatReader &reader, int64 startSample, int64 numSamplesToRead)
bool writeFromFloatArrays(const float *const *channels, int numChannels, int numSamples)
bool writeFromAudioSource(AudioSource &source, int numSamplesToRead, int samplesPerBlock=2048)
virtual bool write(const int **samplesToWrite, int numSamples)=0
int getNumChannels() const noexcept
AudioFormatWriter(OutputStream *destStream, const String &formatName, double sampleRate, unsigned int numberOfChannels, unsigned int bitsPerSample)
bool writeFromAudioSampleBuffer(const AudioBuffer< float > &source, int startSample, int numSamples)
bool isFloatingPoint() const noexcept
virtual void getNextAudioBlock(const AudioSourceChannelInfo &bufferToFill)=0
static void JUCE_CALLTYPE convertFixedToFloat(float *dest, const int *src, float multiplier, int numValues) noexcept