1 /* 2 * ModChannel.h 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 10 11 #pragma once 12 13 #include "openmpt/all/BuildSettings.hpp" 14 15 #include "ModSample.h" 16 #include "ModInstrument.h" 17 #include "modcommand.h" 18 #include "Paula.h" 19 #include "tuningbase.h" 20 21 OPENMPT_NAMESPACE_BEGIN 22 23 class CSoundFile; 24 25 // Mix Channel Struct 26 struct ModChannel 27 { 28 // Envelope playback info 29 struct EnvInfo 30 { 31 uint32 nEnvPosition = 0; 32 int16 nEnvValueAtReleaseJump = NOT_YET_RELEASED; 33 FlagSet<EnvelopeFlags> flags; 34 ResetModChannel::EnvInfo35 void Reset() 36 { 37 nEnvPosition = 0; 38 nEnvValueAtReleaseJump = NOT_YET_RELEASED; 39 } 40 }; 41 42 // Information used in the mixer (should be kept tight for better caching) 43 SamplePosition position; // Current play position (fixed point) 44 SamplePosition increment; // Sample speed relative to mixing frequency (fixed point) 45 const void *pCurrentSample; // Currently playing sample (nullptr if no sample is playing) 46 int32 leftVol; // 0...4096 (12 bits, since 16 bits + 12 bits = 28 bits = 0dB in integer mixer, see MIXING_ATTENUATION) 47 int32 rightVol; // Ditto 48 int32 leftRamp; // Ramping delta, 20.12 fixed point (see VOLUMERAMPPRECISION) 49 int32 rightRamp; // Ditto 50 int32 rampLeftVol; // Current ramping volume, 20.12 fixed point (see VOLUMERAMPPRECISION) 51 int32 rampRightVol; // Ditto 52 mixsample_t nFilter_Y[2][2]; // Filter memory - two history items per sample channel 53 mixsample_t nFilter_A0, nFilter_B0, nFilter_B1; // Filter coeffs 54 mixsample_t nFilter_HP; 55 56 SmpLength nLength; 57 SmpLength nLoopStart; 58 SmpLength nLoopEnd; 59 FlagSet<ChannelFlags> dwFlags; 60 mixsample_t nROfs, nLOfs; 61 uint32 nRampLength; 62 63 const ModSample *pModSample; // Currently assigned sample slot (may already be stopped) 64 Paula::State paulaState; 65 66 // Information not used in the mixer 67 const ModInstrument *pModInstrument; // Currently assigned instrument slot 68 SmpLength prevNoteOffset; // Offset for instrument-less notes for ProTracker/ScreamTracker 69 SmpLength oldOffset; // Offset command memory 70 FlagSet<ChannelFlags> dwOldFlags; // Flags from previous tick 71 int32 newLeftVol, newRightVol; 72 int32 nRealVolume, nRealPan; 73 int32 nVolume, nPan, nFadeOutVol; 74 int32 nPeriod; // Frequency in Hz if CSoundFile::PeriodsAreFrequencies() or using custom tuning, 4x Amiga periods otherwise 75 int32 nC5Speed, nPortamentoDest; 76 int32 cachedPeriod, glissandoPeriod; 77 int32 nCalcVolume; // Calculated channel volume, 14-Bit (without global volume, pre-amp etc applied) - for MIDI macros 78 EnvInfo VolEnv, PanEnv, PitchEnv; // Envelope playback info 79 int32 nGlobalVol; // Channel volume (CV in ITTECH.TXT) 0...64 80 int32 nInsVol; // Sample / Instrument volume (SV * IV in ITTECH.TXT) 0...64 81 int32 nAutoVibDepth; 82 uint32 nEFxOffset; // Offset memory for Invert Loop (EFx, .MOD only) 83 ROWINDEX nPatternLoop; 84 uint16 portamentoSlide; 85 int16 nTranspose; 86 int16 nFineTune; 87 int16 microTuning; // Micro-tuning / MIDI pitch wheel command 88 int16 nVolSwing, nPanSwing; 89 int16 nCutSwing, nResSwing; 90 uint16 nRestorePanOnNewNote; // If > 0, nPan should be set to nRestorePanOnNewNote - 1 on new note. Used to recover from pan swing and IT sample / instrument panning. High bit set = surround 91 CHANNELINDEX nMasterChn; 92 ModCommand rowCommand; 93 // 8-bit members 94 ResamplingMode resamplingMode; 95 uint8 nRestoreResonanceOnNewNote; // See nRestorePanOnNewNote 96 uint8 nRestoreCutoffOnNewNote; // ditto 97 uint8 nNote; 98 NewNoteAction nNNA; 99 uint8 nLastNote; // Last note, ignoring note offs and cuts - for MIDI macros 100 uint8 nArpeggioLastNote, nArpeggioBaseNote; // For plugin arpeggio 101 uint8 nNewNote, nNewIns, nOldIns, nCommand, nArpeggio; 102 uint8 nRetrigParam, nRetrigCount; 103 uint8 nOldVolumeSlide, nOldFineVolUpDown; 104 uint8 nOldPortaUp, nOldPortaDown, nOldFinePortaUpDown, nOldExtraFinePortaUpDown; 105 uint8 nOldPanSlide, nOldChnVolSlide; 106 uint8 nOldGlobalVolSlide; 107 uint8 nAutoVibPos, nVibratoPos, nTremoloPos, nPanbrelloPos; 108 uint8 nVibratoType, nVibratoSpeed, nVibratoDepth; 109 uint8 nTremoloType, nTremoloSpeed, nTremoloDepth; 110 uint8 nPanbrelloType, nPanbrelloSpeed, nPanbrelloDepth; 111 int8 nPanbrelloOffset, nPanbrelloRandomMemory; 112 uint8 nOldCmdEx, nOldVolParam, nOldTempo; 113 uint8 nOldHiOffset; 114 uint8 nCutOff, nResonance; 115 uint8 nTremorCount, nTremorParam; 116 uint8 nPatternLoopCount; 117 uint8 nLeftVU, nRightVU; 118 uint8 nActiveMacro; 119 FilterMode nFilterMode; 120 uint8 nEFxSpeed, nEFxDelay; // memory for Invert Loop (EFx, .MOD only) 121 uint8 noteSlideParam, noteSlideCounter; // IMF / PTM Note Slide 122 uint8 lastZxxParam; // Memory for \xx slides 123 bool isFirstTick : 1; // Execute tick-0 effects on this channel? (condition differs between formats due to Pattern Delay commands) 124 bool triggerNote : 1; // Trigger note on this tick on this channel if there is one? 125 bool isPreviewNote : 1; // Notes preview in editor 126 bool isPaused : 1; // Don't mix or increment channel position, but keep the note alive 127 bool portaTargetReached : 1; // Tone portamento is finished 128 129 //-->Variables used to make user-definable tuning modes work with pattern effects. 130 //If true, freq should be recalculated in ReadNote() on first tick. 131 //Currently used only for vibrato things - using in other context might be 132 //problematic. 133 bool m_ReCalculateFreqOnFirstTick : 1; 134 135 //To tell whether to calculate frequency. 136 bool m_CalculateFreq : 1; 137 138 int32 m_PortamentoFineSteps, m_PortamentoTickSlide; 139 140 //NOTE_PCs memory. 141 float m_plugParamValueStep, m_plugParamTargetValue; 142 uint16 m_RowPlugParam; 143 PLUGINDEX m_RowPlug; 144 ClearRowCmdModChannel145 void ClearRowCmd() { rowCommand = ModCommand(); } 146 147 // Get a reference to a specific envelope of this channel GetEnvelopeModChannel148 const EnvInfo &GetEnvelope(EnvelopeType envType) const 149 { 150 switch(envType) 151 { 152 case ENV_VOLUME: 153 default: 154 return VolEnv; 155 case ENV_PANNING: 156 return PanEnv; 157 case ENV_PITCH: 158 return PitchEnv; 159 } 160 } 161 GetEnvelopeModChannel162 EnvInfo &GetEnvelope(EnvelopeType envType) 163 { 164 return const_cast<EnvInfo &>(static_cast<const ModChannel *>(this)->GetEnvelope(envType)); 165 } 166 ResetEnvelopesModChannel167 void ResetEnvelopes() 168 { 169 VolEnv.Reset(); 170 PanEnv.Reset(); 171 PitchEnv.Reset(); 172 } 173 174 enum ResetFlags 175 { 176 resetChannelSettings = 1, // Reload initial channel settings 177 resetSetPosBasic = 2, // Reset basic runtime channel attributes 178 resetSetPosAdvanced = 4, // Reset more runtime channel attributes 179 resetSetPosFull = resetSetPosBasic | resetSetPosAdvanced | resetChannelSettings, // Reset all runtime channel attributes 180 resetTotal = resetSetPosFull, 181 }; 182 183 void Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel, ChannelFlags muteFlag); 184 void Stop(); 185 IsSamplePlayingModChannel186 bool IsSamplePlaying() const noexcept { return !increment.IsZero(); } 187 GetVSTVolumeModChannel188 uint32 GetVSTVolume() const noexcept { return (pModInstrument) ? pModInstrument->nGlobalVol * 4 : nVolume; } 189 190 ModCommand::NOTE GetPluginNote(bool realNoteMapping) const; 191 192 // Check if the channel has a valid MIDI output. A return value of true implies that pModInstrument != nullptr. HasMIDIOutputModChannel193 bool HasMIDIOutput() const noexcept { return pModInstrument != nullptr && pModInstrument->HasValidMIDIChannel(); } 194 // Check if the channel uses custom tuning. A return value of true implies that pModInstrument != nullptr. HasCustomTuningModChannel195 bool HasCustomTuning() const noexcept { return pModInstrument != nullptr && pModInstrument->pTuning != nullptr; } 196 197 // Check if currently processed loop is a sustain loop. pModSample is not checked for validity! InSustainLoopModChannel198 bool InSustainLoop() const noexcept { return (dwFlags & (CHN_LOOP | CHN_KEYOFF)) == CHN_LOOP && pModSample->uFlags[CHN_SUSTAINLOOP]; } 199 200 void UpdateInstrumentVolume(const ModSample *smp, const ModInstrument *ins); 201 202 void SetInstrumentPan(int32 pan, const CSoundFile &sndFile); 203 204 void RecalcTuningFreq(Tuning::RATIOTYPE vibratoFactor, Tuning::NOTEINDEXTYPE arpeggioSteps, const CSoundFile &sndFile); 205 206 // IT command S73-S7E 207 void InstrumentControl(uint8 param, const CSoundFile &sndFile); 208 GetMIDIPitchBendModChannel209 int32 GetMIDIPitchBend() const noexcept { return (static_cast<int32>(microTuning) + 0x8000) / 4; } 210 }; 211 212 213 // Default pattern channel settings 214 struct ModChannelSettings 215 { 216 #ifdef MODPLUG_TRACKER 217 static constexpr uint32 INVALID_COLOR = 0xFFFFFFFF; 218 uint32 color = INVALID_COLOR; // For pattern editor 219 #endif // MODPLUG_TRACKER 220 FlagSet<ChannelFlags> dwFlags; // Channel flags 221 uint16 nPan = 128; // Initial pan (0...256) 222 uint16 nVolume = 64; // Initial channel volume (0...64) 223 PLUGINDEX nMixPlugin = 0; // Assigned plugin 224 225 mpt::charbuf<MAX_CHANNELNAME> szName; // Channel name 226 ResetModChannelSettings227 void Reset() 228 { 229 *this = {}; 230 } 231 }; 232 233 OPENMPT_NAMESPACE_END 234