OpenShot Library | libopenshot-audio  0.2.0
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 
27 namespace 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,
48  const AudioChannelSet& channelLayout_,
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 
61 {
62  delete output;
63 }
64 
65 static 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)
95  numSamplesToRead = reader.lengthInSamples;
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 
104  if (reader.usesFloatingPointData != isFloatingPoint())
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 
122  numSamplesToRead -= numToDo;
123  startSample += numToDo;
124  }
125 
126  return true;
127 }
128 
129 bool 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);
139 
140  source.getNextAudioBlock (info);
141 
142  if (! writeFromAudioSampleBuffer (tempBuffer, 0, numToDo))
143  return false;
144 
145  numSamplesToRead -= numToDo;
146  }
147 
148  return true;
149 }
150 
151 bool 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 
188 bool 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 //==============================================================================
214 {
215 public:
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 
323 private:
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 
337 AudioFormatWriter::ThreadedWriter::ThreadedWriter (AudioFormatWriter* writer, TimeSliceThread& backgroundThread, int numSamplesToBuffer)
338  : buffer (new AudioFormatWriter::ThreadedWriter::Buffer (backgroundThread, writer, (int) writer->numChannels, numSamplesToBuffer))
339 {
340 }
341 
343 {
344 }
345 
346 bool AudioFormatWriter::ThreadedWriter::write (const float* const* data, int numSamples)
347 {
348  return buffer->write (data, numSamples);
349 }
350 
352 {
353  buffer->setDataReceiver (receiver);
354 }
355 
356 void AudioFormatWriter::ThreadedWriter::setFlushInterval (int numSamplesPerFlush) noexcept
357 {
358  buffer->setFlushInterval (numSamplesPerFlush);
359 }
360 
361 } // namespace juce
juce::AudioFormatWriter::ThreadedWriter::ThreadedWriter
ThreadedWriter(AudioFormatWriter *writer, TimeSliceThread &backgroundThread, int numSamplesToBuffer)
Creates a ThreadedWriter for a given writer and a thread.
Definition: juce_AudioFormatWriter.cpp:337
juce::Thread::notify
void notify() const
Wakes up the thread.
Definition: juce_Thread.cpp:305
juce::AudioFormatReader::read
bool read(float *const *destChannels, int numDestChannels, int64 startSampleInSource, int numSamplesToRead)
Reads samples from the stream.
Definition: juce_AudioFormatReader.cpp:47
juce::AudioSourceChannelInfo::clearActiveBufferRegion
void clearActiveBufferRegion() const
Convenient method to clear the buffer if the source is not producing any data.
Definition: juce_AudioSource.h:88
juce::FloatVectorOperations::convertFixedToFloat
static void JUCE_CALLTYPE convertFixedToFloat(float *dest, const int *src, float multiplier, int numValues) noexcept
Converts a stream of integers to floats, multiplying each one by the given multiplier.
Definition: juce_FloatVectorOperations.cpp:873
juce::AudioSource
Base class for objects that can produce a continuous stream of audio.
Definition: juce_AudioSource.h:113
juce::AudioFormatReader::lengthInSamples
int64 lengthInSamples
The total number of samples in the audio stream.
Definition: juce_AudioFormatReader.h:232
juce::AudioBuffer< float >
juce::AudioFormatWriter::getNumChannels
int getNumChannels() const noexcept
Returns the number of channels being written.
Definition: juce_AudioFormatWriter.h:175
juce::AudioFormatWriter::writeFromAudioSource
bool writeFromAudioSource(AudioSource &source, int numSamplesToRead, int samplesPerBlock=2048)
Reads some samples from an AudioSource, and writes these to the output.
Definition: juce_AudioFormatWriter.cpp:129
juce::AudioBuffer::getReadPointer
const Type * getReadPointer(int channelNumber) const noexcept
Returns a pointer to an array of read-only samples in one of the buffer's channels.
Definition: juce_AudioSampleBuffer.h:251
juce::AudioFormatWriter::ThreadedWriter::Buffer
Definition: juce_AudioFormatWriter.cpp:213
juce::AudioBuffer::getWritePointer
Type * getWritePointer(int channelNumber) noexcept
Returns a writeable pointer to one of the buffer's channels.
Definition: juce_AudioSampleBuffer.h:277
juce::AudioFormatWriter::~AudioFormatWriter
virtual ~AudioFormatWriter()
Destructor.
Definition: juce_AudioFormatWriter.cpp:60
juce::AudioSource::getNextAudioBlock
virtual void getNextAudioBlock(const AudioSourceChannelInfo &bufferToFill)=0
Called repeatedly to fetch subsequent blocks of audio data.
juce::Thread::isThreadRunning
bool isThreadRunning() const
Returns true if the thread is currently active.
Definition: juce_Thread.cpp:160
juce::OutputStream
The base class for streams that write data to some kind of destination.
Definition: juce_OutputStream.h:41
juce::AudioFormatWriter::ThreadedWriter::write
bool write(const float *const *data, int numSamples)
Pushes some incoming audio data into the FIFO.
Definition: juce_AudioFormatWriter.cpp:346
juce::TimeSliceThread::addTimeSliceClient
void addTimeSliceClient(TimeSliceClient *clientToAdd, int millisecondsBeforeStarting=0)
Adds a client to the list.
Definition: juce_TimeSliceThread.cpp:36
juce::TimeSliceClient
Used by the TimeSliceThread class.
Definition: juce_TimeSliceThread.h:47
juce::AudioFormatWriter::write
virtual bool write(const int **samplesToWrite, int numSamples)=0
Writes a set of samples to the audio stream.
juce::AudioFormatWriter::AudioFormatWriter
AudioFormatWriter(OutputStream *destStream, const String &formatName, double sampleRate, unsigned int numberOfChannels, unsigned int bitsPerSample)
Creates an AudioFormatWriter object.
Definition: juce_AudioFormatWriter.cpp:30
juce::AbstractFifo::finishedRead
void finishedRead(int numRead) noexcept
Called after reading from the FIFO, to indicate that this many items have now been consumed.
Definition: juce_AbstractFifo.cpp:121
juce::TimeSliceThread
A thread that keeps a list of clients, and calls each one in turn, giving them all a chance to run so...
Definition: juce_TimeSliceThread.h:86
juce::AudioChannelSet
Represents a set of audio channel types.
Definition: juce_AudioChannelSet.h:50
juce::AudioFormatWriter::ThreadedWriter::IncomingDataReceiver
Receiver for incoming data.
Definition: juce_AudioFormatWriter.h:220
juce::AudioBuffer::copyFrom
void copyFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples) noexcept
Copies samples from another buffer to this one.
Definition: juce_AudioSampleBuffer.h:840
juce::AudioBuffer::getArrayOfReadPointers
const Type ** getArrayOfReadPointers() const noexcept
Returns an array of pointers to the channels in the buffer.
Definition: juce_AudioSampleBuffer.h:303
juce::AudioBuffer::getNumChannels
int getNumChannels() const noexcept
Returns the number of channels of audio data that this buffer contains.
Definition: juce_AudioSampleBuffer.h:237
juce::AudioFormatWriter::output
OutputStream * output
The output stream for use by subclasses.
Definition: juce_AudioFormatWriter.h:268
juce::AudioSourceChannelInfo
Used by AudioSource::getNextAudioBlock().
Definition: juce_AudioSource.h:36
juce::AudioFormatWriter::ThreadedWriter::~ThreadedWriter
~ThreadedWriter()
Destructor.
Definition: juce_AudioFormatWriter.cpp:342
juce::GenericScopedLock
Automatically locks and unlocks a mutex object.
Definition: juce_ScopedLock.h:58
juce::AbstractFifo::prepareToRead
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.
Definition: juce_AbstractFifo.cpp:95
juce::AudioFormatWriter::ThreadedWriter::setFlushInterval
void setFlushInterval(int numSamplesPerFlush) noexcept
Sets how many samples should be written before calling the AudioFormatWriter::flush method.
Definition: juce_AudioFormatWriter.cpp:356
juce::AudioFormatWriter::ThreadedWriter::Buffer::useTimeSlice
int useTimeSlice() override
Called back by a TimeSliceThread.
Definition: juce_AudioFormatWriter.cpp:258
juce::AbstractFifo::finishedWrite
void finishedWrite(int numWritten) noexcept
Called after writing from the FIFO, to indicate that this many items have been added.
Definition: juce_AbstractFifo.cpp:83
juce::AbstractFifo::prepareToWrite
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.
Definition: juce_AbstractFifo.cpp:57
juce::AudioFormatWriter::ThreadedWriter
Provides a FIFO for an AudioFormatWriter, allowing you to push incoming data into a buffer which will...
Definition: juce_AudioFormatWriter.h:188
juce::AudioFormatWriter::isFloatingPoint
bool isFloatingPoint() const noexcept
Returns true if it's a floating-point format, false if it's fixed-point.
Definition: juce_AudioFormatWriter.h:181
juce::String
The JUCE String class!
Definition: juce_String.h:42
juce::AudioFormatWriter
Writes samples to an audio file stream.
Definition: juce_AudioFormatWriter.h:48
juce::AudioFormatWriter::ThreadedWriter::setDataReceiver
void setDataReceiver(IncomingDataReceiver *)
Allows you to specify a callback that this writer should update with the incoming data.
Definition: juce_AudioFormatWriter.cpp:351
juce::AudioFormatWriter::writeFromAudioSampleBuffer
bool writeFromAudioSampleBuffer(const AudioBuffer< float > &source, int startSample, int numSamples)
Writes some samples from an AudioBuffer.
Definition: juce_AudioFormatWriter.cpp:188
juce::AbstractFifo::getTotalSize
int getTotalSize() const noexcept
Returns the total size of the buffer being managed.
Definition: juce_AbstractFifo.cpp:33
juce::AudioFormatWriter::numChannels
unsigned int numChannels
The number of channels being written to the stream.
Definition: juce_AudioFormatWriter.h:256
juce::AudioFormatReader::usesFloatingPointData
bool usesFloatingPointData
Indicates whether the data is floating-point or fixed.
Definition: juce_AudioFormatReader.h:238
juce::AudioFormatWriter::writeFromAudioReader
bool writeFromAudioReader(AudioFormatReader &reader, int64 startSample, int64 numSamplesToRead)
Reads a section of samples from an AudioFormatReader, and writes these to the output.
Definition: juce_AudioFormatWriter.cpp:82
juce::TimeSliceThread::removeTimeSliceClient
void removeTimeSliceClient(TimeSliceClient *clientToRemove)
Removes a client from the list.
Definition: juce_TimeSliceThread.cpp:47
juce::AudioFormatReader
Reads samples from an audio file stream.
Definition: juce_AudioFormatReader.h:48
juce::AudioFormatWriter::flush
virtual bool flush()
Some formats may support a flush operation that makes sure the file is in a valid state before carryi...
Definition: juce_AudioFormatWriter.cpp:207
juce::AudioBuffer::getNumSamples
int getNumSamples() const noexcept
Returns the number of samples allocated in each of the buffer's channels.
Definition: juce_AudioSampleBuffer.h:242
juce::AudioFormatWriter::writeFromFloatArrays
bool writeFromFloatArrays(const float *const *channels, int numChannels, int numSamples)
Writes some samples from a set of float data channels.
Definition: juce_AudioFormatWriter.cpp:151