184 lines
7.2 KiB
C++
184 lines
7.2 KiB
C++
/*
|
|
* ModInstrument.h
|
|
* ---------------
|
|
* Purpose: Module Instrument header class and helpers
|
|
* Notes : (currently none)
|
|
* Authors: OpenMPT Devs
|
|
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
|
*/
|
|
|
|
|
|
#pragma once
|
|
|
|
#include "BuildSettings.h"
|
|
|
|
#include "tuningbase.h"
|
|
#include "Snd_defs.h"
|
|
#include "../common/FlagSet.h"
|
|
#include "../common/misc_util.h"
|
|
#include <set>
|
|
|
|
OPENMPT_NAMESPACE_BEGIN
|
|
|
|
// Instrument Nodes
|
|
struct EnvelopeNode
|
|
{
|
|
typedef uint16 tick_t;
|
|
typedef uint8 value_t;
|
|
|
|
tick_t tick = 0; // Envelope node position (x axis)
|
|
value_t value = 0; // Envelope node value (y axis)
|
|
|
|
EnvelopeNode() { }
|
|
EnvelopeNode(tick_t tick, value_t value) : tick(tick), value(value) { }
|
|
|
|
bool operator== (const EnvelopeNode &other) const { return tick == other.tick && value == other.value; }
|
|
};
|
|
|
|
// Instrument Envelopes
|
|
struct InstrumentEnvelope : public std::vector<EnvelopeNode>
|
|
{
|
|
FlagSet<EnvelopeFlags> dwFlags; // Envelope flags
|
|
uint8 nLoopStart = 0; // Loop start node
|
|
uint8 nLoopEnd = 0; // Loop end node
|
|
uint8 nSustainStart = 0; // Sustain start node
|
|
uint8 nSustainEnd = 0; // Sustain end node
|
|
uint8 nReleaseNode = ENV_RELEASE_NODE_UNSET; // Release node
|
|
|
|
// Convert envelope data between various formats.
|
|
void Convert(MODTYPE fromType, MODTYPE toType);
|
|
|
|
// Get envelope value at a given tick. Assumes that the envelope data is in rage [0, rangeIn],
|
|
// returns value in range [0, rangeOut].
|
|
int32 GetValueFromPosition(int position, int32 rangeOut, int32 rangeIn = ENVELOPE_MAX) const;
|
|
|
|
// Ensure that ticks are ordered in increasing order and values are within the allowed range.
|
|
void Sanitize(uint8 maxValue = ENVELOPE_MAX);
|
|
|
|
uint32 size() const { return static_cast<uint32>(std::vector<EnvelopeNode>::size()); }
|
|
|
|
using std::vector<EnvelopeNode>::push_back;
|
|
void push_back(EnvelopeNode::tick_t tick, EnvelopeNode::value_t value) { push_back(EnvelopeNode(tick, value)); }
|
|
};
|
|
|
|
// Instrument Struct
|
|
struct ModInstrument
|
|
{
|
|
uint32 nFadeOut; // Instrument fadeout speed
|
|
uint32 nGlobalVol; // Global volume (0...64, all sample volumes are multiplied with this - TODO: This is 0...128 in Impulse Tracker)
|
|
uint32 nPan; // Default pan (0...256), if the appropriate flag is set. Sample panning overrides instrument panning.
|
|
|
|
uint16 nVolRampUp; // Default sample ramping up, 0 = use global default
|
|
|
|
uint16 wMidiBank; // MIDI Bank (1...16384). 0 = Don't send.
|
|
uint8 nMidiProgram; // MIDI Program (1...128). 0 = Don't send.
|
|
uint8 nMidiChannel; // MIDI Channel (1...16). 0 = Don't send. 17 = Mapped (Send to tracker channel modulo 16).
|
|
uint8 nMidiDrumKey; // Drum set note mapping (currently only used by the .MID loader)
|
|
int8 midiPWD; // MIDI Pitch Wheel Depth in semitones
|
|
|
|
FlagSet<InstrumentFlags> dwFlags; // Instrument flags
|
|
NewNoteAction nNNA; // New note action
|
|
DuplicateCheckType nDCT; // Duplicate check type (i.e. which condition will trigger the duplicate note action)
|
|
DuplicateNoteAction nDNA; // Duplicate note action
|
|
uint8 nPanSwing; // Random panning factor (0...64)
|
|
uint8 nVolSwing; // Random volume factor (0...100)
|
|
uint8 nIFC; // Default filter cutoff (0...127). Used if the high bit is set
|
|
uint8 nIFR; // Default filter resonance (0...127). Used if the high bit is set
|
|
|
|
int8 nPPS; // Pitch/Pan separation (i.e. how wide the panning spreads, -32...32)
|
|
uint8 nPPC; // Pitch/Pan centre (zero-based, default is NOTE_MIDDLE_C - 1)
|
|
|
|
PLUGINDEX nMixPlug; // Plugin assigned to this instrument (0 = no plugin, 1 = first plugin)
|
|
uint8 nCutSwing; // Random cutoff factor (0...64)
|
|
uint8 nResSwing; // Random resonance factor (0...64)
|
|
InstrFilterMode nFilterMode; // Default filter mode
|
|
PlugVelocityHandling pluginVelocityHandling; // How to deal with plugin velocity
|
|
PlugVolumeHandling pluginVolumeHandling; // How to deal with plugin volume
|
|
ResamplingMode resampling; // Resampling mode
|
|
TEMPO pitchToTempoLock; // BPM at which the samples assigned to this instrument loop correctly (0 = unset)
|
|
CTuning *pTuning; // sample tuning assigned to this instrument
|
|
|
|
InstrumentEnvelope VolEnv; // Volume envelope data
|
|
InstrumentEnvelope PanEnv; // Panning envelope data
|
|
InstrumentEnvelope PitchEnv; // Pitch / filter envelope data
|
|
|
|
uint8 NoteMap[128]; // Note mapping, e.g. C-5 => D-5.
|
|
SAMPLEINDEX Keyboard[128]; // Sample mapping, e.g. C-5 => Sample 1
|
|
|
|
char name[MAX_INSTRUMENTNAME];
|
|
char filename[MAX_INSTRUMENTFILENAME];
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// WHEN adding new members here, ALSO update InstrumentExtensions.cpp
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
void SetTuning(CTuning* pT)
|
|
{
|
|
pTuning = pT;
|
|
}
|
|
|
|
ModInstrument(SAMPLEINDEX sample = 0);
|
|
|
|
// Assign all notes to a given sample.
|
|
void AssignSample(SAMPLEINDEX sample)
|
|
{
|
|
for(size_t n = 0; n < CountOf(Keyboard); n++)
|
|
{
|
|
Keyboard[n] = sample;
|
|
}
|
|
}
|
|
|
|
// Reset note mapping (i.e. every note is mapped to itself)
|
|
void ResetNoteMap()
|
|
{
|
|
for(size_t n = 0; n < CountOf(NoteMap); n++)
|
|
{
|
|
NoteMap[n] = static_cast<uint8>(n + 1);
|
|
}
|
|
}
|
|
|
|
bool IsCutoffEnabled() const { return (nIFC & 0x80) != 0; }
|
|
bool IsResonanceEnabled() const { return (nIFR & 0x80) != 0; }
|
|
uint8 GetCutoff() const { return (nIFC & 0x7F); }
|
|
uint8 GetResonance() const { return (nIFR & 0x7F); }
|
|
void SetCutoff(uint8 cutoff, bool enable) { nIFC = std::min<uint8>(cutoff, 0x7F) | (enable ? 0x80 : 0x00); }
|
|
void SetResonance(uint8 resonance, bool enable) { nIFR = std::min<uint8>(resonance, 0x7F) | (enable ? 0x80 : 0x00); }
|
|
|
|
bool HasValidMIDIChannel() const { return (nMidiChannel >= 1 && nMidiChannel <= 17); }
|
|
|
|
// Get a reference to a specific envelope of this instrument
|
|
const InstrumentEnvelope &GetEnvelope(EnvelopeType envType) const
|
|
{
|
|
switch(envType)
|
|
{
|
|
case ENV_VOLUME:
|
|
default:
|
|
return VolEnv;
|
|
case ENV_PANNING:
|
|
return PanEnv;
|
|
case ENV_PITCH:
|
|
return PitchEnv;
|
|
}
|
|
}
|
|
|
|
InstrumentEnvelope &GetEnvelope(EnvelopeType envType)
|
|
{
|
|
return const_cast<InstrumentEnvelope &>(static_cast<const ModInstrument &>(*this).GetEnvelope(envType));
|
|
}
|
|
|
|
// Get a set of all samples referenced by this instrument
|
|
std::set<SAMPLEINDEX> GetSamples() const;
|
|
|
|
// Write sample references into a bool vector. If a sample is referenced by this instrument, true is written.
|
|
// The caller has to initialize the vector.
|
|
void GetSamples(std::vector<bool> &referencedSamples) const;
|
|
|
|
// Translate instrument properties between two given formats.
|
|
void Convert(MODTYPE fromType, MODTYPE toType);
|
|
|
|
// Sanitize all instrument data.
|
|
void Sanitize(MODTYPE modType);
|
|
|
|
};
|
|
|
|
OPENMPT_NAMESPACE_END
|