OpenShot Library | OpenShotAudio  0.2.2
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
void clearActiveBufferRegion() const
Convenient method to clear the buffer if the source is not producing any data.
bool writeFromAudioReader(AudioFormatReader &reader, int64 startSample, int64 numSamplesToRead)
Reads a section of samples from an AudioFormatReader, and writes these to the output.
virtual ~AudioFormatWriter()
Destructor.
OutputStream * output
The output stream for use by subclasses.
Represents a set of audio channel types.
virtual void getNextAudioBlock(const AudioSourceChannelInfo &bufferToFill)=0
Called repeatedly to fetch subsequent blocks of audio data.
bool write(const float *const *data, int numSamples)
Pushes some incoming audio data into the FIFO.
virtual bool write(const int **samplesToWrite, int numSamples)=0
Writes a set of samples to the audio stream.
bool usesFloatingPointData
Indicates whether the data is floating-point or fixed.
virtual bool flush()
Some formats may support a flush operation that makes sure the file is in a valid state before carryi...
int useTimeSlice() override
Called back by a TimeSliceThread.
void setDataReceiver(IncomingDataReceiver *)
Allows you to specify a callback that this writer should update with the incoming data...
int64 lengthInSamples
The total number of samples in the audio stream.
The JUCE String class!
Definition: juce_String.h:42
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.
double sampleRate
The sample rate of the stream.
AudioFormatWriter(OutputStream *destStream, const String &formatName, double sampleRate, unsigned int numberOfChannels, unsigned int bitsPerSample)
Creates an AudioFormatWriter object.
const Type * getReadPointer(int channelNumber) const noexcept
Returns a pointer to an array of read-only samples in one of the buffer&#39;s channels.
Base class for objects that can produce a continuous stream of audio.
AudioChannelSet channelLayout
The audio channel layout that the writer should use.
Encapsulates the logic required to implement a lock-free FIFO.
Used by the TimeSliceThread class.
int getNumChannels() const noexcept
Returns the number of channels of audio data that this buffer contains.
bool usesFloatingPointData
True if it&#39;s a floating-point format, false if it&#39;s fixed-point.
bool isFloatingPoint() const noexcept
Returns true if it&#39;s a floating-point format, false if it&#39;s fixed-point.
bool writeFromAudioSampleBuffer(const AudioBuffer< float > &source, int startSample, int numSamples)
Writes some samples from an AudioBuffer.
bool writeFromFloatArrays(const float *const *channels, int numChannels, int numSamples)
Writes some samples from a set of float data channels.
A thread that keeps a list of clients, and calls each one in turn, giving them all a chance to run so...
The base class for streams that write data to some kind of destination.
Writes samples to an audio file stream.
A re-entrant mutex.
bool writeFromAudioSource(AudioSource &source, int numSamplesToRead, int samplesPerBlock=2048)
Reads some samples from an AudioSource, and writes these to the output.
bool read(float *const *destChannels, int numDestChannels, int64 startSampleInSource, int numSamplesToRead)
Reads samples from the stream.
unsigned int numChannels
The number of channels being written to the stream.
Type * getWritePointer(int channelNumber) noexcept
Returns a writeable pointer to one of the buffer&#39;s channels.
int getNumChannels() const noexcept
Returns the number of channels being written.
Reads samples from an audio file stream.
void setFlushInterval(int numSamplesPerFlush) noexcept
Sets how many samples should be written before calling the AudioFormatWriter::flush method...
int getNumSamples() const noexcept
Returns the number of samples allocated in each of the buffer&#39;s channels.
Used by AudioSource::getNextAudioBlock().
Provides a FIFO for an AudioFormatWriter, allowing you to push incoming data into a buffer which will...
Automatically locks and unlocks a mutex object.
unsigned int bitsPerSample
The bit depth of the file.
const Type ** getArrayOfReadPointers() const noexcept
Returns an array of pointers to the channels in the buffer.
ThreadedWriter(AudioFormatWriter *writer, TimeSliceThread &backgroundThread, int numSamplesToBuffer)
Creates a ThreadedWriter for a given writer and a thread.