2021-12-26 11:29:43 +00:00
/*
* ModChannel . h
* - - - - - - - - - - - -
* Purpose : Module Channel header class and helpers
* Notes : ( currently none )
* Authors : OpenMPT Devs
* The OpenMPT source code is released under the BSD license . Read LICENSE for more details .
*/
# pragma once
# include "BuildSettings.h"
# include "ModSample.h"
# include "ModInstrument.h"
# include "modcommand.h"
# include "Paula.h"
# include "tuningbase.h"
OPENMPT_NAMESPACE_BEGIN
class CSoundFile ;
// Mix Channel Struct
struct ModChannel
{
// Envelope playback info
struct EnvInfo
{
FlagSet < EnvelopeFlags > flags ;
uint32 nEnvPosition = 0 ;
int32 nEnvValueAtReleaseJump = NOT_YET_RELEASED ;
void Reset ( )
{
nEnvPosition = 0 ;
nEnvValueAtReleaseJump = NOT_YET_RELEASED ;
}
} ;
// Information used in the mixer (should be kept tight for better caching)
SamplePosition position ; // Current play position (fixed point)
SamplePosition increment ; // Sample speed relative to mixing frequency (fixed point)
const void * pCurrentSample ; // Currently playing sample (nullptr if no sample is playing)
int32 leftVol ; // 0...4096 (12 bits, since 16 bits + 12 bits = 28 bits = 0dB in integer mixer, see MIXING_ATTENUATION)
int32 rightVol ; // Ditto
int32 leftRamp ; // Ramping delta, 20.12 fixed point (see VOLUMERAMPPRECISION)
int32 rightRamp ; // Ditto
int32 rampLeftVol ; // Current ramping volume, 20.12 fixed point (see VOLUMERAMPPRECISION)
int32 rampRightVol ; // Ditto
mixsample_t nFilter_Y [ 2 ] [ 2 ] ; // Filter memory - two history items per sample channel
mixsample_t nFilter_A0 , nFilter_B0 , nFilter_B1 ; // Filter coeffs
mixsample_t nFilter_HP ;
SmpLength nLength ;
SmpLength nLoopStart ;
SmpLength nLoopEnd ;
FlagSet < ChannelFlags > dwFlags ;
mixsample_t nROfs , nLOfs ;
uint32 nRampLength ;
const ModSample * pModSample ; // Currently assigned sample slot (may already be stopped)
Paula : : State paulaState ;
// Information not used in the mixer
const ModInstrument * pModInstrument ; // Currently assigned instrument slot
SmpLength prevNoteOffset ; // Offset for instrument-less notes for ProTracker/ScreamTracker
SmpLength oldOffset ;
FlagSet < ChannelFlags > dwOldFlags ; // Flags from previous tick
int32 newLeftVol , newRightVol ;
int32 nRealVolume , nRealPan ;
int32 nVolume , nPan , nFadeOutVol ;
2022-01-30 23:19:36 +00:00
int32 nPeriod ; // Frequency in Hz if CSoundFile::PeriodsAreFrequencies() or using custom tuning, 4x Amiga periods otherwise
2021-12-26 11:29:43 +00:00
int32 nC5Speed , nPortamentoDest ;
int32 cachedPeriod , glissandoPeriod ;
int32 nCalcVolume ; // Calculated channel volume, 14-Bit (without global volume, pre-amp etc applied) - for MIDI macros
EnvInfo VolEnv , PanEnv , PitchEnv ; // Envelope playback info
int32 nGlobalVol ; // Channel volume (CV in ITTECH.TXT) 0...64
int32 nInsVol ; // Sample / Instrument volume (SV * IV in ITTECH.TXT) 0...64
int32 nFineTune , nTranspose ;
int32 nPortamentoSlide , nAutoVibDepth ;
uint32 nEFxOffset ; // Offset memory for Invert Loop (EFx, .MOD only)
int16 nVolSwing , nPanSwing ;
int16 nCutSwing , nResSwing ;
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
int16 nRetrigCount , nRetrigParam ;
ROWINDEX nPatternLoop ;
CHANNELINDEX nMasterChn ;
ModCommand rowCommand ;
// 8-bit members
ResamplingMode resamplingMode ;
uint8 nRestoreResonanceOnNewNote ; // See nRestorePanOnNewNote
uint8 nRestoreCutoffOnNewNote ; // ditto
uint8 nNote ;
NewNoteAction nNNA ;
uint8 nLastNote ; // Last note, ignoring note offs and cuts - for MIDI macros
uint8 nArpeggioLastNote , nArpeggioBaseNote ; // For plugin arpeggio
uint8 nNewNote , nNewIns , nOldIns , nCommand , nArpeggio ;
uint8 nOldVolumeSlide , nOldFineVolUpDown ;
uint8 nOldPortaUp , nOldPortaDown , nOldFinePortaUpDown , nOldExtraFinePortaUpDown ;
uint8 nOldPanSlide , nOldChnVolSlide ;
uint8 nOldGlobalVolSlide ;
uint8 nAutoVibPos , nVibratoPos , nTremoloPos , nPanbrelloPos ;
uint8 nVibratoType , nVibratoSpeed , nVibratoDepth ;
uint8 nTremoloType , nTremoloSpeed , nTremoloDepth ;
uint8 nPanbrelloType , nPanbrelloSpeed , nPanbrelloDepth ;
int8 nPanbrelloOffset , nPanbrelloRandomMemory ;
uint8 nOldCmdEx , nOldVolParam , nOldTempo ;
uint8 nOldHiOffset ;
uint8 nCutOff , nResonance ;
uint8 nTremorCount , nTremorParam ;
uint8 nPatternLoopCount ;
uint8 nLeftVU , nRightVU ;
uint8 nActiveMacro ;
FilterMode nFilterMode ;
uint8 nEFxSpeed , nEFxDelay ; // memory for Invert Loop (EFx, .MOD only)
uint8 nNoteSlideCounter , nNoteSlideSpeed , nNoteSlideStep ; // IMF / PTM Note Slide
2022-01-30 23:19:36 +00:00
uint8 lastZxxParam ; // Memory for \xx slides
bool isFirstTick : 1 ; // Execute tick-0 effects on this channel? (condition differs between formats due to Pattern Delay commands)
bool triggerNote : 1 ; // Trigger note on this tick on this channel if there is one?
bool isPreviewNote : 1 ; // Notes preview in editor
2021-12-26 11:29:43 +00:00
//-->Variables used to make user-definable tuning modes work with pattern effects.
//If true, freq should be recalculated in ReadNote() on first tick.
//Currently used only for vibrato things - using in other context might be
//problematic.
bool m_ReCalculateFreqOnFirstTick : 1 ;
//To tell whether to calculate frequency.
bool m_CalculateFreq : 1 ;
int32 m_PortamentoFineSteps , m_PortamentoTickSlide ;
//NOTE_PCs memory.
float m_plugParamValueStep , m_plugParamTargetValue ;
uint16 m_RowPlugParam ;
PLUGINDEX m_RowPlug ;
void ClearRowCmd ( ) { rowCommand = ModCommand ( ) ; }
// Get a reference to a specific envelope of this channel
const EnvInfo & GetEnvelope ( EnvelopeType envType ) const
{
switch ( envType )
{
case ENV_VOLUME :
default :
return VolEnv ;
case ENV_PANNING :
return PanEnv ;
case ENV_PITCH :
return PitchEnv ;
}
}
EnvInfo & GetEnvelope ( EnvelopeType envType )
{
return const_cast < EnvInfo & > ( static_cast < const ModChannel * > ( this ) - > GetEnvelope ( envType ) ) ;
}
void ResetEnvelopes ( )
{
VolEnv . Reset ( ) ;
PanEnv . Reset ( ) ;
PitchEnv . Reset ( ) ;
}
enum ResetFlags
{
resetChannelSettings = 1 , // Reload initial channel settings
resetSetPosBasic = 2 , // Reset basic runtime channel attributes
resetSetPosAdvanced = 4 , // Reset more runtime channel attributes
resetSetPosFull = resetSetPosBasic | resetSetPosAdvanced | resetChannelSettings , // Reset all runtime channel attributes
resetTotal = resetSetPosFull ,
} ;
void Reset ( ResetFlags resetMask , const CSoundFile & sndFile , CHANNELINDEX sourceChannel , ChannelFlags muteFlag ) ;
void Stop ( ) ;
bool IsSamplePlaying ( ) const noexcept { return ! increment . IsZero ( ) ; }
uint32 GetVSTVolume ( ) const noexcept { return ( pModInstrument ) ? pModInstrument - > nGlobalVol * 4 : nVolume ; }
ModCommand : : NOTE GetPluginNote ( bool realNoteMapping ) const ;
// Check if the channel has a valid MIDI output. A return value of true implies that pModInstrument != nullptr.
bool HasMIDIOutput ( ) const noexcept { return pModInstrument ! = nullptr & & pModInstrument - > HasValidMIDIChannel ( ) ; }
// Check if the channel uses custom tuning. A return value of true implies that pModInstrument != nullptr.
bool HasCustomTuning ( ) const noexcept { return pModInstrument ! = nullptr & & pModInstrument - > pTuning ! = nullptr ; }
// Check if currently processed loop is a sustain loop. pModSample is not checked for validity!
bool InSustainLoop ( ) const noexcept { return ( dwFlags & ( CHN_LOOP | CHN_KEYOFF ) ) = = CHN_LOOP & & pModSample - > uFlags [ CHN_SUSTAINLOOP ] ; }
void UpdateInstrumentVolume ( const ModSample * smp , const ModInstrument * ins ) ;
void SetInstrumentPan ( int32 pan , const CSoundFile & sndFile ) ;
2022-06-11 14:27:02 +00:00
void RestorePanAndFilter ( ) ;
2021-12-26 11:29:43 +00:00
void RecalcTuningFreq ( Tuning : : RATIOTYPE vibratoFactor , Tuning : : NOTEINDEXTYPE arpeggioSteps , const CSoundFile & sndFile ) ;
// IT command S73-S7E
void InstrumentControl ( uint8 param , const CSoundFile & sndFile ) ;
} ;
// Default pattern channel settings
struct ModChannelSettings
{
FlagSet < ChannelFlags > dwFlags ; // Channel flags
uint16 nPan ; // Initial pan (0...256)
uint16 nVolume ; // Initial channel volume (0...64)
PLUGINDEX nMixPlugin ; // Assigned plugin
mpt : : charbuf < MAX_CHANNELNAME > szName ; // Channel name
ModChannelSettings ( )
{
Reset ( ) ;
}
void Reset ( )
{
dwFlags . reset ( ) ;
nPan = 128 ;
nVolume = 64 ;
nMixPlugin = 0 ;
szName = " " ;
}
} ;
OPENMPT_NAMESPACE_END