2 |
* * |
* * |
3 |
* libsf2 - C++ cross-platform SF2 format file access library * |
* libsf2 - C++ cross-platform SF2 format file access library * |
4 |
* * |
* * |
5 |
* Copyright (C) 2009 by Grigor Iliev <grigor@grigoriliev.com> * |
* Copyright (C) 2009-2010 by Grigor Iliev <grigor@grigoriliev.com> * |
6 |
* * |
* * |
7 |
* This library is free software; you can redistribute it and/or modify * |
* This library is free software; you can redistribute it and/or modify * |
8 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
28 |
#include <vector> |
#include <vector> |
29 |
|
|
30 |
|
|
31 |
#if WORDS_BIGENDIAN |
#define RIFF_ID(x) (*((uint32_t*) x)) |
|
#define ENDIAN_SWAP(x) \ |
|
|
( (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24) ) |
|
|
#else |
|
|
#define ENDIAN_SWAP(x) (x) |
|
|
#endif |
|
32 |
|
|
|
#define RIFF_ID(x) ENDIAN_SWAP( (*((uint32_t*) x)) ) |
|
33 |
|
|
34 |
|
#define RIFF_TYPE_SF2 RIFF_ID("sfbk") |
|
#define RIFF_TYPE_SF2 RIFF_ID("sfbk") |
|
35 |
|
|
36 |
// Level 0 |
// Level 0 |
37 |
#define LIST_TYPE_INFO RIFF_ID("INFO") |
#define LIST_TYPE_SDTA RIFF_ID("sdta") |
38 |
#define LIST_TYPE_SDTA RIFF_ID("sdta") |
#define LIST_TYPE_PDTA RIFF_ID("pdta") |
|
#define LIST_TYPE_PDTA RIFF_ID("pdta") |
|
39 |
|
|
40 |
// Level 1 |
// Level 1 |
41 |
//<INFO-list> |
//<INFO-list> |
42 |
#define CHUNK_ID_IFIL RIFF_ID("ifil") |
#define CHUNK_ID_IFIL RIFF_ID("ifil") |
43 |
#define CHUNK_ID_ISNG RIFF_ID("isng") |
#define CHUNK_ID_ISNG RIFF_ID("isng") |
44 |
#define CHUNK_ID_INAM RIFF_ID("INAM") |
#define CHUNK_ID_IROM RIFF_ID("irom") |
45 |
#define CHUNK_ID_IROM RIFF_ID("irom") |
#define CHUNK_ID_IVER RIFF_ID("iver") |
|
#define CHUNK_ID_IVER RIFF_ID("iver") |
|
|
#define CHUNK_ID_ICRD RIFF_ID("ICRD") |
|
|
#define CHUNK_ID_IENG RIFF_ID("IENG") |
|
|
#define CHUNK_ID_IPRD RIFF_ID("IPRD") |
|
|
#define CHUNK_ID_ICOP RIFF_ID("ICOP") |
|
|
#define CHUNK_ID_ICMT RIFF_ID("ICMT") |
|
|
#define CHUNK_ID_ISFT RIFF_ID("ISFT") |
|
46 |
|
|
47 |
//<sdta-list> |
//<sdta-list> |
48 |
#define CHUNK_ID_SMPL RIFF_ID("smpl") |
#define CHUNK_ID_SM24 RIFF_ID("sm24") |
|
#define CHUNK_ID_SM24 RIFF_ID("sm24") |
|
49 |
|
|
50 |
//<pdta-list> |
//<pdta-list> |
51 |
#define CHUNK_ID_PHDR RIFF_ID("phdr") |
#define CHUNK_ID_PHDR RIFF_ID("phdr") |
52 |
#define CHUNK_ID_PBAG RIFF_ID("pbag") |
#define CHUNK_ID_PBAG RIFF_ID("pbag") |
53 |
#define CHUNK_ID_PMOD RIFF_ID("pmod") |
#define CHUNK_ID_PMOD RIFF_ID("pmod") |
54 |
#define CHUNK_ID_PGEN RIFF_ID("pgen") |
#define CHUNK_ID_PGEN RIFF_ID("pgen") |
55 |
#define CHUNK_ID_INST RIFF_ID("inst") |
#define CHUNK_ID_INST RIFF_ID("inst") |
56 |
#define CHUNK_ID_IBAG RIFF_ID("ibag") |
#define CHUNK_ID_IBAG RIFF_ID("ibag") |
57 |
#define CHUNK_ID_IMOD RIFF_ID("imod") |
#define CHUNK_ID_IMOD RIFF_ID("imod") |
58 |
#define CHUNK_ID_IGEN RIFF_ID("igen") |
#define CHUNK_ID_IGEN RIFF_ID("igen") |
59 |
#define CHUNK_ID_SHDR RIFF_ID("shdr") |
#define CHUNK_ID_SHDR RIFF_ID("shdr") |
|
|
|
|
#define NONE 0x1ffffff |
|
60 |
|
|
61 |
/** SoundFont specific classes and definitions */ |
/** SoundFont specific classes and definitions */ |
62 |
namespace sf2 { |
namespace sf2 { |
63 |
|
|
64 |
|
static uint NONE = 0x1ffffff; |
65 |
|
|
66 |
|
double ToSeconds(int Timecents); |
67 |
|
double ToRatio(int Centibels); |
68 |
|
double ToHz(int cents); |
69 |
|
|
70 |
typedef struct _PresetBag { |
typedef struct _PresetBag { |
71 |
uint16_t GenNdx; |
uint16_t GenNdx; |
72 |
uint16_t ModNdx; |
uint16_t ModNdx; |
85 |
} ModList; |
} ModList; |
86 |
|
|
87 |
typedef struct _RangesType { |
typedef struct _RangesType { |
88 |
|
#if WORDS_BIGENDIAN |
89 |
|
uint8_t byHi; |
90 |
|
uint8_t byLo; |
91 |
|
#else |
92 |
uint8_t byLo; |
uint8_t byLo; |
93 |
uint8_t byHi; |
uint8_t byHi; |
94 |
|
#endif |
95 |
} RangesType; |
} RangesType; |
96 |
|
|
97 |
typedef union _GenAmountType { |
typedef union _GenAmountType { |
141 |
HOLD_MOD_ENV, |
HOLD_MOD_ENV, |
142 |
DECAY_MOD_ENV, |
DECAY_MOD_ENV, |
143 |
SUSTAIN_MOD_ENV, |
SUSTAIN_MOD_ENV, |
144 |
RELEASEMODENV, // 30 |
RELEASE_MOD_ENV, // 30 |
145 |
KEYNUM_TO_MOD_ENV_HOLD, |
KEYNUM_TO_MOD_ENV_HOLD, |
146 |
KEYNUM_TO_MOD_ENV_DECAY, |
KEYNUM_TO_MOD_ENV_DECAY, |
147 |
DELAY_VOL_ENV, |
DELAY_VOL_ENV, |
214 |
class ModulatorItem { |
class ModulatorItem { |
215 |
public: |
public: |
216 |
Modulator ModSrcOper; |
Modulator ModSrcOper; |
217 |
SFGenerator ModDestOper; |
SFGenerator ModDestOper; |
218 |
uint16_t ModAmount; |
uint16_t ModAmount; |
219 |
Modulator ModAmtSrcOper; |
Modulator ModAmtSrcOper; |
220 |
SFTransform ModTransOper; |
SFTransform ModTransOper; |
221 |
|
|
222 |
ModulatorItem(ModList& mod); |
ModulatorItem(ModList& mod); |
223 |
}; |
}; |
359 |
int startAddrsOffset, startAddrsCoarseOffset, endAddrsOffset, endAddrsCoarseOffset; |
int startAddrsOffset, startAddrsCoarseOffset, endAddrsOffset, endAddrsCoarseOffset; |
360 |
int startloopAddrsOffset, startloopAddrsCoarseOffset, endloopAddrsOffset, endloopAddrsCoarseOffset; |
int startloopAddrsOffset, startloopAddrsCoarseOffset, endloopAddrsOffset, endloopAddrsCoarseOffset; |
361 |
|
|
362 |
double EG1PreAttackDelay; |
int modEnvToPitch , modLfoToPitch, modEnvToFilterFc, modLfoToFilterFc; // in cents |
363 |
double EG1Attack; |
int modLfoToVolume /* in centibels */, freqModLfo /* in absolute cents */; |
364 |
double EG1Hold; |
int delayModLfo; // in absolute timecents |
365 |
double EG1Decay; |
int vibLfoToPitch, freqVibLfo /* in absolute cents */; |
366 |
double EG1Sustain; // Sustain value of the sample amplitude EG (in permilles) |
int delayVibLfo; // in absolute timecents |
367 |
double EG1Release; |
int initialFilterFc /* in absolute cents */, initialFilterQ /* in centibels */; |
368 |
|
|
369 |
double EG2PreAttackDelay; |
uint exclusiveClass; // exclusive group |
|
double EG2Attack; |
|
|
double EG2Hold; |
|
|
double EG2Decay; |
|
|
double EG2Sustain; // Sustain value of the filter cutoff EG (in permilles) |
|
|
double EG2Release; |
|
370 |
|
|
371 |
Sample* pSample; |
Sample* pSample; |
372 |
bool HasLoop; |
bool HasLoop; |
380 |
|
|
381 |
int GetUnityNote(); |
int GetUnityNote(); |
382 |
|
|
383 |
|
/** |
384 |
|
* @returns The instrument to which this region belongs, or |
385 |
|
* NULL if it's preset region. |
386 |
|
*/ |
387 |
|
Instrument* GetParentInstrument() { return pParentInstrument; } |
388 |
|
|
389 |
std::vector<ModulatorItem> modulators; |
std::vector<ModulatorItem> modulators; |
390 |
|
|
391 |
|
|
392 |
|
// Instrument can be referenced by more than one presets so we need to calculate values on the fly |
393 |
|
int GetPan(Region* pPresetRegion = NULL); // -64 - +63 |
394 |
|
int GetFineTune(Region* pPresetRegion = NULL); // -99 - +99 |
395 |
|
int GetCoarseTune(Region* pPresetRegion = NULL); // -120 - +120 |
396 |
|
double GetEG1PreAttackDelay(Region* pPresetRegion = NULL); // in seconds |
397 |
|
double GetEG1Attack(Region* pPresetRegion = NULL); // in seconds |
398 |
|
double GetEG1Hold(Region* pPresetRegion = NULL); // in seconds |
399 |
|
double GetEG1Decay(Region* pPresetRegion = NULL); // in seconds |
400 |
|
int GetEG1Sustain(Region* pPresetRegion = NULL); // Sustain value of the sample amplitude EG (the decrease in level, expressed in centibels) |
401 |
|
double GetEG1Release(Region* pPresetRegion = NULL); // in seconds |
402 |
|
|
403 |
|
double GetEG2PreAttackDelay(Region* pPresetRegion = NULL); // in seconds |
404 |
|
double GetEG2Attack(Region* pPresetRegion = NULL); // in seconds |
405 |
|
double GetEG2Hold(Region* pPresetRegion = NULL); // in seconds |
406 |
|
double GetEG2Decay(Region* pPresetRegion = NULL); // in seconds |
407 |
|
int GetEG2Sustain(Region* pPresetRegion = NULL); // Sustain value of the filter cutoff EG (in permilles) |
408 |
|
double GetEG2Release(Region* pPresetRegion = NULL); // in seconds |
409 |
|
|
410 |
|
int GetModEnvToPitch(Region* pPresetRegion = NULL); // in cents |
411 |
|
int GetModLfoToPitch(Region* pPresetRegion = NULL); // in cents |
412 |
|
int GetModEnvToFilterFc(Region* pPresetRegion = NULL); // in cents |
413 |
|
int GetModLfoToFilterFc(Region* pPresetRegion = NULL); // in cents |
414 |
|
double GetModLfoToVolume(Region* pPresetRegion = NULL); // in centibels |
415 |
|
double GetFreqModLfo(Region* pPresetRegion = NULL); // in Hz |
416 |
|
double GetDelayModLfo(Region* pPresetRegion = NULL); // in seconds |
417 |
|
int GetVibLfoToPitch(Region* pPresetRegion = NULL); // in cents |
418 |
|
double GetFreqVibLfo(Region* pPresetRegion = NULL); // in Hz |
419 |
|
double GetDelayVibLfo(Region* pPresetRegion = NULL); // in seconds |
420 |
|
int GetInitialFilterFc(Region* pPresetRegion); // in absolute cents |
421 |
|
int GetInitialFilterQ(Region* pPresetRegion); // in centibels |
422 |
|
|
423 |
friend class Instrument; |
friend class Instrument; |
424 |
friend class Preset; |
friend class Preset; |
425 |
|
|
426 |
private: |
private: |
427 |
|
int EG1PreAttackDelay; // in timecents |
428 |
|
int EG1Attack; // in timecents |
429 |
|
int EG1Hold; // in timecents |
430 |
|
int EG1Decay; // in timecents |
431 |
|
int EG1Sustain; // Sustain value (the decrease in level, expressed in centibels) |
432 |
|
int EG1Release; // in timecents |
433 |
|
|
434 |
|
int EG2PreAttackDelay; // in timecents |
435 |
|
int EG2Attack; // in timecents |
436 |
|
int EG2Hold; // in timecents |
437 |
|
int EG2Decay; // in timecents |
438 |
|
int EG2Sustain; // Sustain value of the filter cutoff EG (in permilles) |
439 |
|
int EG2Release; // in timecents |
440 |
|
|
441 |
|
Instrument* pParentInstrument; |
442 |
|
|
443 |
void SetGenerator(sf2::File* pFile, GenList& Gen); |
void SetGenerator(sf2::File* pFile, GenList& Gen); |
444 |
void SetModulator(sf2::File* pFile, ModList& Mod); |
void SetModulator(sf2::File* pFile, ModList& Mod); |
445 |
}; |
}; |
454 |
|
|
455 |
sf2::File* GetFile() { return pFile; } |
sf2::File* GetFile() { return pFile; } |
456 |
String GetName() { return Name; } |
String GetName() { return Name; } |
457 |
|
|
458 |
int GetRegionCount(); |
int GetRegionCount(); |
459 |
Region* GetRegion(int idx); |
Region* GetRegion(int idx); |
460 |
|
|
|
std::vector<Region*> GetRegionsOnKey(int key, uint8_t vel); |
|
|
|
|
461 |
protected: |
protected: |
462 |
std::vector<Region*> regions; |
std::vector<Region*> regions; |
463 |
sf2::File* pFile; |
sf2::File* pFile; |
464 |
}; |
}; |
465 |
|
|
466 |
|
class Query { |
467 |
|
public: |
468 |
|
int key; |
469 |
|
uint8_t vel; |
470 |
|
|
471 |
|
Query(InstrumentBase& instrument); |
472 |
|
Region* next(); |
473 |
|
|
474 |
|
private: |
475 |
|
InstrumentBase& instrument; |
476 |
|
int i; |
477 |
|
}; |
478 |
|
|
479 |
class Instrument : public InstrumentBase { |
class Instrument : public InstrumentBase { |
480 |
public: |
public: |
481 |
Instrument(sf2::File* pFile, RIFF::Chunk* ck); |
Instrument(sf2::File* pFile, RIFF::Chunk* ck); |
484 |
void DeleteRegion(Region* pRegion); |
void DeleteRegion(Region* pRegion); |
485 |
//private: |
//private: |
486 |
uint16_t InstBagNdx; |
uint16_t InstBagNdx; |
487 |
|
|
488 |
/** |
/** |
489 |
* Load all regions (zones, bags) in the range idx1 - idx2 |
* Load all regions (zones, bags) in the range idx1 - idx2 |
490 |
*/ |
*/ |
512 |
* Load all regions (zones, bags) in the range idx1 - idx2 |
* Load all regions (zones, bags) in the range idx1 - idx2 |
513 |
*/ |
*/ |
514 |
void LoadRegions(int idx1, int idx2); |
void LoadRegions(int idx1, int idx2); |
515 |
|
|
516 |
|
Region* CreateRegion(); |
517 |
}; |
}; |
518 |
|
|
519 |
class File { |
class File { |