The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
8.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_AudioFormat.h"
  21. #include "../dsp/juce_AudioSampleBuffer.h"
  22. #include "../../containers/juce_AbstractFifo.h"
  23. //==============================================================================
  24. AudioFormatWriter::AudioFormatWriter (OutputStream* const out,
  25. const String& formatName_,
  26. const double rate,
  27. const unsigned int numChannels_,
  28. const unsigned int bitsPerSample_)
  29. : sampleRate (rate),
  30. numChannels (numChannels_),
  31. bitsPerSample (bitsPerSample_),
  32. usesFloatingPointData (false),
  33. output (out),
  34. formatName (formatName_)
  35. {
  36. }
  37. AudioFormatWriter::~AudioFormatWriter()
  38. {
  39. delete output;
  40. }
  41. bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader,
  42. int64 startSample,
  43. int64 numSamplesToRead)
  44. {
  45. const int bufferSize = 16384;
  46. AudioSampleBuffer tempBuffer (numChannels, bufferSize);
  47. int* buffers [128];
  48. zerostruct (buffers);
  49. for (int i = tempBuffer.getNumChannels(); --i >= 0;)
  50. buffers[i] = reinterpret_cast<int*> (tempBuffer.getSampleData (i, 0));
  51. if (numSamplesToRead < 0)
  52. numSamplesToRead = reader.lengthInSamples;
  53. while (numSamplesToRead > 0)
  54. {
  55. const int numToDo = (int) jmin (numSamplesToRead, (int64) bufferSize);
  56. if (! reader.read (buffers, numChannels, startSample, numToDo, false))
  57. return false;
  58. if (reader.usesFloatingPointData != isFloatingPoint())
  59. {
  60. int** bufferChan = buffers;
  61. while (*bufferChan != 0)
  62. {
  63. int* b = *bufferChan++;
  64. if (isFloatingPoint())
  65. {
  66. // int -> float
  67. const double factor = 1.0 / std::numeric_limits<int>::max();
  68. for (int i = 0; i < numToDo; ++i)
  69. ((float*) b)[i] = (float) (factor * b[i]);
  70. }
  71. else
  72. {
  73. // float -> int
  74. for (int i = 0; i < numToDo; ++i)
  75. {
  76. const double samp = *(const float*) b;
  77. if (samp <= -1.0)
  78. *b++ = std::numeric_limits<int>::min();
  79. else if (samp >= 1.0)
  80. *b++ = std::numeric_limits<int>::max();
  81. else
  82. *b++ = roundToInt (std::numeric_limits<int>::max() * samp);
  83. }
  84. }
  85. }
  86. }
  87. if (! write (const_cast<const int**> (buffers), numToDo))
  88. return false;
  89. numSamplesToRead -= numToDo;
  90. startSample += numToDo;
  91. }
  92. return true;
  93. }
  94. bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, int numSamplesToRead, const int samplesPerBlock)
  95. {
  96. AudioSampleBuffer tempBuffer (getNumChannels(), samplesPerBlock);
  97. while (numSamplesToRead > 0)
  98. {
  99. const int numToDo = jmin (numSamplesToRead, samplesPerBlock);
  100. AudioSourceChannelInfo info;
  101. info.buffer = &tempBuffer;
  102. info.startSample = 0;
  103. info.numSamples = numToDo;
  104. info.clearActiveBufferRegion();
  105. source.getNextAudioBlock (info);
  106. if (! writeFromAudioSampleBuffer (tempBuffer, 0, numToDo))
  107. return false;
  108. numSamplesToRead -= numToDo;
  109. }
  110. return true;
  111. }
  112. bool AudioFormatWriter::writeFromAudioSampleBuffer (const AudioSampleBuffer& source, int startSample, int numSamples)
  113. {
  114. jassert (startSample >= 0 && startSample + numSamples <= source.getNumSamples() && source.getNumChannels() > 0);
  115. if (numSamples <= 0)
  116. return true;
  117. HeapBlock<int> tempBuffer;
  118. HeapBlock<int*> chans (numChannels + 1);
  119. chans [numChannels] = 0;
  120. if (isFloatingPoint())
  121. {
  122. for (int i = numChannels; --i >= 0;)
  123. chans[i] = reinterpret_cast<int*> (source.getSampleData (i, startSample));
  124. }
  125. else
  126. {
  127. tempBuffer.malloc (numSamples * numChannels);
  128. for (unsigned int i = 0; i < numChannels; ++i)
  129. {
  130. typedef AudioData::Pointer <AudioData::Int32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestSampleType;
  131. typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceSampleType;
  132. DestSampleType destData (chans[i] = tempBuffer + i * numSamples);
  133. SourceSampleType sourceData (source.getSampleData (i, startSample));
  134. destData.convertSamples (sourceData, numSamples);
  135. }
  136. }
  137. return write ((const int**) chans.getData(), numSamples);
  138. }
  139. //==============================================================================
  140. class AudioFormatWriter::ThreadedWriter::Buffer : public TimeSliceClient,
  141. public AbstractFifo
  142. {
  143. public:
  144. Buffer (TimeSliceThread& timeSliceThread_, AudioFormatWriter* writer_, int numChannels, int bufferSize)
  145. : AbstractFifo (bufferSize),
  146. buffer (numChannels, bufferSize),
  147. timeSliceThread (timeSliceThread_),
  148. writer (writer_), isRunning (true)
  149. {
  150. timeSliceThread.addTimeSliceClient (this);
  151. }
  152. ~Buffer()
  153. {
  154. isRunning = false;
  155. timeSliceThread.removeTimeSliceClient (this);
  156. while (useTimeSlice())
  157. {}
  158. }
  159. bool write (const float** data, int numSamples)
  160. {
  161. if (numSamples <= 0 || ! isRunning)
  162. return true;
  163. jassert (timeSliceThread.isThreadRunning()); // you need to get your thread running before pumping data into this!
  164. int start1, size1, start2, size2;
  165. prepareToWrite (numSamples, start1, size1, start2, size2);
  166. if (size1 + size2 < numSamples)
  167. return false;
  168. for (int i = buffer.getNumChannels(); --i >= 0;)
  169. {
  170. buffer.copyFrom (i, start1, data[i], size1);
  171. buffer.copyFrom (i, start2, data[i] + size1, size2);
  172. }
  173. finishedWrite (size1 + size2);
  174. timeSliceThread.notify();
  175. return true;
  176. }
  177. bool useTimeSlice()
  178. {
  179. const int numToDo = getTotalSize() / 4;
  180. int start1, size1, start2, size2;
  181. prepareToRead (numToDo, start1, size1, start2, size2);
  182. if (size1 <= 0)
  183. return false;
  184. writer->writeFromAudioSampleBuffer (buffer, start1, size1);
  185. if (size2 > 0)
  186. writer->writeFromAudioSampleBuffer (buffer, start2, size2);
  187. finishedRead (size1 + size2);
  188. return true;
  189. }
  190. private:
  191. AudioSampleBuffer buffer;
  192. TimeSliceThread& timeSliceThread;
  193. ScopedPointer<AudioFormatWriter> writer;
  194. volatile bool isRunning;
  195. Buffer (const Buffer&);
  196. Buffer& operator= (const Buffer&);
  197. };
  198. AudioFormatWriter::ThreadedWriter::ThreadedWriter (AudioFormatWriter* writer, TimeSliceThread& backgroundThread, int numSamplesToBuffer)
  199. : buffer (new AudioFormatWriter::ThreadedWriter::Buffer (backgroundThread, writer, writer->numChannels, numSamplesToBuffer))
  200. {
  201. }
  202. AudioFormatWriter::ThreadedWriter::~ThreadedWriter()
  203. {
  204. }
  205. bool AudioFormatWriter::ThreadedWriter::write (const float** data, int numSamples)
  206. {
  207. return buffer->write (data, numSamples);
  208. }
  209. END_JUCE_NAMESPACE