2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../core/juce_StandardHeader.h"
30 #include "juce_AudioFormat.h"
31 #include "../dsp/juce_AudioSampleBuffer.h"
32 #include "../../containers/juce_AbstractFifo.h"
33 #include "juce_AudioThumbnail.h"
36 //==============================================================================
37 AudioFormatWriter::AudioFormatWriter (OutputStream
* const out
,
38 const String
& formatName_
,
40 const unsigned int numChannels_
,
41 const unsigned int bitsPerSample_
)
43 numChannels (numChannels_
),
44 bitsPerSample (bitsPerSample_
),
45 usesFloatingPointData (false),
47 formatName (formatName_
)
51 AudioFormatWriter::~AudioFormatWriter()
56 bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader
& reader
,
58 int64 numSamplesToRead
)
60 const int bufferSize
= 16384;
61 AudioSampleBuffer
tempBuffer (numChannels
, bufferSize
);
63 int* buffers
[128] = { 0 };
65 for (int i
= tempBuffer
.getNumChannels(); --i
>= 0;)
66 buffers
[i
] = reinterpret_cast<int*> (tempBuffer
.getSampleData (i
, 0));
68 if (numSamplesToRead
< 0)
69 numSamplesToRead
= reader
.lengthInSamples
;
71 while (numSamplesToRead
> 0)
73 const int numToDo
= (int) jmin (numSamplesToRead
, (int64
) bufferSize
);
75 if (! reader
.read (buffers
, numChannels
, startSample
, numToDo
, false))
78 if (reader
.usesFloatingPointData
!= isFloatingPoint())
80 int** bufferChan
= buffers
;
82 while (*bufferChan
!= nullptr)
84 int* b
= *bufferChan
++;
86 if (isFloatingPoint())
89 const double factor
= 1.0 / std::numeric_limits
<int>::max();
91 for (int i
= 0; i
< numToDo
; ++i
)
92 reinterpret_cast<float*> (b
)[i
] = (float) (factor
* b
[i
]);
97 for (int i
= 0; i
< numToDo
; ++i
)
99 const double samp
= *(const float*) b
;
102 *b
++ = std::numeric_limits
<int>::min();
103 else if (samp
>= 1.0)
104 *b
++ = std::numeric_limits
<int>::max();
106 *b
++ = roundToInt (std::numeric_limits
<int>::max() * samp
);
112 if (! write (const_cast<const int**> (buffers
), numToDo
))
115 numSamplesToRead
-= numToDo
;
116 startSample
+= numToDo
;
122 bool AudioFormatWriter::writeFromAudioSource (AudioSource
& source
, int numSamplesToRead
, const int samplesPerBlock
)
124 AudioSampleBuffer
tempBuffer (getNumChannels(), samplesPerBlock
);
126 while (numSamplesToRead
> 0)
128 const int numToDo
= jmin (numSamplesToRead
, samplesPerBlock
);
130 AudioSourceChannelInfo info
;
131 info
.buffer
= &tempBuffer
;
132 info
.startSample
= 0;
133 info
.numSamples
= numToDo
;
134 info
.clearActiveBufferRegion();
136 source
.getNextAudioBlock (info
);
138 if (! writeFromAudioSampleBuffer (tempBuffer
, 0, numToDo
))
141 numSamplesToRead
-= numToDo
;
147 bool AudioFormatWriter::writeFromAudioSampleBuffer (const AudioSampleBuffer
& source
, int startSample
, int numSamples
)
149 jassert (startSample
>= 0 && startSample
+ numSamples
<= source
.getNumSamples() && source
.getNumChannels() > 0);
154 HeapBlock
<int> tempBuffer
;
155 HeapBlock
<int*> chans (numChannels
+ 1);
156 chans
[numChannels
] = 0;
158 if (isFloatingPoint())
160 for (int i
= numChannels
; --i
>= 0;)
161 chans
[i
] = reinterpret_cast<int*> (source
.getSampleData (i
, startSample
));
165 tempBuffer
.malloc (numSamples
* numChannels
);
167 for (unsigned int i
= 0; i
< numChannels
; ++i
)
169 typedef AudioData::Pointer
<AudioData::Int32
, AudioData::NativeEndian
, AudioData::NonInterleaved
, AudioData::NonConst
> DestSampleType
;
170 typedef AudioData::Pointer
<AudioData::Float32
, AudioData::NativeEndian
, AudioData::NonInterleaved
, AudioData::Const
> SourceSampleType
;
172 DestSampleType
destData (chans
[i
] = tempBuffer
+ i
* numSamples
);
173 SourceSampleType
sourceData (source
.getSampleData (i
, startSample
));
174 destData
.convertSamples (sourceData
, numSamples
);
178 return write ((const int**) chans
.getData(), numSamples
);
181 //==============================================================================
182 class AudioFormatWriter::ThreadedWriter::Buffer
: public TimeSliceClient
,
186 Buffer (TimeSliceThread
& timeSliceThread_
, AudioFormatWriter
* writer_
, int numChannels
, int bufferSize_
)
187 : AbstractFifo (bufferSize_
),
188 buffer (numChannels
, bufferSize_
),
189 timeSliceThread (timeSliceThread_
),
191 thumbnailToUpdate (nullptr),
195 timeSliceThread
.addTimeSliceClient (this);
201 timeSliceThread
.removeTimeSliceClient (this);
203 while (writePendingData() == 0)
207 bool write (const float** data
, int numSamples
)
209 if (numSamples
<= 0 || ! isRunning
)
212 jassert (timeSliceThread
.isThreadRunning()); // you need to get your thread running before pumping data into this!
214 int start1
, size1
, start2
, size2
;
215 prepareToWrite (numSamples
, start1
, size1
, start2
, size2
);
217 if (size1
+ size2
< numSamples
)
220 for (int i
= buffer
.getNumChannels(); --i
>= 0;)
222 buffer
.copyFrom (i
, start1
, data
[i
], size1
);
223 buffer
.copyFrom (i
, start2
, data
[i
] + size1
, size2
);
226 finishedWrite (size1
+ size2
);
227 timeSliceThread
.notify();
233 return writePendingData();
236 int writePendingData()
238 const int numToDo
= getTotalSize() / 4;
240 int start1
, size1
, start2
, size2
;
241 prepareToRead (numToDo
, start1
, size1
, start2
, size2
);
246 writer
->writeFromAudioSampleBuffer (buffer
, start1
, size1
);
248 const ScopedLock
sl (thumbnailLock
);
249 if (thumbnailToUpdate
!= nullptr)
250 thumbnailToUpdate
->addBlock (samplesWritten
, buffer
, start1
, size1
);
252 samplesWritten
+= size1
;
256 writer
->writeFromAudioSampleBuffer (buffer
, start2
, size2
);
258 if (thumbnailToUpdate
!= nullptr)
259 thumbnailToUpdate
->addBlock (samplesWritten
, buffer
, start2
, size2
);
261 samplesWritten
+= size2
;
264 finishedRead (size1
+ size2
);
268 void setThumbnail (AudioThumbnail
* thumb
)
270 if (thumb
!= nullptr)
271 thumb
->reset (buffer
.getNumChannels(), writer
->getSampleRate(), 0);
273 const ScopedLock
sl (thumbnailLock
);
274 thumbnailToUpdate
= thumb
;
279 AudioSampleBuffer buffer
;
280 TimeSliceThread
& timeSliceThread
;
281 ScopedPointer
<AudioFormatWriter
> writer
;
282 CriticalSection thumbnailLock
;
283 AudioThumbnail
* thumbnailToUpdate
;
284 int64 samplesWritten
;
285 volatile bool isRunning
;
287 JUCE_DECLARE_NON_COPYABLE (Buffer
);
290 AudioFormatWriter::ThreadedWriter::ThreadedWriter (AudioFormatWriter
* writer
, TimeSliceThread
& backgroundThread
, int numSamplesToBuffer
)
291 : buffer (new AudioFormatWriter::ThreadedWriter::Buffer (backgroundThread
, writer
, writer
->numChannels
, numSamplesToBuffer
))
295 AudioFormatWriter::ThreadedWriter::~ThreadedWriter()
299 bool AudioFormatWriter::ThreadedWriter::write (const float** data
, int numSamples
)
301 return buffer
->write (data
, numSamples
);
304 void AudioFormatWriter::ThreadedWriter::setThumbnailToUpdate (AudioThumbnail
* thumb
)
306 buffer
->setThumbnail (thumb
);