2021-12-26 11:29:43 +00:00
/*
* Snd_Defs . h
* - - - - - - - - - -
* Purpose : Basic definitions of data types , enums , etc . for the playback engine core .
* Notes : ( currently none )
* Authors : Olivier Lapicque
* OpenMPT Devs
* The OpenMPT source code is released under the BSD license . Read LICENSE for more details .
*/
# pragma once
# include "BuildSettings.h"
# include "../common/FlagSet.h"
OPENMPT_NAMESPACE_BEGIN
using ROWINDEX = uint32 ;
inline constexpr ROWINDEX ROWINDEX_INVALID = uint32_max ;
using CHANNELINDEX = uint16 ;
inline constexpr CHANNELINDEX CHANNELINDEX_INVALID = uint16_max ;
using ORDERINDEX = uint16 ;
inline constexpr ORDERINDEX ORDERINDEX_INVALID = uint16_max ;
inline constexpr ORDERINDEX ORDERINDEX_MAX = uint16_max - 1 ;
using PATTERNINDEX = uint16 ;
inline constexpr PATTERNINDEX PATTERNINDEX_INVALID = uint16_max ;
using PLUGINDEX = uint8 ;
inline constexpr PLUGINDEX PLUGINDEX_INVALID = uint8_max ;
using SAMPLEINDEX = uint16 ;
inline constexpr SAMPLEINDEX SAMPLEINDEX_INVALID = uint16_max ;
using INSTRUMENTINDEX = uint16 ;
inline constexpr INSTRUMENTINDEX INSTRUMENTINDEX_INVALID = uint16_max ;
using SEQUENCEINDEX = uint8 ;
inline constexpr SEQUENCEINDEX SEQUENCEINDEX_INVALID = uint8_max ;
using SmpLength = uint32 ;
inline constexpr SmpLength MAX_SAMPLE_LENGTH = 0x10000000 ; // Sample length in frames. Sample size in bytes can be more than this (= 256 MB).
inline constexpr ROWINDEX MAX_PATTERN_ROWS = 1024 ;
inline constexpr ROWINDEX MAX_ROWS_PER_BEAT = 65536 ;
inline constexpr ORDERINDEX MAX_ORDERS = ORDERINDEX_MAX + 1 ;
inline constexpr PATTERNINDEX MAX_PATTERNS = 4000 ;
inline constexpr SAMPLEINDEX MAX_SAMPLES = 4000 ;
inline constexpr INSTRUMENTINDEX MAX_INSTRUMENTS = 256 ;
inline constexpr PLUGINDEX MAX_MIXPLUGINS = 250 ;
inline constexpr SEQUENCEINDEX MAX_SEQUENCES = 50 ;
inline constexpr CHANNELINDEX MAX_BASECHANNELS = 127 ; // Maximum pattern channels.
inline constexpr CHANNELINDEX MAX_CHANNELS = 256 ; // Maximum number of mixing channels.
enum { FREQ_FRACBITS = 4 } ; // Number of fractional bits in return value of CSoundFile::GetFreqFromPeriod()
// String lengths (including trailing null char)
enum
{
MAX_SAMPLENAME = 32 ,
MAX_SAMPLEFILENAME = 22 ,
MAX_INSTRUMENTNAME = 32 ,
MAX_INSTRUMENTFILENAME = 32 ,
MAX_PATTERNNAME = 32 ,
MAX_CHANNELNAME = 20 ,
} ;
enum MODTYPE
{
MOD_TYPE_NONE = 0x00 ,
MOD_TYPE_MOD = 0x01 ,
MOD_TYPE_S3M = 0x02 ,
MOD_TYPE_XM = 0x04 ,
MOD_TYPE_MED = 0x08 ,
MOD_TYPE_MTM = 0x10 ,
MOD_TYPE_IT = 0x20 ,
MOD_TYPE_669 = 0x40 ,
MOD_TYPE_ULT = 0x80 ,
MOD_TYPE_STM = 0x100 ,
MOD_TYPE_FAR = 0x200 ,
MOD_TYPE_DTM = 0x400 ,
MOD_TYPE_AMF = 0x800 ,
MOD_TYPE_AMS = 0x1000 ,
MOD_TYPE_DSM = 0x2000 ,
MOD_TYPE_MDL = 0x4000 ,
MOD_TYPE_OKT = 0x8000 ,
MOD_TYPE_MID = 0x10000 ,
MOD_TYPE_DMF = 0x20000 ,
MOD_TYPE_PTM = 0x40000 ,
MOD_TYPE_DBM = 0x80000 ,
MOD_TYPE_MT2 = 0x100000 ,
MOD_TYPE_AMF0 = 0x200000 ,
MOD_TYPE_PSM = 0x400000 ,
MOD_TYPE_J2B = 0x800000 ,
MOD_TYPE_MPT = 0x1000000 ,
MOD_TYPE_IMF = 0x2000000 ,
MOD_TYPE_DIGI = 0x4000000 ,
MOD_TYPE_STP = 0x8000000 ,
MOD_TYPE_PLM = 0x10000000 ,
MOD_TYPE_SFX = 0x20000000 ,
} ;
DECLARE_FLAGSET ( MODTYPE )
enum MODCONTAINERTYPE
{
MOD_CONTAINERTYPE_NONE = 0x0 ,
MOD_CONTAINERTYPE_UMX = 0x3 ,
MOD_CONTAINERTYPE_XPK = 0x4 ,
MOD_CONTAINERTYPE_PP20 = 0x5 ,
MOD_CONTAINERTYPE_MMCMP = 0x6 ,
MOD_CONTAINERTYPE_WAV = 0x7 , // WAV as module
MOD_CONTAINERTYPE_UAX = 0x8 , // Unreal sample set as module
} ;
// Module channel / sample flags
enum ChannelFlags
{
// Sample Flags
CHN_16BIT = 0x01 , // 16-bit sample
CHN_LOOP = 0x02 , // Looped sample
CHN_PINGPONGLOOP = 0x04 , // Bidi-looped sample
CHN_SUSTAINLOOP = 0x08 , // Sample with sustain loop
CHN_PINGPONGSUSTAIN = 0x10 , // Sample with bidi sustain loop
CHN_PANNING = 0x20 , // Sample with forced panning
CHN_STEREO = 0x40 , // Stereo sample
CHN_REVERSE = 0x80 , // Start sample playback from sample / loop end (Velvet Studio feature)
CHN_SURROUND = 0x100 , // Use surround channel
CHN_ADLIB = 0x200 , // Adlib / OPL instrument is active on this channel
// Channel Flags
CHN_PINGPONGFLAG = 0x80 , // When flag is on, sample is processed backwards - this is intentionally the same flag as CHN_REVERSE.
CHN_MUTE = 0x400 , // Muted channel
CHN_KEYOFF = 0x800 , // Exit sustain
CHN_NOTEFADE = 0x1000 , // Fade note (instrument mode)
CHN_WRAPPED_LOOP = 0x2000 , // Loop just wrapped around to loop start (required for correct interpolation around loop points)
CHN_AMIGAFILTER = 0x4000 , // Apply Amiga low-pass filter
CHN_FILTER = 0x8000 , // Apply resonant filter on sample
CHN_VOLUMERAMP = 0x10000 , // Apply volume ramping
CHN_VIBRATO = 0x20000 , // Apply vibrato
CHN_TREMOLO = 0x40000 , // Apply tremolo
CHN_PORTAMENTO = 0x80000 , // Apply portamento
CHN_GLISSANDO = 0x100000 , // Glissando (force portamento to semitones) mode
CHN_FASTVOLRAMP = 0x200000 , // Force usage of global ramping settings instead of ramping over the complete render buffer length
CHN_EXTRALOUD = 0x400000 , // Force sample to play at 0dB
CHN_REVERB = 0x800000 , // Apply reverb on this channel
CHN_NOREVERB = 0x1000000 , // Disable reverb on this channel
CHN_SOLO = 0x2000000 , // Solo channel
CHN_NOFX = 0x4000000 , // Dry channel (no plugins)
CHN_SYNCMUTE = 0x8000000 , // Keep sample sync on mute
// Sample flags (only present in ModSample::uFlags, may overlap with CHN_CHANNELFLAGS)
SMP_MODIFIED = 0x2000 , // Sample data has been edited in the tracker
SMP_KEEPONDISK = 0x4000 , // Sample is not saved to file, data is restored from original sample file
SMP_NODEFAULTVOLUME = 0x8000 , // Ignore default volume setting
} ;
DECLARE_FLAGSET ( ChannelFlags )
# define CHN_SAMPLEFLAGS (CHN_16BIT | CHN_LOOP | CHN_PINGPONGLOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN | CHN_PANNING | CHN_STEREO | CHN_PINGPONGFLAG | CHN_REVERSE | CHN_SURROUND | CHN_ADLIB)
# define CHN_CHANNELFLAGS (~CHN_SAMPLEFLAGS | CHN_SURROUND)
// Sample flags fit into the first 16 bits, and with the current memory layout, storing them as a 16-bit integer packs struct ModSample nicely.
using SampleFlags = FlagSet < ChannelFlags , uint16 > ;
// Instrument envelope-specific flags
enum EnvelopeFlags : uint8
{
ENV_ENABLED = 0x01 , // env is enabled
ENV_LOOP = 0x02 , // env loop
ENV_SUSTAIN = 0x04 , // env sustain
ENV_CARRY = 0x08 , // env carry
ENV_FILTER = 0x10 , // filter env enabled (this has to be combined with ENV_ENABLED in the pitch envelope's flags)
} ;
DECLARE_FLAGSET ( EnvelopeFlags )
// Envelope value boundaries
# define ENVELOPE_MIN 0 // Vertical min value of a point
# define ENVELOPE_MID 32 // Vertical middle line
# define ENVELOPE_MAX 64 // Vertical max value of a point
# define MAX_ENVPOINTS 240 // Maximum length of each instrument envelope
// Instrument-specific flags
enum InstrumentFlags : uint8
{
INS_SETPANNING = 0x01 , // Panning enabled
INS_MUTE = 0x02 , // Instrument is muted
} ;
DECLARE_FLAGSET ( InstrumentFlags )
// envelope types in instrument editor
enum EnvelopeType : uint8
{
ENV_VOLUME = 0 ,
ENV_PANNING ,
ENV_PITCH ,
ENV_MAXTYPES
} ;
// Filter Modes
enum class FilterMode : uint8
{
Unchanged = 0xFF ,
LowPass = 0 ,
HighPass = 1 ,
} ;
// NNA types (New Note Action)
enum NewNoteAction : uint8
{
NNA_NOTECUT = 0 ,
NNA_CONTINUE = 1 ,
NNA_NOTEOFF = 2 ,
NNA_NOTEFADE = 3 ,
} ;
// DCT types (Duplicate Check Types)
enum DuplicateCheckType : uint8
{
DCT_NONE = 0 ,
DCT_NOTE = 1 ,
DCT_SAMPLE = 2 ,
DCT_INSTRUMENT = 3 ,
DCT_PLUGIN = 4 ,
} ;
// DNA types (Duplicate Note Action)
enum DuplicateNoteAction : uint8
{
DNA_NOTECUT = 0 ,
DNA_NOTEOFF = 1 ,
DNA_NOTEFADE = 2 ,
} ;
// Module flags - contains both song configuration and playback state... Use SONG_FILE_FLAGS and SONG_PLAY_FLAGS distinguish between the two.
enum SongFlags
{
SONG_FASTVOLSLIDES = 0x02 , // Old Scream Tracker 3.0 volume slides
SONG_ITOLDEFFECTS = 0x04 , // Old Impulse Tracker effect implementations
SONG_ITCOMPATGXX = 0x08 , // IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects)
SONG_LINEARSLIDES = 0x10 , // Linear slides vs. Amiga slides
SONG_PATTERNLOOP = 0x20 , // Loop current pattern (pattern editor)
SONG_STEP = 0x40 , // Song is in "step" mode (pattern editor)
SONG_PAUSED = 0x80 , // Song is paused (no tick processing, just rendering audio)
SONG_FADINGSONG = 0x0100 , // Song is fading out
SONG_ENDREACHED = 0x0200 , // Song is finished
SONG_FIRSTTICK = 0x1000 , // Is set when the current tick is the first tick of the row
SONG_MPTFILTERMODE = 0x2000 , // Local filter mode (reset filter on each note)
SONG_SURROUNDPAN = 0x4000 , // Pan in the rear channels
SONG_EXFILTERRANGE = 0x8000 , // Cutoff Filter has double frequency range (up to ~10Khz)
SONG_AMIGALIMITS = 0x1 ' 0000 , // Enforce amiga frequency limits
SONG_S3MOLDVIBRATO = 0x2 ' 0000 , // ScreamTracker 2 vibrato in S3M files
SONG_BREAKTOROW = 0x8 ' 0000 , // Break to row command encountered (internal flag, do not touch)
SONG_POSJUMP = 0x10 ' 0000 , // Position jump encountered (internal flag, do not touch)
SONG_PT_MODE = 0x20 ' 0000 , // ProTracker 1/2 playback mode
SONG_PLAYALLSONGS = 0x40 ' 0000 , // Play all subsongs consecutively (libopenmpt)
SONG_ISAMIGA = 0x80 ' 0000 , // Is an Amiga module and thus qualifies to be played using the Paula BLEP resampler
SONG_IMPORTED = 0x100 ' 0000 , // Song type does not represent actual module format / was imported from a different format (OpenMPT)
} ;
DECLARE_FLAGSET ( SongFlags )
# define SONG_FILE_FLAGS (SONG_FASTVOLSLIDES|SONG_ITOLDEFFECTS|SONG_ITCOMPATGXX|SONG_LINEARSLIDES|SONG_EXFILTERRANGE|SONG_AMIGALIMITS|SONG_S3MOLDVIBRATO|SONG_PT_MODE|SONG_ISAMIGA|SONG_IMPORTED)
# define SONG_PLAY_FLAGS (~SONG_FILE_FLAGS)
// Global Options (Renderer)
# ifndef NO_AGC
# define SNDDSP_AGC 0x40 // Automatic gain control
# endif // ~NO_AGC
# ifndef NO_DSP
# define SNDDSP_MEGABASS 0x02 // Bass expansion
# define SNDDSP_SURROUND 0x08 // Surround mix
# define SNDDSP_BITCRUSH 0x01
# endif // NO_DSP
# ifndef NO_REVERB
# define SNDDSP_REVERB 0x20 // Apply reverb
# endif // NO_REVERB
# ifndef NO_EQ
# define SNDDSP_EQ 0x80 // Apply EQ
# endif // NO_EQ
# define SNDMIX_SOFTPANNING 0x10 // Soft panning mode (this is forced with mixmode RC3 and later)
// Misc Flags (can safely be turned on or off)
# define SNDMIX_MAXDEFAULTPAN 0x80000 // Currently unused (should be used by Amiga MOD loaders)
# define SNDMIX_MUTECHNMODE 0x100000 // Notes are not played on muted channels
# define MAX_GLOBAL_VOLUME 256u
// Resampling modes
enum ResamplingMode : uint8
{
// ATTENTION: Do not change ANY of these values, as they get written out to files in per instrument interpolation settings
// and old files have these exact values in them which should not change meaning.
SRCMODE_NEAREST = 0 , // 1 tap, no AA
SRCMODE_LINEAR = 1 , // 2 tap, no AA
SRCMODE_CUBIC = 2 , // 4 tap, no AA
SRCMODE_SINC8 = 4 , // 8 tap, no AA (yes, index 4) (XMMS-ModPlug)
SRCMODE_SINC8LP = 3 , // 8 tap, with AA (yes, index 3) (Polyphase)
SRCMODE_DEFAULT = 5 , // Only used for instrument settings, not used inside the mixer
SRCMODE_AMIGA = 0xFF , // Not explicitely user-selectable
} ;
namespace Resampling
{
enum class AmigaFilter
{
Off = 0 ,
A500 = 1 ,
A1200 = 2 ,
Unfiltered = 3 ,
} ;
inline std : : array < ResamplingMode , 5 > AllModes ( ) noexcept { return { { SRCMODE_NEAREST , SRCMODE_LINEAR , SRCMODE_CUBIC , SRCMODE_SINC8 , SRCMODE_SINC8LP } } ; }
inline std : : array < ResamplingMode , 6 > AllModesWithDefault ( ) noexcept { return { { SRCMODE_NEAREST , SRCMODE_LINEAR , SRCMODE_CUBIC , SRCMODE_SINC8 , SRCMODE_SINC8LP , SRCMODE_DEFAULT } } ; }
constexpr ResamplingMode Default ( ) noexcept { return SRCMODE_SINC8LP ; }
constexpr bool IsKnownMode ( int mode ) noexcept { return ( mode > = 0 ) & & ( mode < SRCMODE_DEFAULT ) ; }
constexpr ResamplingMode ToKnownMode ( int mode ) noexcept
{
return Resampling : : IsKnownMode ( mode ) ? static_cast < ResamplingMode > ( mode )
: ( mode = = SRCMODE_AMIGA ) ? SRCMODE_LINEAR
: Resampling : : Default ( ) ;
}
constexpr int Length ( ResamplingMode mode ) noexcept
{
return mode = = SRCMODE_NEAREST ? 1
: mode = = SRCMODE_LINEAR ? 2
: mode = = SRCMODE_CUBIC ? 4
: mode = = SRCMODE_SINC8 ? 8
: mode = = SRCMODE_SINC8LP ? 8
: 0 ;
}
constexpr bool HasAA ( ResamplingMode mode ) noexcept { return ( mode = = SRCMODE_SINC8LP ) ; }
constexpr ResamplingMode AddAA ( ResamplingMode mode ) noexcept { return ( mode = = SRCMODE_SINC8 ) ? SRCMODE_SINC8LP : mode ; }
constexpr ResamplingMode RemoveAA ( ResamplingMode mode ) noexcept { return ( mode = = SRCMODE_SINC8LP ) ? SRCMODE_SINC8 : mode ; }
}
// Release node defines
# define ENV_RELEASE_NODE_UNSET 0xFF
# define NOT_YET_RELEASED (-1)
static_assert ( ENV_RELEASE_NODE_UNSET > MAX_ENVPOINTS ) ;
enum PluginPriority
{
ChannelOnly ,
InstrumentOnly ,
PrioritiseInstrument ,
PrioritiseChannel ,
} ;
enum PluginMutePriority
{
EvenIfMuted ,
RespectMutes ,
} ;
// Plugin velocity handling options
enum PlugVelocityHandling : uint8
{
PLUGIN_VELOCITYHANDLING_CHANNEL = 0 ,
PLUGIN_VELOCITYHANDLING_VOLUME
} ;
// Plugin volumecommand handling options
enum PlugVolumeHandling : uint8
{
PLUGIN_VOLUMEHANDLING_MIDI = 0 ,
PLUGIN_VOLUMEHANDLING_DRYWET ,
PLUGIN_VOLUMEHANDLING_IGNORE ,
PLUGIN_VOLUMEHANDLING_CUSTOM ,
PLUGIN_VOLUMEHANDLING_MAX ,
} ;
enum MidiChannel : uint8
{
MidiNoChannel = 0 ,
MidiFirstChannel = 1 ,
MidiLastChannel = 16 ,
MidiMappedChannel = 17 ,
} ;
// Vibrato Types
enum VibratoType : uint8
{
VIB_SINE = 0 ,
VIB_SQUARE ,
VIB_RAMP_UP ,
VIB_RAMP_DOWN ,
VIB_RANDOM
} ;
// Tracker-specific playback behaviour
// Note: The index of every flag has to be fixed, so do not remove flags. Always add new flags at the end!
enum PlayBehaviour
{
MSF_COMPATIBLE_PLAY , // No-op - only used during loading (Old general compatibility flag for IT/MPT/XM)
kMPTOldSwingBehaviour , // MPT 1.16 swing behaviour (IT/MPT, deprecated)
kMIDICCBugEmulation , // Emulate broken volume MIDI CC behaviour (IT/MPT/XM, deprecated)
kOldMIDIPitchBends , // Old VST MIDI pitch bend behaviour (IT/MPT/XM, deprecated)
kFT2VolumeRamping , // Smooth volume ramping like in FT2 (XM)
kMODVBlankTiming , // F21 and above set speed instead of tempo
kSlidesAtSpeed1 , // Execute normal slides at speed 1 as if they were fine slides
kHertzInLinearMode , // Compute note frequency in hertz rather than periods
kTempoClamp , // Clamp tempo to 32-255 range.
kPerChannelGlobalVolSlide , // Global volume slide memory is per-channel
kPanOverride , // Panning commands override surround and random pan variation
kITInstrWithoutNote , // Avoid instrument handling if there is no note
kITVolColFinePortamento , // Volume column portamento never does fine portamento
kITArpeggio , // IT arpeggio algorithm
kITOutOfRangeDelay , // Out-of-range delay command behaviour in IT
kITPortaMemoryShare , // Gxx shares memory with Exx and Fxx
kITPatternLoopTargetReset , // After finishing a pattern loop, set the pattern loop target to the next row
kITFT2PatternLoop , // Nested pattern loop behaviour
kITPingPongNoReset , // Don't reset ping pong direction with instrument numbers
kITEnvelopeReset , // IT envelope reset behaviour
kITClearOldNoteAfterCut , // Forget the previous note after cutting it
kITVibratoTremoloPanbrello , // More IT-like Hxx / hx, Rxx, Yxx and autovibrato handling, including more precise LUTs
kITTremor , // Ixx behaves like in IT
kITRetrigger , // Qxx behaves like in IT
kITMultiSampleBehaviour , // Properly update C-5 frequency when changing in multisampled instrument
kITPortaTargetReached , // Clear portamento target after it has been reached
kITPatternLoopBreak , // Don't reset loop count on pattern break.
kITOffset , // IT-style Oxx edge case handling
kITSwingBehaviour , // IT's swing behaviour
kITNNAReset , // NNA is reset on every note change, not every instrument change
kITSCxStopsSample , // SCx really stops the sample and does not just mute it
kITEnvelopePositionHandling , // IT-style envelope position advance + enable/disable behaviour
kITPortamentoInstrument , // No sample changes during portamento with Compatible Gxx enabled, instrument envelope reset with portamento
kITPingPongMode , // Don't repeat last sample point in ping pong loop, like IT's software mixer
kITRealNoteMapping , // Use triggered note rather than translated note for PPS and other effects
kITHighOffsetNoRetrig , // SAx should not apply an offset effect to a note next to it
kITFilterBehaviour , // User IT's filter coefficients (unless extended filter range is used)
kITNoSurroundPan , // Panning and surround are mutually exclusive
kITShortSampleRetrig , // Don't retrigger already stopped channels
kITPortaNoNote , // Don't apply any portamento if no previous note is playing
kITFT2DontResetNoteOffOnPorta , // Only reset note-off status on portamento in IT Compatible Gxx mode
kITVolColMemory , // IT volume column effects share their memory with the effect column
kITPortamentoSwapResetsPos , // Portamento with sample swap plays the new sample from the beginning
kITEmptyNoteMapSlot , // IT ignores instrument note map entries with no note completely
kITFirstTickHandling , // IT-style first tick handling
kITSampleAndHoldPanbrello , // IT-style sample&hold panbrello waveform
kITClearPortaTarget , // New notes reset portamento target in IT
kITPanbrelloHold , // Don't reset panbrello effect until next note or panning effect
kITPanningReset , // Sample and instrument panning is only applied on note change, not instrument change
kITPatternLoopWithJumpsOld , // Bxx on the same row as SBx terminates the loop in IT (old implementation of kITPatternLoopWithJumps)
kITInstrWithNoteOff , // Instrument number with note-off recalls default volume
kFT2Arpeggio , // FT2 arpeggio algorithm
kFT2Retrigger , // Rxx behaves like in FT2
kFT2VolColVibrato , // Vibrato depth in volume column does not actually execute the vibrato effect
kFT2PortaNoNote , // Don't play portamento-ed note if no previous note is playing
kFT2KeyOff , // FT2-style Kxx handling
kFT2PanSlide , // Volume-column pan slides should be handled like fine slides
kFT2ST3OffsetOutOfRange , // Offset past sample end stops the note
kFT2RestrictXCommand , // Don't allow MPT extensions to Xxx command in XM
kFT2RetrigWithNoteDelay , // Retrigger envelopes if there is a note delay with no note
kFT2SetPanEnvPos , // Lxx only sets the pan env position if the volume envelope's sustain flag is set
kFT2PortaIgnoreInstr , // Portamento plus instrument number applies the volume settings of the new sample, but not the new sample itself.
kFT2VolColMemory , // No volume column memory in FT2
kFT2LoopE60Restart , // Next pattern starts on the same row as the last E60 command
kFT2ProcessSilentChannels , // Keep processing silent channels for later 3xx pickup
kFT2ReloadSampleSettings , // Reload sample settings even if a note-off is placed next to an instrument number
kFT2PortaDelay , // Portamento with note delay next to it is ignored in FT2
kFT2Transpose , // Out-of-range transposed notes in FT2
kFT2PatternLoopWithJumps , // Bxx or Dxx on the same row as E6x terminates the loop in FT2
kFT2PortaTargetNoReset , // Portamento target is not reset with new notes in FT2
kFT2EnvelopeEscape , // FT2 sustain point at end of envelope
kFT2Tremor , // Txx behaves like in FT2
kFT2OutOfRangeDelay , // Out-of-range delay command behaviour in FT2
kFT2Periods , // Use FT2's broken period handling
kFT2PanWithDelayedNoteOff , // Pan command with delayed note-off
kFT2VolColDelay , // FT2-style volume column handling if there is a note delay
kFT2FinetunePrecision , // Only take the upper 4 bits of sample finetune.
kST3NoMutedChannels , // Don't process any effects on muted S3M channels
kST3EffectMemory , // Most effects share the same memory in ST3
kST3PortaSampleChange , // Portamento plus instrument number applies the volume settings of the new sample, but not the new sample itself (GUS behaviour).
kST3VibratoMemory , // Do not remember vibrato type in effect memory
kST3LimitPeriod , // Cut note instead of limiting final period (ModPlug Tracker style)
KST3PortaAfterArpeggio , // Portamento after arpeggio continues at the note where the arpeggio left off
kMODOneShotLoops , // Allow ProTracker-like oneshot loops
kMODIgnorePanning , // Do not process any panning commands
kMODSampleSwap , // On-the-fly sample swapping
kFT2NoteOffFlags , // Set and reset the correct fade/key-off flags with note-off and instrument number after note-off
kITMultiSampleInstrumentNumber , // After portamento to different sample within multi-sampled instrument, lone instrument numbers in patterns always recall the new sample's default settings
kRowDelayWithNoteDelay , // Retrigger note delays on every reptition of a row
kFT2MODTremoloRampWaveform , // FT2-/ProTracker-compatible tremolo ramp down / triangle waveform
kFT2PortaUpDownMemory , // Portamento up and down have separate memory
kMODOutOfRangeNoteDelay , // ProTracker behaviour for out-of-range note delays
kMODTempoOnSecondTick , // ProTracker sets tempo after the first tick
kFT2PanSustainRelease , // If the sustain point of a panning envelope is reached before key-off, FT2 does not escape it anymore
kLegacyReleaseNode , // Legacy release node volume processing
kOPLBeatingOscillators , // Emulate beating FM oscillators from CDFM / Composer 670
kST3OffsetWithoutInstrument , // Note without instrument uses same offset as previous note
kReleaseNodePastSustainBug , // OpenMPT 1.23.01.02 / r4009 broke release nodes past the sustain point, fixed in OpenMPT 1.28
kFT2NoteDelayWithoutInstr , // Sometime between OpenMPT 1.18.03.00 and 1.19.01.00, delayed instrument-less notes in XM started recalling the default sample volume and panning
kOPLFlexibleNoteOff , // Full control after note-off over OPL voices, ^^^ sends note cut instead of just note-off
kITInstrWithNoteOffOldEffects , // Instrument number with note-off recalls default volume - special cases with Old Effects enabled
kMIDIVolumeOnNoteOffBug , // Update MIDI channel volume on note-off (legacy bug emulation)
kITDoNotOverrideChannelPan , // Sample / instrument pan does not override channel pan for following samples / instruments that are not panned
kITPatternLoopWithJumps , // Bxx right of SBx terminates the loop in IT
kITDCTBehaviour , // DCT="Sample" requires sample instrument, DCT="Note" checks old pattern note against new pattern note (previously was checking old pattern note against new translated note)
kOPLwithNNA , // NNA note-off / fade are applied to OPL channels
kST3RetrigAfterNoteCut , // Qxy does not retrigger note after it has been cut with ^^^ or SCx
kST3SampleSwap , // On-the-fly sample swapping (SoundBlaster behaviour)
kOPLRealRetrig , // Retrigger effect (Qxy) restarts OPL notes
kOPLNoResetAtEnvelopeEnd , // Do not reset OPL channel status at end of envelope (OpenMPT 1.28 inconsistency with samples)
// Add new play behaviours here.
kMaxPlayBehaviours ,
} ;
// Tempo swing determines how much every row in modern tempo mode contributes to a beat.
class TempoSwing : public std : : vector < uint32 >
{
public :
enum { Unity = 1u < < 24 } ;
// Normalize the tempo swing coefficients so that they add up to exactly the specified tempo again
void Normalize ( ) ;
void resize ( size_type newSize , value_type val = Unity ) { std : : vector < uint32 > : : resize ( newSize , val ) ; Normalize ( ) ; }
static void Serialize ( std : : ostream & oStrm , const TempoSwing & swing ) ;
static void Deserialize ( std : : istream & iStrm , TempoSwing & swing , const size_t ) ;
} ;
// Sample position and sample position increment value
struct SamplePosition
{
using value_t = int64 ;
using unsigned_value_t = uint64 ;
protected :
value_t v = 0 ;
public :
enum : uint32 { fractMax = 0xFFFFFFFFu } ;
MPT_CONSTEXPR11_FUN SamplePosition ( ) { }
MPT_CONSTEXPR11_FUN explicit SamplePosition ( value_t pos ) : v ( pos ) { }
MPT_CONSTEXPR11_FUN SamplePosition ( int32 intPart , uint32 fractPart ) : v ( ( static_cast < value_t > ( intPart ) * ( 1ll < < 32 ) ) | fractPart ) { }
static SamplePosition Ratio ( uint32 dividend , uint32 divisor ) { return SamplePosition ( ( static_cast < int64 > ( dividend ) < < 32 ) / divisor ) ; }
static SamplePosition FromDouble ( double pos ) { return SamplePosition ( static_cast < value_t > ( pos * 4294967296.0 ) ) ; }
// Set integer and fractional part
MPT_CONSTEXPR14_FUN SamplePosition & Set ( int32 intPart , uint32 fractPart = 0 ) { v = ( static_cast < int64 > ( intPart ) < < 32 ) | fractPart ; return * this ; }
// Set integer part, keep fractional part
MPT_CONSTEXPR14_FUN SamplePosition & SetInt ( int32 intPart ) { v = ( static_cast < value_t > ( intPart ) < < 32 ) | GetFract ( ) ; return * this ; }
// Get integer part (as sample length / position)
MPT_CONSTEXPR11_FUN SmpLength GetUInt ( ) const { return static_cast < SmpLength > ( static_cast < unsigned_value_t > ( v ) > > 32 ) ; }
// Get integer part
MPT_CONSTEXPR11_FUN int32 GetInt ( ) const { return static_cast < int32 > ( static_cast < unsigned_value_t > ( v ) > > 32 ) ; }
// Get fractional part
MPT_CONSTEXPR11_FUN uint32 GetFract ( ) const { return static_cast < uint32 > ( v ) ; }
// Get the inverted fractional part
MPT_CONSTEXPR11_FUN SamplePosition GetInvertedFract ( ) const { return SamplePosition ( 0x100000000ll - GetFract ( ) ) ; }
// Get the raw fixed-point value
MPT_CONSTEXPR11_FUN int64 GetRaw ( ) const { return v ; }
// Negate the current value
MPT_CONSTEXPR14_FUN SamplePosition & Negate ( ) { v = - v ; return * this ; }
// Multiply and divide by given integer scalars
MPT_CONSTEXPR14_FUN SamplePosition & MulDiv ( uint32 mul , uint32 div ) { v = ( v * mul ) / div ; return * this ; }
// Removes the integer part, only keeping fractions
MPT_CONSTEXPR14_FUN SamplePosition & RemoveInt ( ) { v & = fractMax ; return * this ; }
// Check if value is 1.0
MPT_CONSTEXPR11_FUN bool IsUnity ( ) const { return v = = 0x100000000ll ; }
// Check if value is 0
MPT_CONSTEXPR11_FUN bool IsZero ( ) const { return v = = 0 ; }
// Check if value is > 0
MPT_CONSTEXPR11_FUN bool IsPositive ( ) const { return v > 0 ; }
// Check if value is < 0
MPT_CONSTEXPR11_FUN bool IsNegative ( ) const { return v < 0 ; }
// Addition / subtraction of another fixed-point number
SamplePosition operator + ( const SamplePosition & other ) const { return SamplePosition ( v + other . v ) ; }
SamplePosition operator - ( const SamplePosition & other ) const { return SamplePosition ( v - other . v ) ; }
void operator + = ( const SamplePosition & other ) { v + = other . v ; }
void operator - = ( const SamplePosition & other ) { v - = other . v ; }
// Multiplication with integer scalar
template < typename T >
SamplePosition operator * ( T other ) const { return SamplePosition ( static_cast < value_t > ( v * other ) ) ; }
template < typename T >
void operator * = ( T other ) { v = static_cast < value_t > ( v * other ) ; }
// Division by other fractional point number; returns scalar
value_t operator / ( SamplePosition other ) const { return v / other . v ; }
// Division by scalar; returns fractional point number
SamplePosition operator / ( int div ) const { return SamplePosition ( v / div ) ; }
MPT_CONSTEXPR11_FUN bool operator = = ( const SamplePosition & other ) const { return v = = other . v ; }
MPT_CONSTEXPR11_FUN bool operator ! = ( const SamplePosition & other ) const { return v ! = other . v ; }
MPT_CONSTEXPR11_FUN bool operator < = ( const SamplePosition & other ) const { return v < = other . v ; }
MPT_CONSTEXPR11_FUN bool operator > = ( const SamplePosition & other ) const { return v > = other . v ; }
MPT_CONSTEXPR11_FUN bool operator < ( const SamplePosition & other ) const { return v < other . v ; }
MPT_CONSTEXPR11_FUN bool operator > ( const SamplePosition & other ) const { return v > other . v ; }
} ;
// Aaaand another fixed-point type, e.g. used for fractional tempos
// Note that this doesn't use classical bit shifting for the fixed point part.
// This is mostly for the clarity of stored values and to be able to represent any value .0000 to .9999 properly.
// For easier debugging, use the Debugger Visualizers available in build/vs/debug/
// to easily display the stored values.
template < size_t FFact , typename T >
struct FPInt
{
protected :
T v ;
MPT_CONSTEXPR11_FUN FPInt ( T rawValue ) : v ( rawValue ) { }
public :
enum : size_t { fractFact = FFact } ;
using store_t = T ;
MPT_CONSTEXPR11_FUN FPInt ( ) : v ( 0 ) { }
MPT_CONSTEXPR11_FUN FPInt ( T intPart , T fractPart ) : v ( ( intPart * fractFact ) + ( fractPart % fractFact ) ) { }
2022-01-30 23:19:36 +00:00
explicit MPT_CONSTEXPR11_FUN FPInt ( float f ) : v ( mpt : : saturate_round < T > ( f * float ( fractFact ) ) ) { }
explicit MPT_CONSTEXPR11_FUN FPInt ( double f ) : v ( mpt : : saturate_round < T > ( f * double ( fractFact ) ) ) { }
2021-12-26 11:29:43 +00:00
// Set integer and fractional part
MPT_CONSTEXPR14_FUN FPInt < fractFact , T > & Set ( T intPart , T fractPart = 0 ) { v = ( intPart * fractFact ) + ( fractPart % fractFact ) ; return * this ; }
// Set raw internal representation directly
MPT_CONSTEXPR14_FUN FPInt < fractFact , T > & SetRaw ( T value ) { v = value ; return * this ; }
// Retrieve the integer part of the stored value
MPT_CONSTEXPR11_FUN T GetInt ( ) const { return v / fractFact ; }
// Retrieve the fractional part of the stored value
MPT_CONSTEXPR11_FUN T GetFract ( ) const { return v % fractFact ; }
// Retrieve the raw internal representation of the stored value
MPT_CONSTEXPR11_FUN T GetRaw ( ) const { return v ; }
// Formats the stored value as a floating-point value
MPT_CONSTEXPR11_FUN double ToDouble ( ) const { return v / double ( fractFact ) ; }
MPT_CONSTEXPR11_FUN friend FPInt < fractFact , T > operator + ( const FPInt < fractFact , T > & a , const FPInt < fractFact , T > & b ) noexcept { return FPInt < fractFact , T > ( a . v + b . v ) ; }
MPT_CONSTEXPR11_FUN friend FPInt < fractFact , T > operator - ( const FPInt < fractFact , T > & a , const FPInt < fractFact , T > & b ) noexcept { return FPInt < fractFact , T > ( a . v - b . v ) ; }
MPT_CONSTEXPR14_FUN FPInt < fractFact , T > operator + = ( const FPInt < fractFact , T > & other ) noexcept { v + = other . v ; return * this ; }
MPT_CONSTEXPR14_FUN FPInt < fractFact , T > operator - = ( const FPInt < fractFact , T > & other ) noexcept { v - = other . v ; return * this ; }
MPT_CONSTEXPR11_FUN friend bool operator = = ( const FPInt < fractFact , T > & a , const FPInt < fractFact , T > & b ) noexcept { return a . v = = b . v ; }
MPT_CONSTEXPR11_FUN friend bool operator ! = ( const FPInt < fractFact , T > & a , const FPInt < fractFact , T > & b ) noexcept { return a . v ! = b . v ; }
MPT_CONSTEXPR11_FUN friend bool operator < = ( const FPInt < fractFact , T > & a , const FPInt < fractFact , T > & b ) noexcept { return a . v < = b . v ; }
MPT_CONSTEXPR11_FUN friend bool operator > = ( const FPInt < fractFact , T > & a , const FPInt < fractFact , T > & b ) noexcept { return a . v > = b . v ; }
MPT_CONSTEXPR11_FUN friend bool operator < ( const FPInt < fractFact , T > & a , const FPInt < fractFact , T > & b ) noexcept { return a . v < b . v ; }
MPT_CONSTEXPR11_FUN friend bool operator > ( const FPInt < fractFact , T > & a , const FPInt < fractFact , T > & b ) noexcept { return a . v > b . v ; }
} ;
using TEMPO = FPInt < 10000 , uint32 > ;
using OPLPatch = std : : array < uint8 , 12 > ;
OPENMPT_NAMESPACE_END