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.

440 lines
17KB

  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_AiffAudioFormat.h"
  21. #include "../../io/streams/juce_BufferedInputStream.h"
  22. #include "../../core/juce_PlatformUtilities.h"
  23. #include "../../text/juce_LocalisedStrings.h"
  24. //==============================================================================
  25. static const char* const aiffFormatName = "AIFF file";
  26. static const char* const aiffExtensions[] = { ".aiff", ".aif", 0 };
  27. //==============================================================================
  28. class AiffAudioFormatReader : public AudioFormatReader
  29. {
  30. public:
  31. int bytesPerFrame;
  32. int64 dataChunkStart;
  33. bool littleEndian;
  34. //==============================================================================
  35. AiffAudioFormatReader (InputStream* in)
  36. : AudioFormatReader (in, TRANS (aiffFormatName))
  37. {
  38. if (input->readInt() == chunkName ("FORM"))
  39. {
  40. const int len = input->readIntBigEndian();
  41. const int64 end = input->getPosition() + len;
  42. const int nextType = input->readInt();
  43. if (nextType == chunkName ("AIFF") || nextType == chunkName ("AIFC"))
  44. {
  45. bool hasGotVer = false;
  46. bool hasGotData = false;
  47. bool hasGotType = false;
  48. while (input->getPosition() < end)
  49. {
  50. const int type = input->readInt();
  51. const uint32 length = (uint32) input->readIntBigEndian();
  52. const int64 chunkEnd = input->getPosition() + length;
  53. if (type == chunkName ("FVER"))
  54. {
  55. hasGotVer = true;
  56. const int ver = input->readIntBigEndian();
  57. if (ver != 0 && ver != (int) 0xa2805140)
  58. break;
  59. }
  60. else if (type == chunkName ("COMM"))
  61. {
  62. hasGotType = true;
  63. numChannels = (unsigned int) input->readShortBigEndian();
  64. lengthInSamples = input->readIntBigEndian();
  65. bitsPerSample = input->readShortBigEndian();
  66. bytesPerFrame = (numChannels * bitsPerSample) >> 3;
  67. unsigned char sampleRateBytes[10];
  68. input->read (sampleRateBytes, 10);
  69. const int byte0 = sampleRateBytes[0];
  70. if ((byte0 & 0x80) != 0
  71. || byte0 <= 0x3F || byte0 > 0x40
  72. || (byte0 == 0x40 && sampleRateBytes[1] > 0x1C))
  73. break;
  74. unsigned int sampRate = ByteOrder::bigEndianInt (sampleRateBytes + 2);
  75. sampRate >>= (16414 - ByteOrder::bigEndianShort (sampleRateBytes));
  76. sampleRate = (int) sampRate;
  77. if (length <= 18)
  78. {
  79. // some types don't have a chunk large enough to include a compression
  80. // type, so assume it's just big-endian pcm
  81. littleEndian = false;
  82. }
  83. else
  84. {
  85. const int compType = input->readInt();
  86. if (compType == chunkName ("NONE") || compType == chunkName ("twos"))
  87. {
  88. littleEndian = false;
  89. }
  90. else if (compType == chunkName ("sowt"))
  91. {
  92. littleEndian = true;
  93. }
  94. else
  95. {
  96. sampleRate = 0;
  97. break;
  98. }
  99. }
  100. }
  101. else if (type == chunkName ("SSND"))
  102. {
  103. hasGotData = true;
  104. const int offset = input->readIntBigEndian();
  105. dataChunkStart = input->getPosition() + 4 + offset;
  106. lengthInSamples = (bytesPerFrame > 0) ? jmin (lengthInSamples, (int64) (length / bytesPerFrame)) : 0;
  107. }
  108. else if ((hasGotVer && hasGotData && hasGotType)
  109. || chunkEnd < input->getPosition()
  110. || input->isExhausted())
  111. {
  112. break;
  113. }
  114. input->setPosition (chunkEnd);
  115. }
  116. }
  117. }
  118. }
  119. ~AiffAudioFormatReader()
  120. {
  121. }
  122. //==============================================================================
  123. bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
  124. int64 startSampleInFile, int numSamples)
  125. {
  126. const int64 samplesAvailable = lengthInSamples - startSampleInFile;
  127. if (samplesAvailable < numSamples)
  128. {
  129. for (int i = numDestChannels; --i >= 0;)
  130. if (destSamples[i] != 0)
  131. zeromem (destSamples[i] + startOffsetInDestBuffer, sizeof (int) * numSamples);
  132. numSamples = (int) samplesAvailable;
  133. }
  134. if (numSamples <= 0)
  135. return true;
  136. input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame);
  137. while (numSamples > 0)
  138. {
  139. const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
  140. char tempBuffer [tempBufSize];
  141. const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
  142. const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
  143. if (bytesRead < numThisTime * bytesPerFrame)
  144. {
  145. jassert (bytesRead >= 0);
  146. zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead);
  147. }
  148. jassert (! usesFloatingPointData); // (would need to add support for this if it's possible)
  149. if (littleEndian)
  150. {
  151. switch (bitsPerSample)
  152. {
  153. case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
  154. case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
  155. case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
  156. case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
  157. default: jassertfalse; break;
  158. }
  159. }
  160. else
  161. {
  162. switch (bitsPerSample)
  163. {
  164. case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
  165. case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
  166. case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
  167. case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
  168. default: jassertfalse; break;
  169. }
  170. }
  171. startOffsetInDestBuffer += numThisTime;
  172. numSamples -= numThisTime;
  173. }
  174. return true;
  175. }
  176. juce_UseDebuggingNewOperator
  177. private:
  178. AiffAudioFormatReader (const AiffAudioFormatReader&);
  179. AiffAudioFormatReader& operator= (const AiffAudioFormatReader&);
  180. static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
  181. };
  182. //==============================================================================
  183. class AiffAudioFormatWriter : public AudioFormatWriter
  184. {
  185. public:
  186. //==============================================================================
  187. AiffAudioFormatWriter (OutputStream* out, double sampleRate_, unsigned int numChans, int bits)
  188. : AudioFormatWriter (out, TRANS (aiffFormatName), sampleRate_, numChans, bits),
  189. lengthInSamples (0),
  190. bytesWritten (0),
  191. writeFailed (false)
  192. {
  193. headerPosition = out->getPosition();
  194. writeHeader();
  195. }
  196. ~AiffAudioFormatWriter()
  197. {
  198. if ((bytesWritten & 1) != 0)
  199. output->writeByte (0);
  200. writeHeader();
  201. }
  202. //==============================================================================
  203. bool write (const int** data, int numSamples)
  204. {
  205. jassert (data != 0 && *data != 0); // the input must contain at least one channel!
  206. if (writeFailed)
  207. return false;
  208. const int bytes = numChannels * numSamples * bitsPerSample / 8;
  209. tempBlock.ensureSize (bytes, false);
  210. switch (bitsPerSample)
  211. {
  212. case 8: WriteHelper<AudioData::Int8, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
  213. case 16: WriteHelper<AudioData::Int16, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
  214. case 24: WriteHelper<AudioData::Int24, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
  215. case 32: WriteHelper<AudioData::Int32, AudioData::Int32, AudioData::BigEndian>::write (tempBlock.getData(), numChannels, data, numSamples); break;
  216. default: jassertfalse; break;
  217. }
  218. if (bytesWritten + bytes >= (uint32) 0xfff00000
  219. || ! output->write (tempBlock.getData(), bytes))
  220. {
  221. // failed to write to disk, so let's try writing the header.
  222. // If it's just run out of disk space, then if it does manage
  223. // to write the header, we'll still have a useable file..
  224. writeHeader();
  225. writeFailed = true;
  226. return false;
  227. }
  228. else
  229. {
  230. bytesWritten += bytes;
  231. lengthInSamples += numSamples;
  232. return true;
  233. }
  234. }
  235. juce_UseDebuggingNewOperator
  236. private:
  237. MemoryBlock tempBlock;
  238. uint32 lengthInSamples, bytesWritten;
  239. int64 headerPosition;
  240. bool writeFailed;
  241. static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
  242. AiffAudioFormatWriter (const AiffAudioFormatWriter&);
  243. AiffAudioFormatWriter& operator= (const AiffAudioFormatWriter&);
  244. void writeHeader()
  245. {
  246. const bool couldSeekOk = output->setPosition (headerPosition);
  247. (void) couldSeekOk;
  248. // if this fails, you've given it an output stream that can't seek! It needs
  249. // to be able to seek back to write the header
  250. jassert (couldSeekOk);
  251. const int headerLen = 54;
  252. int audioBytes = lengthInSamples * ((bitsPerSample * numChannels) / 8);
  253. audioBytes += (audioBytes & 1);
  254. output->writeInt (chunkName ("FORM"));
  255. output->writeIntBigEndian (headerLen + audioBytes - 8);
  256. output->writeInt (chunkName ("AIFF"));
  257. output->writeInt (chunkName ("COMM"));
  258. output->writeIntBigEndian (18);
  259. output->writeShortBigEndian ((short) numChannels);
  260. output->writeIntBigEndian (lengthInSamples);
  261. output->writeShortBigEndian ((short) bitsPerSample);
  262. uint8 sampleRateBytes[10];
  263. zeromem (sampleRateBytes, 10);
  264. if (sampleRate <= 1)
  265. {
  266. sampleRateBytes[0] = 0x3f;
  267. sampleRateBytes[1] = 0xff;
  268. sampleRateBytes[2] = 0x80;
  269. }
  270. else
  271. {
  272. int mask = 0x40000000;
  273. sampleRateBytes[0] = 0x40;
  274. if (sampleRate >= mask)
  275. {
  276. jassertfalse;
  277. sampleRateBytes[1] = 0x1d;
  278. }
  279. else
  280. {
  281. int n = (int) sampleRate;
  282. int i;
  283. for (i = 0; i <= 32 ; ++i)
  284. {
  285. if ((n & mask) != 0)
  286. break;
  287. mask >>= 1;
  288. }
  289. n = n << (i + 1);
  290. sampleRateBytes[1] = (uint8) (29 - i);
  291. sampleRateBytes[2] = (uint8) ((n >> 24) & 0xff);
  292. sampleRateBytes[3] = (uint8) ((n >> 16) & 0xff);
  293. sampleRateBytes[4] = (uint8) ((n >> 8) & 0xff);
  294. sampleRateBytes[5] = (uint8) (n & 0xff);
  295. }
  296. }
  297. output->write (sampleRateBytes, 10);
  298. output->writeInt (chunkName ("SSND"));
  299. output->writeIntBigEndian (audioBytes + 8);
  300. output->writeInt (0);
  301. output->writeInt (0);
  302. jassert (output->getPosition() == headerLen);
  303. }
  304. };
  305. //==============================================================================
  306. AiffAudioFormat::AiffAudioFormat()
  307. : AudioFormat (TRANS (aiffFormatName), StringArray (aiffExtensions))
  308. {
  309. }
  310. AiffAudioFormat::~AiffAudioFormat()
  311. {
  312. }
  313. const Array <int> AiffAudioFormat::getPossibleSampleRates()
  314. {
  315. const int rates[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 };
  316. return Array <int> (rates);
  317. }
  318. const Array <int> AiffAudioFormat::getPossibleBitDepths()
  319. {
  320. const int depths[] = { 8, 16, 24, 0 };
  321. return Array <int> (depths);
  322. }
  323. bool AiffAudioFormat::canDoStereo() { return true; }
  324. bool AiffAudioFormat::canDoMono() { return true; }
  325. #if JUCE_MAC
  326. bool AiffAudioFormat::canHandleFile (const File& f)
  327. {
  328. if (AudioFormat::canHandleFile (f))
  329. return true;
  330. const OSType type = PlatformUtilities::getTypeOfFile (f.getFullPathName());
  331. return type == 'AIFF' || type == 'AIFC'
  332. || type == 'aiff' || type == 'aifc';
  333. }
  334. #endif
  335. AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream, const bool deleteStreamIfOpeningFails)
  336. {
  337. ScopedPointer <AiffAudioFormatReader> w (new AiffAudioFormatReader (sourceStream));
  338. if (w->sampleRate != 0)
  339. return w.release();
  340. if (! deleteStreamIfOpeningFails)
  341. w->input = 0;
  342. return 0;
  343. }
  344. AudioFormatWriter* AiffAudioFormat::createWriterFor (OutputStream* out,
  345. double sampleRate,
  346. unsigned int numberOfChannels,
  347. int bitsPerSample,
  348. const StringPairArray& /*metadataValues*/,
  349. int /*qualityOptionIndex*/)
  350. {
  351. if (getPossibleBitDepths().contains (bitsPerSample))
  352. return new AiffAudioFormatWriter (out, sampleRate, numberOfChannels, bitsPerSample);
  353. return 0;
  354. }
  355. END_JUCE_NAMESPACE