1
0

modcommand.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * modcommand.h
  3. * ------------
  4. * Purpose: ModCommand declarations and helpers. One ModCommand corresponds to one pattern cell.
  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. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include "Snd_defs.h"
  12. #include "../common/misc_util.h"
  13. OPENMPT_NAMESPACE_BEGIN
  14. class CSoundFile;
  15. // Note definitions
  16. enum : uint8 // ModCommand::NOTE
  17. {
  18. NOTE_NONE = 0, // Empty note cell
  19. NOTE_MIN = 1, // Minimum note value
  20. NOTE_MAX = 120, // Maximum note value
  21. NOTE_MIDDLEC = (5 * 12 + NOTE_MIN),
  22. NOTE_KEYOFF = 0xFF, // === (Note Off, releases envelope / fades samples, stops plugin note)
  23. NOTE_NOTECUT = 0xFE, // ^^^ (Cuts sample / stops all plugin notes)
  24. NOTE_FADE = 0xFD, // ~~~ (Fades samples, stops plugin note)
  25. NOTE_PC = 0xFC, // Param Control 'note'. Changes param value on first tick.
  26. NOTE_PCS = 0xFB, // Param Control (Smooth) 'note'. Interpolates param value during the whole row.
  27. NOTE_MIN_SPECIAL = NOTE_PCS,
  28. NOTE_MAX_SPECIAL = NOTE_KEYOFF,
  29. };
  30. // Volume Column commands
  31. enum VolumeCommand : uint8
  32. {
  33. VOLCMD_NONE = 0,
  34. VOLCMD_VOLUME = 1,
  35. VOLCMD_PANNING = 2,
  36. VOLCMD_VOLSLIDEUP = 3,
  37. VOLCMD_VOLSLIDEDOWN = 4,
  38. VOLCMD_FINEVOLUP = 5,
  39. VOLCMD_FINEVOLDOWN = 6,
  40. VOLCMD_VIBRATOSPEED = 7,
  41. VOLCMD_VIBRATODEPTH = 8,
  42. VOLCMD_PANSLIDELEFT = 9,
  43. VOLCMD_PANSLIDERIGHT = 10,
  44. VOLCMD_TONEPORTAMENTO = 11,
  45. VOLCMD_PORTAUP = 12,
  46. VOLCMD_PORTADOWN = 13,
  47. VOLCMD_PLAYCONTROL = 14,
  48. VOLCMD_OFFSET = 15,
  49. MAX_VOLCMDS
  50. };
  51. // Effect column commands
  52. enum EffectCommand : uint8
  53. {
  54. CMD_NONE = 0,
  55. CMD_ARPEGGIO = 1,
  56. CMD_PORTAMENTOUP = 2,
  57. CMD_PORTAMENTODOWN = 3,
  58. CMD_TONEPORTAMENTO = 4,
  59. CMD_VIBRATO = 5,
  60. CMD_TONEPORTAVOL = 6,
  61. CMD_VIBRATOVOL = 7,
  62. CMD_TREMOLO = 8,
  63. CMD_PANNING8 = 9,
  64. CMD_OFFSET = 10,
  65. CMD_VOLUMESLIDE = 11,
  66. CMD_POSITIONJUMP = 12,
  67. CMD_VOLUME = 13,
  68. CMD_PATTERNBREAK = 14,
  69. CMD_RETRIG = 15,
  70. CMD_SPEED = 16,
  71. CMD_TEMPO = 17,
  72. CMD_TREMOR = 18,
  73. CMD_MODCMDEX = 19,
  74. CMD_S3MCMDEX = 20,
  75. CMD_CHANNELVOLUME = 21,
  76. CMD_CHANNELVOLSLIDE = 22,
  77. CMD_GLOBALVOLUME = 23,
  78. CMD_GLOBALVOLSLIDE = 24,
  79. CMD_KEYOFF = 25,
  80. CMD_FINEVIBRATO = 26,
  81. CMD_PANBRELLO = 27,
  82. CMD_XFINEPORTAUPDOWN = 28,
  83. CMD_PANNINGSLIDE = 29,
  84. CMD_SETENVPOSITION = 30,
  85. CMD_MIDI = 31,
  86. CMD_SMOOTHMIDI = 32,
  87. CMD_DELAYCUT = 33,
  88. CMD_XPARAM = 34,
  89. CMD_FINETUNE = 35,
  90. CMD_FINETUNE_SMOOTH = 36,
  91. CMD_DUMMY = 37,
  92. CMD_NOTESLIDEUP = 38, // IMF Gxy / PTM Jxy (Slide y notes up every x ticks)
  93. CMD_NOTESLIDEDOWN = 39, // IMF Hxy / PTM Kxy (Slide y notes down every x ticks)
  94. CMD_NOTESLIDEUPRETRIG = 40, // PTM Lxy (Slide y notes up every x ticks + retrigger note)
  95. CMD_NOTESLIDEDOWNRETRIG = 41, // PTM Mxy (Slide y notes down every x ticks + retrigger note)
  96. CMD_REVERSEOFFSET = 42, // PTM Nxx Revert sample + offset
  97. CMD_DBMECHO = 43, // DBM enable/disable echo
  98. CMD_OFFSETPERCENTAGE = 44, // PLM Percentage Offset
  99. CMD_DIGIREVERSESAMPLE = 45, // DIGI reverse sample
  100. MAX_EFFECTS
  101. };
  102. enum EffectType : uint8
  103. {
  104. EFFECT_TYPE_NORMAL = 0,
  105. EFFECT_TYPE_GLOBAL = 1,
  106. EFFECT_TYPE_VOLUME = 2,
  107. EFFECT_TYPE_PANNING = 3,
  108. EFFECT_TYPE_PITCH = 4,
  109. MAX_EFFECT_TYPE = 5
  110. };
  111. class ModCommand
  112. {
  113. public:
  114. using NOTE = uint8;
  115. using INSTR = uint8;
  116. using VOL = uint8;
  117. using VOLCMD = uint8;
  118. using COMMAND = uint8;
  119. using PARAM = uint8;
  120. // Defines the maximum value for column data when interpreted as 2-byte value
  121. // (for example volcmd and vol). The valid value range is [0, maxColumnValue].
  122. static constexpr int maxColumnValue = 999;
  123. // Returns empty modcommand.
  124. static ModCommand Empty() { return ModCommand(); }
  125. bool operator==(const ModCommand &mc) const
  126. {
  127. return (note == mc.note)
  128. && (instr == mc.instr)
  129. && (volcmd == mc.volcmd)
  130. && (command == mc.command)
  131. && ((volcmd == VOLCMD_NONE && !IsPcNote()) || vol == mc.vol)
  132. && ((command == CMD_NONE && !IsPcNote()) || param == mc.param);
  133. }
  134. bool operator!=(const ModCommand& mc) const { return !(*this == mc); }
  135. void Set(NOTE n, INSTR ins, uint16 volcol, uint16 effectcol) { note = n; instr = ins; SetValueVolCol(volcol); SetValueEffectCol(effectcol); }
  136. uint16 GetValueVolCol() const { return GetValueVolCol(volcmd, vol); }
  137. static uint16 GetValueVolCol(uint8 volcmd, uint8 vol) { return (volcmd << 8) + vol; }
  138. void SetValueVolCol(const uint16 val) { volcmd = static_cast<VOLCMD>(val >> 8); vol = static_cast<uint8>(val & 0xFF); }
  139. uint16 GetValueEffectCol() const { return GetValueEffectCol(command, param); }
  140. static uint16 GetValueEffectCol(uint8 command, uint8 param) { return (command << 8) + param; }
  141. void SetValueEffectCol(const uint16 val) { command = static_cast<COMMAND>(val >> 8); param = static_cast<uint8>(val & 0xFF); }
  142. // Clears modcommand.
  143. void Clear() { memset(this, 0, sizeof(ModCommand)); }
  144. // Returns true if modcommand is empty, false otherwise.
  145. bool IsEmpty() const
  146. {
  147. return (note == NOTE_NONE && instr == 0 && volcmd == VOLCMD_NONE && command == CMD_NONE);
  148. }
  149. // Returns true if instrument column represents plugin index.
  150. bool IsInstrPlug() const { return IsPcNote(); }
  151. // Returns true if and only if note is NOTE_PC or NOTE_PCS.
  152. bool IsPcNote() const { return IsPcNote(note); }
  153. static bool IsPcNote(NOTE note) { return note == NOTE_PC || note == NOTE_PCS; }
  154. // Returns true if and only if note is a valid musical note.
  155. bool IsNote() const { return mpt::is_in_range(note, NOTE_MIN, NOTE_MAX); }
  156. static bool IsNote(NOTE note) { return mpt::is_in_range(note, NOTE_MIN, NOTE_MAX); }
  157. // Returns true if and only if note is a valid special note.
  158. bool IsSpecialNote() const { return mpt::is_in_range(note, NOTE_MIN_SPECIAL, NOTE_MAX_SPECIAL); }
  159. static bool IsSpecialNote(NOTE note) { return mpt::is_in_range(note, NOTE_MIN_SPECIAL, NOTE_MAX_SPECIAL); }
  160. // Returns true if and only if note is a valid musical note or the note entry is empty.
  161. bool IsNoteOrEmpty() const { return note == NOTE_NONE || IsNote(); }
  162. static bool IsNoteOrEmpty(NOTE note) { return note == NOTE_NONE || IsNote(note); }
  163. // Returns true if any of the commands in this cell trigger a tone portamento.
  164. bool IsPortamento() const { return command == CMD_TONEPORTAMENTO || command == CMD_TONEPORTAVOL || volcmd == VOLCMD_TONEPORTAMENTO; }
  165. // Returns true if the cell contains a sliding or otherwise continuous effect command.
  166. bool IsContinousCommand(const CSoundFile &sndFile) const;
  167. bool IsContinousVolColCommand() const;
  168. // Returns true if the cell contains a sliding command with separate up/down nibbles.
  169. bool IsSlideUpDownCommand() const;
  170. // Returns true if the cell contains an effect command that may affect the global state of the module.
  171. bool IsGlobalCommand() const { return IsGlobalCommand(command, param); }
  172. static bool IsGlobalCommand(COMMAND command, PARAM param);
  173. // Returns true if the note is inside the Amiga frequency range
  174. bool IsAmigaNote() const { return IsAmigaNote(note); }
  175. static bool IsAmigaNote(NOTE note) { return !IsNote(note) || (note >= NOTE_MIDDLEC - 12 && note < NOTE_MIDDLEC + 24); }
  176. static EffectType GetEffectType(COMMAND cmd);
  177. EffectType GetEffectType() const { return GetEffectType(command); }
  178. static EffectType GetVolumeEffectType(VOLCMD volcmd);
  179. EffectType GetVolumeEffectType() const { return GetVolumeEffectType(volcmd); }
  180. // Convert a complete ModCommand item from one format to another
  181. void Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &sndFile);
  182. // Convert MOD/XM Exx to S3M/IT Sxx
  183. void ExtendedMODtoS3MEffect();
  184. // Convert S3M/IT Sxx to MOD/XM Exx
  185. void ExtendedS3MtoMODEffect();
  186. // "Importance" of every FX command. Table is used for importing from formats with multiple effect columns
  187. // and is approximately the same as in SchismTracker.
  188. static size_t GetEffectWeight(COMMAND cmd);
  189. // Try to convert a an effect into a volume column effect. Returns true on success.
  190. static bool ConvertVolEffect(uint8 &effect, uint8 &param, bool force);
  191. // 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).
  192. static std::pair<EffectCommand, PARAM> TwoRegularCommandsToMPT(uint8 &effect1, uint8 &param1, uint8 &effect2, uint8 &param2);
  193. // Try to combine two commands into one. Returns true on success and the combined command is placed in eff1 / param1.
  194. static bool CombineEffects(uint8 &eff1, uint8 &param1, uint8 &eff2, uint8 &param2);
  195. public:
  196. uint8 note = NOTE_NONE;
  197. uint8 instr = 0;
  198. uint8 volcmd = VOLCMD_NONE;
  199. uint8 command = CMD_NONE;
  200. uint8 vol = 0;
  201. uint8 param = 0;
  202. };
  203. OPENMPT_NAMESPACE_END