diff options
author | James Cowgill <jcowgill@debian.org> | 2016-10-03 10:03:42 +0100 |
---|---|---|
committer | James Cowgill <jcowgill@debian.org> | 2016-10-03 10:03:42 +0100 |
commit | 8afe53282f39c89e2425dbf1afd438719e1aedeb (patch) | |
tree | bdf8aadb1d7e65ea1c12a7813a3334b0e70a8a41 /soundlib/Snd_defs.h |
New upstream version 0.2.7025~beta20.1
Diffstat (limited to 'soundlib/Snd_defs.h')
-rw-r--r-- | soundlib/Snd_defs.h | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/soundlib/Snd_defs.h b/soundlib/Snd_defs.h new file mode 100644 index 0000000..8161409 --- /dev/null +++ b/soundlib/Snd_defs.h @@ -0,0 +1,519 @@ +/* + * 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 "../common/typedefs.h" +#include "../common/FlagSet.h" + + +OPENMPT_NAMESPACE_BEGIN + + +typedef uint32 ROWINDEX; + const ROWINDEX ROWINDEX_INVALID = uint32_max; +typedef uint16 CHANNELINDEX; + const CHANNELINDEX CHANNELINDEX_INVALID = uint16_max; +typedef uint16 ORDERINDEX; + const ORDERINDEX ORDERINDEX_INVALID = uint16_max; + const ORDERINDEX ORDERINDEX_MAX = uint16_max - 1; +typedef uint16 PATTERNINDEX; + const PATTERNINDEX PATTERNINDEX_INVALID = uint16_max; +typedef uint8 PLUGINDEX; + const PLUGINDEX PLUGINDEX_INVALID = uint8_max; +typedef uint16 SAMPLEINDEX; + const SAMPLEINDEX SAMPLEINDEX_INVALID = uint16_max; +typedef uint16 INSTRUMENTINDEX; + const INSTRUMENTINDEX INSTRUMENTINDEX_INVALID = uint16_max; +typedef uint8 SEQUENCEINDEX; + const SEQUENCEINDEX SEQUENCEINDEX_INVALID = uint8_max; + +typedef uintptr_t SmpLength; + + +const SmpLength MAX_SAMPLE_LENGTH = 0x10000000; // Sample length in *samples* + // Note: Sample size in bytes can be more than this (= 256 MB). + +const ROWINDEX MAX_PATTERN_ROWS = 1024; +const ORDERINDEX MAX_ORDERS = 256; +const PATTERNINDEX MAX_PATTERNS = 240; +const SAMPLEINDEX MAX_SAMPLES = 4000; +const INSTRUMENTINDEX MAX_INSTRUMENTS = 256; +const PLUGINDEX MAX_MIXPLUGINS = 250; + +const SEQUENCEINDEX MAX_SEQUENCES = 50; + +const CHANNELINDEX MAX_BASECHANNELS = 127; // Maximum pattern channels. +const CHANNELINDEX MAX_CHANNELS = 256; // Maximum number of mixing channels. + +#define FREQ_FRACBITS 4 // Number of fractional bits in return value of CSoundFile::GetFreqFromPeriod() + +// String lengths (including trailing null char) +#define MAX_SAMPLENAME 32 +#define MAX_SAMPLEFILENAME 22 +#define MAX_INSTRUMENTNAME 32 +#define MAX_INSTRUMENTFILENAME 32 +#define MAX_PATTERNNAME 32 +#define 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_WAV = 0x400, // PCM as module + 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_AMS2 = 0x4000000, + MOD_TYPE_DIGI = 0x8000000, + MOD_TYPE_UAX = 0x10000000, // sampleset as module + MOD_TYPE_PLM = 0x20000000, + MOD_TYPE_SFX = 0x40000000, +}; +DECLARE_FLAGSET(MODTYPE) + + +enum MODCONTAINERTYPE +{ + MOD_CONTAINERTYPE_NONE = 0x0, + MOD_CONTAINERTYPE_MO3 = 0x1, + MOD_CONTAINERTYPE_GDM = 0x2, + MOD_CONTAINERTYPE_UMX = 0x3, + MOD_CONTAINERTYPE_XPK = 0x4, + MOD_CONTAINERTYPE_PP20 = 0x5, + MOD_CONTAINERTYPE_MMCMP= 0x6, +}; + + +// Channel 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) - this is intentionally the same flag as CHN_PINGPONGFLAG. + // Channel Flags + CHN_PINGPONGFLAG = 0x80, // when flag is on, sample is processed backwards + CHN_MUTE = 0x100, // muted channel + CHN_KEYOFF = 0x200, // exit sustain + CHN_NOTEFADE = 0x400, // fade note (instrument mode) + CHN_SURROUND = 0x800, // use surround channel + // UNUSED = 0x1000, + // UNUSED = 0x2000, + CHN_FILTER = 0x4000, // Apply resonant filter on sample + CHN_VOLUMERAMP = 0x8000, // Apply volume ramping + CHN_VIBRATO = 0x10000, // Apply vibrato + CHN_TREMOLO = 0x20000, // Apply tremolo + //CHN_PANBRELLO = 0x40000, // Apply panbrello + CHN_PORTAMENTO = 0x80000, // Apply portamento + CHN_GLISSANDO = 0x100000, // Glissando 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 -> CODE#0012 -> DESC="midi keyboard split" -! NEW_FEATURE#0012 + CHN_NOFX = 0x4000000, // dry channel -> CODE#0015 -> DESC="channels management dlg" -! NEW_FEATURE#0015 + CHN_SYNCMUTE = 0x8000000, // keep sample sync on mute + + // Sample storage flags (also saved in ModSample::uFlags, but are not relevant to mixing) + SMP_MODIFIED = 0x1000, // Sample data has been edited in the tracker + SMP_KEEPONDISK = 0x2000, // Sample is not saved to file, data is restored from original sample file +}; +DECLARE_FLAGSET(ChannelFlags) + +#define CHN_SAMPLEFLAGS (CHN_16BIT | CHN_LOOP | CHN_PINGPONGLOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN | CHN_PANNING | CHN_STEREO | CHN_PINGPONGFLAG | CHN_REVERSE) +#define CHN_CHANNELFLAGS (~CHN_SAMPLEFLAGS) + +// 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. +typedef FlagSet<ChannelFlags, uint16> SampleFlags; + + +// Instrument envelope-specific flags +enum EnvelopeFlags +{ + 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 +{ + INS_SETPANNING = 0x01, // Panning enabled + INS_MUTE = 0x02, // Instrument is muted +}; +DECLARE_FLAGSET(InstrumentFlags) + + +// envelope types in instrument editor +enum EnvelopeType +{ + ENV_VOLUME = 0, + ENV_PANNING, + ENV_PITCH, +}; + +// Filter Modes +#define FLTMODE_UNCHANGED 0xFF +#define FLTMODE_LOWPASS 0 +#define FLTMODE_HIGHPASS 1 + + +// NNA types (New Note Action) +#define NNA_NOTECUT 0 +#define NNA_CONTINUE 1 +#define NNA_NOTEOFF 2 +#define NNA_NOTEFADE 3 + +// DCT types (Duplicate Check Types) +#define DCT_NONE 0 +#define DCT_NOTE 1 +#define DCT_SAMPLE 2 +#define DCT_INSTRUMENT 3 +#define DCT_PLUGIN 4 + +// DNA types (Duplicate Note Action) +#define DNA_NOTECUT 0 +#define DNA_NOTEOFF 1 +#define 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_EMBEDMIDICFG = 0x0001, // Embed macros in file + SONG_FASTVOLSLIDES = 0x0002, // Old Scream Tracker 3.0 volume slides + SONG_ITOLDEFFECTS = 0x0004, // Old Impulse Tracker effect implementations + SONG_ITCOMPATGXX = 0x0008, // IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects) + SONG_LINEARSLIDES = 0x0010, // Linear slides vs. Amiga slides + SONG_PATTERNLOOP = 0x0020, // Loop current pattern (pattern editor) + SONG_STEP = 0x0040, // Song is in "step" mode (pattern editor) + SONG_PAUSED = 0x0080, // Song is paused (no tick processing, just rendering audio) + SONG_FADINGSONG = 0x0100, // Song is fading out + SONG_ENDREACHED = 0x0200, // Song is finished + //SONG_GLOBALFADE = 0x0400, // Song is fading out + //SONG_CPUVERYHIGH = 0x0800, // High CPU usage + 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 = 0x10000, // Enforce amiga frequency limits + SONG_S3MOLDVIBRATO = 0x20000, // ScreamTracker 2 vibrato in S3M files + //SONG_ITPEMBEDIH = 0x40000, // Embed instrument headers in project file + SONG_BREAKTOROW = 0x80000, // Break to row command encountered (internal flag, do not touch) + SONG_POSJUMP = 0x100000, // Position jump encountered (internal flag, do not touch) + SONG_PT_MODE = 0x200000, // ProTracker 1/2 playback mode + SONG_PLAYALLSONGS = 0x400000, // Play all subsongs consecutively (libopenmpt) +}; +DECLARE_FLAGSET(SongFlags) + +#define SONG_FILE_FLAGS (SONG_EMBEDMIDICFG|SONG_FASTVOLSLIDES|SONG_ITOLDEFFECTS|SONG_ITCOMPATGXX|SONG_LINEARSLIDES|SONG_EXFILTERRANGE|SONG_AMIGALIMITS|SONG_PT_MODE) +#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 +#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 // Used by the MOD loader (currently unused) +#define SNDMIX_MUTECHNMODE 0x100000 // Notes are not played on muted channels + + +#define MAX_GLOBAL_VOLUME 256u + +// Resampling modes +enum ResamplingMode +{ + // 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, + SRCMODE_LINEAR = 1, + SRCMODE_SPLINE = 2, + SRCMODE_POLYPHASE = 3, + SRCMODE_FIRFILTER = 4, + SRCMODE_DEFAULT = 5, +}; + +static inline bool IsKnownResamplingMode(int mode) +{ + return (mode >= 0) && (mode < SRCMODE_DEFAULT); +} + + +// 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 +{ + PLUGIN_VELOCITYHANDLING_CHANNEL = 0, + PLUGIN_VELOCITYHANDLING_VOLUME +}; + +//Plugin volumecommand handling options +enum PLUGVOLUMEHANDLING +{ + PLUGIN_VOLUMEHANDLING_MIDI = 0, + PLUGIN_VOLUMEHANDLING_DRYWET, + PLUGIN_VOLUMEHANDLING_IGNORE, + PLUGIN_VOLUMEHANDLING_CUSTOM, + PLUGIN_VOLUMEHANDLING_MAX, +}; + +enum MidiChannel +{ + MidiNoChannel = 0, + MidiFirstChannel = 1, + MidiLastChannel = 16, + MidiMappedChannel = 17, +}; + + +// Vibrato Types +enum VibratoType +{ + 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 + kITDontResetNoteOffOnPorta, // 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 + kITPatternLoopWithJumps, // Bxx on the same row as SBx terminates the loop in IT + 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 + kFT2OffsetOutOfRange, // FT2-style 9xx edge case handling + 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. + kST3VibratoMemory, // Do not remember vibrato type in effect memory + kST3LimitPeriod, // Cut note instead of limiting final period (ModPlug Tracker style) + + kMODOneShotLoops, // Allow ProTracker-like oneshot loops + kMODIgnorePanning, // Do not process any panning commands + kMODSampleSwap, // On-the-fly sample swapping + + // 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); +}; + + +// 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. +template<size_t FFact, typename T> +struct FPInt +{ +protected: + T v; + FPInt(T rawValue) : v(rawValue) { } + +public: + static const size_t fractFact = FFact; + + FPInt() : v(0) { } + FPInt(const FPInt<fractFact, T> &other) : v(other.v) { } + FPInt(T intPart, T fractPart) : v((intPart * fractFact) + (fractPart % fractFact)) { } + explicit FPInt(float f) : v(static_cast<T>(f * float(fractFact))) { } + explicit FPInt(double f) : v(static_cast<T>(f * double(fractFact))) { } + + // Set integer and fractional part + FPInt<fractFact, T> &Set(T intPart, T fractPart = 0) { v = (intPart * fractFact) + (fractPart % fractFact); return *this; } + // Set raw internal representation directly + FPInt<fractFact, T> &SetRaw(T value) { v = value; return *this; } + // Retrieve the integer part of the stored value + T GetInt() const { return v / fractFact; } + // Retrieve the fractional part of the stored value + T GetFract() const { return v % fractFact; } + // Retrieve the raw internal representation of the stored value + T GetRaw() const { return v; } + // Formats the stored value as a floating-point value + double ToDouble() const { return v / double(fractFact); } + + FPInt<fractFact, T> operator+ (const FPInt<fractFact, T> &other) const { return FPInt<fractFact, T>(v + other.v); } + FPInt<fractFact, T> operator- (const FPInt<fractFact, T> &other) const { return FPInt<fractFact, T>(v - other.v); } + void operator+= (const FPInt<fractFact, T> &other) { v += other.v; } + void operator-= (const FPInt<fractFact, T> &other) { v -= other.v; } + + bool operator== (const FPInt<fractFact, T> &other) const { return v == other.v; } + bool operator!= (const FPInt<fractFact, T> &other) const { return v != other.v; } + bool operator<= (const FPInt<fractFact, T> &other) const { return v <= other.v; } + bool operator>= (const FPInt<fractFact, T> &other) const { return v >= other.v; } + bool operator< (const FPInt<fractFact, T> &other) const { return v < other.v; } + bool operator> (const FPInt<fractFact, T> &other) const { return v > other.v; } +}; + +typedef FPInt<10000, uint32_t> TEMPO; + +OPENMPT_NAMESPACE_END |