Fastmix.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. /*
  2. * Fastmix.cpp
  3. * -----------
  4. * Purpose: Mixer core for rendering samples, mixing plugins, etc...
  5. * Notes : If this is Fastmix.cpp, where is Slowmix.cpp? :)
  6. * Authors: Olivier Lapicque
  7. * OpenMPT Devs
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. // FIXME:
  11. // - Playing samples backwards should reverse interpolation LUTs for interpolation modes
  12. // with more than two taps since they're not symmetric. We might need separate LUTs
  13. // because otherwise we will add tons of branches.
  14. // - Loop wraparound works pretty well in general, but not at the start of bidi samples.
  15. // - The loop lookahead stuff might still fail for samples with backward loops.
  16. #include "stdafx.h"
  17. #include "Sndfile.h"
  18. #include "MixerLoops.h"
  19. #include "MixFuncTable.h"
  20. #include "plugins/PlugInterface.h"
  21. #include <cfloat> // For FLT_EPSILON
  22. #include <algorithm>
  23. OPENMPT_NAMESPACE_BEGIN
  24. /////////////////////////////////////////////////////////////////////////
  25. struct MixLoopState
  26. {
  27. const int8 * samplePointer = nullptr;
  28. const int8 * lookaheadPointer = nullptr;
  29. SmpLength lookaheadStart = 0;
  30. uint32 maxSamples = 0;
  31. const uint8 ITPingPongDiff;
  32. const bool precisePingPongLoops;
  33. MixLoopState(const CSoundFile &sndFile, const ModChannel &chn)
  34. : ITPingPongDiff{sndFile.m_playBehaviour[kITPingPongMode] ? uint8(1) : uint8(0)}
  35. , precisePingPongLoops{!sndFile.m_playBehaviour[kImprecisePingPongLoops]}
  36. {
  37. if(chn.pCurrentSample == nullptr)
  38. return;
  39. UpdateLookaheadPointers(chn);
  40. // For platforms that have no fast 64-bit division, precompute this constant
  41. // as it won't change during the invocation of CreateStereoMix.
  42. SamplePosition increment = chn.increment;
  43. if(increment.IsNegative())
  44. increment.Negate();
  45. maxSamples = 16384u / (increment.GetUInt() + 1u);
  46. if(maxSamples < 2)
  47. maxSamples = 2;
  48. }
  49. // Calculate offset of loop wrap-around buffer for this sample.
  50. void UpdateLookaheadPointers(const ModChannel &chn)
  51. {
  52. samplePointer = static_cast<const int8 *>(chn.pCurrentSample);
  53. lookaheadPointer = nullptr;
  54. if(!samplePointer)
  55. return;
  56. if(chn.nLoopEnd < InterpolationLookaheadBufferSize)
  57. lookaheadStart = chn.nLoopStart;
  58. else
  59. lookaheadStart = std::max(chn.nLoopStart, chn.nLoopEnd - InterpolationLookaheadBufferSize);
  60. // We only need to apply the loop wrap-around logic if the sample is actually looping and if interpolation is applied.
  61. // If there is no interpolation happening, there is no lookahead happening the sample read-out is exact.
  62. if(chn.dwFlags[CHN_LOOP] && chn.resamplingMode != SRCMODE_NEAREST)
  63. {
  64. const bool inSustainLoop = chn.InSustainLoop() && chn.nLoopStart == chn.pModSample->nSustainStart && chn.nLoopEnd == chn.pModSample->nSustainEnd;
  65. // Do not enable wraparound magic if we're previewing a custom loop!
  66. if(inSustainLoop || chn.nLoopEnd == chn.pModSample->nLoopEnd)
  67. {
  68. SmpLength lookaheadOffset = 3 * InterpolationLookaheadBufferSize + chn.pModSample->nLength - chn.nLoopEnd;
  69. if(inSustainLoop)
  70. {
  71. lookaheadOffset += 4 * InterpolationLookaheadBufferSize;
  72. }
  73. lookaheadPointer = samplePointer + lookaheadOffset * chn.pModSample->GetBytesPerSample();
  74. }
  75. }
  76. }
  77. // Returns the buffer length required to render a certain amount of samples, based on the channel's playback speed.
  78. static MPT_FORCEINLINE uint32 DistanceToBufferLength(SamplePosition from, SamplePosition to, SamplePosition inc)
  79. {
  80. return static_cast<uint32>((to - from - SamplePosition(1)) / inc) + 1;
  81. }
  82. // Check how many samples can be rendered without encountering loop or sample end, and also update loop position / direction
  83. MPT_FORCEINLINE uint32 GetSampleCount(ModChannel &chn, uint32 nSamples) const
  84. {
  85. int32 nLoopStart = chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0;
  86. SamplePosition nInc = chn.increment;
  87. if(nSamples <= 0 || nInc.IsZero() || !chn.nLength || !samplePointer)
  88. return 0;
  89. // Part 1: Making sure the play position is valid, and if necessary, invert the play direction in case we reached a loop boundary of a ping-pong loop.
  90. chn.pCurrentSample = samplePointer;
  91. // Under zero ?
  92. if (chn.position.GetInt() < nLoopStart)
  93. {
  94. if (nInc.IsNegative())
  95. {
  96. // Invert loop direction for bidi loops
  97. chn.position = SamplePosition(nLoopStart + nLoopStart, 0) - chn.position;
  98. if ((chn.position.GetInt() < nLoopStart) || (chn.position.GetUInt() >= (nLoopStart + chn.nLength) / 2))
  99. {
  100. chn.position.Set(nLoopStart, 0);
  101. }
  102. if(chn.dwFlags[CHN_PINGPONGLOOP])
  103. {
  104. chn.dwFlags.reset(CHN_PINGPONGFLAG); // go forward
  105. nInc.Negate();
  106. chn.increment = nInc;
  107. } else
  108. {
  109. chn.position.SetInt(chn.nLength - 1);
  110. }
  111. if(!chn.dwFlags[CHN_LOOP] || chn.position.GetUInt() >= chn.nLength)
  112. {
  113. chn.position.Set(chn.nLength);
  114. return 0;
  115. }
  116. } else
  117. {
  118. // We probably didn't hit the loop end yet (first loop), so we do nothing
  119. if (chn.position.GetInt() < 0) chn.position.SetInt(0);
  120. }
  121. } else if (chn.position.GetUInt() >= chn.nLength)
  122. {
  123. // Past the end
  124. if(!chn.dwFlags[CHN_LOOP])
  125. return 0; // not looping -> stop this channel
  126. if(chn.dwFlags[CHN_PINGPONGLOOP])
  127. {
  128. // Invert loop
  129. if (nInc.IsPositive())
  130. {
  131. nInc.Negate();
  132. chn.increment = nInc;
  133. }
  134. chn.dwFlags.set(CHN_PINGPONGFLAG);
  135. // Adjust loop position
  136. if(precisePingPongLoops)
  137. {
  138. // More accurate loop end overshoot calculation.
  139. // Test cases: BidiPrecision.it, BidiPrecision.xm
  140. const auto overshoot = chn.position - SamplePosition(chn.nLength, 0);
  141. const auto loopLength = chn.nLoopEnd - chn.nLoopStart - ITPingPongDiff;
  142. if(overshoot.GetUInt() < loopLength)
  143. chn.position = SamplePosition(chn.nLength - ITPingPongDiff, 0) - overshoot;
  144. else
  145. chn.position = SamplePosition(chn.nLoopStart, 0);
  146. } else
  147. {
  148. SamplePosition invFract = chn.position.GetInvertedFract();
  149. chn.position = SamplePosition(chn.nLength - (chn.position.GetInt() - chn.nLength) - invFract.GetInt(), invFract.GetFract());
  150. if(chn.position.GetUInt() <= chn.nLoopStart || chn.position.GetUInt() >= chn.nLength)
  151. {
  152. // Impulse Tracker's software mixer would put a -2 (instead of -1) in the following line (doesn't happen on a GUS)
  153. chn.position.SetInt(chn.nLength - std::min(chn.nLength, static_cast<SmpLength>(ITPingPongDiff + 1)));
  154. }
  155. }
  156. } else
  157. {
  158. if (nInc.IsNegative()) // This is a bug
  159. {
  160. nInc.Negate();
  161. chn.increment = nInc;
  162. }
  163. // Restart at loop start
  164. chn.position += SamplePosition(nLoopStart - chn.nLength, 0);
  165. MPT_ASSERT(chn.position.GetInt() >= nLoopStart);
  166. // Interpolate correctly after wrapping around
  167. chn.dwFlags.set(CHN_WRAPPED_LOOP);
  168. }
  169. }
  170. // Part 2: Compute how many samples we can render until we reach the end of sample / loop boundary / etc.
  171. SamplePosition nPos = chn.position;
  172. const SmpLength nPosInt = nPos.GetUInt();
  173. if(nPos.GetInt() < nLoopStart)
  174. {
  175. // too big increment, and/or too small loop length
  176. if(nPos.IsNegative() || nInc.IsNegative())
  177. return 0;
  178. } else
  179. {
  180. // Not testing for equality since we might be going backwards from the very end of the sample
  181. if(nPosInt > chn.nLength)
  182. return 0;
  183. // If going forwards and we're preceisely at the end, there's no point in going further
  184. if(nPosInt == chn.nLength && nInc.IsPositive())
  185. return 0;
  186. }
  187. uint32 nSmpCount = nSamples;
  188. SamplePosition nInv = nInc;
  189. if (nInc.IsNegative())
  190. {
  191. nInv.Negate();
  192. }
  193. LimitMax(nSamples, maxSamples);
  194. SamplePosition incSamples = nInc * (nSamples - 1);
  195. int32 nPosDest = (nPos + incSamples).GetInt();
  196. const bool isAtLoopStart = (nPosInt >= chn.nLoopStart && nPosInt < chn.nLoopStart + InterpolationLookaheadBufferSize);
  197. if(!isAtLoopStart)
  198. {
  199. chn.dwFlags.reset(CHN_WRAPPED_LOOP);
  200. }
  201. // Loop wrap-around magic.
  202. bool checkDest = true;
  203. if(lookaheadPointer != nullptr)
  204. {
  205. if(nPosInt >= lookaheadStart)
  206. {
  207. #if 0
  208. const uint32 oldCount = nSmpCount;
  209. // When going backwards - we can only go back up to lookaheadStart.
  210. // When going forwards - read through the whole pre-computed wrap-around buffer if possible.
  211. // TODO: ProTracker sample swapping needs hard cut at sample end.
  212. int32 samplesToRead = nInc.IsNegative()
  213. ? (nPosInt - lookaheadStart)
  214. //: 2 * InterpolationMaxLookahead - (nPosInt - mixLoopState.lookaheadStart);
  215. : (chn.nLoopEnd - nPosInt);
  216. //LimitMax(samplesToRead, chn.nLoopEnd - chn.nLoopStart);
  217. nSmpCount = SamplesToBufferLength(samplesToRead, chn);
  218. Limit(nSmpCount, 1u, oldCount);
  219. #else
  220. if (nInc.IsNegative())
  221. {
  222. nSmpCount = DistanceToBufferLength(SamplePosition(lookaheadStart, 0), nPos, nInv);
  223. } else
  224. {
  225. nSmpCount = DistanceToBufferLength(nPos, SamplePosition(chn.nLoopEnd, 0), nInv);
  226. }
  227. #endif
  228. chn.pCurrentSample = lookaheadPointer;
  229. checkDest = false;
  230. } else if(chn.dwFlags[CHN_WRAPPED_LOOP] && isAtLoopStart)
  231. {
  232. // We just restarted the loop, so interpolate correctly after wrapping around
  233. nSmpCount = DistanceToBufferLength(nPos, SamplePosition(nLoopStart + InterpolationLookaheadBufferSize, 0), nInv);
  234. chn.pCurrentSample = lookaheadPointer + (chn.nLoopEnd - nLoopStart) * chn.pModSample->GetBytesPerSample();
  235. checkDest = false;
  236. } else if(nInc.IsPositive() && static_cast<SmpLength>(nPosDest) >= lookaheadStart && nSmpCount > 1)
  237. {
  238. // We shouldn't read that far if we're not using the pre-computed wrap-around buffer.
  239. nSmpCount = DistanceToBufferLength(nPos, SamplePosition(lookaheadStart, 0), nInv);
  240. checkDest = false;
  241. }
  242. }
  243. if(checkDest)
  244. {
  245. // Fix up sample count if target position is invalid
  246. if (nInc.IsNegative())
  247. {
  248. if (nPosDest < nLoopStart)
  249. {
  250. nSmpCount = DistanceToBufferLength(SamplePosition(nLoopStart, 0), nPos, nInv);
  251. }
  252. } else
  253. {
  254. if (nPosDest >= (int32)chn.nLength)
  255. {
  256. nSmpCount = DistanceToBufferLength(nPos, SamplePosition(chn.nLength, 0), nInv);
  257. }
  258. }
  259. }
  260. Limit(nSmpCount, uint32(1u), nSamples);
  261. #ifdef MPT_BUILD_DEBUG
  262. {
  263. SmpLength posDest = (nPos + nInc * (nSmpCount - 1)).GetUInt();
  264. if (posDest < 0 || posDest > chn.nLength)
  265. {
  266. // We computed an invalid delta!
  267. MPT_ASSERT_NOTREACHED();
  268. return 0;
  269. }
  270. }
  271. #endif
  272. return nSmpCount;
  273. }
  274. };
  275. // Render count * number of channels samples
  276. void CSoundFile::CreateStereoMix(int count)
  277. {
  278. mixsample_t *pOfsL, *pOfsR;
  279. if(!count)
  280. return;
  281. // Resetting sound buffer
  282. StereoFill(MixSoundBuffer, count, m_dryROfsVol, m_dryLOfsVol);
  283. if(m_MixerSettings.gnChannels > 2)
  284. StereoFill(MixRearBuffer, count, m_surroundROfsVol, m_surroundLOfsVol);
  285. CHANNELINDEX nchmixed = 0;
  286. for(uint32 nChn = 0; nChn < m_nMixChannels; nChn++)
  287. {
  288. ModChannel &chn = m_PlayState.Chn[m_PlayState.ChnMix[nChn]];
  289. if(!chn.pCurrentSample && !chn.nLOfs && !chn.nROfs)
  290. continue;
  291. pOfsR = &m_dryROfsVol;
  292. pOfsL = &m_dryLOfsVol;
  293. uint32 functionNdx = MixFuncTable::ResamplingModeToMixFlags(static_cast<ResamplingMode>(chn.resamplingMode));
  294. if(chn.dwFlags[CHN_16BIT]) functionNdx |= MixFuncTable::ndx16Bit;
  295. if(chn.dwFlags[CHN_STEREO]) functionNdx |= MixFuncTable::ndxStereo;
  296. #ifndef NO_FILTER
  297. if(chn.dwFlags[CHN_FILTER]) functionNdx |= MixFuncTable::ndxFilter;
  298. #endif
  299. mixsample_t *pbuffer = MixSoundBuffer;
  300. #ifndef NO_REVERB
  301. if(((m_MixerSettings.DSPMask & SNDDSP_REVERB) && !chn.dwFlags[CHN_NOREVERB]) || chn.dwFlags[CHN_REVERB])
  302. {
  303. m_Reverb.TouchReverbSendBuffer(ReverbSendBuffer, m_RvbROfsVol, m_RvbLOfsVol, count);
  304. pbuffer = ReverbSendBuffer;
  305. pOfsR = &m_RvbROfsVol;
  306. pOfsL = &m_RvbLOfsVol;
  307. }
  308. #endif
  309. if(chn.dwFlags[CHN_SURROUND] && m_MixerSettings.gnChannels > 2)
  310. {
  311. pbuffer = MixRearBuffer;
  312. pOfsR = &m_surroundROfsVol;
  313. pOfsL = &m_surroundLOfsVol;
  314. }
  315. //Look for plugins associated with this implicit tracker channel.
  316. #ifndef NO_PLUGINS
  317. PLUGINDEX nMixPlugin = GetBestPlugin(m_PlayState, m_PlayState.ChnMix[nChn], PrioritiseInstrument, RespectMutes);
  318. if ((nMixPlugin > 0) && (nMixPlugin <= MAX_MIXPLUGINS) && m_MixPlugins[nMixPlugin - 1].pMixPlugin != nullptr)
  319. {
  320. // Render into plugin buffer instead of global buffer
  321. SNDMIXPLUGINSTATE &mixState = m_MixPlugins[nMixPlugin - 1].pMixPlugin->m_MixState;
  322. if (mixState.pMixBuffer)
  323. {
  324. pbuffer = mixState.pMixBuffer;
  325. pOfsR = &mixState.nVolDecayR;
  326. pOfsL = &mixState.nVolDecayL;
  327. if (!(mixState.dwFlags & SNDMIXPLUGINSTATE::psfMixReady))
  328. {
  329. StereoFill(pbuffer, count, *pOfsR, *pOfsL);
  330. mixState.dwFlags |= SNDMIXPLUGINSTATE::psfMixReady;
  331. }
  332. }
  333. }
  334. #endif // NO_PLUGINS
  335. if(chn.isPaused)
  336. {
  337. EndChannelOfs(chn, pbuffer, count);
  338. *pOfsR += chn.nROfs;
  339. *pOfsL += chn.nLOfs;
  340. chn.nROfs = chn.nLOfs = 0;
  341. continue;
  342. }
  343. MixLoopState mixLoopState(*this, chn);
  344. ////////////////////////////////////////////////////
  345. CHANNELINDEX naddmix = 0;
  346. int nsamples = count;
  347. // Keep mixing this sample until the buffer is filled.
  348. do
  349. {
  350. uint32 nrampsamples = nsamples;
  351. int32 nSmpCount;
  352. if(chn.nRampLength > 0)
  353. {
  354. if (nrampsamples > chn.nRampLength) nrampsamples = chn.nRampLength;
  355. }
  356. if((nSmpCount = mixLoopState.GetSampleCount(chn, nrampsamples)) <= 0)
  357. {
  358. // Stopping the channel
  359. chn.pCurrentSample = nullptr;
  360. chn.nLength = 0;
  361. chn.position.Set(0);
  362. chn.nRampLength = 0;
  363. EndChannelOfs(chn, pbuffer, nsamples);
  364. *pOfsR += chn.nROfs;
  365. *pOfsL += chn.nLOfs;
  366. chn.nROfs = chn.nLOfs = 0;
  367. chn.dwFlags.reset(CHN_PINGPONGFLAG);
  368. break;
  369. }
  370. // Should we mix this channel ?
  371. if((nchmixed >= m_MixerSettings.m_nMaxMixChannels) // Too many channels
  372. || (!chn.nRampLength && !(chn.leftVol | chn.rightVol))) // Channel is completely silent
  373. {
  374. chn.position += chn.increment * nSmpCount;
  375. chn.nROfs = chn.nLOfs = 0;
  376. pbuffer += nSmpCount * 2;
  377. naddmix = 0;
  378. }
  379. #ifdef MODPLUG_TRACKER
  380. else if(m_SamplePlayLengths != nullptr)
  381. {
  382. // Detecting the longest play time for each sample for optimization
  383. SmpLength pos = chn.position.GetUInt();
  384. chn.position += chn.increment * nSmpCount;
  385. if(!chn.increment.IsNegative())
  386. {
  387. pos = chn.position.GetUInt();
  388. }
  389. size_t smp = std::distance(static_cast<const ModSample*>(static_cast<std::decay<decltype(Samples)>::type>(Samples)), chn.pModSample);
  390. if(smp < m_SamplePlayLengths->size())
  391. {
  392. (*m_SamplePlayLengths)[smp] = std::max((*m_SamplePlayLengths)[smp], pos);
  393. }
  394. }
  395. #endif
  396. else
  397. {
  398. // Do mixing
  399. mixsample_t *pbufmax = pbuffer + (nSmpCount * 2);
  400. chn.nROfs = -*(pbufmax - 2);
  401. chn.nLOfs = -*(pbufmax - 1);
  402. #ifdef MPT_BUILD_DEBUG
  403. SamplePosition targetpos = chn.position + chn.increment * nSmpCount;
  404. #endif
  405. MixFuncTable::Functions[functionNdx | (chn.nRampLength ? MixFuncTable::ndxRamp : 0)](chn, m_Resampler, pbuffer, nSmpCount);
  406. #ifdef MPT_BUILD_DEBUG
  407. MPT_ASSERT(chn.position.GetUInt() == targetpos.GetUInt());
  408. #endif
  409. chn.nROfs += *(pbufmax - 2);
  410. chn.nLOfs += *(pbufmax - 1);
  411. pbuffer = pbufmax;
  412. naddmix = 1;
  413. }
  414. nsamples -= nSmpCount;
  415. if (chn.nRampLength)
  416. {
  417. if (chn.nRampLength <= static_cast<uint32>(nSmpCount))
  418. {
  419. // Ramping is done
  420. chn.nRampLength = 0;
  421. chn.leftVol = chn.newLeftVol;
  422. chn.rightVol = chn.newRightVol;
  423. chn.rightRamp = chn.leftRamp = 0;
  424. if(chn.dwFlags[CHN_NOTEFADE] && !chn.nFadeOutVol)
  425. {
  426. chn.nLength = 0;
  427. chn.pCurrentSample = nullptr;
  428. }
  429. } else
  430. {
  431. chn.nRampLength -= nSmpCount;
  432. }
  433. }
  434. const bool pastLoopEnd = chn.position.GetUInt() >= chn.nLoopEnd && chn.dwFlags[CHN_LOOP];
  435. const bool pastSampleEnd = chn.position.GetUInt() >= chn.nLength && !chn.dwFlags[CHN_LOOP] && chn.nLength && !chn.nMasterChn;
  436. const bool doSampleSwap = m_playBehaviour[kMODSampleSwap] && chn.nNewIns && chn.nNewIns <= GetNumSamples() && chn.pModSample != &Samples[chn.nNewIns];
  437. if((pastLoopEnd || pastSampleEnd) && doSampleSwap)
  438. {
  439. // ProTracker compatibility: Instrument changes without a note do not happen instantly, but rather when the sample loop has finished playing.
  440. // Test case: PTInstrSwap.mod, PTSwapNoLoop.mod
  441. const ModSample &smp = Samples[chn.nNewIns];
  442. chn.pModSample = &smp;
  443. chn.pCurrentSample = smp.samplev();
  444. chn.dwFlags = (chn.dwFlags & CHN_CHANNELFLAGS) | smp.uFlags;
  445. chn.nLength = smp.uFlags[CHN_LOOP] ? smp.nLoopEnd : 0; // non-looping sample continue in oneshot mode (i.e. they will most probably just play silence)
  446. chn.nLoopStart = smp.nLoopStart;
  447. chn.nLoopEnd = smp.nLoopEnd;
  448. chn.position.SetInt(chn.nLoopStart);
  449. mixLoopState.UpdateLookaheadPointers(chn);
  450. if(!chn.pCurrentSample)
  451. {
  452. break;
  453. }
  454. } else if(pastLoopEnd && !doSampleSwap && m_playBehaviour[kMODOneShotLoops] && chn.nLoopStart == 0)
  455. {
  456. // ProTracker "oneshot" loops (if loop start is 0, play the whole sample once and then repeat until loop end)
  457. chn.position.SetInt(0);
  458. chn.nLoopEnd = chn.nLength = chn.pModSample->nLoopEnd;
  459. }
  460. } while(nsamples > 0);
  461. // Restore sample pointer in case it got changed through loop wrap-around
  462. chn.pCurrentSample = mixLoopState.samplePointer;
  463. nchmixed += naddmix;
  464. #ifndef NO_PLUGINS
  465. if(naddmix && nMixPlugin > 0 && nMixPlugin <= MAX_MIXPLUGINS && m_MixPlugins[nMixPlugin - 1].pMixPlugin)
  466. {
  467. m_MixPlugins[nMixPlugin - 1].pMixPlugin->ResetSilence();
  468. }
  469. #endif // NO_PLUGINS
  470. }
  471. m_nMixStat = std::max(m_nMixStat, nchmixed);
  472. }
  473. void CSoundFile::ProcessPlugins(uint32 nCount)
  474. {
  475. #ifndef NO_PLUGINS
  476. // If any sample channels are active or any plugin has some input, possibly suspended master plugins need to be woken up.
  477. bool masterHasInput = (m_nMixStat > 0);
  478. #ifdef MPT_INTMIXER
  479. const float IntToFloat = m_PlayConfig.getIntToFloat();
  480. const float FloatToInt = m_PlayConfig.getFloatToInt();
  481. #endif // MPT_INTMIXER
  482. // Setup float inputs from samples
  483. for(PLUGINDEX plug = 0; plug < MAX_MIXPLUGINS; plug++)
  484. {
  485. SNDMIXPLUGIN &plugin = m_MixPlugins[plug];
  486. if(plugin.pMixPlugin != nullptr
  487. && plugin.pMixPlugin->m_MixState.pMixBuffer != nullptr
  488. && plugin.pMixPlugin->m_mixBuffer.Ok())
  489. {
  490. IMixPlugin *mixPlug = plugin.pMixPlugin;
  491. SNDMIXPLUGINSTATE &state = mixPlug->m_MixState;
  492. //We should only ever reach this point if the song is playing.
  493. if (!mixPlug->IsSongPlaying())
  494. {
  495. //Plugin doesn't know it is in a song that is playing;
  496. //we must have added it during playback. Initialise it!
  497. mixPlug->NotifySongPlaying(true);
  498. mixPlug->Resume();
  499. }
  500. // Setup float input
  501. float *plugInputL = mixPlug->m_mixBuffer.GetInputBuffer(0);
  502. float *plugInputR = mixPlug->m_mixBuffer.GetInputBuffer(1);
  503. if (state.dwFlags & SNDMIXPLUGINSTATE::psfMixReady)
  504. {
  505. #ifdef MPT_INTMIXER
  506. StereoMixToFloat(state.pMixBuffer, plugInputL, plugInputR, nCount, IntToFloat);
  507. #else
  508. DeinterleaveStereo(state.pMixBuffer, plugInputL, plugInputR, nCount);
  509. #endif // MPT_INTMIXER
  510. } else if (state.nVolDecayR || state.nVolDecayL)
  511. {
  512. StereoFill(state.pMixBuffer, nCount, state.nVolDecayR, state.nVolDecayL);
  513. #ifdef MPT_INTMIXER
  514. StereoMixToFloat(state.pMixBuffer, plugInputL, plugInputR, nCount, IntToFloat);
  515. #else
  516. DeinterleaveStereo(state.pMixBuffer, plugInputL, plugInputR, nCount);
  517. #endif // MPT_INTMIXER
  518. } else
  519. {
  520. memset(plugInputL, 0, nCount * sizeof(plugInputL[0]));
  521. memset(plugInputR, 0, nCount * sizeof(plugInputR[0]));
  522. }
  523. state.dwFlags &= ~SNDMIXPLUGINSTATE::psfMixReady;
  524. if(!plugin.IsMasterEffect() && !(state.dwFlags & SNDMIXPLUGINSTATE::psfSilenceBypass))
  525. {
  526. masterHasInput = true;
  527. }
  528. }
  529. }
  530. // Convert mix buffer
  531. #ifdef MPT_INTMIXER
  532. StereoMixToFloat(MixSoundBuffer, MixFloatBuffer[0], MixFloatBuffer[1], nCount, IntToFloat);
  533. #else
  534. DeinterleaveStereo(MixSoundBuffer, MixFloatBuffer[0], MixFloatBuffer[1], nCount);
  535. #endif // MPT_INTMIXER
  536. float *pMixL = MixFloatBuffer[0];
  537. float *pMixR = MixFloatBuffer[1];
  538. const bool positionChanged = HasPositionChanged();
  539. // Process Plugins
  540. for(PLUGINDEX plug = 0; plug < MAX_MIXPLUGINS; plug++)
  541. {
  542. SNDMIXPLUGIN &plugin = m_MixPlugins[plug];
  543. if (plugin.pMixPlugin != nullptr
  544. && plugin.pMixPlugin->m_MixState.pMixBuffer != nullptr
  545. && plugin.pMixPlugin->m_mixBuffer.Ok())
  546. {
  547. IMixPlugin *pObject = plugin.pMixPlugin;
  548. if(!plugin.IsMasterEffect() && !plugin.pMixPlugin->ShouldProcessSilence() && !(plugin.pMixPlugin->m_MixState.dwFlags & SNDMIXPLUGINSTATE::psfHasInput))
  549. {
  550. // If plugin has no inputs and isn't a master plugin, we shouldn't let it process silence if possible.
  551. // I have yet to encounter a VST plugin which actually sets this flag.
  552. bool hasInput = false;
  553. for(PLUGINDEX inPlug = 0; inPlug < plug; inPlug++)
  554. {
  555. if(m_MixPlugins[inPlug].GetOutputPlugin() == plug)
  556. {
  557. hasInput = true;
  558. break;
  559. }
  560. }
  561. if(!hasInput)
  562. {
  563. continue;
  564. }
  565. }
  566. bool isMasterMix = false;
  567. float *plugInputL = pObject->m_mixBuffer.GetInputBuffer(0);
  568. float *plugInputR = pObject->m_mixBuffer.GetInputBuffer(1);
  569. if (pMixL == plugInputL)
  570. {
  571. isMasterMix = true;
  572. pMixL = MixFloatBuffer[0];
  573. pMixR = MixFloatBuffer[1];
  574. }
  575. SNDMIXPLUGINSTATE &state = plugin.pMixPlugin->m_MixState;
  576. float *pOutL = pMixL;
  577. float *pOutR = pMixR;
  578. if (!plugin.IsOutputToMaster())
  579. {
  580. PLUGINDEX nOutput = plugin.GetOutputPlugin();
  581. if(nOutput > plug && nOutput < MAX_MIXPLUGINS
  582. && m_MixPlugins[nOutput].pMixPlugin != nullptr)
  583. {
  584. IMixPlugin *outPlugin = m_MixPlugins[nOutput].pMixPlugin;
  585. if(!(state.dwFlags & SNDMIXPLUGINSTATE::psfSilenceBypass)) outPlugin->ResetSilence();
  586. if(outPlugin->m_mixBuffer.Ok())
  587. {
  588. pOutL = outPlugin->m_mixBuffer.GetInputBuffer(0);
  589. pOutR = outPlugin->m_mixBuffer.GetInputBuffer(1);
  590. }
  591. }
  592. }
  593. /*
  594. if (plugin.multiRouting) {
  595. int nOutput=0;
  596. for (int nOutput=0; nOutput < plugin.nOutputs / 2; nOutput++) {
  597. destinationPlug = plugin.multiRoutingDestinations[nOutput];
  598. pOutState = m_MixPlugins[destinationPlug].pMixState;
  599. pOutputs[2 * nOutput] = plugInputL;
  600. pOutputs[2 * (nOutput + 1)] = plugInputR;
  601. }
  602. }*/
  603. if (plugin.IsMasterEffect())
  604. {
  605. if (!isMasterMix)
  606. {
  607. float *pInL = plugInputL;
  608. float *pInR = plugInputR;
  609. for (uint32 i=0; i<nCount; i++)
  610. {
  611. pInL[i] += pMixL[i];
  612. pInR[i] += pMixR[i];
  613. pMixL[i] = 0;
  614. pMixR[i] = 0;
  615. }
  616. }
  617. pMixL = pOutL;
  618. pMixR = pOutR;
  619. if(masterHasInput)
  620. {
  621. // Samples or plugins are being rendered, so turn off auto-bypass for this master effect.
  622. if(plugin.pMixPlugin != nullptr) plugin.pMixPlugin->ResetSilence();
  623. SNDMIXPLUGIN *chain = &plugin;
  624. PLUGINDEX out = chain->GetOutputPlugin(), prevOut = plug;
  625. while(out > prevOut && out < MAX_MIXPLUGINS)
  626. {
  627. chain = &m_MixPlugins[out];
  628. prevOut = out;
  629. out = chain->GetOutputPlugin();
  630. if(chain->pMixPlugin)
  631. {
  632. chain->pMixPlugin->ResetSilence();
  633. }
  634. }
  635. }
  636. }
  637. if(plugin.IsBypassed() || (plugin.IsAutoSuspendable() && (state.dwFlags & SNDMIXPLUGINSTATE::psfSilenceBypass)))
  638. {
  639. const float * const pInL = plugInputL;
  640. const float * const pInR = plugInputR;
  641. for (uint32 i=0; i<nCount; i++)
  642. {
  643. pOutL[i] += pInL[i];
  644. pOutR[i] += pInR[i];
  645. }
  646. } else
  647. {
  648. if(positionChanged)
  649. pObject->PositionChanged();
  650. pObject->Process(pOutL, pOutR, nCount);
  651. state.inputSilenceCount += nCount;
  652. if(plugin.IsAutoSuspendable() && pObject->GetNumOutputChannels() > 0 && state.inputSilenceCount >= m_MixerSettings.gdwMixingFreq * 4)
  653. {
  654. bool isSilent = true;
  655. for(uint32 i = 0; i < nCount; i++)
  656. {
  657. if(pOutL[i] >= FLT_EPSILON || pOutL[i] <= -FLT_EPSILON
  658. || pOutR[i] >= FLT_EPSILON || pOutR[i] <= -FLT_EPSILON)
  659. {
  660. isSilent = false;
  661. break;
  662. }
  663. }
  664. if(isSilent)
  665. {
  666. state.dwFlags |= SNDMIXPLUGINSTATE::psfSilenceBypass;
  667. } else
  668. {
  669. state.inputSilenceCount = 0;
  670. }
  671. }
  672. }
  673. state.dwFlags &= ~SNDMIXPLUGINSTATE::psfHasInput;
  674. }
  675. }
  676. #ifdef MPT_INTMIXER
  677. FloatToStereoMix(pMixL, pMixR, MixSoundBuffer, nCount, FloatToInt);
  678. #else
  679. InterleaveStereo(pMixL, pMixR, MixSoundBuffer, nCount);
  680. #endif // MPT_INTMIXER
  681. #else
  682. MPT_UNREFERENCED_PARAMETER(nCount);
  683. #endif // NO_PLUGINS
  684. }
  685. OPENMPT_NAMESPACE_END