Audio plugin host https://kx.studio/carla
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.

977 lines
44KB

  1. /*
  2. ==============================================================================
  3. This file is part of the Water library.
  4. Copyright (c) 2015 ROLI Ltd.
  5. Copyright (C) 2018 Filipe Coelho <falktx@falktx.com>
  6. Permission is granted to use this software under the terms of either:
  7. a) the GPL v2 (or any later version)
  8. b) the Affero GPL v3
  9. Details of these licenses can be found at: www.gnu.org/licenses
  10. Water 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. */
  15. #include "WavAudioFormat.h"
  16. #include "../audioformat/AudioFormatReader.h"
  17. #include "../memory/ByteOrder.h"
  18. #include "../memory/MemoryBlock.h"
  19. #include "../streams/InputStream.h"
  20. #include "../streams/MemoryOutputStream.h"
  21. #include "../xml/XmlDocument.h"
  22. #include "../xml/XmlElement.h"
  23. namespace water {
  24. static const char* const wavFormatName = "WAV file";
  25. //==============================================================================
  26. const char* const WavAudioFormat::bwavDescription = "bwav description";
  27. const char* const WavAudioFormat::bwavOriginator = "bwav originator";
  28. const char* const WavAudioFormat::bwavOriginatorRef = "bwav originator ref";
  29. const char* const WavAudioFormat::bwavOriginationDate = "bwav origination date";
  30. const char* const WavAudioFormat::bwavOriginationTime = "bwav origination time";
  31. const char* const WavAudioFormat::bwavTimeReference = "bwav time reference";
  32. const char* const WavAudioFormat::bwavCodingHistory = "bwav coding history";
  33. #if 0
  34. StringPairArray WavAudioFormat::createBWAVMetadata (const String& description,
  35. const String& originator,
  36. const String& originatorRef,
  37. Time date,
  38. const int64 timeReferenceSamples,
  39. const String& codingHistory)
  40. {
  41. StringPairArray m;
  42. m.set (bwavDescription, description);
  43. m.set (bwavOriginator, originator);
  44. m.set (bwavOriginatorRef, originatorRef);
  45. m.set (bwavOriginationDate, date.formatted ("%Y-%m-%d"));
  46. m.set (bwavOriginationTime, date.formatted ("%H:%M:%S"));
  47. m.set (bwavTimeReference, String (timeReferenceSamples));
  48. m.set (bwavCodingHistory, codingHistory);
  49. return m;
  50. }
  51. #endif
  52. const char* const WavAudioFormat::acidOneShot = "acid one shot";
  53. const char* const WavAudioFormat::acidRootSet = "acid root set";
  54. const char* const WavAudioFormat::acidStretch = "acid stretch";
  55. const char* const WavAudioFormat::acidDiskBased = "acid disk based";
  56. const char* const WavAudioFormat::acidizerFlag = "acidizer flag";
  57. const char* const WavAudioFormat::acidRootNote = "acid root note";
  58. const char* const WavAudioFormat::acidBeats = "acid beats";
  59. const char* const WavAudioFormat::acidDenominator = "acid denominator";
  60. const char* const WavAudioFormat::acidNumerator = "acid numerator";
  61. const char* const WavAudioFormat::acidTempo = "acid tempo";
  62. const char* const WavAudioFormat::riffInfoArchivalLocation = "IARL";
  63. const char* const WavAudioFormat::riffInfoArtist = "IART";
  64. const char* const WavAudioFormat::riffInfoBaseURL = "IBSU";
  65. const char* const WavAudioFormat::riffInfoCinematographer = "ICNM";
  66. const char* const WavAudioFormat::riffInfoComment = "CMNT";
  67. const char* const WavAudioFormat::riffInfoComments = "COMM";
  68. const char* const WavAudioFormat::riffInfoCommissioned = "ICMS";
  69. const char* const WavAudioFormat::riffInfoCopyright = "ICOP";
  70. const char* const WavAudioFormat::riffInfoCostumeDesigner = "ICDS";
  71. const char* const WavAudioFormat::riffInfoCountry = "ICNT";
  72. const char* const WavAudioFormat::riffInfoCropped = "ICRP";
  73. const char* const WavAudioFormat::riffInfoDateCreated = "ICRD";
  74. const char* const WavAudioFormat::riffInfoDateTimeOriginal = "IDIT";
  75. const char* const WavAudioFormat::riffInfoDefaultAudioStream = "ICAS";
  76. const char* const WavAudioFormat::riffInfoDimension = "IDIM";
  77. const char* const WavAudioFormat::riffInfoDirectory = "DIRC";
  78. const char* const WavAudioFormat::riffInfoDistributedBy = "IDST";
  79. const char* const WavAudioFormat::riffInfoDotsPerInch = "IDPI";
  80. const char* const WavAudioFormat::riffInfoEditedBy = "IEDT";
  81. const char* const WavAudioFormat::riffInfoEighthLanguage = "IAS8";
  82. const char* const WavAudioFormat::riffInfoEncodedBy = "CODE";
  83. const char* const WavAudioFormat::riffInfoEndTimecode = "TCDO";
  84. const char* const WavAudioFormat::riffInfoEngineer = "IENG";
  85. const char* const WavAudioFormat::riffInfoFifthLanguage = "IAS5";
  86. const char* const WavAudioFormat::riffInfoFirstLanguage = "IAS1";
  87. const char* const WavAudioFormat::riffInfoFourthLanguage = "IAS4";
  88. const char* const WavAudioFormat::riffInfoGenre = "GENR";
  89. const char* const WavAudioFormat::riffInfoKeywords = "IKEY";
  90. const char* const WavAudioFormat::riffInfoLanguage = "LANG";
  91. const char* const WavAudioFormat::riffInfoLength = "TLEN";
  92. const char* const WavAudioFormat::riffInfoLightness = "ILGT";
  93. const char* const WavAudioFormat::riffInfoLocation = "LOCA";
  94. const char* const WavAudioFormat::riffInfoLogoIconURL = "ILIU";
  95. const char* const WavAudioFormat::riffInfoLogoURL = "ILGU";
  96. const char* const WavAudioFormat::riffInfoMedium = "IMED";
  97. const char* const WavAudioFormat::riffInfoMoreInfoBannerImage = "IMBI";
  98. const char* const WavAudioFormat::riffInfoMoreInfoBannerURL = "IMBU";
  99. const char* const WavAudioFormat::riffInfoMoreInfoText = "IMIT";
  100. const char* const WavAudioFormat::riffInfoMoreInfoURL = "IMIU";
  101. const char* const WavAudioFormat::riffInfoMusicBy = "IMUS";
  102. const char* const WavAudioFormat::riffInfoNinthLanguage = "IAS9";
  103. const char* const WavAudioFormat::riffInfoNumberOfParts = "PRT2";
  104. const char* const WavAudioFormat::riffInfoOrganisation = "TORG";
  105. const char* const WavAudioFormat::riffInfoPart = "PRT1";
  106. const char* const WavAudioFormat::riffInfoProducedBy = "IPRO";
  107. const char* const WavAudioFormat::riffInfoProductionDesigner = "IPDS";
  108. const char* const WavAudioFormat::riffInfoProductionStudio = "ISDT";
  109. const char* const WavAudioFormat::riffInfoRate = "RATE";
  110. const char* const WavAudioFormat::riffInfoRated = "AGES";
  111. const char* const WavAudioFormat::riffInfoRating = "IRTD";
  112. const char* const WavAudioFormat::riffInfoRippedBy = "IRIP";
  113. const char* const WavAudioFormat::riffInfoSecondaryGenre = "ISGN";
  114. const char* const WavAudioFormat::riffInfoSecondLanguage = "IAS2";
  115. const char* const WavAudioFormat::riffInfoSeventhLanguage = "IAS7";
  116. const char* const WavAudioFormat::riffInfoSharpness = "ISHP";
  117. const char* const WavAudioFormat::riffInfoSixthLanguage = "IAS6";
  118. const char* const WavAudioFormat::riffInfoSoftware = "ISFT";
  119. const char* const WavAudioFormat::riffInfoSoundSchemeTitle = "DISP";
  120. const char* const WavAudioFormat::riffInfoSource = "ISRC";
  121. const char* const WavAudioFormat::riffInfoSourceFrom = "ISRF";
  122. const char* const WavAudioFormat::riffInfoStarring_ISTR = "ISTR";
  123. const char* const WavAudioFormat::riffInfoStarring_STAR = "STAR";
  124. const char* const WavAudioFormat::riffInfoStartTimecode = "TCOD";
  125. const char* const WavAudioFormat::riffInfoStatistics = "STAT";
  126. const char* const WavAudioFormat::riffInfoSubject = "ISBJ";
  127. const char* const WavAudioFormat::riffInfoTapeName = "TAPE";
  128. const char* const WavAudioFormat::riffInfoTechnician = "ITCH";
  129. const char* const WavAudioFormat::riffInfoThirdLanguage = "IAS3";
  130. const char* const WavAudioFormat::riffInfoTimeCode = "ISMP";
  131. const char* const WavAudioFormat::riffInfoTitle = "INAM";
  132. const char* const WavAudioFormat::riffInfoTrackNumber = "TRCK";
  133. const char* const WavAudioFormat::riffInfoURL = "TURL";
  134. const char* const WavAudioFormat::riffInfoVegasVersionMajor = "VMAJ";
  135. const char* const WavAudioFormat::riffInfoVegasVersionMinor = "VMIN";
  136. const char* const WavAudioFormat::riffInfoVersion = "TVER";
  137. const char* const WavAudioFormat::riffInfoWatermarkURL = "IWMU";
  138. const char* const WavAudioFormat::riffInfoWrittenBy = "IWRI";
  139. const char* const WavAudioFormat::riffInfoYear = "YEAR";
  140. const char* const WavAudioFormat::ISRC = "ISRC";
  141. const char* const WavAudioFormat::tracktionLoopInfo = "tracktion loop info";
  142. //==============================================================================
  143. namespace WavFileHelpers
  144. {
  145. inline int chunkName (const char* const name) noexcept { return (int) ByteOrder::littleEndianInt (name); }
  146. inline size_t roundUpSize (size_t sz) noexcept { return (sz + 3) & ~3u; }
  147. #if _MSVC_VER
  148. #pragma pack (push, 1)
  149. #endif
  150. struct BWAVChunk
  151. {
  152. char description [256];
  153. char originator [32];
  154. char originatorRef [32];
  155. char originationDate [10];
  156. char originationTime [8];
  157. uint32 timeRefLow;
  158. uint32 timeRefHigh;
  159. uint16 version;
  160. uint8 umid[64];
  161. uint8 reserved[190];
  162. char codingHistory[1];
  163. void copyTo (StringPairArray& values, const int totalSize) const
  164. {
  165. values.set (WavAudioFormat::bwavDescription, String::fromUTF8 (description, sizeof (description)));
  166. values.set (WavAudioFormat::bwavOriginator, String::fromUTF8 (originator, sizeof (originator)));
  167. values.set (WavAudioFormat::bwavOriginatorRef, String::fromUTF8 (originatorRef, sizeof (originatorRef)));
  168. values.set (WavAudioFormat::bwavOriginationDate, String::fromUTF8 (originationDate, sizeof (originationDate)));
  169. values.set (WavAudioFormat::bwavOriginationTime, String::fromUTF8 (originationTime, sizeof (originationTime)));
  170. const uint32 timeLow = ByteOrder::swapIfBigEndian (timeRefLow);
  171. const uint32 timeHigh = ByteOrder::swapIfBigEndian (timeRefHigh);
  172. const int64 time = (((int64) timeHigh) << 32) + timeLow;
  173. values.set (WavAudioFormat::bwavTimeReference, String (time));
  174. values.set (WavAudioFormat::bwavCodingHistory,
  175. String::fromUTF8 (codingHistory, totalSize - (int) offsetof (BWAVChunk, codingHistory)));
  176. }
  177. } WATER_PACKED;
  178. //==============================================================================
  179. struct SMPLChunk
  180. {
  181. struct SampleLoop
  182. {
  183. uint32 identifier;
  184. uint32 type; // these are different in AIFF and WAV
  185. uint32 start;
  186. uint32 end;
  187. uint32 fraction;
  188. uint32 playCount;
  189. } WATER_PACKED;
  190. uint32 manufacturer;
  191. uint32 product;
  192. uint32 samplePeriod;
  193. uint32 midiUnityNote;
  194. uint32 midiPitchFraction;
  195. uint32 smpteFormat;
  196. uint32 smpteOffset;
  197. uint32 numSampleLoops;
  198. uint32 samplerData;
  199. SampleLoop loops[1];
  200. template <typename NameType>
  201. static void setValue (StringPairArray& values, NameType name, uint32 val)
  202. {
  203. values.set (name, String (ByteOrder::swapIfBigEndian (val)));
  204. }
  205. static void setValue (StringPairArray& values, int prefix, const char* name, uint32 val)
  206. {
  207. setValue (values, "Loop" + String (prefix) + name, val);
  208. }
  209. void copyTo (StringPairArray& values, const int totalSize) const
  210. {
  211. setValue (values, "Manufacturer", manufacturer);
  212. setValue (values, "Product", product);
  213. setValue (values, "SamplePeriod", samplePeriod);
  214. setValue (values, "MidiUnityNote", midiUnityNote);
  215. setValue (values, "MidiPitchFraction", midiPitchFraction);
  216. setValue (values, "SmpteFormat", smpteFormat);
  217. setValue (values, "SmpteOffset", smpteOffset);
  218. setValue (values, "NumSampleLoops", numSampleLoops);
  219. setValue (values, "SamplerData", samplerData);
  220. for (int i = 0; i < (int) numSampleLoops; ++i)
  221. {
  222. if ((uint8*) (loops + (i + 1)) > ((uint8*) this) + totalSize)
  223. break;
  224. setValue (values, i, "Identifier", loops[i].identifier);
  225. setValue (values, i, "Type", loops[i].type);
  226. setValue (values, i, "Start", loops[i].start);
  227. setValue (values, i, "End", loops[i].end);
  228. setValue (values, i, "Fraction", loops[i].fraction);
  229. setValue (values, i, "PlayCount", loops[i].playCount);
  230. }
  231. }
  232. template <typename NameType>
  233. static uint32 getValue (const StringPairArray& values, NameType name, const char* def)
  234. {
  235. return ByteOrder::swapIfBigEndian ((uint32) values.getValue (name, def).getIntValue());
  236. }
  237. static uint32 getValue (const StringPairArray& values, int prefix, const char* name, const char* def)
  238. {
  239. return getValue (values, "Loop" + String (prefix) + name, def);
  240. }
  241. } WATER_PACKED;
  242. //==============================================================================
  243. struct InstChunk
  244. {
  245. int8 baseNote;
  246. int8 detune;
  247. int8 gain;
  248. int8 lowNote;
  249. int8 highNote;
  250. int8 lowVelocity;
  251. int8 highVelocity;
  252. static void setValue (StringPairArray& values, const char* name, int val)
  253. {
  254. values.set (name, String (val));
  255. }
  256. void copyTo (StringPairArray& values) const
  257. {
  258. setValue (values, "MidiUnityNote", baseNote);
  259. setValue (values, "Detune", detune);
  260. setValue (values, "Gain", gain);
  261. setValue (values, "LowNote", lowNote);
  262. setValue (values, "HighNote", highNote);
  263. setValue (values, "LowVelocity", lowVelocity);
  264. setValue (values, "HighVelocity", highVelocity);
  265. }
  266. static int8 getValue (const StringPairArray& values, const char* name, const char* def)
  267. {
  268. return (int8) values.getValue (name, def).getIntValue();
  269. }
  270. } WATER_PACKED;
  271. //==============================================================================
  272. struct CueChunk
  273. {
  274. struct Cue
  275. {
  276. uint32 identifier;
  277. uint32 order;
  278. uint32 chunkID;
  279. uint32 chunkStart;
  280. uint32 blockStart;
  281. uint32 offset;
  282. } WATER_PACKED;
  283. uint32 numCues;
  284. Cue cues[1];
  285. static void setValue (StringPairArray& values, int prefix, const char* name, uint32 val)
  286. {
  287. values.set ("Cue" + String (prefix) + name, String (ByteOrder::swapIfBigEndian (val)));
  288. }
  289. void copyTo (StringPairArray& values, const int totalSize) const
  290. {
  291. values.set ("NumCuePoints", String (ByteOrder::swapIfBigEndian (numCues)));
  292. for (int i = 0; i < (int) numCues; ++i)
  293. {
  294. if ((uint8*) (cues + (i + 1)) > ((uint8*) this) + totalSize)
  295. break;
  296. setValue (values, i, "Identifier", cues[i].identifier);
  297. setValue (values, i, "Order", cues[i].order);
  298. setValue (values, i, "ChunkID", cues[i].chunkID);
  299. setValue (values, i, "ChunkStart", cues[i].chunkStart);
  300. setValue (values, i, "BlockStart", cues[i].blockStart);
  301. setValue (values, i, "Offset", cues[i].offset);
  302. }
  303. }
  304. } WATER_PACKED;
  305. //==============================================================================
  306. /** Reads a RIFF List Info chunk from a stream positioned just after the size byte. */
  307. namespace ListInfoChunk
  308. {
  309. static const char* const types[] =
  310. {
  311. WavAudioFormat::riffInfoArchivalLocation,
  312. WavAudioFormat::riffInfoArtist,
  313. WavAudioFormat::riffInfoBaseURL,
  314. WavAudioFormat::riffInfoCinematographer,
  315. WavAudioFormat::riffInfoComment,
  316. WavAudioFormat::riffInfoComments,
  317. WavAudioFormat::riffInfoCommissioned,
  318. WavAudioFormat::riffInfoCopyright,
  319. WavAudioFormat::riffInfoCostumeDesigner,
  320. WavAudioFormat::riffInfoCountry,
  321. WavAudioFormat::riffInfoCropped,
  322. WavAudioFormat::riffInfoDateCreated,
  323. WavAudioFormat::riffInfoDateTimeOriginal,
  324. WavAudioFormat::riffInfoDefaultAudioStream,
  325. WavAudioFormat::riffInfoDimension,
  326. WavAudioFormat::riffInfoDirectory,
  327. WavAudioFormat::riffInfoDistributedBy,
  328. WavAudioFormat::riffInfoDotsPerInch,
  329. WavAudioFormat::riffInfoEditedBy,
  330. WavAudioFormat::riffInfoEighthLanguage,
  331. WavAudioFormat::riffInfoEncodedBy,
  332. WavAudioFormat::riffInfoEndTimecode,
  333. WavAudioFormat::riffInfoEngineer,
  334. WavAudioFormat::riffInfoFifthLanguage,
  335. WavAudioFormat::riffInfoFirstLanguage,
  336. WavAudioFormat::riffInfoFourthLanguage,
  337. WavAudioFormat::riffInfoGenre,
  338. WavAudioFormat::riffInfoKeywords,
  339. WavAudioFormat::riffInfoLanguage,
  340. WavAudioFormat::riffInfoLength,
  341. WavAudioFormat::riffInfoLightness,
  342. WavAudioFormat::riffInfoLocation,
  343. WavAudioFormat::riffInfoLogoIconURL,
  344. WavAudioFormat::riffInfoLogoURL,
  345. WavAudioFormat::riffInfoMedium,
  346. WavAudioFormat::riffInfoMoreInfoBannerImage,
  347. WavAudioFormat::riffInfoMoreInfoBannerURL,
  348. WavAudioFormat::riffInfoMoreInfoText,
  349. WavAudioFormat::riffInfoMoreInfoURL,
  350. WavAudioFormat::riffInfoMusicBy,
  351. WavAudioFormat::riffInfoNinthLanguage,
  352. WavAudioFormat::riffInfoNumberOfParts,
  353. WavAudioFormat::riffInfoOrganisation,
  354. WavAudioFormat::riffInfoPart,
  355. WavAudioFormat::riffInfoProducedBy,
  356. WavAudioFormat::riffInfoProductionDesigner,
  357. WavAudioFormat::riffInfoProductionStudio,
  358. WavAudioFormat::riffInfoRate,
  359. WavAudioFormat::riffInfoRated,
  360. WavAudioFormat::riffInfoRating,
  361. WavAudioFormat::riffInfoRippedBy,
  362. WavAudioFormat::riffInfoSecondaryGenre,
  363. WavAudioFormat::riffInfoSecondLanguage,
  364. WavAudioFormat::riffInfoSeventhLanguage,
  365. WavAudioFormat::riffInfoSharpness,
  366. WavAudioFormat::riffInfoSixthLanguage,
  367. WavAudioFormat::riffInfoSoftware,
  368. WavAudioFormat::riffInfoSoundSchemeTitle,
  369. WavAudioFormat::riffInfoSource,
  370. WavAudioFormat::riffInfoSourceFrom,
  371. WavAudioFormat::riffInfoStarring_ISTR,
  372. WavAudioFormat::riffInfoStarring_STAR,
  373. WavAudioFormat::riffInfoStartTimecode,
  374. WavAudioFormat::riffInfoStatistics,
  375. WavAudioFormat::riffInfoSubject,
  376. WavAudioFormat::riffInfoTapeName,
  377. WavAudioFormat::riffInfoTechnician,
  378. WavAudioFormat::riffInfoThirdLanguage,
  379. WavAudioFormat::riffInfoTimeCode,
  380. WavAudioFormat::riffInfoTitle,
  381. WavAudioFormat::riffInfoTrackNumber,
  382. WavAudioFormat::riffInfoURL,
  383. WavAudioFormat::riffInfoVegasVersionMajor,
  384. WavAudioFormat::riffInfoVegasVersionMinor,
  385. WavAudioFormat::riffInfoVersion,
  386. WavAudioFormat::riffInfoWatermarkURL,
  387. WavAudioFormat::riffInfoWrittenBy,
  388. WavAudioFormat::riffInfoYear
  389. };
  390. static bool isMatchingTypeIgnoringCase (const int value, const char* const name) noexcept
  391. {
  392. for (int i = 0; i < 4; ++i)
  393. if ((uint32) name[i] != CharacterFunctions::toUpperCase ((uint32) ((value >> (i * 8)) & 0xff)))
  394. return false;
  395. return true;
  396. }
  397. static void addToMetadata (StringPairArray& values, InputStream& input, int64 chunkEnd)
  398. {
  399. while (input.getPosition() < chunkEnd)
  400. {
  401. const int infoType = input.readInt();
  402. int64 infoLength = chunkEnd - input.getPosition();
  403. if (infoLength > 0)
  404. {
  405. infoLength = jmin (infoLength, (int64) input.readInt());
  406. if (infoLength <= 0)
  407. return;
  408. for (int i = 0; i < numElementsInArray (types); ++i)
  409. {
  410. if (isMatchingTypeIgnoringCase (infoType, types[i]))
  411. {
  412. MemoryBlock mb;
  413. input.readIntoMemoryBlock (mb, (ssize_t) infoLength);
  414. values.set (types[i], String::createStringFromData ((const char*) mb.getData(),
  415. (int) mb.getSize()));
  416. break;
  417. }
  418. }
  419. }
  420. }
  421. }
  422. }
  423. //==============================================================================
  424. struct AcidChunk
  425. {
  426. /** Reads an acid RIFF chunk from a stream positioned just after the size byte. */
  427. AcidChunk (InputStream& input, size_t length)
  428. {
  429. zerostruct (*this);
  430. input.read (this, (int) jmin (sizeof (*this), length));
  431. }
  432. AcidChunk (const StringPairArray& values)
  433. {
  434. zerostruct (*this);
  435. flags = getFlagIfPresent (values, WavAudioFormat::acidOneShot, 0x01)
  436. | getFlagIfPresent (values, WavAudioFormat::acidRootSet, 0x02)
  437. | getFlagIfPresent (values, WavAudioFormat::acidStretch, 0x04)
  438. | getFlagIfPresent (values, WavAudioFormat::acidDiskBased, 0x08)
  439. | getFlagIfPresent (values, WavAudioFormat::acidizerFlag, 0x10);
  440. if (values[WavAudioFormat::acidRootSet].getIntValue() != 0)
  441. rootNote = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidRootNote].getIntValue());
  442. numBeats = ByteOrder::swapIfBigEndian ((uint32) values[WavAudioFormat::acidBeats].getIntValue());
  443. meterDenominator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidDenominator].getIntValue());
  444. meterNumerator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidNumerator].getIntValue());
  445. if (values.containsKey (WavAudioFormat::acidTempo))
  446. tempo = swapFloatByteOrder (values[WavAudioFormat::acidTempo].getFloatValue());
  447. }
  448. MemoryBlock toMemoryBlock() const
  449. {
  450. return (flags != 0 || rootNote != 0 || numBeats != 0 || meterDenominator != 0 || meterNumerator != 0)
  451. ? MemoryBlock (this, sizeof (*this)) : MemoryBlock();
  452. }
  453. void addToMetadata (StringPairArray& values) const
  454. {
  455. setBoolFlag (values, WavAudioFormat::acidOneShot, 0x01);
  456. setBoolFlag (values, WavAudioFormat::acidRootSet, 0x02);
  457. setBoolFlag (values, WavAudioFormat::acidStretch, 0x04);
  458. setBoolFlag (values, WavAudioFormat::acidDiskBased, 0x08);
  459. setBoolFlag (values, WavAudioFormat::acidizerFlag, 0x10);
  460. if (flags & 0x02) // root note set
  461. values.set (WavAudioFormat::acidRootNote, String (ByteOrder::swapIfBigEndian (rootNote)));
  462. values.set (WavAudioFormat::acidBeats, String (ByteOrder::swapIfBigEndian (numBeats)));
  463. values.set (WavAudioFormat::acidDenominator, String (ByteOrder::swapIfBigEndian (meterDenominator)));
  464. values.set (WavAudioFormat::acidNumerator, String (ByteOrder::swapIfBigEndian (meterNumerator)));
  465. values.set (WavAudioFormat::acidTempo, String (swapFloatByteOrder (tempo)));
  466. }
  467. void setBoolFlag (StringPairArray& values, const char* name, uint32 mask) const
  468. {
  469. values.set (name, (flags & ByteOrder::swapIfBigEndian (mask)) ? "1" : "0");
  470. }
  471. static uint32 getFlagIfPresent (const StringPairArray& values, const char* name, uint32 flag)
  472. {
  473. return values[name].getIntValue() != 0 ? ByteOrder::swapIfBigEndian (flag) : 0;
  474. }
  475. static float swapFloatByteOrder (const float x) noexcept
  476. {
  477. #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
  478. union { uint32 asInt; float asFloat; } n;
  479. n.asFloat = x;
  480. n.asInt = ByteOrder::swap (n.asInt);
  481. return n.asFloat;
  482. #else
  483. return x;
  484. #endif
  485. }
  486. uint32 flags;
  487. uint16 rootNote;
  488. uint16 reserved1;
  489. float reserved2;
  490. uint32 numBeats;
  491. uint16 meterDenominator;
  492. uint16 meterNumerator;
  493. float tempo;
  494. } WATER_PACKED;
  495. //==============================================================================
  496. namespace AXMLChunk
  497. {
  498. static void addToMetadata (StringPairArray& destValues, const String& source)
  499. {
  500. ScopedPointer<XmlElement> xml (XmlDocument::parse (source));
  501. if (xml != nullptr && xml->hasTagName ("ebucore:ebuCoreMain"))
  502. {
  503. if (XmlElement* xml2 = xml->getChildByName ("ebucore:coreMetadata"))
  504. {
  505. if (XmlElement* xml3 = xml2->getChildByName ("ebucore:identifier"))
  506. {
  507. if (XmlElement* xml4 = xml3->getChildByName ("dc:identifier"))
  508. {
  509. const String ISRCCode (xml4->getAllSubText().fromFirstOccurrenceOf ("ISRC:", false, true));
  510. if (ISRCCode.isNotEmpty())
  511. destValues.set (WavAudioFormat::ISRC, ISRCCode);
  512. }
  513. }
  514. }
  515. }
  516. }
  517. };
  518. //==============================================================================
  519. struct ExtensibleWavSubFormat
  520. {
  521. uint32 data1;
  522. uint16 data2;
  523. uint16 data3;
  524. uint8 data4[8];
  525. bool operator== (const ExtensibleWavSubFormat& other) const noexcept { return memcmp (this, &other, sizeof (*this)) == 0; }
  526. bool operator!= (const ExtensibleWavSubFormat& other) const noexcept { return ! operator== (other); }
  527. } WATER_PACKED;
  528. static const ExtensibleWavSubFormat pcmFormat = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
  529. static const ExtensibleWavSubFormat IEEEFloatFormat = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
  530. static const ExtensibleWavSubFormat ambisonicFormat = { 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } };
  531. struct DataSize64Chunk // chunk ID = 'ds64' if data size > 0xffffffff, 'JUNK' otherwise
  532. {
  533. uint32 riffSizeLow; // low 4 byte size of RF64 block
  534. uint32 riffSizeHigh; // high 4 byte size of RF64 block
  535. uint32 dataSizeLow; // low 4 byte size of data chunk
  536. uint32 dataSizeHigh; // high 4 byte size of data chunk
  537. uint32 sampleCountLow; // low 4 byte sample count of fact chunk
  538. uint32 sampleCountHigh; // high 4 byte sample count of fact chunk
  539. uint32 tableLength; // number of valid entries in array 'table'
  540. } WATER_PACKED;
  541. #if _MSVC_VER
  542. #pragma pack (pop)
  543. #endif
  544. }
  545. //==============================================================================
  546. class WavAudioFormatReader : public AudioFormatReader
  547. {
  548. public:
  549. WavAudioFormatReader (InputStream* const in)
  550. : AudioFormatReader (in, wavFormatName),
  551. bwavChunkStart (0),
  552. bwavSize (0),
  553. dataLength (0),
  554. isRF64 (false)
  555. {
  556. using namespace WavFileHelpers;
  557. uint64 len = 0;
  558. uint64 end = 0;
  559. int cueNoteIndex = 0;
  560. int cueLabelIndex = 0;
  561. int cueRegionIndex = 0;
  562. const int firstChunkType = input->readInt();
  563. if (firstChunkType == chunkName ("RF64"))
  564. {
  565. input->skipNextBytes (4); // size is -1 for RF64
  566. isRF64 = true;
  567. }
  568. else if (firstChunkType == chunkName ("RIFF"))
  569. {
  570. len = (uint64) (uint32) input->readInt();
  571. end = len + (uint64) input->getPosition();
  572. }
  573. else
  574. {
  575. return;
  576. }
  577. const int64 startOfRIFFChunk = input->getPosition();
  578. if (input->readInt() == chunkName ("WAVE"))
  579. {
  580. if (isRF64 && input->readInt() == chunkName ("ds64"))
  581. {
  582. const uint32 length = (uint32) input->readInt();
  583. if (length < 28)
  584. return;
  585. const int64 chunkEnd = input->getPosition() + length + (length & 1);
  586. len = (uint64) input->readInt64();
  587. end = len + (uint64) startOfRIFFChunk;
  588. dataLength = input->readInt64();
  589. input->setPosition (chunkEnd);
  590. }
  591. while ((uint64) input->getPosition() < end && ! input->isExhausted())
  592. {
  593. const int chunkType = input->readInt();
  594. uint32 length = (uint32) input->readInt();
  595. const int64 chunkEnd = input->getPosition() + length + (length & 1);
  596. if (chunkType == chunkName ("fmt "))
  597. {
  598. // read the format chunk
  599. const unsigned short format = (unsigned short) input->readShort();
  600. numChannels = (unsigned int) input->readShort();
  601. sampleRate = input->readInt();
  602. const int bytesPerSec = input->readInt();
  603. input->skipNextBytes (2);
  604. bitsPerSample = (unsigned int) (int) input->readShort();
  605. if (bitsPerSample > 64)
  606. {
  607. bytesPerFrame = bytesPerSec / (int) sampleRate;
  608. bitsPerSample = 8 * (unsigned int) bytesPerFrame / numChannels;
  609. }
  610. else
  611. {
  612. bytesPerFrame = numChannels * bitsPerSample / 8;
  613. }
  614. if (format == 3)
  615. {
  616. usesFloatingPointData = true;
  617. }
  618. else if (format == 0xfffe /*WAVE_FORMAT_EXTENSIBLE*/)
  619. {
  620. if (length < 40) // too short
  621. {
  622. bytesPerFrame = 0;
  623. }
  624. else
  625. {
  626. input->skipNextBytes (4); // skip over size and bitsPerSample
  627. metadataValues.set ("ChannelMask", String (input->readInt()));
  628. ExtensibleWavSubFormat subFormat;
  629. subFormat.data1 = (uint32) input->readInt();
  630. subFormat.data2 = (uint16) input->readShort();
  631. subFormat.data3 = (uint16) input->readShort();
  632. input->read (subFormat.data4, sizeof (subFormat.data4));
  633. if (subFormat == IEEEFloatFormat)
  634. usesFloatingPointData = true;
  635. else if (subFormat != pcmFormat && subFormat != ambisonicFormat)
  636. bytesPerFrame = 0;
  637. }
  638. }
  639. else if (format != 1)
  640. {
  641. bytesPerFrame = 0;
  642. }
  643. }
  644. else if (chunkType == chunkName ("data"))
  645. {
  646. if (! isRF64) // data size is expected to be -1, actual data size is in ds64 chunk
  647. dataLength = length;
  648. dataChunkStart = input->getPosition();
  649. lengthInSamples = (bytesPerFrame > 0) ? (dataLength / bytesPerFrame) : 0;
  650. }
  651. else if (chunkType == chunkName ("bext"))
  652. {
  653. bwavChunkStart = input->getPosition();
  654. bwavSize = length;
  655. HeapBlock<BWAVChunk> bwav;
  656. bwav.calloc (jmax ((size_t) length + 1, sizeof (BWAVChunk)), 1);
  657. input->read (bwav, (int) length);
  658. bwav->copyTo (metadataValues, (int) length);
  659. }
  660. else if (chunkType == chunkName ("smpl"))
  661. {
  662. HeapBlock<SMPLChunk> smpl;
  663. smpl.calloc (jmax ((size_t) length + 1, sizeof (SMPLChunk)), 1);
  664. input->read (smpl, (int) length);
  665. smpl->copyTo (metadataValues, (int) length);
  666. }
  667. else if (chunkType == chunkName ("inst") || chunkType == chunkName ("INST")) // need to check which...
  668. {
  669. HeapBlock<InstChunk> inst;
  670. inst.calloc (jmax ((size_t) length + 1, sizeof (InstChunk)), 1);
  671. input->read (inst, (int) length);
  672. inst->copyTo (metadataValues);
  673. }
  674. else if (chunkType == chunkName ("cue "))
  675. {
  676. HeapBlock<CueChunk> cue;
  677. cue.calloc (jmax ((size_t) length + 1, sizeof (CueChunk)), 1);
  678. input->read (cue, (int) length);
  679. cue->copyTo (metadataValues, (int) length);
  680. }
  681. else if (chunkType == chunkName ("axml"))
  682. {
  683. MemoryBlock axml;
  684. input->readIntoMemoryBlock (axml, (ssize_t) length);
  685. AXMLChunk::addToMetadata (metadataValues, axml.toString());
  686. }
  687. else if (chunkType == chunkName ("LIST"))
  688. {
  689. const int subChunkType = input->readInt();
  690. if (subChunkType == chunkName ("info") || subChunkType == chunkName ("INFO"))
  691. {
  692. ListInfoChunk::addToMetadata (metadataValues, *input, chunkEnd);
  693. }
  694. else if (subChunkType == chunkName ("adtl"))
  695. {
  696. while (input->getPosition() < chunkEnd)
  697. {
  698. const int adtlChunkType = input->readInt();
  699. const uint32 adtlLength = (uint32) input->readInt();
  700. const int64 adtlChunkEnd = input->getPosition() + (adtlLength + (adtlLength & 1));
  701. if (adtlChunkType == chunkName ("labl") || adtlChunkType == chunkName ("note"))
  702. {
  703. String prefix;
  704. if (adtlChunkType == chunkName ("labl"))
  705. prefix << "CueLabel" << cueLabelIndex++;
  706. else if (adtlChunkType == chunkName ("note"))
  707. prefix << "CueNote" << cueNoteIndex++;
  708. const uint32 identifier = (uint32) input->readInt();
  709. const int stringLength = (int) adtlLength - 4;
  710. MemoryBlock textBlock;
  711. input->readIntoMemoryBlock (textBlock, stringLength);
  712. metadataValues.set (prefix + "Identifier", String (identifier));
  713. metadataValues.set (prefix + "Text", textBlock.toString());
  714. }
  715. else if (adtlChunkType == chunkName ("ltxt"))
  716. {
  717. const String prefix ("CueRegion" + String (cueRegionIndex++));
  718. const uint32 identifier = (uint32) input->readInt();
  719. const uint32 sampleLength = (uint32) input->readInt();
  720. const uint32 purpose = (uint32) input->readInt();
  721. const uint16 country = (uint16) input->readInt();
  722. const uint16 language = (uint16) input->readInt();
  723. const uint16 dialect = (uint16) input->readInt();
  724. const uint16 codePage = (uint16) input->readInt();
  725. const uint32 stringLength = adtlLength - 20;
  726. MemoryBlock textBlock;
  727. input->readIntoMemoryBlock (textBlock, (int) stringLength);
  728. metadataValues.set (prefix + "Identifier", String (identifier));
  729. metadataValues.set (prefix + "SampleLength", String (sampleLength));
  730. metadataValues.set (prefix + "Purpose", String (purpose));
  731. metadataValues.set (prefix + "Country", String (country));
  732. metadataValues.set (prefix + "Language", String (language));
  733. metadataValues.set (prefix + "Dialect", String (dialect));
  734. metadataValues.set (prefix + "CodePage", String (codePage));
  735. metadataValues.set (prefix + "Text", textBlock.toString());
  736. }
  737. input->setPosition (adtlChunkEnd);
  738. }
  739. }
  740. }
  741. else if (chunkType == chunkName ("acid"))
  742. {
  743. AcidChunk (*input, length).addToMetadata (metadataValues);
  744. }
  745. else if (chunkType == chunkName ("Trkn"))
  746. {
  747. MemoryBlock tracktion;
  748. input->readIntoMemoryBlock (tracktion, (ssize_t) length);
  749. metadataValues.set (WavAudioFormat::tracktionLoopInfo, tracktion.toString());
  750. }
  751. else if (chunkEnd <= input->getPosition())
  752. {
  753. break;
  754. }
  755. input->setPosition (chunkEnd);
  756. }
  757. }
  758. if (cueLabelIndex > 0) metadataValues.set ("NumCueLabels", String (cueLabelIndex));
  759. if (cueNoteIndex > 0) metadataValues.set ("NumCueNotes", String (cueNoteIndex));
  760. if (cueRegionIndex > 0) metadataValues.set ("NumCueRegions", String (cueRegionIndex));
  761. if (metadataValues.size() > 0) metadataValues.set ("MetaDataSource", "WAV");
  762. }
  763. //==============================================================================
  764. bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
  765. int64 startSampleInFile, int numSamples) override
  766. {
  767. clearSamplesBeyondAvailableLength (destSamples, numDestChannels, startOffsetInDestBuffer,
  768. startSampleInFile, numSamples, lengthInSamples);
  769. if (numSamples <= 0)
  770. return true;
  771. input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame);
  772. while (numSamples > 0)
  773. {
  774. const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
  775. char tempBuffer [tempBufSize];
  776. const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
  777. const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
  778. if (bytesRead < numThisTime * bytesPerFrame)
  779. {
  780. jassert (bytesRead >= 0);
  781. zeromem (tempBuffer + bytesRead, (size_t) (numThisTime * bytesPerFrame - bytesRead));
  782. }
  783. copySampleData (bitsPerSample, usesFloatingPointData,
  784. destSamples, startOffsetInDestBuffer, numDestChannels,
  785. tempBuffer, (int) numChannels, numThisTime);
  786. startOffsetInDestBuffer += numThisTime;
  787. numSamples -= numThisTime;
  788. }
  789. return true;
  790. }
  791. static void copySampleData (unsigned int bitsPerSample, const bool usesFloatingPointData,
  792. int* const* destSamples, int startOffsetInDestBuffer, int numDestChannels,
  793. const void* sourceData, int numChannels, int numSamples) noexcept
  794. {
  795. switch (bitsPerSample)
  796. {
  797. case 8:
  798. ReadHelper<AudioData::Int32, AudioData::UInt8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numChannels, numSamples);
  799. break;
  800. case 16:
  801. ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numChannels, numSamples);
  802. break;
  803. case 24:
  804. ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numChannels, numSamples);
  805. break;
  806. case 32:
  807. if (usesFloatingPointData)
  808. ReadHelper<AudioData::Float32, AudioData::Float32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numChannels, numSamples);
  809. else
  810. ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numChannels, numSamples);
  811. break;
  812. default:
  813. jassertfalse;
  814. break;
  815. }
  816. }
  817. int64 bwavChunkStart, bwavSize;
  818. int64 dataChunkStart, dataLength;
  819. int bytesPerFrame;
  820. bool isRF64;
  821. private:
  822. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WavAudioFormatReader)
  823. };
  824. //==============================================================================
  825. WavAudioFormat::WavAudioFormat() : AudioFormat (wavFormatName, ".wav .bwf") {}
  826. WavAudioFormat::~WavAudioFormat() {}
  827. Array<int> WavAudioFormat::getPossibleSampleRates()
  828. {
  829. const int rates[] = { 8000, 11025, 12000, 16000, 22050, 32000, 44100,
  830. 48000, 88200, 96000, 176400, 192000, 352800, 384000 };
  831. return Array<int> (rates, numElementsInArray (rates));
  832. }
  833. Array<int> WavAudioFormat::getPossibleBitDepths()
  834. {
  835. const int depths[] = { 8, 16, 24, 32 };
  836. return Array<int> (depths, numElementsInArray (depths));
  837. }
  838. bool WavAudioFormat::canDoStereo() { return true; }
  839. bool WavAudioFormat::canDoMono() { return true; }
  840. AudioFormatReader* WavAudioFormat::createReaderFor (InputStream* sourceStream,
  841. const bool deleteStreamIfOpeningFails)
  842. {
  843. ScopedPointer<WavAudioFormatReader> r (new WavAudioFormatReader (sourceStream));
  844. if (r->sampleRate > 0 && r->numChannels > 0 && r->bytesPerFrame > 0)
  845. return r.release();
  846. if (! deleteStreamIfOpeningFails)
  847. r->input = nullptr;
  848. return nullptr;
  849. }
  850. }