diff options
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/soundlib/modcommand.h')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/soundlib/modcommand.h | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/soundlib/modcommand.h b/Src/external_dependencies/openmpt-trunk/soundlib/modcommand.h new file mode 100644 index 00000000..bf9049a9 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/soundlib/modcommand.h @@ -0,0 +1,235 @@ +/* + * modcommand.h + * ------------ + * Purpose: ModCommand declarations and helpers. One ModCommand corresponds to one pattern cell. + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +#include "openmpt/all/BuildSettings.hpp" + +#include "Snd_defs.h" +#include "../common/misc_util.h" + +OPENMPT_NAMESPACE_BEGIN + +class CSoundFile; + +// Note definitions +enum : uint8 // ModCommand::NOTE +{ + NOTE_NONE = 0, // Empty note cell + NOTE_MIN = 1, // Minimum note value + NOTE_MAX = 120, // Maximum note value + NOTE_MIDDLEC = (5 * 12 + NOTE_MIN), + NOTE_KEYOFF = 0xFF, // === (Note Off, releases envelope / fades samples, stops plugin note) + NOTE_NOTECUT = 0xFE, // ^^^ (Cuts sample / stops all plugin notes) + NOTE_FADE = 0xFD, // ~~~ (Fades samples, stops plugin note) + NOTE_PC = 0xFC, // Param Control 'note'. Changes param value on first tick. + NOTE_PCS = 0xFB, // Param Control (Smooth) 'note'. Interpolates param value during the whole row. + NOTE_MIN_SPECIAL = NOTE_PCS, + NOTE_MAX_SPECIAL = NOTE_KEYOFF, +}; + + +// Volume Column commands +enum VolumeCommand : uint8 +{ + VOLCMD_NONE = 0, + VOLCMD_VOLUME = 1, + VOLCMD_PANNING = 2, + VOLCMD_VOLSLIDEUP = 3, + VOLCMD_VOLSLIDEDOWN = 4, + VOLCMD_FINEVOLUP = 5, + VOLCMD_FINEVOLDOWN = 6, + VOLCMD_VIBRATOSPEED = 7, + VOLCMD_VIBRATODEPTH = 8, + VOLCMD_PANSLIDELEFT = 9, + VOLCMD_PANSLIDERIGHT = 10, + VOLCMD_TONEPORTAMENTO = 11, + VOLCMD_PORTAUP = 12, + VOLCMD_PORTADOWN = 13, + VOLCMD_PLAYCONTROL = 14, + VOLCMD_OFFSET = 15, + MAX_VOLCMDS +}; + + +// Effect column commands +enum EffectCommand : uint8 +{ + CMD_NONE = 0, + CMD_ARPEGGIO = 1, + CMD_PORTAMENTOUP = 2, + CMD_PORTAMENTODOWN = 3, + CMD_TONEPORTAMENTO = 4, + CMD_VIBRATO = 5, + CMD_TONEPORTAVOL = 6, + CMD_VIBRATOVOL = 7, + CMD_TREMOLO = 8, + CMD_PANNING8 = 9, + CMD_OFFSET = 10, + CMD_VOLUMESLIDE = 11, + CMD_POSITIONJUMP = 12, + CMD_VOLUME = 13, + CMD_PATTERNBREAK = 14, + CMD_RETRIG = 15, + CMD_SPEED = 16, + CMD_TEMPO = 17, + CMD_TREMOR = 18, + CMD_MODCMDEX = 19, + CMD_S3MCMDEX = 20, + CMD_CHANNELVOLUME = 21, + CMD_CHANNELVOLSLIDE = 22, + CMD_GLOBALVOLUME = 23, + CMD_GLOBALVOLSLIDE = 24, + CMD_KEYOFF = 25, + CMD_FINEVIBRATO = 26, + CMD_PANBRELLO = 27, + CMD_XFINEPORTAUPDOWN = 28, + CMD_PANNINGSLIDE = 29, + CMD_SETENVPOSITION = 30, + CMD_MIDI = 31, + CMD_SMOOTHMIDI = 32, + CMD_DELAYCUT = 33, + CMD_XPARAM = 34, + CMD_FINETUNE = 35, + CMD_FINETUNE_SMOOTH = 36, + CMD_DUMMY = 37, + CMD_NOTESLIDEUP = 38, // IMF Gxy / PTM Jxy (Slide y notes up every x ticks) + CMD_NOTESLIDEDOWN = 39, // IMF Hxy / PTM Kxy (Slide y notes down every x ticks) + CMD_NOTESLIDEUPRETRIG = 40, // PTM Lxy (Slide y notes up every x ticks + retrigger note) + CMD_NOTESLIDEDOWNRETRIG = 41, // PTM Mxy (Slide y notes down every x ticks + retrigger note) + CMD_REVERSEOFFSET = 42, // PTM Nxx Revert sample + offset + CMD_DBMECHO = 43, // DBM enable/disable echo + CMD_OFFSETPERCENTAGE = 44, // PLM Percentage Offset + CMD_DIGIREVERSESAMPLE = 45, // DIGI reverse sample + MAX_EFFECTS +}; + + +enum EffectType : uint8 +{ + EFFECT_TYPE_NORMAL = 0, + EFFECT_TYPE_GLOBAL = 1, + EFFECT_TYPE_VOLUME = 2, + EFFECT_TYPE_PANNING = 3, + EFFECT_TYPE_PITCH = 4, + MAX_EFFECT_TYPE = 5 +}; + + +class ModCommand +{ +public: + using NOTE = uint8; + using INSTR = uint8; + using VOL = uint8; + using VOLCMD = uint8; + using COMMAND = uint8; + using PARAM = uint8; + + // Defines the maximum value for column data when interpreted as 2-byte value + // (for example volcmd and vol). The valid value range is [0, maxColumnValue]. + static constexpr int maxColumnValue = 999; + + // Returns empty modcommand. + static ModCommand Empty() { return ModCommand(); } + + bool operator==(const ModCommand &mc) const + { + return (note == mc.note) + && (instr == mc.instr) + && (volcmd == mc.volcmd) + && (command == mc.command) + && ((volcmd == VOLCMD_NONE && !IsPcNote()) || vol == mc.vol) + && ((command == CMD_NONE && !IsPcNote()) || param == mc.param); + } + bool operator!=(const ModCommand& mc) const { return !(*this == mc); } + + void Set(NOTE n, INSTR ins, uint16 volcol, uint16 effectcol) { note = n; instr = ins; SetValueVolCol(volcol); SetValueEffectCol(effectcol); } + + uint16 GetValueVolCol() const { return GetValueVolCol(volcmd, vol); } + static uint16 GetValueVolCol(uint8 volcmd, uint8 vol) { return (volcmd << 8) + vol; } + void SetValueVolCol(const uint16 val) { volcmd = static_cast<VOLCMD>(val >> 8); vol = static_cast<uint8>(val & 0xFF); } + + uint16 GetValueEffectCol() const { return GetValueEffectCol(command, param); } + static uint16 GetValueEffectCol(uint8 command, uint8 param) { return (command << 8) + param; } + void SetValueEffectCol(const uint16 val) { command = static_cast<COMMAND>(val >> 8); param = static_cast<uint8>(val & 0xFF); } + + // Clears modcommand. + void Clear() { memset(this, 0, sizeof(ModCommand)); } + + // Returns true if modcommand is empty, false otherwise. + bool IsEmpty() const + { + return (note == NOTE_NONE && instr == 0 && volcmd == VOLCMD_NONE && command == CMD_NONE); + } + + // Returns true if instrument column represents plugin index. + bool IsInstrPlug() const { return IsPcNote(); } + + // Returns true if and only if note is NOTE_PC or NOTE_PCS. + bool IsPcNote() const { return IsPcNote(note); } + static bool IsPcNote(NOTE note) { return note == NOTE_PC || note == NOTE_PCS; } + + // Returns true if and only if note is a valid musical note. + bool IsNote() const { return mpt::is_in_range(note, NOTE_MIN, NOTE_MAX); } + static bool IsNote(NOTE note) { return mpt::is_in_range(note, NOTE_MIN, NOTE_MAX); } + // Returns true if and only if note is a valid special note. + bool IsSpecialNote() const { return mpt::is_in_range(note, NOTE_MIN_SPECIAL, NOTE_MAX_SPECIAL); } + static bool IsSpecialNote(NOTE note) { return mpt::is_in_range(note, NOTE_MIN_SPECIAL, NOTE_MAX_SPECIAL); } + // Returns true if and only if note is a valid musical note or the note entry is empty. + bool IsNoteOrEmpty() const { return note == NOTE_NONE || IsNote(); } + static bool IsNoteOrEmpty(NOTE note) { return note == NOTE_NONE || IsNote(note); } + // Returns true if any of the commands in this cell trigger a tone portamento. + bool IsPortamento() const { return command == CMD_TONEPORTAMENTO || command == CMD_TONEPORTAVOL || volcmd == VOLCMD_TONEPORTAMENTO; } + // Returns true if the cell contains a sliding or otherwise continuous effect command. + bool IsContinousCommand(const CSoundFile &sndFile) const; + bool IsContinousVolColCommand() const; + // Returns true if the cell contains a sliding command with separate up/down nibbles. + bool IsSlideUpDownCommand() const; + // Returns true if the cell contains an effect command that may affect the global state of the module. + bool IsGlobalCommand() const { return IsGlobalCommand(command, param); } + static bool IsGlobalCommand(COMMAND command, PARAM param); + + // Returns true if the note is inside the Amiga frequency range + bool IsAmigaNote() const { return IsAmigaNote(note); } + static bool IsAmigaNote(NOTE note) { return !IsNote(note) || (note >= NOTE_MIDDLEC - 12 && note < NOTE_MIDDLEC + 24); } + + static EffectType GetEffectType(COMMAND cmd); + EffectType GetEffectType() const { return GetEffectType(command); } + static EffectType GetVolumeEffectType(VOLCMD volcmd); + EffectType GetVolumeEffectType() const { return GetVolumeEffectType(volcmd); } + + // Convert a complete ModCommand item from one format to another + void Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &sndFile); + // Convert MOD/XM Exx to S3M/IT Sxx + void ExtendedMODtoS3MEffect(); + // Convert S3M/IT Sxx to MOD/XM Exx + void ExtendedS3MtoMODEffect(); + + // "Importance" of every FX command. Table is used for importing from formats with multiple effect columns + // and is approximately the same as in SchismTracker. + static size_t GetEffectWeight(COMMAND cmd); + // Try to convert a an effect into a volume column effect. Returns true on success. + static bool ConvertVolEffect(uint8 &effect, uint8 ¶m, bool force); + // Takes two "normal" effect commands and converts them to volume column + effect column commands. Returns the dropped command + param (CMD_NONE if nothing had to be dropped). + static std::pair<EffectCommand, PARAM> TwoRegularCommandsToMPT(uint8 &effect1, uint8 ¶m1, uint8 &effect2, uint8 ¶m2); + // Try to combine two commands into one. Returns true on success and the combined command is placed in eff1 / param1. + static bool CombineEffects(uint8 &eff1, uint8 ¶m1, uint8 &eff2, uint8 ¶m2); + +public: + uint8 note = NOTE_NONE; + uint8 instr = 0; + uint8 volcmd = VOLCMD_NONE; + uint8 command = CMD_NONE; + uint8 vol = 0; + uint8 param = 0; +}; + +OPENMPT_NAMESPACE_END |