-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsf2.h
335 lines (284 loc) · 8.73 KB
/
sf2.h
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
// sf2.h Soundfont type definitions.
#ifndef __SF2_H
#define __SF2_H
#include <stdint.h>
#include <cassert>
#include <map>
#include <list>
#include <vector>
#include <string>
// Used SF2 'spec' @ http://freepats.zenvoid.org/sf2/sfspec24.pdf
////////////////////////////////////////////////////////////////////////////////
// SF2 data structures
#pragma pack(push, 1) // exact fit - no padding
#define SF_NAME_LEN 20
typedef struct sfPresetHeader // PHDR elements
{
char achPresetName[SF_NAME_LEN];
uint16_t wPreset;
uint16_t wBank;
uint16_t wPresetBagNdx;
uint32_t dwLibrary;
uint32_t dwGenre;
uint32_t dwMorphology;
sfPresetHeader();
} sfPresetHeader_t;
typedef struct sfPresetBag // PBAG elements
{
uint16_t wGenNdx;
uint16_t wModNdx;
sfPresetBag();
} sfPresetBag_t;
// For now we are not interested in all contents so just ensure proper size
#define SFModulator uint16_t
#define SFGenerator uint16_t
#define SFTransform uint16_t
#define genAmountType uint16_t
#define SFSampleLink uint16_t
typedef struct sfModList // PMOD / IMOD elements
{
SFModulator sfModSrcOper;
SFGenerator sfModDestOper;
uint16_t modAmount;
SFModulator sfModAmtSrcOper;
SFTransform sfModTransOper;
sfModList();
} sfModList_t;
typedef struct sfGenList // PGEN / IGEN elements
{
SFGenerator sfGenOper;
genAmountType genAmount;
sfGenList();
} sfGenList_t;
typedef struct sfInst_t // INST elements
{
char achInstName[SF_NAME_LEN];
uint16_t wInstBagNdx;
sfInst_t();
} sfInst_t;
typedef struct sfInstBag // IBAG elements
{
uint16_t wInstGenNdx;
uint16_t wInstModNdx;
sfInstBag();
} sfInstBag_t;
typedef struct sfSample // SHDR elements
{
char achSampleName[20];
uint32_t dwStart;
uint32_t dwEnd;
uint32_t dwStartloop;
uint32_t dwEndloop;
uint32_t dwSampleRate;
uint8_t byOriginalPitch;
char chPitchCorrection;
uint16_t wSampleLink;
SFSampleLink sfSampleType;
sfSample();
} sfSample_t;
#pragma pack(pop) // back to padding
typedef enum // just those we are intersted in
{
INSTRUMENT = 41, // for PGEN
SAMPLEID = 53 // for IGEN
} sfGenEnumLink_t;
////////////////////////////////////////////////////////////////////////////////
// forwards
class IFFChunk;
class IFFDigest;
////////////////////////////////////////////////////////////////////////////////
// global debug helper
void displayChunkHierarchy(IFFChunk *ck);
// global helper
void sf2NameToStr(std::string &strDest, const char *sf2Name);
////////////////////////////////////////////////////////////////////////////////
class SF2Samples
{
public:
SF2Samples() :
ck_sdta(0), ck_smpl(0), ck_sm24(0) {};
bool Analyse(IFFChunk *_ck_sdta);
uint32_t GetSampleCount();
IFFChunk *sdta() { return ck_sdta; }
IFFChunk *smpl() { return ck_smpl; }
IFFChunk *sm24() { return ck_sm24; }
protected:
IFFChunk *ck_sdta; // root
IFFChunk *ck_smpl;
IFFChunk *ck_sm24;
};
////////////////////////////////////////////////////////////////////////////////
// Hyda structs & classes
// Common (presets / instInfoVector)
typedef struct {
// modIdxs / genIdxs store indexes to valid data: pointers to terminators
// are ignored
std::list<uint16_t> modIdxs;
std::list<uint16_t> genIdxs;
// generator specific data
bool instOrSample;
uint16_t instOrSampleIdx;
} bagInfo_t;
// Presets
typedef struct {
int phdrIdx;
int pbagIdxStart;
// pbagInfoVec:
// size: number of pbags
// list of idxs: modifiers / generators
std::vector<bagInfo_t> pbagInfoVec;
} presInfo_t;
// Keep presets sorted
typedef std::map<uint16_t, presInfo_t> presetMap_t;
typedef presetMap_t::iterator presetMapIter_t;
typedef std::map<uint16_t, presetMap_t> bankPresetMap_t;
typedef bankPresetMap_t::iterator bankPresetMapIter_t;
// instInfoVector
typedef struct {
int ibagIdxStart;
std::vector<bagInfo_t> ibagInfoVec;
} instInfo_t;
typedef std::vector<instInfo_t> instInfoVector_t;
class SF2Hydra
{
public:
SF2Hydra() :
ck_pdta(0), ck_phdr(0), ck_pbag(0), ck_pmod(0), ck_pgen(0),
ck_inst(0), ck_ibag(0), ck_imod(0), ck_igen(0), ck_shdr(0),
phdr_data(0), phdr_count(0), pbag_data(0), pbag_count(0),
pmod_data(0), pmod_count(0), pmod_count_used(0),
pgen_data(0), pgen_count(0), pgen_count_used(0),
inst_data(0), inst_count(0), ibag_data(0), ibag_count(0),
imod_data(0), imod_count(0), imod_count_used(0),
igen_data(0), igen_count(0), igen_count_used(0),
shdr_data(0), shdr_count(0) {};
bool Analyse(IFFChunk *_ck_pdta, SF2Samples *samples);
// Preset getters
inline bankPresetMapIter_t bank_begin() { return bank_presets.begin(); }
inline bankPresetMapIter_t bank_end() { return bank_presets.end(); }
inline presetMapIter_t preset_begin(const bankPresetMapIter_t &bi) {
return bi->second.begin(); }
inline presetMapIter_t preset_end(const bankPresetMapIter_t &bi) {
return bi->second.end(); }
inline const sfPresetHeader_t& getPresetHeader(const presetMapIter_t &pi) {
return phdr_data[pi->second.phdrIdx]; }
inline const presInfo_t& getPresetInfo(const presetMapIter_t &pi) {
return pi->second; }
// Preset modulator (PMOD) getter
const sfModList_t& getPresetModulator(uint16_t i);
// Preset generator (PGEN) getter
const sfGenList_t& getPresetGenerator(uint16_t i);
// Instrument getter (as array - we need index access)
inline uint16_t instrument_count() { return inst_count-1; /* no terminal */}
const sfInst_t& getInstrument(uint16_t i);
const instInfo_t& getInstrumentInfo(uint16_t i);
// Instrument modulator (IMOD) getter
const sfModList_t& getInstrumentModulator(uint16_t i);
// Preset generator (IGEN) getter
const sfGenList_t& getInstrumentGenerator(uint16_t i);
// Sample (SHDR) getter
const sfSample_t& getSample(uint16_t i);
private:
bool CheckAllChunks(SF2Samples *samples);
bool AnalysePhdrPbag();
bool AnalyseInstIbag();
// return true if instrument/sample was found (=> global for first zone)
bool CheckInstrumentOrSample(
const sfGenList_t *gen_data,
std::list<uint16_t> &genList,
const sfGenEnumLink_t instSampleID,
uint16_t& instSampleIdx);
// Chunks
IFFChunk *ck_pdta; // root
IFFChunk *ck_phdr;
IFFChunk *ck_pbag;
IFFChunk *ck_pmod;
IFFChunk *ck_pgen;
IFFChunk *ck_inst;
IFFChunk *ck_ibag;
IFFChunk *ck_imod;
IFFChunk *ck_igen;
IFFChunk *ck_shdr;
// data array pinters an len counters (..count: terminal included!)
// preset header
sfPresetHeader_t *phdr_data;
int phdr_count;
bankPresetMap_t bank_presets;
// preset zones
sfPresetBag_t *pbag_data;
uint16_t pbag_count;
// preset zone modulators
sfModList_t *pmod_data;
uint16_t pmod_count;
uint16_t pmod_count_used;
// preset zone generators
sfGenList_t *pgen_data;
uint16_t pgen_count;
uint16_t pgen_count_used;
// instInfoVector
sfInst_t *inst_data;
uint16_t inst_count;
instInfoVector_t instInfoVector;
// instrument zones
sfInstBag_t *ibag_data;
uint16_t ibag_count;
// instrument zone modulators
sfModList_t *imod_data;
uint16_t imod_count;
uint16_t imod_count_used;
// instrument zone generators
sfGenList_t *igen_data;
uint16_t igen_count;
uint16_t igen_count_used;
// sample headers
sfSample_t *shdr_data;
uint16_t shdr_count;
};
////////////////////////////////////////////////////////////////////////////////
class SF2File
{
public:
SF2File() :
digest(0), ck_info(0) {};
bool Analyse(IFFDigest *_digest);
IFFChunk *getInfo() { return ck_info; }
SF2Samples &getSamples() { return samples; }
SF2Hydra &getHydra() { return hydra; }
protected:
IFFDigest *digest;
IFFChunk *ck_info; // No detailed analysis yet
SF2Samples samples;
SF2Hydra hydra;
};
////////////////////////////////////////////////////////////////////////////////
class SF2FileSplitter
{
public:
SF2FileSplitter(SF2File *_SF2SourceFile) :
SF2SourceFile(_SF2SourceFile), sampleCountTotal(0) {};
void clearPresets();
void addPreset(presetMapIter_t preset);
char *createSplit(std::size_t &len);
private:
void prepareSplit();
std::size_t getLenOrWriteData(char* data, std::size_t maxLen);
void addSampleAreaForSHDR(uint32_t shdrIdx);
SF2File *SF2SourceFile;
std::list<presetMapIter_t> presetList;
// Working variables to re-sort indexes
std::list<uint16_t> pbagIdxForPHDRList;
std::list<sfPresetBag_t> pbagList;
std::list<uint16_t> pmodIdxList;
std::list<uint16_t> pgenIdxList;
std::list<uint16_t> instIdxList;
std::map<uint16_t, uint16_t> instIdxMapper; // key:source / val:dest
std::list<uint16_t> ibagIdxForINSTList;
std::list<sfInstBag_t> ibagList;
std::list<uint16_t> imodIdxList;
std::list<uint16_t> igenIdxList;
std::list<uint16_t> shdrIdxList;
std::map<uint16_t, uint16_t> shdrIdxMapper; // key:source / val:dest
std::map<uint32_t/*start*/, std::map<uint32_t/*end*/, uint32_t/*offset*/> > sampleAreas;
uint32_t sampleCountTotal;
};
#endif