aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/soundlib/Dlsbank.h
blob: d9c3fde2722c5cf56ee86204967d4652020bd7f1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * DLSBank.h
 * ---------
 * Purpose: Sound bank loading.
 * Notes  : Supported sound bank types: DLS (including embedded DLS in MSS & RMI), SF2
 * Authors: Olivier Lapicque
 *          OpenMPT Devs
 * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
 */


#pragma once

#include "openmpt/all/BuildSettings.hpp"

OPENMPT_NAMESPACE_BEGIN
class CSoundFile;
OPENMPT_NAMESPACE_END
#include "Snd_defs.h"

OPENMPT_NAMESPACE_BEGIN

#ifdef MODPLUG_TRACKER


struct DLSREGION
{
	uint32 ulLoopStart;
	uint32 ulLoopEnd;
	uint16 nWaveLink;
	uint16 uPercEnv;
	uint16 usVolume;     // 0..256
	uint16 fuOptions;    // flags + key group
	int16 sFineTune;     // +128 = +1 semitone
	int16 panning = -1;  // -1= unset (DLS), otherwise 0...256
	uint8  uKeyMin;
	uint8  uKeyMax;
	uint8  uUnityNote;
	uint8  tuning = 100;

	constexpr bool IsDummy() const noexcept { return uKeyMin == 0xFF || nWaveLink == Util::MaxValueOfType(nWaveLink); }
};

struct DLSENVELOPE
{
	// Volume Envelope
	uint16 wVolAttack;       // Attack Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s]
	uint16 wVolDecay;        // Decay Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s]
	uint16 wVolRelease;      // Release Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s]
	uint8 nVolSustainLevel;  // Sustain Level: 0-128, 128=100%
	uint8 nDefPan;           // Default Pan
};

// Special Bank bits
#define F_INSTRUMENT_DRUMS		0x80000000

struct DLSINSTRUMENT
{
	uint32 ulBank = 0, ulInstrument = 0;
	uint32 nMelodicEnv = 0;
	std::vector<DLSREGION> Regions;
	char szName[32];
	// SF2 stuff (DO NOT USE! -> used internally by the SF2 loader)
	uint16 wPresetBagNdx = 0, wPresetBagNum = 0;
};

struct DLSSAMPLEEX
{
	char   szName[20];
	uint32 dwLen;
	uint32 dwStartloop;
	uint32 dwEndloop;
	uint32 dwSampleRate;
	uint8  byOriginalPitch;
	int8   chPitchCorrection;
	bool   compressed = false;
};


#define SOUNDBANK_TYPE_INVALID	0
#define SOUNDBANK_TYPE_DLS		0x01
#define SOUNDBANK_TYPE_SF2		0x02

struct SOUNDBANKINFO
{
	std::string szBankName,
		szCopyRight,
		szComments,
		szEngineer,
		szSoftware,		// ISFT: Software
		szDescription;	// ISBJ: Subject
};

struct IFFCHUNK;
struct SF2LoaderInfo;

class CDLSBank
{
protected:
	SOUNDBANKINFO m_BankInfo;
	mpt::PathString m_szFileName;
	size_t m_dwWavePoolOffset;
	uint32 m_nType;
	// DLS Information
	uint32 m_nMaxWaveLink;
	uint32 m_sf2version = 0;
	std::vector<size_t> m_WaveForms;
	std::vector<DLSINSTRUMENT> m_Instruments;
	std::vector<DLSSAMPLEEX> m_SamplesEx;
	std::vector<DLSENVELOPE> m_Envelopes;

public:
	CDLSBank();

	bool operator==(const CDLSBank &other) const noexcept { return !mpt::PathString::CompareNoCase(m_szFileName, other.m_szFileName); }

	static bool IsDLSBank(const mpt::PathString &filename);
	static uint32 MakeMelodicCode(uint32 bank, uint32 instr) { return ((bank << 16) | (instr));}
	static uint32 MakeDrumCode(uint32 rgn, uint32 instr) { return (0x80000000 | (rgn << 16) | (instr));}

public:
	bool Open(const mpt::PathString &filename);
	bool Open(FileReader file);
	mpt::PathString GetFileName() const { return m_szFileName; }
	uint32 GetBankType() const { return m_nType; }
	const SOUNDBANKINFO &GetBankInfo() const { return m_BankInfo; }

public:
	uint32 GetNumInstruments() const { return static_cast<uint32>(m_Instruments.size()); }
	uint32 GetNumSamples() const { return static_cast<uint32>(m_WaveForms.size()); }
	const DLSINSTRUMENT *GetInstrument(uint32 iIns) const { return iIns < m_Instruments.size() ? &m_Instruments[iIns] : nullptr; }
	const DLSINSTRUMENT *FindInstrument(bool isDrum, uint32 bank = 0xFF, uint32 program = 0xFF, uint32 key = 0xFF, uint32 *pInsNo = nullptr) const;
	bool FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum) const;
	uint32 GetRegionFromKey(uint32 nIns, uint32 nKey) const;
	bool ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector<uint8> &waveData, uint32 &length) const;
	bool ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose = 0) const;
	bool ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn) const;
	const char *GetRegionName(uint32 nIns, uint32 nRgn) const;
	uint16 GetPanning(uint32 ins, uint32 region) const;

// Internal Loader Functions
protected:
	bool UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, FileReader chunk);
	bool UpdateSF2PresetData(SF2LoaderInfo &sf2info, const IFFCHUNK &header, FileReader &chunk);
	bool ConvertSF2ToDLS(SF2LoaderInfo &sf2info);

public:
	// DLS Unit conversion
	static int32 DLS32BitTimeCentsToMilliseconds(int32 lTimeCents);
	static int32 DLS32BitRelativeGainToLinear(int32 lCentibels);	// 0dB = 0x10000
	static int32 DLS32BitRelativeLinearToGain(int32 lGain);		// 0dB = 0x10000
	static int32 DLSMidiVolumeToLinear(uint32 nMidiVolume);		// [0-127] -> [0-0x10000]
};


#endif // MODPLUG_TRACKER


OPENMPT_NAMESPACE_END