1
0

ModSample.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. /*
  2. * ModSample.h
  3. * -----------
  4. * Purpose: Module Sample header class and helpers
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "Sndfile.h"
  11. #include "ModSample.h"
  12. #include "modsmp_ctrl.h"
  13. #include "mpt/base/numbers.hpp"
  14. #include <cmath>
  15. OPENMPT_NAMESPACE_BEGIN
  16. // Translate sample properties between two given formats.
  17. void ModSample::Convert(MODTYPE fromType, MODTYPE toType)
  18. {
  19. // Convert between frequency and transpose values if necessary.
  20. if((!(toType & (MOD_TYPE_MOD | MOD_TYPE_XM))) && (fromType & (MOD_TYPE_MOD | MOD_TYPE_XM)))
  21. {
  22. TransposeToFrequency();
  23. RelativeTone = 0;
  24. nFineTune = 0;
  25. // TransposeToFrequency assumes NTSC middle-C frequency like FT2, but we play MODs with PAL middle-C!
  26. if(fromType == MOD_TYPE_MOD)
  27. nC5Speed = Util::muldivr_unsigned(nC5Speed, 8272, 8363);
  28. } else if((toType & (MOD_TYPE_MOD | MOD_TYPE_XM)) && (!(fromType & (MOD_TYPE_MOD | MOD_TYPE_XM))))
  29. {
  30. // FrequencyToTranspose assumes NTSC middle-C frequency like FT2, but we play MODs with PAL middle-C!
  31. if(toType == MOD_TYPE_MOD)
  32. nC5Speed = Util::muldivr_unsigned(nC5Speed, 8363, 8272);
  33. FrequencyToTranspose();
  34. }
  35. // No ping-pong loop, panning and auto-vibrato for MOD / S3M samples
  36. if(toType & (MOD_TYPE_MOD | MOD_TYPE_S3M))
  37. {
  38. uFlags.reset(CHN_PINGPONGLOOP | CHN_PANNING);
  39. nVibDepth = 0;
  40. nVibRate = 0;
  41. nVibSweep = 0;
  42. nVibType = VIB_SINE;
  43. RelativeTone = 0;
  44. }
  45. // No global volume / sustain loops for MOD/S3M/XM
  46. if(toType & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_S3M))
  47. {
  48. nGlobalVol = 64;
  49. // Sustain loops - convert to normal loops
  50. if(uFlags[CHN_SUSTAINLOOP])
  51. {
  52. // We probably overwrite a normal loop here, but since sustain loops are evaluated before normal loops, this is just correct.
  53. nLoopStart = nSustainStart;
  54. nLoopEnd = nSustainEnd;
  55. uFlags.set(CHN_LOOP);
  56. uFlags.set(CHN_PINGPONGLOOP, uFlags[CHN_PINGPONGSUSTAIN]);
  57. }
  58. nSustainStart = nSustainEnd = 0;
  59. uFlags.reset(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN);
  60. }
  61. // All XM samples have default panning, and XM's autovibrato settings are rather limited.
  62. if(toType & MOD_TYPE_XM)
  63. {
  64. if(!uFlags[CHN_PANNING])
  65. {
  66. uFlags.set(CHN_PANNING);
  67. nPan = 128;
  68. }
  69. LimitMax(nVibDepth, uint8(15));
  70. LimitMax(nVibRate, uint8(63));
  71. }
  72. // Autovibrato sweep setting is inverse in XM (0 = "no sweep") and IT (0 = "no vibrato")
  73. if(((fromType & MOD_TYPE_XM) && (toType & (MOD_TYPE_IT | MOD_TYPE_MPT))) || ((toType & MOD_TYPE_XM) && (fromType & (MOD_TYPE_IT | MOD_TYPE_MPT))))
  74. {
  75. if(nVibRate != 0 && nVibDepth != 0)
  76. {
  77. if(nVibSweep != 0)
  78. nVibSweep = mpt::saturate_cast<decltype(nVibSweep)>(Util::muldivr_unsigned(nVibDepth, 256, nVibSweep));
  79. else
  80. nVibSweep = 255;
  81. }
  82. }
  83. // Convert incompatible autovibrato types
  84. if(toType == MOD_TYPE_IT && nVibType == VIB_RAMP_UP)
  85. {
  86. nVibType = VIB_RAMP_DOWN;
  87. } else if(toType == MOD_TYPE_XM && nVibType == VIB_RANDOM)
  88. {
  89. nVibType = VIB_SINE;
  90. }
  91. // No external samples in formats other than MPTM.
  92. if(toType != MOD_TYPE_MPT)
  93. {
  94. uFlags.reset(SMP_KEEPONDISK);
  95. }
  96. // No Adlib instruments in formats that can't handle it.
  97. if(!CSoundFile::SupportsOPL(toType) && uFlags[CHN_ADLIB])
  98. {
  99. SetAdlib(false);
  100. } else if(toType == MOD_TYPE_S3M && uFlags[CHN_ADLIB])
  101. {
  102. // No support for OPL3 waveforms in S3M
  103. adlib[8] &= 0x03;
  104. adlib[9] &= 0x03;
  105. }
  106. }
  107. // Initialize sample slot with default values.
  108. void ModSample::Initialize(MODTYPE type)
  109. {
  110. FreeSample();
  111. nLength = 0;
  112. nLoopStart = nLoopEnd = 0;
  113. nSustainStart = nSustainEnd = 0;
  114. nC5Speed = 8363;
  115. nPan = 128;
  116. nVolume = 256;
  117. nGlobalVol = 64;
  118. uFlags.reset(CHN_PANNING | CHN_SUSTAINLOOP | CHN_LOOP | CHN_PINGPONGLOOP | CHN_PINGPONGSUSTAIN | CHN_ADLIB | SMP_MODIFIED | SMP_KEEPONDISK);
  119. if(type == MOD_TYPE_XM)
  120. {
  121. uFlags.set(CHN_PANNING);
  122. }
  123. RelativeTone = 0;
  124. nFineTune = 0;
  125. nVibType = VIB_SINE;
  126. nVibSweep = 0;
  127. nVibDepth = 0;
  128. nVibRate = 0;
  129. rootNote = 0;
  130. filename = "";
  131. RemoveAllCuePoints();
  132. }
  133. // Returns sample rate of the sample.
  134. uint32 ModSample::GetSampleRate(const MODTYPE type) const
  135. {
  136. uint32 rate;
  137. if(CSoundFile::UseFinetuneAndTranspose(type))
  138. rate = TransposeToFrequency(RelativeTone, nFineTune);
  139. else
  140. rate = nC5Speed;
  141. // TransposeToFrequency assumes NTSC middle-C frequency like FT2, but we play MODs with PAL middle-C!
  142. if(type == MOD_TYPE_MOD)
  143. rate = Util::muldivr_unsigned(rate, 8272, 8363);
  144. return (rate > 0) ? rate : 8363;
  145. }
  146. // Copies sample data from another sample slot and ensures that the 16-bit/stereo flags are set accordingly.
  147. bool ModSample::CopyWaveform(const ModSample &smpFrom)
  148. {
  149. if(!smpFrom.HasSampleData())
  150. return false;
  151. // If we duplicate a sample slot, avoid deleting the sample we just copy from
  152. if(smpFrom.sampleb() == sampleb())
  153. pData.pSample = nullptr;
  154. LimitMax(nLength, smpFrom.nLength);
  155. uFlags.set(CHN_16BIT, smpFrom.uFlags[CHN_16BIT]);
  156. uFlags.set(CHN_STEREO, smpFrom.uFlags[CHN_STEREO]);
  157. if(AllocateSample())
  158. {
  159. memcpy(sampleb(), smpFrom.sampleb(), GetSampleSizeInBytes());
  160. return true;
  161. }
  162. return false;
  163. }
  164. // Allocate sample based on a ModSample's properties.
  165. // Returns number of bytes allocated, 0 on failure.
  166. size_t ModSample::AllocateSample()
  167. {
  168. FreeSample();
  169. if((pData.pSample = AllocateSample(nLength, GetBytesPerSample())) == nullptr)
  170. {
  171. return 0;
  172. } else
  173. {
  174. return GetSampleSizeInBytes();
  175. }
  176. }
  177. // Allocate sample memory. On success, a pointer to the silenced sample buffer is returned. On failure, nullptr is returned.
  178. // numFrames must contain the sample length, bytesPerSample the size of a sampling point multiplied with the number of channels.
  179. void *ModSample::AllocateSample(SmpLength numFrames, size_t bytesPerSample)
  180. {
  181. const size_t allocSize = GetRealSampleBufferSize(numFrames, bytesPerSample);
  182. if(allocSize != 0)
  183. {
  184. char *p = new(std::nothrow) char[allocSize];
  185. if(p != nullptr)
  186. {
  187. memset(p, 0, allocSize);
  188. return p + (InterpolationLookaheadBufferSize * MaxSamplingPointSize);
  189. }
  190. }
  191. return nullptr;
  192. }
  193. // Compute sample buffer size in bytes, including any overhead introduced by pre-computed loops and such. Returns 0 if sample is too big.
  194. size_t ModSample::GetRealSampleBufferSize(SmpLength numSamples, size_t bytesPerSample)
  195. {
  196. // Number of required lookahead samples:
  197. // * 1x InterpolationMaxLookahead samples before the actual sample start. This is set to MaxSamplingPointSize due to the way AllocateSample/FreeSample currently work.
  198. // * 1x InterpolationMaxLookahead samples of silence after the sample end (if normal loop end == sample end, this can be optimized out).
  199. // * 2x InterpolationMaxLookahead before the loop point (because we start at InterpolationMaxLookahead before the loop point and will look backwards from there as well)
  200. // * 2x InterpolationMaxLookahead after the loop point (for wrap-around)
  201. // * 4x InterpolationMaxLookahead for the sustain loop (same as the two points above)
  202. const SmpLength maxSize = Util::MaxValueOfType(numSamples);
  203. const SmpLength lookaheadBufferSize = (MaxSamplingPointSize + 1 + 4 + 4) * InterpolationLookaheadBufferSize;
  204. if(numSamples == 0 || numSamples > MAX_SAMPLE_LENGTH || lookaheadBufferSize > maxSize - numSamples)
  205. {
  206. return 0;
  207. }
  208. numSamples += lookaheadBufferSize;
  209. if(maxSize / bytesPerSample < numSamples)
  210. {
  211. return 0;
  212. }
  213. return numSamples * bytesPerSample;
  214. }
  215. void ModSample::FreeSample()
  216. {
  217. FreeSample(pData.pSample);
  218. pData.pSample = nullptr;
  219. }
  220. void ModSample::FreeSample(void *samplePtr)
  221. {
  222. if(samplePtr)
  223. {
  224. delete[](((char *)samplePtr) - (InterpolationLookaheadBufferSize * MaxSamplingPointSize));
  225. }
  226. }
  227. // Set loop points and update loop wrap-around buffer
  228. void ModSample::SetLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile)
  229. {
  230. nLoopStart = start;
  231. nLoopEnd = end;
  232. LimitMax(nLoopEnd, nLength);
  233. if(nLoopStart < nLoopEnd)
  234. {
  235. uFlags.set(CHN_LOOP, enable);
  236. uFlags.set(CHN_PINGPONGLOOP, pingpong && enable);
  237. } else
  238. {
  239. nLoopStart = nLoopEnd = 0;
  240. uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP);
  241. }
  242. PrecomputeLoops(sndFile, true);
  243. }
  244. // Set sustain loop points and update loop wrap-around buffer
  245. void ModSample::SetSustainLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile)
  246. {
  247. nSustainStart = start;
  248. nSustainEnd = end;
  249. LimitMax(nLoopEnd, nLength);
  250. if(nSustainStart < nSustainEnd)
  251. {
  252. uFlags.set(CHN_SUSTAINLOOP, enable);
  253. uFlags.set(CHN_PINGPONGSUSTAIN, pingpong && enable);
  254. } else
  255. {
  256. nSustainStart = nSustainEnd = 0;
  257. uFlags.reset(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN);
  258. }
  259. PrecomputeLoops(sndFile, true);
  260. }
  261. namespace // Unnamed namespace for local implementation functions.
  262. {
  263. template <typename T>
  264. class PrecomputeLoop
  265. {
  266. protected:
  267. T *target;
  268. const T *sampleData;
  269. SmpLength loopEnd;
  270. int numChannels;
  271. bool pingpong;
  272. bool ITPingPongMode;
  273. public:
  274. PrecomputeLoop(T *target, const T *sampleData, SmpLength loopEnd, int numChannels, bool pingpong, bool ITPingPongMode)
  275. : target(target), sampleData(sampleData), loopEnd(loopEnd), numChannels(numChannels), pingpong(pingpong), ITPingPongMode(ITPingPongMode)
  276. {
  277. if(loopEnd > 0)
  278. {
  279. CopyLoop(true);
  280. CopyLoop(false);
  281. }
  282. }
  283. void CopyLoop(bool direction) const
  284. {
  285. // Direction: true = start reading and writing forward, false = start reading and writing backward (write direction never changes)
  286. const int numSamples = 2 * InterpolationLookaheadBufferSize + (direction ? 1 : 0); // Loop point is included in forward loop expansion
  287. T *dest = target + numChannels * (2 * InterpolationLookaheadBufferSize - 1); // Write buffer offset
  288. SmpLength readPosition = loopEnd - 1;
  289. const int writeIncrement = direction ? 1 : -1;
  290. int readIncrement = writeIncrement;
  291. for(int i = 0; i < numSamples; i++)
  292. {
  293. // Copy sample over to lookahead buffer
  294. for(int c = 0; c < numChannels; c++)
  295. {
  296. dest[c] = sampleData[readPosition * numChannels + c];
  297. }
  298. dest += writeIncrement * numChannels;
  299. if(readPosition == loopEnd - 1 && readIncrement > 0)
  300. {
  301. // Reached end of loop while going forward
  302. if(pingpong)
  303. {
  304. readIncrement = -1;
  305. if(ITPingPongMode && readPosition > 0)
  306. {
  307. readPosition--;
  308. }
  309. } else
  310. {
  311. readPosition = 0;
  312. }
  313. } else if(readPosition == 0 && readIncrement < 0)
  314. {
  315. // Reached start of loop while going backward
  316. if(pingpong)
  317. {
  318. readIncrement = 1;
  319. } else
  320. {
  321. readPosition = loopEnd - 1;
  322. }
  323. } else
  324. {
  325. readPosition += readIncrement;
  326. }
  327. }
  328. }
  329. };
  330. template <typename T>
  331. void PrecomputeLoopsImpl(ModSample &smp, const CSoundFile &sndFile)
  332. {
  333. const int numChannels = smp.GetNumChannels();
  334. const int copySamples = numChannels * InterpolationLookaheadBufferSize;
  335. T *sampleData = static_cast<T *>(smp.samplev());
  336. T *afterSampleStart = sampleData + smp.nLength * numChannels;
  337. T *loopLookAheadStart = afterSampleStart + copySamples;
  338. T *sustainLookAheadStart = loopLookAheadStart + 4 * copySamples;
  339. // Hold sample on the same level as the last sampling point at the end to prevent extra pops with interpolation.
  340. // Do the same at the sample start, too.
  341. for(int i = 0; i < (int)InterpolationLookaheadBufferSize; i++)
  342. {
  343. for(int c = 0; c < numChannels; c++)
  344. {
  345. afterSampleStart[i * numChannels + c] = afterSampleStart[-numChannels + c];
  346. sampleData[-(i + 1) * numChannels + c] = sampleData[c];
  347. }
  348. }
  349. if(smp.uFlags[CHN_LOOP])
  350. {
  351. PrecomputeLoop<T>(loopLookAheadStart,
  352. sampleData + smp.nLoopStart * numChannels,
  353. smp.nLoopEnd - smp.nLoopStart,
  354. numChannels,
  355. smp.uFlags[CHN_PINGPONGLOOP],
  356. sndFile.m_playBehaviour[kITPingPongMode]);
  357. }
  358. if(smp.uFlags[CHN_SUSTAINLOOP])
  359. {
  360. PrecomputeLoop<T>(sustainLookAheadStart,
  361. sampleData + smp.nSustainStart * numChannels,
  362. smp.nSustainEnd - smp.nSustainStart,
  363. numChannels,
  364. smp.uFlags[CHN_PINGPONGSUSTAIN],
  365. sndFile.m_playBehaviour[kITPingPongMode]);
  366. }
  367. }
  368. } // unnamed namespace
  369. void ModSample::PrecomputeLoops(CSoundFile &sndFile, bool updateChannels)
  370. {
  371. if(!HasSampleData())
  372. return;
  373. SanitizeLoops();
  374. // Update channels with possibly changed loop values
  375. if(updateChannels)
  376. {
  377. ctrlSmp::UpdateLoopPoints(*this, sndFile);
  378. }
  379. if(GetElementarySampleSize() == 2)
  380. PrecomputeLoopsImpl<int16>(*this, sndFile);
  381. else if(GetElementarySampleSize() == 1)
  382. PrecomputeLoopsImpl<int8>(*this, sndFile);
  383. }
  384. // Remove loop points if they're invalid.
  385. void ModSample::SanitizeLoops()
  386. {
  387. LimitMax(nSustainEnd, nLength);
  388. LimitMax(nLoopEnd, nLength);
  389. if(nSustainStart >= nSustainEnd)
  390. {
  391. nSustainStart = nSustainEnd = 0;
  392. uFlags.reset(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN);
  393. }
  394. if(nLoopStart >= nLoopEnd)
  395. {
  396. nLoopStart = nLoopEnd = 0;
  397. uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP);
  398. }
  399. }
  400. /////////////////////////////////////////////////////////////
  401. // Transpose <-> Frequency conversions
  402. uint32 ModSample::TransposeToFrequency(int transpose, int finetune)
  403. {
  404. return mpt::saturate_round<uint32>(std::pow(2.0, (transpose * 128.0 + finetune) * (1.0 / (12.0 * 128.0))) * 8363.0);
  405. }
  406. void ModSample::TransposeToFrequency()
  407. {
  408. nC5Speed = TransposeToFrequency(RelativeTone, nFineTune);
  409. }
  410. // Return a pair of {transpose, finetune}
  411. std::pair<int8, int8> ModSample::FrequencyToTranspose(uint32 freq)
  412. {
  413. if(!freq)
  414. return {};
  415. const auto f2t = mpt::saturate_round<int32>(std::log(freq * (1.0 / 8363.0)) * (12.0 * 128.0 * (1.0 / mpt::numbers::ln2)));
  416. const auto fine = std::div(Clamp(f2t, -16384, 16383), int32(128));
  417. return {static_cast<int8>(fine.quot), static_cast<int8>(fine.rem)};
  418. }
  419. void ModSample::FrequencyToTranspose()
  420. {
  421. std::tie(RelativeTone, nFineTune) = FrequencyToTranspose(nC5Speed);
  422. }
  423. // Transpose the sample by amount specified in octaves (i.e. amount=1 transposes one octave up)
  424. void ModSample::Transpose(double amount)
  425. {
  426. nC5Speed = mpt::saturate_round<uint32>(nC5Speed * std::pow(2.0, amount));
  427. }
  428. // Check if the sample has any valid cue points
  429. bool ModSample::HasAnyCuePoints() const
  430. {
  431. if(uFlags[CHN_ADLIB])
  432. return false;
  433. for(auto pt : cues)
  434. {
  435. if(pt < nLength)
  436. return true;
  437. }
  438. return false;
  439. }
  440. // Check if the sample's cue points are the default cue point set.
  441. bool ModSample::HasCustomCuePoints() const
  442. {
  443. if(uFlags[CHN_ADLIB])
  444. return false;
  445. for(SmpLength i = 0; i < std::size(cues); i++)
  446. {
  447. if(cues[i] != (i + 1) << 11)
  448. return true;
  449. }
  450. return false;
  451. }
  452. void ModSample::SetDefaultCuePoints()
  453. {
  454. // Default cues compatible with old-style volume column offset
  455. for(int i = 0; i < 9; i++)
  456. {
  457. cues[i] = (i + 1) << 11;
  458. }
  459. }
  460. void ModSample::Set16BitCuePoints()
  461. {
  462. // Cue points that are useful for extending regular offset command
  463. for(int i = 0; i < 9; i++)
  464. {
  465. cues[i] = (i + 1) << 16;
  466. }
  467. }
  468. void ModSample::RemoveAllCuePoints()
  469. {
  470. if(!uFlags[CHN_ADLIB])
  471. cues.fill(MAX_SAMPLE_LENGTH);
  472. }
  473. void ModSample::SetAdlib(bool enable, OPLPatch patch)
  474. {
  475. if(!enable && uFlags[CHN_ADLIB])
  476. {
  477. SetDefaultCuePoints();
  478. }
  479. uFlags.set(CHN_ADLIB, enable);
  480. if(enable)
  481. {
  482. // Bogus sample to make playback work
  483. uFlags.reset(CHN_16BIT | CHN_STEREO);
  484. nLength = 4;
  485. AllocateSample();
  486. adlib = patch;
  487. }
  488. }
  489. OPENMPT_NAMESPACE_END