1 /*
2  * DLSBank.h
3  * ---------
4  * Purpose: Sound bank loading.
5  * Notes  : Supported sound bank types: DLS (including embedded DLS in MSS & RMI), SF2
6  * Authors: Olivier Lapicque
7  *          OpenMPT Devs
8  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
9  */
10 
11 
12 #pragma once
13 
14 #include "openmpt/all/BuildSettings.hpp"
15 
16 OPENMPT_NAMESPACE_BEGIN
17 class CSoundFile;
18 OPENMPT_NAMESPACE_END
19 #include "Snd_defs.h"
20 
21 OPENMPT_NAMESPACE_BEGIN
22 
23 #ifdef MODPLUG_TRACKER
24 
25 
26 struct DLSREGION
27 {
28 	uint32 ulLoopStart;
29 	uint32 ulLoopEnd;
30 	uint16 nWaveLink;
31 	uint16 uPercEnv;
32 	uint16 usVolume;     // 0..256
33 	uint16 fuOptions;    // flags + key group
34 	int16 sFineTune;     // +128 = +1 semitone
35 	int16 panning = -1;  // -1= unset (DLS), otherwise 0...256
36 	uint8  uKeyMin;
37 	uint8  uKeyMax;
38 	uint8  uUnityNote;
39 	uint8  tuning = 100;
40 
IsDummyDLSREGION41 	constexpr bool IsDummy() const noexcept { return uKeyMin == 0xFF || nWaveLink == Util::MaxValueOfType(nWaveLink); }
42 };
43 
44 struct DLSENVELOPE
45 {
46 	// Volume Envelope
47 	uint16 wVolAttack;       // Attack Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s]
48 	uint16 wVolDecay;        // Decay Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s]
49 	uint16 wVolRelease;      // Release Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s]
50 	uint8 nVolSustainLevel;  // Sustain Level: 0-128, 128=100%
51 	uint8 nDefPan;           // Default Pan
52 };
53 
54 // Special Bank bits
55 #define F_INSTRUMENT_DRUMS		0x80000000
56 
57 struct DLSINSTRUMENT
58 {
59 	uint32 ulBank = 0, ulInstrument = 0;
60 	uint32 nMelodicEnv = 0;
61 	std::vector<DLSREGION> Regions;
62 	char szName[32];
63 	// SF2 stuff (DO NOT USE! -> used internally by the SF2 loader)
64 	uint16 wPresetBagNdx = 0, wPresetBagNum = 0;
65 };
66 
67 struct DLSSAMPLEEX
68 {
69 	char   szName[20];
70 	uint32 dwLen;
71 	uint32 dwStartloop;
72 	uint32 dwEndloop;
73 	uint32 dwSampleRate;
74 	uint8  byOriginalPitch;
75 	int8   chPitchCorrection;
76 	bool   compressed = false;
77 };
78 
79 
80 #define SOUNDBANK_TYPE_INVALID	0
81 #define SOUNDBANK_TYPE_DLS		0x01
82 #define SOUNDBANK_TYPE_SF2		0x02
83 
84 struct SOUNDBANKINFO
85 {
86 	std::string szBankName,
87 		szCopyRight,
88 		szComments,
89 		szEngineer,
90 		szSoftware,		// ISFT: Software
91 		szDescription;	// ISBJ: Subject
92 };
93 
94 struct IFFCHUNK;
95 struct SF2LoaderInfo;
96 
97 class CDLSBank
98 {
99 protected:
100 	SOUNDBANKINFO m_BankInfo;
101 	mpt::PathString m_szFileName;
102 	size_t m_dwWavePoolOffset;
103 	uint32 m_nType;
104 	// DLS Information
105 	uint32 m_nMaxWaveLink;
106 	uint32 m_sf2version = 0;
107 	std::vector<size_t> m_WaveForms;
108 	std::vector<DLSINSTRUMENT> m_Instruments;
109 	std::vector<DLSSAMPLEEX> m_SamplesEx;
110 	std::vector<DLSENVELOPE> m_Envelopes;
111 
112 public:
113 	CDLSBank();
114 	static bool IsDLSBank(const mpt::PathString &filename);
MakeMelodicCode(uint32 bank,uint32 instr)115 	static uint32 MakeMelodicCode(uint32 bank, uint32 instr) { return ((bank << 16) | (instr));}
MakeDrumCode(uint32 rgn,uint32 instr)116 	static uint32 MakeDrumCode(uint32 rgn, uint32 instr) { return (0x80000000 | (rgn << 16) | (instr));}
117 
118 public:
119 	bool Open(const mpt::PathString &filename);
120 	bool Open(FileReader file);
GetFileName()121 	mpt::PathString GetFileName() const { return m_szFileName; }
GetBankType()122 	uint32 GetBankType() const { return m_nType; }
GetBankInfo()123 	const SOUNDBANKINFO &GetBankInfo() const { return m_BankInfo; }
124 
125 public:
GetNumInstruments()126 	uint32 GetNumInstruments() const { return static_cast<uint32>(m_Instruments.size()); }
GetNumSamples()127 	uint32 GetNumSamples() const { return static_cast<uint32>(m_WaveForms.size()); }
GetInstrument(uint32 iIns)128 	const DLSINSTRUMENT *GetInstrument(uint32 iIns) const { return iIns < m_Instruments.size() ? &m_Instruments[iIns] : nullptr; }
129 	const DLSINSTRUMENT *FindInstrument(bool isDrum, uint32 bank = 0xFF, uint32 program = 0xFF, uint32 key = 0xFF, uint32 *pInsNo = nullptr) const;
130 	bool FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum) const;
131 	uint32 GetRegionFromKey(uint32 nIns, uint32 nKey) const;
132 	bool ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector<uint8> &waveData, uint32 &length) const;
133 	bool ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose = 0) const;
134 	bool ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn) const;
135 	const char *GetRegionName(uint32 nIns, uint32 nRgn) const;
136 	uint16 GetPanning(uint32 ins, uint32 region) const;
137 
138 // Internal Loader Functions
139 protected:
140 	bool UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, FileReader chunk);
141 	bool UpdateSF2PresetData(SF2LoaderInfo &sf2info, const IFFCHUNK &header, FileReader &chunk);
142 	bool ConvertSF2ToDLS(SF2LoaderInfo &sf2info);
143 
144 public:
145 	// DLS Unit conversion
146 	static int32 DLS32BitTimeCentsToMilliseconds(int32 lTimeCents);
147 	static int32 DLS32BitRelativeGainToLinear(int32 lCentibels);	// 0dB = 0x10000
148 	static int32 DLS32BitRelativeLinearToGain(int32 lGain);		// 0dB = 0x10000
149 	static int32 DLSMidiVolumeToLinear(uint32 nMidiVolume);		// [0-127] -> [0-0x10000]
150 };
151 
152 
153 #endif // MODPLUG_TRACKER
154 
155 
156 OPENMPT_NAMESPACE_END
157