JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_AudioFormatWriter.cpp
Go to the documentation of this file.
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
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
45 const String& formatName_,
46 const double rate,
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
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)
72 else if (samp >= 1.0)
74 else
76
77 ++dest;
78 }
79}
80
82 int64 startSample,
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)
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
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
124 startSample += numToDo;
125 }
126
127 return true;
128}
129
130bool 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);
140
141 source.getNextAudioBlock (info);
142
143 if (! writeFromAudioSampleBuffer (tempBuffer, 0, numToDo))
144 return false;
145
147 }
148
149 return true;
150}
151
152bool 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
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
189bool 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)
196
197 const float* chans[256];
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
209{
210 return false;
211}
212
213//==============================================================================
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;
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;
329 CriticalSection thumbnailLock;
330 IncomingDataReceiver* receiver = {};
331 int64 samplesWritten = 0;
332 int samplesPerFlush = 0, flushSampleCounter = 0;
333 std::atomic<bool> isRunning { true };
334
336};
337
339 : buffer (new AudioFormatWriter::ThreadedWriter::Buffer (backgroundThread, writer, (int) writer->numChannels, numSamplesToBuffer))
340{
341}
342
346
347bool AudioFormatWriter::ThreadedWriter::write (const float* const* data, int numSamples)
348{
349 return buffer->write (data, numSamples);
350}
351
356
358{
359 buffer->setFlushInterval (numSamplesPerFlush);
360}
361
362} // namespace juce
void prepareToWrite(int numToWrite, int &startIndex1, int &blockSize1, int &startIndex2, int &blockSize2) const noexcept
Returns the location within the buffer at which an incoming block of data should be written.
int getTotalSize() const noexcept
Returns the total size of the buffer being managed.
void prepareToRead(int numWanted, int &startIndex1, int &blockSize1, int &startIndex2, int &blockSize2) const noexcept
Returns the location within the buffer from which the next block of data should be read.
void finishedRead(int numRead) noexcept
Called after reading from the FIFO, to indicate that this many items have now been consumed.
void finishedWrite(int numWritten) noexcept
Called after writing from the FIFO, to indicate that this many items have been added.
A multi-channel buffer containing floating point audio samples.
Type * getWritePointer(int channelNumber) noexcept
Returns a writeable pointer to one of the buffer's channels.
int getNumChannels() const noexcept
Returns the number of channels of audio data that this buffer contains.
int getNumSamples() const noexcept
Returns the number of samples allocated in each of the buffer's channels.
void copyFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples) noexcept
Copies samples from another buffer to this one.
const Type * getReadPointer(int channelNumber) const noexcept
Returns a pointer to an array of read-only samples in one of the buffer's channels.
const Type *const * getArrayOfReadPointers() const noexcept
Returns an array of pointers to the channels in the buffer.
Represents a set of audio channel types.
Reads samples from an audio file stream.
bool usesFloatingPointData
Indicates whether the data is floating-point or fixed.
bool read(float *const *destChannels, int numDestChannels, int64 startSampleInSource, int numSamplesToRead)
Reads samples from the stream.
int64 lengthInSamples
The total number of samples in the audio stream.
int useTimeSlice() override
Called back by a TimeSliceThread.
Provides a FIFO for an AudioFormatWriter, allowing you to push incoming data into a buffer which will...
bool write(const float *const *data, int numSamples)
Pushes some incoming audio data into the FIFO.
void setDataReceiver(IncomingDataReceiver *)
Allows you to specify a callback that this writer should update with the incoming data.
ThreadedWriter(AudioFormatWriter *writer, TimeSliceThread &backgroundThread, int numSamplesToBuffer)
Creates a ThreadedWriter for a given writer and a thread.
void setFlushInterval(int numSamplesPerFlush) noexcept
Sets how many samples should be written before calling the AudioFormatWriter::flush method.
Writes samples to an audio file stream.
bool writeFromAudioReader(AudioFormatReader &reader, int64 startSample, int64 numSamplesToRead)
Reads a section of samples from an AudioFormatReader, and writes these to the output.
unsigned int numChannels
The number of channels being written to the stream.
bool writeFromFloatArrays(const float *const *channels, int numChannels, int numSamples)
Writes some samples from a set of float data channels.
bool writeFromAudioSource(AudioSource &source, int numSamplesToRead, int samplesPerBlock=2048)
Reads some samples from an AudioSource, and writes these to the output.
virtual bool flush()
Some formats may support a flush operation that makes sure the file is in a valid state before carryi...
virtual bool write(const int **samplesToWrite, int numSamples)=0
Writes a set of samples to the audio stream.
int getNumChannels() const noexcept
Returns the number of channels being written.
AudioFormatWriter(OutputStream *destStream, const String &formatName, double sampleRate, unsigned int numberOfChannels, unsigned int bitsPerSample)
Creates an AudioFormatWriter object.
bool writeFromAudioSampleBuffer(const AudioBuffer< float > &source, int startSample, int numSamples)
Writes some samples from an AudioBuffer.
virtual ~AudioFormatWriter()
Destructor.
bool isFloatingPoint() const noexcept
Returns true if it's a floating-point format, false if it's fixed-point.
OutputStream * output
The output stream for use by subclasses.
Base class for objects that can produce a continuous stream of audio.
virtual void getNextAudioBlock(const AudioSourceChannelInfo &bufferToFill)=0
Called repeatedly to fetch subsequent blocks of audio data.
Automatically locks and unlocks a mutex object.
The base class for streams that write data to some kind of destination.
The JUCE String class!
Definition juce_String.h:53
void notify() const
Wakes up the thread.
bool isThreadRunning() const
Returns true if the thread is currently active.
Used by the TimeSliceThread class.
A thread that keeps a list of clients, and calls each one in turn, giving them all a chance to run so...
void removeTimeSliceClient(TimeSliceClient *clientToRemove)
Removes a client from the list.
void addTimeSliceClient(TimeSliceClient *clientToAdd, int millisecondsBeforeStarting=0)
Adds a client to the list.
T data(T... args)
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE(className)
This is a shorthand macro for deleting a class's copy constructor and copy assignment operator.
typedef int
T max(T... args)
T min(T... args)
JUCE Namespace.
CriticalSection::ScopedLockType ScopedLock
Automatically locks and unlocks a CriticalSection object.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
constexpr int numElementsInArray(Type(&)[N]) noexcept
Handy function for getting the number of elements in a simple const C array.
long long int64
A platform-independent 64-bit integer type.
T size(T... args)
Used by AudioSource::getNextAudioBlock().
void clearActiveBufferRegion() const
Convenient method to clear the buffer if the source is not producing any data.
typedef size_t