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.

juce_AudioDataConverters.cpp 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. The code included in this file is provided under the terms of the ISC license
  8. http://www.isc.org/downloads/software-support-policy/isc-license. Permission
  9. To use, copy, modify, and/or distribute this software for any purpose with or
  10. without fee is hereby granted provided that the above copyright notice and
  11. this permission notice appear in all copies.
  12. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  13. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  14. DISCLAIMED.
  15. ==============================================================================
  16. */
  17. namespace juce
  18. {
  19. void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
  20. {
  21. auto maxVal = (double) 0x7fff;
  22. auto intData = static_cast<char*> (dest);
  23. if (dest != (void*) source || destBytesPerSample <= 4)
  24. {
  25. for (int i = 0; i < numSamples; ++i)
  26. {
  27. *unalignedPointerCast<uint16*> (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
  28. intData += destBytesPerSample;
  29. }
  30. }
  31. else
  32. {
  33. intData += destBytesPerSample * numSamples;
  34. for (int i = numSamples; --i >= 0;)
  35. {
  36. intData -= destBytesPerSample;
  37. *unalignedPointerCast<uint16*> (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
  38. }
  39. }
  40. }
  41. void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
  42. {
  43. auto maxVal = (double) 0x7fff;
  44. auto intData = static_cast<char*> (dest);
  45. if (dest != (void*) source || destBytesPerSample <= 4)
  46. {
  47. for (int i = 0; i < numSamples; ++i)
  48. {
  49. *unalignedPointerCast<uint16*> (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
  50. intData += destBytesPerSample;
  51. }
  52. }
  53. else
  54. {
  55. intData += destBytesPerSample * numSamples;
  56. for (int i = numSamples; --i >= 0;)
  57. {
  58. intData -= destBytesPerSample;
  59. *unalignedPointerCast<uint16*> (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
  60. }
  61. }
  62. }
  63. void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
  64. {
  65. auto maxVal = (double) 0x7fffff;
  66. auto intData = static_cast<char*> (dest);
  67. if (dest != (void*) source || destBytesPerSample <= 4)
  68. {
  69. for (int i = 0; i < numSamples; ++i)
  70. {
  71. ByteOrder::littleEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
  72. intData += destBytesPerSample;
  73. }
  74. }
  75. else
  76. {
  77. intData += destBytesPerSample * numSamples;
  78. for (int i = numSamples; --i >= 0;)
  79. {
  80. intData -= destBytesPerSample;
  81. ByteOrder::littleEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
  82. }
  83. }
  84. }
  85. void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
  86. {
  87. auto maxVal = (double) 0x7fffff;
  88. auto intData = static_cast<char*> (dest);
  89. if (dest != (void*) source || destBytesPerSample <= 4)
  90. {
  91. for (int i = 0; i < numSamples; ++i)
  92. {
  93. ByteOrder::bigEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
  94. intData += destBytesPerSample;
  95. }
  96. }
  97. else
  98. {
  99. intData += destBytesPerSample * numSamples;
  100. for (int i = numSamples; --i >= 0;)
  101. {
  102. intData -= destBytesPerSample;
  103. ByteOrder::bigEndian24BitToChars (roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])), intData);
  104. }
  105. }
  106. }
  107. void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
  108. {
  109. auto maxVal = (double) 0x7fffffff;
  110. auto intData = static_cast<char*> (dest);
  111. if (dest != (void*) source || destBytesPerSample <= 4)
  112. {
  113. for (int i = 0; i < numSamples; ++i)
  114. {
  115. *unalignedPointerCast<uint32*> (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
  116. intData += destBytesPerSample;
  117. }
  118. }
  119. else
  120. {
  121. intData += destBytesPerSample * numSamples;
  122. for (int i = numSamples; --i >= 0;)
  123. {
  124. intData -= destBytesPerSample;
  125. *unalignedPointerCast<uint32*> (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
  126. }
  127. }
  128. }
  129. void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
  130. {
  131. auto maxVal = (double) 0x7fffffff;
  132. auto intData = static_cast<char*> (dest);
  133. if (dest != (void*) source || destBytesPerSample <= 4)
  134. {
  135. for (int i = 0; i < numSamples; ++i)
  136. {
  137. *unalignedPointerCast<uint32*> (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
  138. intData += destBytesPerSample;
  139. }
  140. }
  141. else
  142. {
  143. intData += destBytesPerSample * numSamples;
  144. for (int i = numSamples; --i >= 0;)
  145. {
  146. intData -= destBytesPerSample;
  147. *unalignedPointerCast<uint32*> (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
  148. }
  149. }
  150. }
  151. void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
  152. {
  153. jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
  154. char* d = static_cast<char*> (dest);
  155. for (int i = 0; i < numSamples; ++i)
  156. {
  157. *unalignedPointerCast<float*> (d) = source[i];
  158. #if JUCE_BIG_ENDIAN
  159. *unalignedPointerCast<uint32*> (d) = ByteOrder::swap (*unalignedPointerCast<uint32*> (d));
  160. #endif
  161. d += destBytesPerSample;
  162. }
  163. }
  164. void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
  165. {
  166. jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
  167. auto d = static_cast<char*> (dest);
  168. for (int i = 0; i < numSamples; ++i)
  169. {
  170. *unalignedPointerCast<float*> (d) = source[i];
  171. #if JUCE_LITTLE_ENDIAN
  172. *unalignedPointerCast<uint32*> (d) = ByteOrder::swap (*unalignedPointerCast<uint32*> (d));
  173. #endif
  174. d += destBytesPerSample;
  175. }
  176. }
  177. //==============================================================================
  178. void AudioDataConverters::convertInt16LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
  179. {
  180. const float scale = 1.0f / 0x7fff;
  181. auto intData = static_cast<const char*> (source);
  182. if (source != (void*) dest || srcBytesPerSample >= 4)
  183. {
  184. for (int i = 0; i < numSamples; ++i)
  185. {
  186. dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*unalignedPointerCast<const uint16*> (intData));
  187. intData += srcBytesPerSample;
  188. }
  189. }
  190. else
  191. {
  192. intData += srcBytesPerSample * numSamples;
  193. for (int i = numSamples; --i >= 0;)
  194. {
  195. intData -= srcBytesPerSample;
  196. dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*unalignedPointerCast<const uint16*> (intData));
  197. }
  198. }
  199. }
  200. void AudioDataConverters::convertInt16BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
  201. {
  202. const float scale = 1.0f / 0x7fff;
  203. auto intData = static_cast<const char*> (source);
  204. if (source != (void*) dest || srcBytesPerSample >= 4)
  205. {
  206. for (int i = 0; i < numSamples; ++i)
  207. {
  208. dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*unalignedPointerCast<const uint16*> (intData));
  209. intData += srcBytesPerSample;
  210. }
  211. }
  212. else
  213. {
  214. intData += srcBytesPerSample * numSamples;
  215. for (int i = numSamples; --i >= 0;)
  216. {
  217. intData -= srcBytesPerSample;
  218. dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*unalignedPointerCast<const uint16*> (intData));
  219. }
  220. }
  221. }
  222. void AudioDataConverters::convertInt24LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
  223. {
  224. const float scale = 1.0f / 0x7fffff;
  225. auto intData = static_cast<const char*> (source);
  226. if (source != (void*) dest || srcBytesPerSample >= 4)
  227. {
  228. for (int i = 0; i < numSamples; ++i)
  229. {
  230. dest[i] = scale * (short) ByteOrder::littleEndian24Bit (intData);
  231. intData += srcBytesPerSample;
  232. }
  233. }
  234. else
  235. {
  236. intData += srcBytesPerSample * numSamples;
  237. for (int i = numSamples; --i >= 0;)
  238. {
  239. intData -= srcBytesPerSample;
  240. dest[i] = scale * (short) ByteOrder::littleEndian24Bit (intData);
  241. }
  242. }
  243. }
  244. void AudioDataConverters::convertInt24BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
  245. {
  246. const float scale = 1.0f / 0x7fffff;
  247. auto intData = static_cast<const char*> (source);
  248. if (source != (void*) dest || srcBytesPerSample >= 4)
  249. {
  250. for (int i = 0; i < numSamples; ++i)
  251. {
  252. dest[i] = scale * (short) ByteOrder::bigEndian24Bit (intData);
  253. intData += srcBytesPerSample;
  254. }
  255. }
  256. else
  257. {
  258. intData += srcBytesPerSample * numSamples;
  259. for (int i = numSamples; --i >= 0;)
  260. {
  261. intData -= srcBytesPerSample;
  262. dest[i] = scale * (short) ByteOrder::bigEndian24Bit (intData);
  263. }
  264. }
  265. }
  266. void AudioDataConverters::convertInt32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
  267. {
  268. const float scale = 1.0f / (float) 0x7fffffff;
  269. auto intData = static_cast<const char*> (source);
  270. if (source != (void*) dest || srcBytesPerSample >= 4)
  271. {
  272. for (int i = 0; i < numSamples; ++i)
  273. {
  274. dest[i] = scale * (float) ByteOrder::swapIfBigEndian (*unalignedPointerCast<const uint32*> (intData));
  275. intData += srcBytesPerSample;
  276. }
  277. }
  278. else
  279. {
  280. intData += srcBytesPerSample * numSamples;
  281. for (int i = numSamples; --i >= 0;)
  282. {
  283. intData -= srcBytesPerSample;
  284. dest[i] = scale * (float) ByteOrder::swapIfBigEndian (*unalignedPointerCast<const uint32*> (intData));
  285. }
  286. }
  287. }
  288. void AudioDataConverters::convertInt32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
  289. {
  290. const float scale = 1.0f / (float) 0x7fffffff;
  291. auto intData = static_cast<const char*> (source);
  292. if (source != (void*) dest || srcBytesPerSample >= 4)
  293. {
  294. for (int i = 0; i < numSamples; ++i)
  295. {
  296. dest[i] = scale * (float) ByteOrder::swapIfLittleEndian (*unalignedPointerCast<const uint32*> (intData));
  297. intData += srcBytesPerSample;
  298. }
  299. }
  300. else
  301. {
  302. intData += srcBytesPerSample * numSamples;
  303. for (int i = numSamples; --i >= 0;)
  304. {
  305. intData -= srcBytesPerSample;
  306. dest[i] = scale * (float) ByteOrder::swapIfLittleEndian (*unalignedPointerCast<const uint32*> (intData));
  307. }
  308. }
  309. }
  310. void AudioDataConverters::convertFloat32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
  311. {
  312. auto s = static_cast<const char*> (source);
  313. for (int i = 0; i < numSamples; ++i)
  314. {
  315. dest[i] = *unalignedPointerCast<const float*> (s);
  316. #if JUCE_BIG_ENDIAN
  317. auto d = unalignedPointerCast<uint32*> (dest + i);
  318. *d = ByteOrder::swap (*d);
  319. #endif
  320. s += srcBytesPerSample;
  321. }
  322. }
  323. void AudioDataConverters::convertFloat32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
  324. {
  325. auto s = static_cast<const char*> (source);
  326. for (int i = 0; i < numSamples; ++i)
  327. {
  328. dest[i] = *unalignedPointerCast<const float*> (s);
  329. #if JUCE_LITTLE_ENDIAN
  330. auto d = unalignedPointerCast<uint32*> (dest + i);
  331. *d = ByteOrder::swap (*d);
  332. #endif
  333. s += srcBytesPerSample;
  334. }
  335. }
  336. //==============================================================================
  337. void AudioDataConverters::convertFloatToFormat (DataFormat destFormat, const float* source, void* dest, int numSamples)
  338. {
  339. switch (destFormat)
  340. {
  341. case int16LE: convertFloatToInt16LE (source, dest, numSamples); break;
  342. case int16BE: convertFloatToInt16BE (source, dest, numSamples); break;
  343. case int24LE: convertFloatToInt24LE (source, dest, numSamples); break;
  344. case int24BE: convertFloatToInt24BE (source, dest, numSamples); break;
  345. case int32LE: convertFloatToInt32LE (source, dest, numSamples); break;
  346. case int32BE: convertFloatToInt32BE (source, dest, numSamples); break;
  347. case float32LE: convertFloatToFloat32LE (source, dest, numSamples); break;
  348. case float32BE: convertFloatToFloat32BE (source, dest, numSamples); break;
  349. default: jassertfalse; break;
  350. }
  351. }
  352. void AudioDataConverters::convertFormatToFloat (DataFormat sourceFormat, const void* source, float* dest, int numSamples)
  353. {
  354. switch (sourceFormat)
  355. {
  356. case int16LE: convertInt16LEToFloat (source, dest, numSamples); break;
  357. case int16BE: convertInt16BEToFloat (source, dest, numSamples); break;
  358. case int24LE: convertInt24LEToFloat (source, dest, numSamples); break;
  359. case int24BE: convertInt24BEToFloat (source, dest, numSamples); break;
  360. case int32LE: convertInt32LEToFloat (source, dest, numSamples); break;
  361. case int32BE: convertInt32BEToFloat (source, dest, numSamples); break;
  362. case float32LE: convertFloat32LEToFloat (source, dest, numSamples); break;
  363. case float32BE: convertFloat32BEToFloat (source, dest, numSamples); break;
  364. default: jassertfalse; break;
  365. }
  366. }
  367. //==============================================================================
  368. void AudioDataConverters::interleaveSamples (const float** source, float* dest, int numSamples, int numChannels)
  369. {
  370. for (int chan = 0; chan < numChannels; ++chan)
  371. {
  372. auto i = chan;
  373. auto src = source [chan];
  374. for (int j = 0; j < numSamples; ++j)
  375. {
  376. dest [i] = src [j];
  377. i += numChannels;
  378. }
  379. }
  380. }
  381. void AudioDataConverters::deinterleaveSamples (const float* source, float** dest, int numSamples, int numChannels)
  382. {
  383. for (int chan = 0; chan < numChannels; ++chan)
  384. {
  385. auto i = chan;
  386. auto dst = dest [chan];
  387. for (int j = 0; j < numSamples; ++j)
  388. {
  389. dst [j] = source [i];
  390. i += numChannels;
  391. }
  392. }
  393. }
  394. //==============================================================================
  395. //==============================================================================
  396. #if JUCE_UNIT_TESTS
  397. class AudioConversionTests : public UnitTest
  398. {
  399. public:
  400. AudioConversionTests()
  401. : UnitTest ("Audio data conversion", UnitTestCategories::audio)
  402. {}
  403. template <class F1, class E1, class F2, class E2>
  404. struct Test5
  405. {
  406. static void test (UnitTest& unitTest, Random& r)
  407. {
  408. test (unitTest, false, r);
  409. test (unitTest, true, r);
  410. }
  411. static void test (UnitTest& unitTest, bool inPlace, Random& r)
  412. {
  413. const int numSamples = 2048;
  414. int32 original [(size_t) numSamples],
  415. converted[(size_t) numSamples],
  416. reversed [(size_t) numSamples];
  417. {
  418. AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> d (original);
  419. bool clippingFailed = false;
  420. for (int i = 0; i < numSamples / 2; ++i)
  421. {
  422. d.setAsFloat (r.nextFloat() * 2.2f - 1.1f);
  423. if (! d.isFloatingPoint())
  424. clippingFailed = d.getAsFloat() > 1.0f || d.getAsFloat() < -1.0f || clippingFailed;
  425. ++d;
  426. d.setAsInt32 (r.nextInt());
  427. ++d;
  428. }
  429. unitTest.expect (! clippingFailed);
  430. }
  431. // convert data from the source to dest format..
  432. std::unique_ptr<AudioData::Converter> conv (new AudioData::ConverterInstance<AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>,
  433. AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst>>());
  434. conv->convertSamples (inPlace ? reversed : converted, original, numSamples);
  435. // ..and back again..
  436. conv.reset (new AudioData::ConverterInstance<AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>,
  437. AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst>>());
  438. if (! inPlace)
  439. zeromem (reversed, sizeof (reversed));
  440. conv->convertSamples (reversed, inPlace ? reversed : converted, numSamples);
  441. {
  442. int biggestDiff = 0;
  443. AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d1 (original);
  444. AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const> d2 (reversed);
  445. const int errorMargin = 2 * AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution()
  446. + AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>::get32BitResolution();
  447. for (int i = 0; i < numSamples; ++i)
  448. {
  449. biggestDiff = jmax (biggestDiff, std::abs (d1.getAsInt32() - d2.getAsInt32()));
  450. ++d1;
  451. ++d2;
  452. }
  453. unitTest.expect (biggestDiff <= errorMargin);
  454. }
  455. }
  456. };
  457. template <class F1, class E1, class FormatType>
  458. struct Test3
  459. {
  460. static void test (UnitTest& unitTest, Random& r)
  461. {
  462. Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest, r);
  463. Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest, r);
  464. }
  465. };
  466. template <class FormatType, class Endianness>
  467. struct Test2
  468. {
  469. static void test (UnitTest& unitTest, Random& r)
  470. {
  471. Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest, r);
  472. Test3 <FormatType, Endianness, AudioData::UInt8>::test (unitTest, r);
  473. Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest, r);
  474. Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest, r);
  475. Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest, r);
  476. Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest, r);
  477. }
  478. };
  479. template <class FormatType>
  480. struct Test1
  481. {
  482. static void test (UnitTest& unitTest, Random& r)
  483. {
  484. Test2 <FormatType, AudioData::BigEndian>::test (unitTest, r);
  485. Test2 <FormatType, AudioData::LittleEndian>::test (unitTest, r);
  486. }
  487. };
  488. void runTest() override
  489. {
  490. auto r = getRandom();
  491. beginTest ("Round-trip conversion: Int8");
  492. Test1 <AudioData::Int8>::test (*this, r);
  493. beginTest ("Round-trip conversion: Int16");
  494. Test1 <AudioData::Int16>::test (*this, r);
  495. beginTest ("Round-trip conversion: Int24");
  496. Test1 <AudioData::Int24>::test (*this, r);
  497. beginTest ("Round-trip conversion: Int32");
  498. Test1 <AudioData::Int32>::test (*this, r);
  499. beginTest ("Round-trip conversion: Float32");
  500. Test1 <AudioData::Float32>::test (*this, r);
  501. }
  502. };
  503. static AudioConversionTests audioConversionUnitTests;
  504. #endif
  505. } // namespace juce