OpenShot Audio Library | OpenShotAudio: juce_AudioFormatWriter.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.4.0

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