1 /*
2  * ModInstrument.h
3  * ---------------
4  * Purpose: Module Instrument header class and helpers
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 
10 
11 #pragma once
12 
13 #include "openmpt/all/BuildSettings.hpp"
14 
15 #include "modcommand.h"
16 #include "tuningbase.h"
17 #include "Snd_defs.h"
18 #include "openmpt/base/FlagSet.hpp"
19 #include "../common/misc_util.h"
20 #include <set>
21 
22 OPENMPT_NAMESPACE_BEGIN
23 
24 class CSoundFile;
25 
26 // Instrument Nodes
27 struct EnvelopeNode
28 {
29 	using tick_t = uint16 ;
30 	using value_t = uint8;
31 
32 	tick_t tick = 0;   // Envelope node position (x axis)
33 	value_t value = 0; // Envelope node value (y axis)
34 
EnvelopeNodeEnvelopeNode35 	EnvelopeNode() { }
EnvelopeNodeEnvelopeNode36 	EnvelopeNode(tick_t tick, value_t value) : tick(tick), value(value) { }
37 
38 	bool operator== (const EnvelopeNode &other) const { return tick == other.tick && value == other.value; }
39 };
40 
41 // Instrument Envelopes
42 struct InstrumentEnvelope : public std::vector<EnvelopeNode>
43 {
44 	FlagSet<EnvelopeFlags> dwFlags; // Envelope flags
45 	uint8 nLoopStart = 0;           // Loop start node
46 	uint8 nLoopEnd = 0;             // Loop end node
47 	uint8 nSustainStart = 0;        // Sustain start node
48 	uint8 nSustainEnd = 0;          // Sustain end node
49 	uint8 nReleaseNode = ENV_RELEASE_NODE_UNSET; // Release node
50 
51 	// Convert envelope data between various formats.
52 	void Convert(MODTYPE fromType, MODTYPE toType);
53 
54 	// Get envelope value at a given tick. Assumes that the envelope data is in rage [0, rangeIn],
55 	// returns value in range [0, rangeOut].
56 	int32 GetValueFromPosition(int position, int32 rangeOut, int32 rangeIn = ENVELOPE_MAX) const;
57 
58 	// Ensure that ticks are ordered in increasing order and values are within the allowed range.
59 	void Sanitize(uint8 maxValue = ENVELOPE_MAX);
60 
sizeInstrumentEnvelope61 	uint32 size() const { return static_cast<uint32>(std::vector<EnvelopeNode>::size()); }
62 
63 	using std::vector<EnvelopeNode>::push_back;
push_backInstrumentEnvelope64 	void push_back(EnvelopeNode::tick_t tick, EnvelopeNode::value_t value) { emplace_back(tick, value); }
65 };
66 
67 // Instrument Struct
68 struct ModInstrument
69 {
70 	uint32 nFadeOut = 256;   // Instrument fadeout speed
71 	uint32 nGlobalVol = 64;  // Global volume (0...64, all sample volumes are multiplied with this - TODO: This is 0...128 in Impulse Tracker)
72 	uint32 nPan = 32 * 4;    // Default pan (0...256), if the appropriate flag is set. Sample panning overrides instrument panning.
73 
74 	uint16 nVolRampUp = 0;  // Default sample ramping up, 0 = use global default
75 
76 	ResamplingMode resampling = SRCMODE_DEFAULT;  // Resampling mode
77 
78 	FlagSet<InstrumentFlags> dwFlags;                         // Instrument flags
79 	NewNoteAction nNNA = NewNoteAction::NoteCut;              // New note action
80 	DuplicateCheckType nDCT = DuplicateCheckType::None;       // Duplicate check type (i.e. which condition will trigger the duplicate note action)
81 	DuplicateNoteAction nDNA = DuplicateNoteAction::NoteCut;  // Duplicate note action
82 
83 	uint8 nPanSwing = 0;  // Random panning factor (0...64)
84 	uint8 nVolSwing = 0;  // Random volume factor (0...100)
85 
86 	uint8 nIFC = 0;                                 // Default filter cutoff (0...127). Used if the high bit is set
87 	uint8 nIFR = 0;                                 // Default filter resonance (0...127). Used if the high bit is set
88 	uint8 nCutSwing = 0;                            // Random cutoff factor (0...64)
89 	uint8 nResSwing = 0;                            // Random resonance factor (0...64)
90 	FilterMode filterMode = FilterMode::Unchanged;  // Default filter mode
91 
92 	int8 nPPS = 0;                         // Pitch/Pan separation (i.e. how wide the panning spreads, -32...32)
93 	uint8 nPPC = NOTE_MIDDLEC - NOTE_MIN;  // Pitch/Pan centre (zero-based)
94 
95 	uint16 wMidiBank = 0;    // MIDI Bank (1...16384). 0 = Don't send.
96 	uint8 nMidiProgram = 0;  // MIDI Program (1...128). 0 = Don't send.
97 	uint8 nMidiChannel = 0;  // MIDI Channel (1...16). 0 = Don't send. 17 = Mapped (Send to tracker channel modulo 16).
98 	uint8 nMidiDrumKey = 0;  // Drum set note mapping (currently only used by the .MID loader)
99 	int8 midiPWD = 2;        // MIDI Pitch Wheel Depth and CMD_FINETUNE depth in semitones
100 	PLUGINDEX nMixPlug = 0;  // Plugin assigned to this instrument (0 = no plugin, 1 = first plugin)
101 
102 	PlugVelocityHandling pluginVelocityHandling = PLUGIN_VELOCITYHANDLING_CHANNEL;  // How to deal with plugin velocity
103 	PlugVolumeHandling pluginVolumeHandling = PLUGIN_VOLUMEHANDLING_IGNORE;         // How to deal with plugin volume
104 
105 	TEMPO pitchToTempoLock;      // BPM at which the samples assigned to this instrument loop correctly (0 = unset)
106 	CTuning *pTuning = nullptr;  // sample tuning assigned to this instrument
107 
108 	InstrumentEnvelope VolEnv;    // Volume envelope data
109 	InstrumentEnvelope PanEnv;    // Panning envelope data
110 	InstrumentEnvelope PitchEnv;  // Pitch / filter envelope data
111 
112 	std::array<uint8, 128> NoteMap;         // Note mapping, e.g. C-5 => D-5
113 	std::array<SAMPLEINDEX, 128> Keyboard;  // Sample mapping, e.g. C-5 => Sample 1
114 
115 	mpt::charbuf<MAX_INSTRUMENTNAME> name;
116 	mpt::charbuf<MAX_INSTRUMENTFILENAME> filename;
117 
GetNameModInstrument118 	std::string GetName() const { return name; }
GetFilenameModInstrument119 	std::string GetFilename() const { return filename; }
120 
121 	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
122 	// WHEN adding new members here, ALSO update InstrumentExtensions.cpp
123 	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
124 
125 	ModInstrument(SAMPLEINDEX sample = 0);
126 
127 	// Assign all notes to a given sample.
AssignSampleModInstrument128 	void AssignSample(SAMPLEINDEX sample)
129 	{
130 		Keyboard.fill(sample);
131 	}
132 
133 	// Reset note mapping (i.e. every note is mapped to itself)
ResetNoteMapModInstrument134 	void ResetNoteMap()
135 	{
136 		for(size_t n = 0; n < std::size(NoteMap); n++)
137 		{
138 			NoteMap[n] = static_cast<uint8>(n + 1);
139 		}
140 	}
141 
142 	// Transpose entire note mapping by given number of semitones
143 	void Transpose(int8 amount);
144 
IsCutoffEnabledModInstrument145 	bool IsCutoffEnabled() const { return (nIFC & 0x80) != 0; }
IsResonanceEnabledModInstrument146 	bool IsResonanceEnabled() const { return (nIFR & 0x80) != 0; }
GetCutoffModInstrument147 	uint8 GetCutoff() const { return (nIFC & 0x7F); }
GetResonanceModInstrument148 	uint8 GetResonance() const { return (nIFR & 0x7F); }
SetCutoffModInstrument149 	void SetCutoff(uint8 cutoff, bool enable) { nIFC = std::min(cutoff, uint8(0x7F)) | (enable ? 0x80 : 0x00); }
SetResonanceModInstrument150 	void SetResonance(uint8 resonance, bool enable) { nIFR = std::min(resonance, uint8(0x7F)) | (enable ? 0x80 : 0x00); }
151 
HasValidMIDIChannelModInstrument152 	bool HasValidMIDIChannel() const { return (nMidiChannel >= 1 && nMidiChannel <= 17); }
153 	uint8 GetMIDIChannel(const CSoundFile &sndFile, CHANNELINDEX chn) const;
154 
SetTuningModInstrument155 	void SetTuning(CTuning *pT)
156 	{
157 		pTuning = pT;
158 	}
159 
160 	// Get a reference to a specific envelope of this instrument
GetEnvelopeModInstrument161 	const InstrumentEnvelope &GetEnvelope(EnvelopeType envType) const
162 	{
163 		switch(envType)
164 		{
165 		case ENV_VOLUME:
166 		default:
167 			return VolEnv;
168 		case ENV_PANNING:
169 			return PanEnv;
170 		case ENV_PITCH:
171 			return PitchEnv;
172 		}
173 	}
174 
GetEnvelopeModInstrument175 	InstrumentEnvelope &GetEnvelope(EnvelopeType envType)
176 	{
177 		return const_cast<InstrumentEnvelope &>(static_cast<const ModInstrument &>(*this).GetEnvelope(envType));
178 	}
179 
180 	// Get a set of all samples referenced by this instrument
181 	std::set<SAMPLEINDEX> GetSamples() const;
182 
183 	// Write sample references into a bool vector. If a sample is referenced by this instrument, true is written.
184 	// The caller has to initialize the vector.
185 	void GetSamples(std::vector<bool> &referencedSamples) const;
186 
187 	// Translate instrument properties between two given formats.
188 	void Convert(MODTYPE fromType, MODTYPE toType);
189 
190 	// Sanitize all instrument data.
191 	void Sanitize(MODTYPE modType);
192 
193 };
194 
195 OPENMPT_NAMESPACE_END
196