1
0

ModChannel.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * ModChannel.cpp
  3. * --------------
  4. * Purpose: Module Channel 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 "ModChannel.h"
  12. #include "tuning.h"
  13. OPENMPT_NAMESPACE_BEGIN
  14. void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel, ChannelFlags muteFlag)
  15. {
  16. if(resetMask & resetSetPosBasic)
  17. {
  18. nNote = nNewNote = NOTE_NONE;
  19. nNewIns = nOldIns = 0;
  20. pModSample = nullptr;
  21. pModInstrument = nullptr;
  22. nPortamentoDest = 0;
  23. nCommand = CMD_NONE;
  24. nPatternLoopCount = 0;
  25. nPatternLoop = 0;
  26. nFadeOutVol = 0;
  27. dwFlags.set(CHN_KEYOFF | CHN_NOTEFADE);
  28. dwOldFlags.reset();
  29. //IT compatibility 15. Retrigger
  30. if(sndFile.m_playBehaviour[kITRetrigger])
  31. {
  32. nRetrigParam = 1;
  33. nRetrigCount = 0;
  34. }
  35. microTuning = 0;
  36. nTremorCount = 0;
  37. nEFxSpeed = 0;
  38. prevNoteOffset = 0;
  39. lastZxxParam = 0xFF;
  40. isFirstTick = false;
  41. triggerNote = false;
  42. isPreviewNote = false;
  43. isPaused = false;
  44. portaTargetReached = false;
  45. rowCommand.Clear();
  46. }
  47. if(resetMask & resetSetPosAdvanced)
  48. {
  49. increment = SamplePosition(0);
  50. nPeriod = 0;
  51. position.Set(0);
  52. nLength = 0;
  53. nLoopStart = 0;
  54. nLoopEnd = 0;
  55. nROfs = nLOfs = 0;
  56. pModSample = nullptr;
  57. pModInstrument = nullptr;
  58. nCutOff = 0x7F;
  59. nResonance = 0;
  60. nFilterMode = FilterMode::LowPass;
  61. rightVol = leftVol = 0;
  62. newRightVol = newLeftVol = 0;
  63. rightRamp = leftRamp = 0;
  64. nVolume = 0; // Needs to be 0 for SMP_NODEFAULTVOLUME flag
  65. nVibratoPos = nTremoloPos = nPanbrelloPos = 0;
  66. nOldHiOffset = 0;
  67. nLeftVU = nRightVU = 0;
  68. // Custom tuning related
  69. m_ReCalculateFreqOnFirstTick = false;
  70. m_CalculateFreq = false;
  71. m_PortamentoFineSteps = 0;
  72. m_PortamentoTickSlide = 0;
  73. }
  74. if(resetMask & resetChannelSettings)
  75. {
  76. if(sourceChannel < MAX_BASECHANNELS)
  77. {
  78. dwFlags = sndFile.ChnSettings[sourceChannel].dwFlags;
  79. nPan = sndFile.ChnSettings[sourceChannel].nPan;
  80. nGlobalVol = sndFile.ChnSettings[sourceChannel].nVolume;
  81. if(dwFlags[CHN_MUTE])
  82. {
  83. dwFlags.reset(CHN_MUTE);
  84. dwFlags.set(muteFlag);
  85. }
  86. } else
  87. {
  88. dwFlags.reset();
  89. nPan = 128;
  90. nGlobalVol = 64;
  91. }
  92. nRestorePanOnNewNote = 0;
  93. nRestoreCutoffOnNewNote = 0;
  94. nRestoreResonanceOnNewNote = 0;
  95. }
  96. }
  97. void ModChannel::Stop()
  98. {
  99. nPeriod = 0;
  100. increment.Set(0);
  101. position.Set(0);
  102. nLeftVU = nRightVU = 0;
  103. nVolume = 0;
  104. pCurrentSample = nullptr;
  105. }
  106. void ModChannel::UpdateInstrumentVolume(const ModSample *smp, const ModInstrument *ins)
  107. {
  108. nInsVol = 64;
  109. if(smp != nullptr)
  110. nInsVol = smp->nGlobalVol;
  111. if(ins != nullptr)
  112. nInsVol = (nInsVol * ins->nGlobalVol) / 64;
  113. }
  114. ModCommand::NOTE ModChannel::GetPluginNote(bool realNoteMapping) const
  115. {
  116. if(nArpeggioLastNote != NOTE_NONE)
  117. {
  118. // If an arpeggio is playing, this definitely the last playing note, which may be different from the arpeggio base note stored in nNote.
  119. return nArpeggioLastNote;
  120. }
  121. ModCommand::NOTE plugNote = mpt::saturate_cast<ModCommand::NOTE>(nNote - nTranspose);
  122. // Caution: When in compatible mode, ModChannel::nNote stores the "real" note, not the mapped note!
  123. if(realNoteMapping && pModInstrument != nullptr && plugNote >= NOTE_MIN && plugNote < (std::size(pModInstrument->NoteMap) + NOTE_MIN))
  124. {
  125. plugNote = pModInstrument->NoteMap[plugNote - NOTE_MIN];
  126. }
  127. return plugNote;
  128. }
  129. void ModChannel::SetInstrumentPan(int32 pan, const CSoundFile &sndFile)
  130. {
  131. // IT compatibility: Instrument and sample panning does not override channel panning
  132. // Test case: PanResetInstr.it
  133. if(sndFile.m_playBehaviour[kITDoNotOverrideChannelPan])
  134. {
  135. nRestorePanOnNewNote = static_cast<uint16>(nPan + 1);
  136. if(dwFlags[CHN_SURROUND])
  137. nRestorePanOnNewNote |= 0x8000;
  138. }
  139. nPan = pan;
  140. }
  141. void ModChannel::RestorePanAndFilter()
  142. {
  143. if(nRestorePanOnNewNote > 0)
  144. {
  145. nPan = (nRestorePanOnNewNote & 0x7FFF) - 1;
  146. if(nRestorePanOnNewNote & 0x8000)
  147. dwFlags.set(CHN_SURROUND);
  148. nRestorePanOnNewNote = 0;
  149. }
  150. if(nRestoreResonanceOnNewNote > 0)
  151. {
  152. nResonance = nRestoreResonanceOnNewNote - 1;
  153. nRestoreResonanceOnNewNote = 0;
  154. }
  155. if(nRestoreCutoffOnNewNote > 0)
  156. {
  157. nCutOff = nRestoreCutoffOnNewNote - 1;
  158. nRestoreCutoffOnNewNote = 0;
  159. }
  160. }
  161. void ModChannel::RecalcTuningFreq(Tuning::RATIOTYPE vibratoFactor, Tuning::NOTEINDEXTYPE arpeggioSteps, const CSoundFile &sndFile)
  162. {
  163. if(!HasCustomTuning())
  164. return;
  165. ModCommand::NOTE note = ModCommand::IsNote(nNote) ? nNote : nLastNote;
  166. if(sndFile.m_playBehaviour[kITRealNoteMapping] && note >= NOTE_MIN && note <= NOTE_MAX)
  167. note = pModInstrument->NoteMap[note - NOTE_MIN];
  168. nPeriod = mpt::saturate_round<uint32>(nC5Speed * vibratoFactor * pModInstrument->pTuning->GetRatio(note - NOTE_MIDDLEC + arpeggioSteps, nFineTune + m_PortamentoFineSteps) * (1 << FREQ_FRACBITS));
  169. }
  170. // IT command S73-S7E
  171. void ModChannel::InstrumentControl(uint8 param, const CSoundFile &sndFile)
  172. {
  173. param &= 0x0F;
  174. switch(param)
  175. {
  176. case 0x3: nNNA = NewNoteAction::NoteCut; break;
  177. case 0x4: nNNA = NewNoteAction::Continue; break;
  178. case 0x5: nNNA = NewNoteAction::NoteOff; break;
  179. case 0x6: nNNA = NewNoteAction::NoteFade; break;
  180. case 0x7: VolEnv.flags.reset(ENV_ENABLED); break;
  181. case 0x8: VolEnv.flags.set(ENV_ENABLED); break;
  182. case 0x9: PanEnv.flags.reset(ENV_ENABLED); break;
  183. case 0xA: PanEnv.flags.set(ENV_ENABLED); break;
  184. case 0xB: PitchEnv.flags.reset(ENV_ENABLED); break;
  185. case 0xC: PitchEnv.flags.set(ENV_ENABLED); break;
  186. case 0xD: // S7D: Enable pitch envelope, force to play as pitch envelope
  187. case 0xE: // S7E: Enable pitch envelope, force to play as filter envelope
  188. if(sndFile.GetType() == MOD_TYPE_MPT)
  189. {
  190. PitchEnv.flags.set(ENV_ENABLED);
  191. PitchEnv.flags.set(ENV_FILTER, param != 0xD);
  192. }
  193. break;
  194. }
  195. }
  196. OPENMPT_NAMESPACE_END