MuseScore/fluid/sfont.h
2012-05-26 14:49:10 +02:00

396 lines
13 KiB
C++

/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* SoundFont loading code borrowed from Smurf SoundFont Editor by Josh Green
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA
*/
#ifndef _FLUID_DEFSFONT_H
#define _FLUID_DEFSFONT_H
#include "config.h"
#include "fluid.h"
namespace FluidS {
class Preset;
class Sample;
class Instrument;
struct SFGen;
struct SFMod;
struct SFChunk;
//---------------------------------------------------------
// SFVersion
//---------------------------------------------------------
struct SFVersion { // version structure
unsigned short major, minor;
SFVersion();
};
//---------------------------------------------------------
// SFont
//---------------------------------------------------------
class SFont {
Fluid* synth;
QFile f;
unsigned samplepos; // the position in the file at which the sample data starts
unsigned samplesize; // the size of the sample data
QList<Instrument*> instruments;
QList<Preset*> presets;
QList<Sample*> sample;
int _id;
SFVersion _version; // sound font version
SFVersion romver; // ROM version
QList<unsigned char*> infos; // list of info strings (1st byte is ID)
void read_listchunk(SFChunk* chunk);
void process_info(int size);
void process_sdta(int size);
void pdtahelper(unsigned int expid, unsigned int reclen, SFChunk* chunk, int* size);
void process_pdta(int size);
void load_phdr(int size);
void load_pbag(int size);
void load_pmod(int size);
void load_pgen(int size);
void load_ihdr(int size);
void load_ibag(int size);
void load_imod(int size);
void load_igen(int size);
void load_shdr(int size);
void fixup_pgen();
void fixup_igen();
void fixup_sample();
void readchunk(SFChunk*);
unsigned short READW();
void READD(unsigned int& var);
void FSKIP(int size) { return safe_fseek(size); }
void FSKIPW();
unsigned char READB();
char READC();
void READSTR(char*);
void safe_fread(void *buf, int count);
void safe_fseek(long ofs);
bool load();
public:
SFont(Fluid* f);
virtual ~SFont();
QString get_name() const { return f.fileName(); }
Preset* get_preset(int bank, int prenum);
bool read(const QString& file);
int load_sampledata();
unsigned int samplePos() const { return samplepos; }
int id() const { return _id; }
void setId(int i) { _id = i; }
void setSamplepos(unsigned v) { samplepos = v; }
void setSamplesize(unsigned v) { samplesize = v; }
unsigned getSamplesize() const { return samplesize; }
const QList<Preset*> getPresets() const { return presets; }
SFVersion version() const { return _version; }
friend class Preset;
};
//---------------------------------------------------------
// Sample
//---------------------------------------------------------
class Sample {
bool _valid;
public:
SFont* sf;
unsigned int start;
unsigned int end;
unsigned int loopstart;
unsigned int loopend;
unsigned int samplerate;
int origpitch;
int pitchadj;
int sampletype;
short* data;
/** The amplitude, that will lower the level of the sample's loop to
the noise floor. Needed for note turnoff optimization, will be
filled out automatically */
/* Set this to zero, when submitting a new sample. */
bool amplitude_that_reaches_noise_floor_is_valid;
double amplitude_that_reaches_noise_floor;
Sample(SFont*);
~Sample();
bool inRom() const;
void optimize();
void load();
bool valid() const { return _valid; }
void setValid(bool v) { _valid = v; }
#ifdef SOUNDFONT3
bool decompressOggVorbis(char* p, int size);
#endif
};
//---------------------------------------------------------
// Zone
//---------------------------------------------------------
class Zone {
public:
union {
Sample* sample;
int sampIdx;
Instrument* instrument;
int instIdx;
};
QList<SFGen*> gen;
QList<SFMod*> mod;
int keylo, keyhi, vello, velhi;
Generator genlist[GEN_LAST];
QList<Mod*> modlist; // List of modulators
public:
Zone();
~Zone();
bool importZone();
bool inside_range(int key, int vel) const;
Instrument* get_inst() const { return instrument; }
Sample* get_sample() const { return sample; }
};
//---------------------------------------------------------
// Instrument
//---------------------------------------------------------
class Instrument {
public:
Zone* global_zone;
QList<Zone*> zones;
public:
Instrument();
~Instrument();
Zone* get_global_zone() const { return global_zone; }
QList<Zone*> get_zone() { return zones; }
bool import_sfont();
};
//---------------------------------------------------------
// Preset
//---------------------------------------------------------
class Preset {
public:
QString name; // the name of the preset
SFont* sfont;
int bank; // the bank number
int num; // the preset number
Zone* _global_zone; // the global zone of the preset
QList<Zone*> zones;
public:
Preset(SFont* sfont);
~Preset();
QString get_name() const { return name; }
int get_banknum() const { return bank; }
int get_num() const { return num; }
bool noteon(Fluid*, unsigned id, int chan, int key, int vel, double nt);
void setGlobalZone(Zone* z) { _global_zone = z; }
bool importSfont();
Zone* global_zone() { return _global_zone; }
void loadSamples();
QList<Zone*> getZones() { return zones; }
};
//---------------------------------------------------------
// SFChunk
//---------------------------------------------------------
struct SFChunk { // RIFF file chunk structure
unsigned int id; // chunk id
unsigned int size; // size of the following chunk
};
struct SFMod { /* Modulator structure */
unsigned short src; /* source modulator */
unsigned short dest; /* destination generator */
signed short amount; /* signed, degree of modulation */
unsigned short amtsrc; /* second source controls amnt of first */
unsigned short trans; /* transform applied to source */
};
union SFGenAmount { /* Generator amount structure */
signed short sword; /* signed 16 bit value */
unsigned short uword; /* unsigned 16 bit value */
struct {
unsigned char lo; /* low value for ranges */
unsigned char hi; /* high value for ranges */
} range;
};
struct SFGen { /* Generator structure */
unsigned short id; /* generator ID */
SFGenAmount amount; /* generator value */
};
/* NOTE: sffd is also used to determine if sound font is new (NULL) */
/* sf file chunk IDs */
enum {
UNKN_ID, RIFF_ID, LIST_ID, SFBK_ID,
INFO_ID, SDTA_ID, PDTA_ID, /* info/sample/preset */
IFIL_ID, ISNG_ID, INAM_ID, IROM_ID, /* info ids (1st byte of info strings) */
IVER_ID, ICRD_ID, IENG_ID, IPRD_ID, /* more info ids */
ICOP_ID, ICMT_ID, ISFT_ID, /* and yet more info ids */
SNAM_ID, SMPL_ID, /* sample ids */
PHDR_ID, PBAG_ID, PMOD_ID, PGEN_ID, /* preset ids */
IHDR_ID, IBAG_ID, IMOD_ID, IGEN_ID, /* instrument ids */
SHDR_ID /* sample info */
};
/* generator types */
enum Gen_Type {
Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddrOfs,
Gen_EndLoopAddrOfs, Gen_StartAddrCoarseOfs, Gen_ModLFO2Pitch,
Gen_VibLFO2Pitch, Gen_ModEnv2Pitch, Gen_FilterFc, Gen_FilterQ,
Gen_ModLFO2FilterFc, Gen_ModEnv2FilterFc, Gen_EndAddrCoarseOfs,
Gen_ModLFO2Vol, Gen_Unused1, Gen_ChorusSend, Gen_ReverbSend, Gen_Pan,
Gen_Unused2, Gen_Unused3, Gen_Unused4,
Gen_ModLFODelay, Gen_ModLFOFreq, Gen_VibLFODelay, Gen_VibLFOFreq,
Gen_ModEnvDelay, Gen_ModEnvAttack, Gen_ModEnvHold, Gen_ModEnvDecay,
Gen_ModEnvSustain, Gen_ModEnvRelease, Gen_Key2ModEnvHold,
Gen_Key2ModEnvDecay, Gen_VolEnvDelay, Gen_VolEnvAttack,
Gen_VolEnvHold, Gen_VolEnvDecay, Gen_VolEnvSustain, Gen_VolEnvRelease,
Gen_Key2VolEnvHold, Gen_Key2VolEnvDecay, Gen_Instrument,
Gen_Reserved1, Gen_KeyRange, Gen_VelRange,
Gen_StartLoopAddrCoarseOfs, Gen_Keynum, Gen_Velocity,
Gen_Attenuation, Gen_Reserved2, Gen_EndLoopAddrCoarseOfs,
Gen_CoarseTune, Gen_FineTune, Gen_SampleId, Gen_SampleModes,
Gen_Reserved3, Gen_ScaleTune, Gen_ExclusiveClass, Gen_OverrideRootKey,
Gen_Dummy
};
#define Gen_MaxValid Gen_Dummy - 1 /* maximum valid generator */
/* generator unit type */
enum Gen_Unit {
None, /* No unit type */
Unit_Smpls, /* in samples */
Unit_32kSmpls, /* in 32k samples */
Unit_Cent, /* in cents (1/100th of a semitone) */
Unit_HzCent, /* in Hz Cents */
Unit_TCent, /* in Time Cents */
Unit_cB, /* in centibels (1/100th of a decibel) */
Unit_Percent, /* in percentage */
Unit_Semitone, /* in semitones */
Unit_Range /* a range of values */
};
/* global data */
#define CHNKIDSTR(id) &idlist[(id - 1) * 4]
/* sfont file chunk sizes */
#define SFPHDRSIZE 38
#define SFBAGSIZE 4
#define SFMODSIZE 10
#define SFGENSIZE 4
#define SFIHDRSIZE 22
#define SFSHDRSIZE 46
/* sfont file data structures */
struct SFPhdr {
unsigned char name[20]; /* preset name */
unsigned short preset; /* preset number */
unsigned short bank; /* bank number */
unsigned short pbagndx; /* index into preset bag */
unsigned int library; /* just for preserving them */
unsigned int genre; /* Not used */
unsigned int morphology; /* Not used */
};
struct SFBag {
unsigned short genndx; /* index into generator list */
unsigned short modndx; /* index into modulator list */
};
struct SFIhdr {
char name[20]; /* Name of instrument */
unsigned short ibagndx; /* Instrument bag index */
};
/* Basic bit swapping functions
*/
#define GUINT16_SWAP_LE_BE_CONSTANT(val) ((unsigned short) ( \
(((unsigned short) (val) & (unsigned short) 0x00ffU) << 8) | \
(((unsigned short) (val) & (unsigned short) 0xff00U) >> 8)))
#define GUINT32_SWAP_LE_BE_CONSTANT(val) ((unsigned int) ( \
(((unsigned int) (val) & (unsigned int) 0x000000ffU) << 24) | \
(((unsigned int) (val) & (unsigned int) 0x0000ff00U) << 8) | \
(((unsigned int) (val) & (unsigned int) 0x00ff0000U) >> 8) | \
(((unsigned int) (val) & (unsigned int) 0xff000000U) >> 24)))
#define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
#define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
#define GINT16_TO_LE(val) ((signed short) (val))
#define GUINT16_TO_LE(val) ((unsigned short) (val))
#define GINT16_TO_BE(val) ((signed short) GUINT16_SWAP_LE_BE (val))
#define GUINT16_TO_BE(val) (GUINT16_SWAP_LE_BE (val))
#define GINT32_TO_LE(val) ((signed int) (val))
#define GUINT32_TO_LE(val) ((unsigned int) (val))
#define GINT32_TO_BE(val) ((signed int) GUINT32_SWAP_LE_BE (val))
#define GUINT32_TO_BE(val) (GUINT32_SWAP_LE_BE (val))
/* The G*_TO_?E() macros are defined in glibconfig.h.
* The transformation is symmetric, so the FROM just maps to the TO.
*/
#define GINT16_FROM_LE(val) (GINT16_TO_LE (val))
#define GUINT16_FROM_LE(val) (GUINT16_TO_LE (val))
#define GINT16_FROM_BE(val) (GINT16_TO_BE (val))
#define GUINT16_FROM_BE(val) (GUINT16_TO_BE (val))
#define GINT32_FROM_LE(val) (GINT32_TO_LE (val))
#define GUINT32_FROM_LE(val) (GUINT32_TO_LE (val))
#define GINT32_FROM_BE(val) (GINT32_TO_BE (val))
#define GUINT32_FROM_BE(val) (GUINT32_TO_BE (val))
}
#endif /* _FLUID_SFONT_H */