mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 14:01:45 +00:00
- Reduced volume, expression, and panning controllers back to 7 bits.
- Added very basic Soundfont support to the internal TiMidity. Things missing: filter, LFOs, modulation envelope, chorus, reverb, and modulators. May or may not be compatible with TiMidity++'s soundfont extensions. - Added support for quoted strings to the TiMidity config parser. SVN r957 (trunk)
This commit is contained in:
parent
d5563fe478
commit
e64586d86f
16 changed files with 3396 additions and 785 deletions
|
@ -1,9 +1,18 @@
|
|||
May 8, 2008
|
||||
- Reduced volume, expression, and panning controllers back to 7 bits.
|
||||
- Added very basic Soundfont support to the internal TiMidity. Things missing:
|
||||
filter, LFOs, modulation envelope, chorus, reverb, and modulators. May or
|
||||
may not be compatible with TiMidity++'s soundfont extensions.
|
||||
|
||||
May 8, 2008 (Changes by Graf Zahl)
|
||||
- Changed all thing coordinates that were stored as shorts into fixed_t.
|
||||
- Separated mapthing2_t into mapthinghexen_t and the internal FMapThing so
|
||||
that it is easier to add new features in the UDMF map format.
|
||||
- Added some initial code to read UDMF maps.
|
||||
|
||||
May 6, 2008
|
||||
- Added support for quoted strings to the TiMidity config parser.
|
||||
|
||||
May 2, 2008 (Changes by Graf Zahl)
|
||||
- Split off the slope creation code from p_Setup.cpp into its own file.
|
||||
- Separated the linedef activation types into a bit mask that allows combination
|
||||
|
|
|
@ -101,7 +101,7 @@ struct FActionMap
|
|||
|
||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||
|
||||
static long ParseCommandLine (const char *args, int *argc, char **argv);
|
||||
static long ParseCommandLine (const char *args, int *argc, char **argv, bool no_escapes);
|
||||
static FConsoleCommand *FindNameInHashTable (FConsoleCommand **table, const char *name, size_t namelen);
|
||||
static FConsoleCommand *ScanChainForName (FConsoleCommand *start, const char *name, size_t namelen, FConsoleCommand **prev);
|
||||
|
||||
|
@ -724,7 +724,7 @@ void AddCommandString (char *cmd, int keynum)
|
|||
// \c becomes just TEXTCOLOR_ESCAPE
|
||||
// $<cvar> is replaced by the contents of <cvar>
|
||||
|
||||
static long ParseCommandLine (const char *args, int *argc, char **argv)
|
||||
static long ParseCommandLine (const char *args, int *argc, char **argv, bool no_escapes)
|
||||
{
|
||||
int count;
|
||||
char *buffplace;
|
||||
|
@ -758,15 +758,15 @@ static long ParseCommandLine (const char *args, int *argc, char **argv)
|
|||
do
|
||||
{
|
||||
stuff = *args++;
|
||||
if (stuff == '\\' && *args == '\"')
|
||||
if (!no_escapes && stuff == '\\' && *args == '\"')
|
||||
{
|
||||
stuff = '\"', args++;
|
||||
}
|
||||
else if (stuff == '\\' && *args == '\\')
|
||||
else if (!no_escapes && stuff == '\\' && *args == '\\')
|
||||
{
|
||||
args++;
|
||||
}
|
||||
else if (stuff == '\\' && *args == 'c')
|
||||
else if (!no_escapes && stuff == '\\' && *args == 'c')
|
||||
{
|
||||
stuff = TEXTCOLOR_ESCAPE, args++;
|
||||
}
|
||||
|
@ -824,11 +824,12 @@ static long ParseCommandLine (const char *args, int *argc, char **argv)
|
|||
return (long)(buffplace - (char *)0);
|
||||
}
|
||||
|
||||
FCommandLine::FCommandLine (const char *commandline)
|
||||
FCommandLine::FCommandLine (const char *commandline, bool no_escapes)
|
||||
{
|
||||
cmd = commandline;
|
||||
_argc = -1;
|
||||
_argv = NULL;
|
||||
noescapes = no_escapes;
|
||||
}
|
||||
|
||||
FCommandLine::~FCommandLine ()
|
||||
|
@ -839,11 +840,20 @@ FCommandLine::~FCommandLine ()
|
|||
}
|
||||
}
|
||||
|
||||
void FCommandLine::Shift()
|
||||
{
|
||||
// Only valid after _argv has been filled.
|
||||
for (int i = 1; i < _argc; ++i)
|
||||
{
|
||||
_argv[i - 1] = _argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
int FCommandLine::argc ()
|
||||
{
|
||||
if (_argc == -1)
|
||||
{
|
||||
argsize = ParseCommandLine (cmd, &_argc, NULL);
|
||||
argsize = ParseCommandLine (cmd, &_argc, NULL, noescapes);
|
||||
}
|
||||
return _argc;
|
||||
}
|
||||
|
@ -855,7 +865,7 @@ char *FCommandLine::operator[] (int i)
|
|||
int count = argc();
|
||||
_argv = new char *[count + (argsize+sizeof(char*)-1)/sizeof(char*)];
|
||||
_argv[0] = (char *)_argv + count*sizeof(char *);
|
||||
ParseCommandLine (cmd, NULL, _argv);
|
||||
ParseCommandLine (cmd, NULL, _argv, noescapes);
|
||||
}
|
||||
return _argv[i];
|
||||
}
|
||||
|
|
|
@ -64,17 +64,19 @@ FString BuildString (int argc, char **argv);
|
|||
class FCommandLine
|
||||
{
|
||||
public:
|
||||
FCommandLine (const char *commandline);
|
||||
FCommandLine (const char *commandline, bool no_escapes = false);
|
||||
~FCommandLine ();
|
||||
int argc ();
|
||||
char *operator[] (int i);
|
||||
const char *args () { return cmd; }
|
||||
void Shift();
|
||||
|
||||
private:
|
||||
const char *cmd;
|
||||
int _argc;
|
||||
char **_argv;
|
||||
long argsize;
|
||||
bool noescapes;
|
||||
};
|
||||
|
||||
typedef void (*CCmdRun) (FCommandLine &argv, APlayerPawn *instigator, int key);
|
||||
|
|
|
@ -623,13 +623,13 @@ FString TimidityMIDIDevice::GetStats()
|
|||
{
|
||||
dots << TEXTCOLOR_GREEN;
|
||||
}
|
||||
if (Renderer->voice[i].envelope_increment == 0)
|
||||
if (!Renderer->voice[i].eg1.env.bUpdating)
|
||||
{
|
||||
dots << "+";
|
||||
}
|
||||
else
|
||||
{
|
||||
dots << ('0' + Renderer->voice[i].envelope_stage);
|
||||
dots << ('0' + Renderer->voice[i].eg1.gf1.stage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
85
src/timidity/gf1patch.h
Normal file
85
src/timidity/gf1patch.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/* GF1 Patch definition: */
|
||||
enum
|
||||
{
|
||||
HEADER_SIZE = 12,
|
||||
ID_SIZE = 10,
|
||||
DESC_SIZE = 60,
|
||||
RESERVED_SIZE = 40,
|
||||
PATCH_HEADER_RESERVED_SIZE = 36,
|
||||
LAYER_RESERVED_SIZE = 40,
|
||||
PATCH_DATA_RESERVED_SIZE = 36,
|
||||
INST_NAME_SIZE = 16,
|
||||
ENVELOPES = 6,
|
||||
MAX_LAYERS = 4
|
||||
};
|
||||
#define GF1_HEADER_TEXT "GF1PATCH110"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#define GCC_PACKED
|
||||
#else
|
||||
#define GCC_PACKED __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
struct GF1PatchHeader
|
||||
{
|
||||
char Header[HEADER_SIZE];
|
||||
char GravisID[ID_SIZE]; /* Id = "ID#000002" */
|
||||
char Description[DESC_SIZE];
|
||||
BYTE Instruments;
|
||||
BYTE Voices;
|
||||
BYTE Channels;
|
||||
WORD WaveForms;
|
||||
WORD MasterVolume;
|
||||
DWORD DataSize;
|
||||
BYTE Reserved[PATCH_HEADER_RESERVED_SIZE];
|
||||
} GCC_PACKED;
|
||||
|
||||
struct GF1InstrumentData
|
||||
{
|
||||
WORD Instrument;
|
||||
char InstrumentName[INST_NAME_SIZE];
|
||||
int InstrumentSize;
|
||||
BYTE Layers;
|
||||
BYTE Reserved[RESERVED_SIZE];
|
||||
} GCC_PACKED;
|
||||
|
||||
struct GF1LayerData
|
||||
{
|
||||
BYTE LayerDuplicate;
|
||||
BYTE Layer;
|
||||
int LayerSize;
|
||||
BYTE Samples;
|
||||
BYTE Reserved[LAYER_RESERVED_SIZE];
|
||||
} GCC_PACKED;
|
||||
|
||||
struct GF1PatchData
|
||||
{
|
||||
char WaveName[7];
|
||||
BYTE Fractions;
|
||||
int WaveSize;
|
||||
int StartLoop;
|
||||
int EndLoop;
|
||||
WORD SampleRate;
|
||||
int LowFrequency;
|
||||
int HighFrequency;
|
||||
int RootFrequency;
|
||||
SWORD Tune;
|
||||
BYTE Balance;
|
||||
BYTE EnvelopeRate[ENVELOPES];
|
||||
BYTE EnvelopeOffset[ENVELOPES];
|
||||
BYTE TremoloSweep;
|
||||
BYTE TremoloRate;
|
||||
BYTE TremoloDepth;
|
||||
BYTE VibratoSweep;
|
||||
BYTE VibratoRate;
|
||||
BYTE VibratoDepth;
|
||||
BYTE Modes;
|
||||
SWORD ScaleFrequency;
|
||||
WORD ScaleFactor; /* From 0 to 2048 or 0 to 2 */
|
||||
BYTE Reserved[PATCH_DATA_RESERVED_SIZE];
|
||||
} GCC_PACKED;
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
#undef GCC_PACKED
|
|
@ -32,16 +32,15 @@
|
|||
#include "m_swap.h"
|
||||
#include "files.h"
|
||||
#include "templates.h"
|
||||
#include "gf1patch.h"
|
||||
|
||||
namespace Timidity
|
||||
{
|
||||
|
||||
extern Instrument *load_instrument_dls(Renderer *song, int drum, int bank, int instrument);
|
||||
|
||||
extern int openmode;
|
||||
|
||||
Instrument::Instrument()
|
||||
: type(INST_GUS), samples(0), sample(NULL)
|
||||
: samples(0), sample(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -52,7 +51,7 @@ Instrument::~Instrument()
|
|||
|
||||
for (i = samples, sp = &(sample[0]); i != 0; i--, sp++)
|
||||
{
|
||||
if (sp->data != NULL)
|
||||
if (sp->type == INST_GUS && sp->data != NULL)
|
||||
{
|
||||
free(sp->data);
|
||||
}
|
||||
|
@ -82,28 +81,6 @@ ToneBank::~ToneBank()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int convert_envelope_rate(Renderer *song, BYTE rate)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = 3 - ((rate>>6) & 0x3);
|
||||
r *= 3;
|
||||
r = (int)(rate & 0x3f) << r; /* 6.9 fixed point */
|
||||
|
||||
/* 15.15 fixed point. */
|
||||
return int(((r * 44100) / song->rate) * song->control_ratio) << 9;
|
||||
}
|
||||
|
||||
int convert_envelope_offset(BYTE offset)
|
||||
{
|
||||
/* This is not too good... Can anyone tell me what these values mean?
|
||||
Are they GUS-style "exponential" volumes? And what does that mean? */
|
||||
|
||||
/* 15.15 fixed point */
|
||||
return offset << (7 + 15);
|
||||
}
|
||||
|
||||
int convert_tremolo_sweep(Renderer *song, BYTE sweep)
|
||||
{
|
||||
if (sweep == 0)
|
||||
|
@ -268,7 +245,6 @@ failread:
|
|||
ip->samples = layer_data.Samples;
|
||||
ip->sample = (Sample *)safe_malloc(sizeof(Sample) * layer_data.Samples);
|
||||
memset(ip->sample, 0, sizeof(Sample) * layer_data.Samples);
|
||||
ip->type = INST_GUS;
|
||||
for (i = 0; i < layer_data.Samples; ++i)
|
||||
{
|
||||
if (sizeof(patch_data) != fp->Read(&patch_data, sizeof(patch_data)))
|
||||
|
@ -286,22 +262,23 @@ fail:
|
|||
sp->loop_start = LittleLong(patch_data.StartLoop);
|
||||
sp->loop_end = LittleLong(patch_data.EndLoop);
|
||||
sp->sample_rate = LittleShort(patch_data.SampleRate);
|
||||
sp->low_freq = LittleLong(patch_data.LowFrequency);
|
||||
sp->high_freq = LittleLong(patch_data.HighFrequency);
|
||||
sp->root_freq = LittleLong(patch_data.RootFrequency);
|
||||
sp->low_freq = float(LittleLong(patch_data.LowFrequency));
|
||||
sp->high_freq = float(LittleLong(patch_data.HighFrequency)) + 0.9999f;
|
||||
sp->root_freq = float(LittleLong(patch_data.RootFrequency));
|
||||
sp->high_vel = 127;
|
||||
sp->velocity = -1;
|
||||
sp->type = INST_GUS;
|
||||
|
||||
// Expand to SF2 range.
|
||||
if (panning == -1)
|
||||
{
|
||||
sp->panning = patch_data.Balance & 0x0F;
|
||||
sp->panning = (sp->panning << 3) | (sp->panning >> 1);
|
||||
sp->panning = (patch_data.Balance & 0x0F) * 1000 / 15 - 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
sp->panning = panning & 0x7f;
|
||||
sp->panning = (panning & 0x7f) * 1000 / 127 - 500;
|
||||
}
|
||||
sp->panning |= sp->panning << 7;
|
||||
song->compute_pan(sp->panning, sp->left_offset, sp->right_offset);
|
||||
song->compute_pan((sp->panning + 500) / 1000.0, INST_GUS, sp->left_offset, sp->right_offset);
|
||||
|
||||
/* tremolo */
|
||||
if (patch_data.TremoloRate == 0 || patch_data.TremoloDepth == 0)
|
||||
|
@ -353,6 +330,10 @@ fail:
|
|||
{
|
||||
sp->scale_factor *= 1024;
|
||||
}
|
||||
else if (sp->scale_factor > 2048)
|
||||
{
|
||||
sp->scale_factor = 1024;
|
||||
}
|
||||
if (sp->scale_factor != 1024)
|
||||
{
|
||||
cmsg(CMSG_INFO, VERB_DEBUG, " * Scale: note %d, factor %d\n",
|
||||
|
@ -444,9 +425,9 @@ fail:
|
|||
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
sp->envelope_rate[j] = convert_envelope_rate(song, patch_data.EnvelopeRate[j]);
|
||||
sp->envelope.gf1.rate[j] = patch_data.EnvelopeRate[j];
|
||||
/* [RH] GF1NEW clamps the offsets to the range [5,251], so we do too. */
|
||||
sp->envelope_offset[j] = convert_envelope_offset(clamp<BYTE>(patch_data.EnvelopeOffset[j], 5, 251));
|
||||
sp->envelope.gf1.offset[j] = clamp<BYTE>(patch_data.EnvelopeOffset[j], 5, 251);
|
||||
}
|
||||
|
||||
/* Then read the sample data */
|
||||
|
@ -648,53 +629,62 @@ static int fill_bank(Renderer *song, int dr, int b)
|
|||
{
|
||||
if (bank->instrument[i] == MAGIC_LOAD_INSTRUMENT)
|
||||
{
|
||||
bank->instrument[i] = NULL;
|
||||
bank->instrument[i] = load_instrument_dls(song, dr, b, i);
|
||||
if (bank->instrument[i] != NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (bank->tone[i].name.IsEmpty())
|
||||
Instrument *ip;
|
||||
ip = load_instrument_font_order(song, 0, dr, b, i);
|
||||
if (ip == NULL)
|
||||
{
|
||||
cmsg(CMSG_WARNING, (b != 0) ? VERB_VERBOSE : VERB_NORMAL,
|
||||
"No instrument mapped to %s %d, program %d%s\n",
|
||||
(dr) ? "drum set" : "tone bank", b, i,
|
||||
(b != 0) ? "" : " - this instrument will not be heard");
|
||||
if (b != 0)
|
||||
if (bank->tone[i].fontbank >= 0)
|
||||
{
|
||||
/* Mark the corresponding instrument in the default
|
||||
bank / drumset for loading (if it isn't already) */
|
||||
if (!dr)
|
||||
{
|
||||
if (tonebank[0]->instrument[i] != NULL)
|
||||
{
|
||||
tonebank[0]->instrument[i] = MAGIC_LOAD_INSTRUMENT;
|
||||
}
|
||||
ip = load_instrument_font(song, bank->tone[i].name, dr, b, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (drumset[0]->instrument[i] != NULL)
|
||||
{
|
||||
drumset[0]->instrument[i] = MAGIC_LOAD_INSTRUMENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
bank->instrument[i] = NULL;
|
||||
errors++;
|
||||
}
|
||||
else if (!(bank->instrument[i] =
|
||||
load_instrument(song, bank->tone[i].name,
|
||||
ip = load_instrument(song, bank->tone[i].name,
|
||||
(dr) ? 1 : 0,
|
||||
bank->tone[i].pan,
|
||||
bank->tone[i].amp,
|
||||
(bank->tone[i].note != -1) ? bank->tone[i].note : ((dr) ? i : -1),
|
||||
(bank->tone[i].strip_loop != -1) ? bank->tone[i].strip_loop : ((dr) ? 1 : -1),
|
||||
(bank->tone[i].strip_envelope != -1) ? bank->tone[i].strip_envelope : ((dr) ? 1 : -1),
|
||||
bank->tone[i].strip_tail)))
|
||||
bank->tone[i].strip_tail);
|
||||
}
|
||||
if (ip == NULL)
|
||||
{
|
||||
ip = load_instrument_font_order(song, 1, dr, b, i);
|
||||
}
|
||||
}
|
||||
bank->instrument[i] = ip;
|
||||
if (ip == NULL)
|
||||
{
|
||||
if (bank->tone[i].name.IsEmpty())
|
||||
{
|
||||
cmsg(CMSG_WARNING, (b != 0) ? VERB_VERBOSE : VERB_NORMAL,
|
||||
"No instrument mapped to %s %d, program %d%s\n",
|
||||
(dr) ? "drum set" : "tone bank", b, i,
|
||||
(b != 0) ? "" : " - this instrument will not be heard");
|
||||
}
|
||||
else
|
||||
{
|
||||
cmsg(CMSG_ERROR, VERB_NORMAL,
|
||||
"Couldn't load instrument %s (%s %d, program %d)\n",
|
||||
bank->tone[i].name.GetChars(),
|
||||
(dr) ? "drum set" : "tone bank", b, i);
|
||||
}
|
||||
if (b != 0)
|
||||
{
|
||||
/* Mark the corresponding instrument in the default
|
||||
bank / drumset for loading (if it isn't already) */
|
||||
if (((dr) ? drumset[0] : tonebank[0])->instrument[i] != NULL)
|
||||
{
|
||||
((dr) ? drumset[0] : tonebank[0])->instrument[i] = MAGIC_LOAD_INSTRUMENT;
|
||||
}
|
||||
}
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1121,13 +1121,14 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
|
|||
DLS_Region *rgn = &ins->regions[index];
|
||||
DLS_Wave *wave = &song->patches->waveList[rgn->wlnk->ulTableIndex];
|
||||
|
||||
sample->type = INST_DLS;
|
||||
sample->self_nonexclusive = !!(rgn->header->fusOptions & F_RGN_OPTION_SELFNONEXCLUSIVE);
|
||||
sample->key_group = (SBYTE)rgn->header->usKeyGroup;
|
||||
sample->low_freq = SDWORD(note_to_freq(rgn->header->RangeKey.usLow));
|
||||
sample->high_freq = SDWORD(note_to_freq(rgn->header->RangeKey.usHigh));
|
||||
sample->root_freq = SDWORD(note_to_freq(rgn->wsmp->usUnityNote));
|
||||
sample->low_vel = rgn->header->RangeVelocity.usLow;
|
||||
sample->high_vel = rgn->header->RangeVelocity.usHigh;
|
||||
sample->low_freq = note_to_freq(rgn->header->RangeKey.usLow);
|
||||
sample->high_freq = note_to_freq(rgn->header->RangeKey.usHigh);
|
||||
sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote);
|
||||
sample->low_vel = (BYTE)rgn->header->RangeVelocity.usLow;
|
||||
sample->high_vel = (BYTE)rgn->header->RangeVelocity.usHigh;
|
||||
|
||||
sample->modes = wave->format->wBitsPerSample == 8 ? PATCH_UNSIGNED : PATCH_16;
|
||||
sample->sample_rate = wave->format->dwSamplesPerSec;
|
||||
|
@ -1174,25 +1175,12 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
|
|||
printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release);
|
||||
*/
|
||||
|
||||
sample->envelope_offset[ATTACK] = to_offset(255);
|
||||
sample->envelope_rate[ATTACK] = calc_rate(song, 255, sample->sample_rate, attack);
|
||||
|
||||
sample->envelope_offset[HOLD] = to_offset(250);
|
||||
sample->envelope_rate[HOLD] = calc_rate(song, 5, sample->sample_rate, hold);
|
||||
|
||||
sample->envelope_offset[DECAY] = to_offset(sustain);
|
||||
sample->envelope_rate[DECAY] = calc_rate(song, 255 - sustain, sample->sample_rate, decay);
|
||||
|
||||
sample->envelope_offset[RELEASE] = to_offset(0);
|
||||
sample->envelope_rate[RELEASE] = calc_rate(song, 5 + sustain, sample->sample_rate, release);
|
||||
|
||||
sample->envelope_offset[RELEASEB] = to_offset(0);
|
||||
sample->envelope_rate[RELEASEB] = to_offset(1);
|
||||
|
||||
sample->envelope_offset[RELEASEC] = to_offset(0);
|
||||
sample->envelope_rate[RELEASEC] = to_offset(1);
|
||||
|
||||
sample->modes |= PATCH_NO_SRELEASE;
|
||||
sample->envelope.sf2.decay_vol = 0;
|
||||
sample->envelope.sf2.attack_vol = (short)attack;
|
||||
sample->envelope.sf2.hold_vol = (short)hold;
|
||||
sample->envelope.sf2.decay_vol = (short)decay;
|
||||
sample->envelope.sf2.release_vol = (short)release;
|
||||
sample->envelope.sf2.sustain_vol = (short)sustain;
|
||||
}
|
||||
|
||||
sample->data_length <<= FRACTION_BITS;
|
||||
|
@ -1236,7 +1224,6 @@ Instrument *load_instrument_dls(Renderer *song, int drum, int bank, int instrume
|
|||
}
|
||||
|
||||
inst = (Instrument *)safe_malloc(sizeof(Instrument));
|
||||
inst->type = INST_DLS;
|
||||
inst->samples = dls_ins->header->cRegions;
|
||||
inst->sample = (Sample *)safe_malloc(inst->samples * sizeof(Sample));
|
||||
memset(inst->sample, 0, inst->samples * sizeof(Sample));
|
||||
|
|
131
src/timidity/instrum_font.cpp
Normal file
131
src/timidity/instrum_font.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "m_swap.h"
|
||||
#include "templates.h"
|
||||
#include "timidity.h"
|
||||
#include "sf2.h"
|
||||
|
||||
namespace Timidity
|
||||
{
|
||||
|
||||
FontFile *Fonts;
|
||||
|
||||
FontFile *ReadDLS(const char *filename, FileReader *f)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void font_freeall()
|
||||
{
|
||||
FontFile *font, *next;
|
||||
|
||||
for (font = Fonts; font != NULL; font = next)
|
||||
{
|
||||
next = font->Next;
|
||||
delete font;
|
||||
}
|
||||
Fonts = NULL;
|
||||
}
|
||||
|
||||
FontFile *font_find(const char *filename)
|
||||
{
|
||||
for (FontFile *font = Fonts; font != NULL; font = font->Next)
|
||||
{
|
||||
if (stricmp(filename, font->Filename) == 0)
|
||||
{
|
||||
return font;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void font_add(const char *filename, int load_order)
|
||||
{
|
||||
FontFile *font;
|
||||
|
||||
font = font_find(filename);
|
||||
if (font != NULL)
|
||||
{
|
||||
font->SetAllOrders(load_order);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileReader *fp = open_filereader(filename, openmode, NULL);
|
||||
|
||||
if (fp != NULL)
|
||||
{
|
||||
if ((font = ReadSF2(filename, fp)) || (font = ReadDLS(filename, fp)))
|
||||
{
|
||||
font->SetAllOrders(load_order);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void font_remove(const char *filename)
|
||||
{
|
||||
FontFile *font;
|
||||
|
||||
font = font_find(filename);
|
||||
if (font != NULL)
|
||||
{
|
||||
// Don't actually remove the font from the list, because instruments
|
||||
// from it might be loaded using the %font extension.
|
||||
font->SetAllOrders(255);
|
||||
}
|
||||
}
|
||||
|
||||
void font_order(int order, int bank, int preset, int keynote)
|
||||
{
|
||||
for (FontFile *font = Fonts; font != NULL; font = font->Next)
|
||||
{
|
||||
font->SetOrder(order, bank, preset, keynote);
|
||||
}
|
||||
}
|
||||
|
||||
Instrument *load_instrument_font(struct Renderer *song, const char *font, int drum, int bank, int instr)
|
||||
{
|
||||
FontFile *fontfile = font_find(font);
|
||||
if (fontfile != NULL)
|
||||
{
|
||||
return fontfile->LoadInstrument(song, drum, bank, instr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Instrument *load_instrument_font_order(struct Renderer *song, int order, int drum, int bank, int instr)
|
||||
{
|
||||
for (FontFile *font = Fonts; font != NULL; font = font->Next)
|
||||
{
|
||||
Instrument *ip = font->LoadInstrument(song, drum, bank, instr);
|
||||
if (ip != NULL)
|
||||
{
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FontFile::FontFile(FString filename)
|
||||
: Filename(filename)
|
||||
{
|
||||
Next = Fonts;
|
||||
Fonts = this;
|
||||
}
|
||||
|
||||
FontFile::~FontFile()
|
||||
{
|
||||
for (FontFile **probe = &Fonts; *probe != NULL; probe = &(*probe)->Next)
|
||||
{
|
||||
if (*probe == this)
|
||||
{
|
||||
*probe = Next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
1533
src/timidity/instrum_sf2.cpp
Normal file
1533
src/timidity/instrum_sf2.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -31,68 +31,117 @@
|
|||
namespace Timidity
|
||||
{
|
||||
|
||||
/* Returns 1 if envelope runs out */
|
||||
int recompute_envelope(Voice *v)
|
||||
static int convert_envelope_rate(Renderer *song, BYTE rate)
|
||||
{
|
||||
int stage;
|
||||
int r;
|
||||
|
||||
stage = v->envelope_stage;
|
||||
r = 3 - ((rate>>6) & 0x3);
|
||||
r *= 3;
|
||||
r = (int)(rate & 0x3f) << r; /* 6.9 fixed point */
|
||||
|
||||
if (stage >= ENVELOPES)
|
||||
/* 15.15 fixed point. */
|
||||
return int(((r * 44100) / song->rate) * song->control_ratio) << 9;
|
||||
}
|
||||
|
||||
void Envelope::Init(Renderer *song, Voice *v)
|
||||
{
|
||||
Type = v->sample->type;
|
||||
env.bUpdating = true;
|
||||
if (Type == INST_GUS)
|
||||
{
|
||||
gf1.Init(song, v);
|
||||
gf1.ApplyToAmp(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
sf2.Init(song, v);
|
||||
sf2.ApplyToAmp(v);
|
||||
}
|
||||
}
|
||||
|
||||
void GF1Envelope::Init(Renderer *song, Voice *v)
|
||||
{
|
||||
/* Ramp up from 0 */
|
||||
stage = 0;
|
||||
volume = 0;
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
offset[i] = v->sample->envelope.gf1.offset[i] << (7 + 15);
|
||||
rate[i] = convert_envelope_rate(song, v->sample->envelope.gf1.rate[i]);
|
||||
}
|
||||
Recompute(v);
|
||||
}
|
||||
|
||||
void GF1Envelope::Release(Voice *v)
|
||||
{
|
||||
if (!(v->sample->modes & PATCH_NO_SRELEASE) || (v->sample->modes & PATCH_FAST_REL))
|
||||
{
|
||||
/* ramp out to minimum volume with rate from final release stage */
|
||||
stage = GF1_RELEASEC+1;
|
||||
target = 0;
|
||||
increment = -rate[GF1_RELEASEC];
|
||||
}
|
||||
else if (v->sample->modes & PATCH_SUSTAIN)
|
||||
{
|
||||
if (stage < GF1_RELEASE)
|
||||
{
|
||||
stage = GF1_RELEASE;
|
||||
}
|
||||
Recompute(v);
|
||||
}
|
||||
bUpdating = true;
|
||||
}
|
||||
|
||||
/* Returns 1 if envelope runs out */
|
||||
bool GF1Envelope::Recompute(Voice *v)
|
||||
{
|
||||
int oldstage;
|
||||
|
||||
oldstage = stage;
|
||||
|
||||
if (oldstage > GF1_RELEASEC)
|
||||
{
|
||||
/* Envelope ran out. */
|
||||
/* play sampled release */
|
||||
v->status &= ~(VOICE_SUSTAINING | VOICE_LPE);
|
||||
v->status |= VOICE_RELEASING;
|
||||
v->envelope_increment = 0;
|
||||
increment = 0;
|
||||
bUpdating = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stage == RELEASE && !(v->status & VOICE_RELEASING) && (v->sample->modes & PATCH_SUSTAIN))
|
||||
if (oldstage == GF1_RELEASE && !(v->status & VOICE_RELEASING) && (v->sample->modes & PATCH_SUSTAIN))
|
||||
{
|
||||
v->status |= VOICE_SUSTAINING;
|
||||
/* Freeze envelope until note turns off. Trumpets want this. */
|
||||
v->envelope_increment = 0;
|
||||
increment = 0;
|
||||
bUpdating = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
v->envelope_stage = stage + 1;
|
||||
stage = oldstage + 1;
|
||||
|
||||
if (v->envelope_volume == v->sample->envelope_offset[stage])
|
||||
if (volume == offset[oldstage])
|
||||
{
|
||||
return recompute_envelope(v);
|
||||
return Recompute(v);
|
||||
}
|
||||
v->envelope_target = v->sample->envelope_offset[stage];
|
||||
v->envelope_increment = v->sample->envelope_rate[stage];
|
||||
if (v->envelope_target < v->envelope_volume)
|
||||
v->envelope_increment = -v->envelope_increment;
|
||||
target = offset[oldstage];
|
||||
increment = rate[oldstage];
|
||||
if (target < volume)
|
||||
increment = -increment;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void apply_envelope_to_amp(Voice *v)
|
||||
bool GF1Envelope::Update(Voice *v)
|
||||
{
|
||||
float env_vol = v->attenuation;
|
||||
float final_amp = v->sample->volume * FINAL_MIX_SCALE;
|
||||
if (v->tremolo_phase_increment != 0)
|
||||
volume += increment;
|
||||
if (((increment < 0) && (volume <= target)) || ((increment > 0) && (volume >= target)))
|
||||
{
|
||||
env_vol *= v->tremolo_volume;
|
||||
}
|
||||
env_vol *= v->envelope_volume / float(1 << 30);
|
||||
// Note: The pan offsets are negative.
|
||||
v->left_mix = MAX(0.f, (float)calc_gf1_amp(env_vol + v->left_offset) * final_amp);
|
||||
v->right_mix = MAX(0.f, (float)calc_gf1_amp(env_vol + v->right_offset) * final_amp);
|
||||
}
|
||||
|
||||
static int update_envelope(Voice *v)
|
||||
{
|
||||
v->envelope_volume += v->envelope_increment;
|
||||
if (((v->envelope_increment < 0) && (v->envelope_volume <= v->envelope_target)) ||
|
||||
((v->envelope_increment > 0) && (v->envelope_volume >= v->envelope_target)))
|
||||
{
|
||||
v->envelope_volume = v->envelope_target;
|
||||
if (recompute_envelope(v))
|
||||
volume = target;
|
||||
if (Recompute(v))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -100,6 +149,214 @@ static int update_envelope(Voice *v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void GF1Envelope::ApplyToAmp(Voice *v)
|
||||
{
|
||||
double env_vol = v->attenuation;
|
||||
double final_amp = v->sample->volume * FINAL_MIX_SCALE;
|
||||
if (v->tremolo_phase_increment != 0)
|
||||
{ // [RH] FIXME: This is wrong. Tremolo should offset the
|
||||
// envelope volume, not scale it.
|
||||
env_vol *= v->tremolo_volume;
|
||||
}
|
||||
env_vol *= volume / float(1 << 30);
|
||||
env_vol = calc_gf1_amp(env_vol) * final_amp;
|
||||
v->left_mix = float(env_vol * v->left_offset);
|
||||
v->right_mix = float(env_vol * v->right_offset);
|
||||
}
|
||||
|
||||
void SF2Envelope::Init(Renderer *song, Voice *v)
|
||||
{
|
||||
stage = 0;
|
||||
volume = 0;
|
||||
DelayTime = v->sample->envelope.sf2.delay_vol;
|
||||
AttackTime = v->sample->envelope.sf2.attack_vol;
|
||||
HoldTime = v->sample->envelope.sf2.hold_vol;
|
||||
DecayTime = v->sample->envelope.sf2.decay_vol;
|
||||
SustainLevel = v->sample->envelope.sf2.sustain_vol;
|
||||
ReleaseTime = v->sample->envelope.sf2.release_vol;
|
||||
SampleRate = song->rate;
|
||||
HoldStart = 0;
|
||||
RateMul = song->control_ratio / song->rate;
|
||||
RateMul_cB = RateMul * 960;
|
||||
bUpdating = true;
|
||||
}
|
||||
|
||||
void SF2Envelope::Release(Voice *v)
|
||||
{
|
||||
if (stage == SF2_ATTACK)
|
||||
{
|
||||
// The attack stage does not use an attenuation in cB like all the rest.
|
||||
volume = log10(volume) * -200;
|
||||
}
|
||||
stage = SF2_RELEASE;
|
||||
bUpdating = true;
|
||||
}
|
||||
|
||||
static double timecent_to_sec(float timecent)
|
||||
{
|
||||
if (timecent == -32768)
|
||||
return 0;
|
||||
return pow(2.0, timecent / 1200.0);
|
||||
}
|
||||
|
||||
static double calc_rate(double ratemul, double sec)
|
||||
{
|
||||
if (sec < 0.006)
|
||||
sec = 0.006;
|
||||
return ratemul / sec;
|
||||
}
|
||||
|
||||
static void shutoff_voice(Voice *v)
|
||||
{
|
||||
v->status &= ~(VOICE_SUSTAINING | VOICE_LPE);
|
||||
v->status |= VOICE_RELEASING | VOICE_STOPPING;
|
||||
}
|
||||
|
||||
static bool check_release(double RateMul, double sec)
|
||||
{
|
||||
double rate = calc_rate(960 * RateMul, sec);
|
||||
|
||||
// Is release rate very fast? If so, don't do the release, but do
|
||||
// the voice off ramp instead.
|
||||
return (rate < 960/20);
|
||||
}
|
||||
|
||||
/* Returns 1 if envelope runs out */
|
||||
bool SF2Envelope::Update(Voice *v)
|
||||
{
|
||||
double sec;
|
||||
double newvolume;
|
||||
|
||||
switch (stage)
|
||||
{
|
||||
case SF2_DELAY:
|
||||
if (v->sample_count >= timecent_to_sec(DelayTime) * SampleRate)
|
||||
{
|
||||
stage = SF2_ATTACK;
|
||||
return Update(v);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case SF2_ATTACK:
|
||||
sec = timecent_to_sec(AttackTime);
|
||||
if (sec <= 0)
|
||||
{ // instantaneous attack
|
||||
newvolume = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
newvolume = volume + calc_rate(RateMul, sec);
|
||||
}
|
||||
if (newvolume >= 1)
|
||||
{
|
||||
volume = 0;
|
||||
HoldStart = v->sample_count;
|
||||
if (HoldTime <= -32768)
|
||||
{ // hold time is 0, so skip right to decay
|
||||
stage = SF2_DECAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
stage = SF2_HOLD;
|
||||
}
|
||||
return Update(v);
|
||||
}
|
||||
break;
|
||||
|
||||
case SF2_HOLD:
|
||||
if (v->sample_count - HoldStart >= timecent_to_sec(HoldTime) * SampleRate)
|
||||
{
|
||||
stage = SF2_DECAY;
|
||||
return Update(v);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case SF2_DECAY:
|
||||
sec = timecent_to_sec(DecayTime);
|
||||
if (sec <= 0)
|
||||
{ // instantaneous decay
|
||||
newvolume = SustainLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
newvolume = volume + calc_rate(RateMul_cB, sec);
|
||||
}
|
||||
if (newvolume >= SustainLevel)
|
||||
{
|
||||
newvolume = SustainLevel;
|
||||
stage = SF2_SUSTAIN;
|
||||
bUpdating = false;
|
||||
if (!(v->status & VOICE_RELEASING))
|
||||
{
|
||||
v->status |= VOICE_SUSTAINING;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SF2_SUSTAIN:
|
||||
// Stay here until released.
|
||||
return 0;
|
||||
|
||||
case SF2_RELEASE:
|
||||
sec = timecent_to_sec(ReleaseTime);
|
||||
if (sec <= 0)
|
||||
{ // instantaneous release
|
||||
newvolume = 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
newvolume = volume + calc_rate(RateMul_cB, sec);
|
||||
}
|
||||
if (newvolume >= 960)
|
||||
{
|
||||
stage = SF2_FINISHED;
|
||||
shutoff_voice(v);
|
||||
bUpdating = false;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SF2_FINISHED:
|
||||
return 1;
|
||||
}
|
||||
volume = (float)newvolume;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EMU 8k/10k don't follow spec in regards to volume attenuation.
|
||||
* This factor is used in the equation pow (10.0, cb / FLUID_ATTEN_POWER_FACTOR).
|
||||
* By the standard this should be -200.0. */
|
||||
#define FLUID_ATTEN_POWER_FACTOR (-531.509)
|
||||
#define atten2amp(x) pow(10.0, (x) / FLUID_ATTEN_POWER_FACTOR)
|
||||
|
||||
void SF2Envelope::ApplyToAmp(Voice *v)
|
||||
{
|
||||
double amp;
|
||||
|
||||
if (stage == SF2_DELAY)
|
||||
{
|
||||
v->left_mix = 0;
|
||||
v->right_mix = 0;
|
||||
return;
|
||||
}
|
||||
else if (stage == SF2_ATTACK)
|
||||
{
|
||||
amp = atten2amp(v->attenuation) * volume;
|
||||
}
|
||||
else
|
||||
{
|
||||
amp = atten2amp(v->attenuation) * cb_to_amp(volume);
|
||||
}
|
||||
amp *= FINAL_MIX_SCALE * 0.5;
|
||||
v->left_mix = float(amp * v->left_offset);
|
||||
v->right_mix = float(amp * v->right_offset);
|
||||
}
|
||||
|
||||
void apply_envelope_to_amp(Voice *v)
|
||||
{
|
||||
v->eg1.ApplyToAmp(v);
|
||||
}
|
||||
|
||||
static void update_tremolo(Voice *v)
|
||||
{
|
||||
int depth = v->sample->tremolo_depth << 7;
|
||||
|
@ -136,7 +393,7 @@ static void update_tremolo(Voice *v)
|
|||
/* Returns 1 if the note died */
|
||||
static int update_signal(Voice *v)
|
||||
{
|
||||
if (v->envelope_increment != 0 && update_envelope(v))
|
||||
if (v->eg1.env.bUpdating && v->eg1.Update(v))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -347,7 +604,7 @@ static void ramp_out(const sample_t *sp, float *lp, Voice *v, int c)
|
|||
|
||||
/* printf("Ramping out: left=%d, c=%d, li=%d\n", left, c, li); */
|
||||
|
||||
if (v->left_offset == 0) // All the way to the left
|
||||
if (v->right_mix == 0) // All the way to the left
|
||||
{
|
||||
left = v->left_mix;
|
||||
li = -(left/c);
|
||||
|
@ -362,7 +619,7 @@ static void ramp_out(const sample_t *sp, float *lp, Voice *v, int c)
|
|||
lp += 2;
|
||||
}
|
||||
}
|
||||
else if (v->right_offset == 0) // All the way to the right
|
||||
else if (v->left_mix == 0) // All the way to the right
|
||||
{
|
||||
right = v->right_mix;
|
||||
ri = -(right/c);
|
||||
|
@ -441,7 +698,7 @@ void mix_voice(Renderer *song, float *buf, Voice *v, int c)
|
|||
}
|
||||
if (v->right_mix == 0) // All the way to the left
|
||||
{
|
||||
if (v->envelope_increment != 0 || v->tremolo_phase_increment != 0)
|
||||
if (v->eg1.env.bUpdating || v->tremolo_phase_increment != 0)
|
||||
{
|
||||
mix_single_left_signal(song->control_ratio, sp, buf, v, count);
|
||||
}
|
||||
|
@ -452,7 +709,7 @@ void mix_voice(Renderer *song, float *buf, Voice *v, int c)
|
|||
}
|
||||
else if (v->left_mix == 0) // All the way to the right
|
||||
{
|
||||
if (v->envelope_increment != 0 || v->tremolo_phase_increment != 0)
|
||||
if (v->eg1.env.bUpdating || v->tremolo_phase_increment != 0)
|
||||
{
|
||||
mix_single_right_signal(song->control_ratio, sp, buf, v, count);
|
||||
}
|
||||
|
@ -463,7 +720,7 @@ void mix_voice(Renderer *song, float *buf, Voice *v, int c)
|
|||
}
|
||||
else // Somewhere in the middle
|
||||
{
|
||||
if (v->envelope_increment || v->tremolo_phase_increment)
|
||||
if (v->eg1.env.bUpdating || v->tremolo_phase_increment)
|
||||
{
|
||||
mix_mystery_signal(song->control_ratio, sp, buf, v, count);
|
||||
}
|
||||
|
@ -472,6 +729,7 @@ void mix_voice(Renderer *song, float *buf, Voice *v, int c)
|
|||
mix_mystery(song->control_ratio, sp, buf, v, count);
|
||||
}
|
||||
}
|
||||
v->sample_count += count;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,6 @@
|
|||
namespace Timidity
|
||||
{
|
||||
|
||||
static const double log_of_2 = 0.69314718055994529;
|
||||
|
||||
void Renderer::reset_voices()
|
||||
{
|
||||
for (int i = 0; i < voices; i++)
|
||||
|
@ -44,8 +42,8 @@ void Renderer::reset_voices()
|
|||
/* Process the Reset All Controllers event */
|
||||
void Renderer::reset_controllers(int c)
|
||||
{
|
||||
channel[c].volume = (100 << 7) | 100;
|
||||
channel[c].expression = 0x3fff;
|
||||
channel[c].volume = 100;
|
||||
channel[c].expression = 127;
|
||||
channel[c].sustain = 0;
|
||||
channel[c].pitchbend = 0x2000;
|
||||
channel[c].pitchfactor = 0; /* to be computed */
|
||||
|
@ -68,55 +66,6 @@ void Renderer::reset_midi()
|
|||
reset_voices();
|
||||
}
|
||||
|
||||
void Renderer::select_sample(int v, Instrument *ip, int vel)
|
||||
{
|
||||
double f, cdiff, diff;
|
||||
int s, i;
|
||||
Sample *sp, *closest;
|
||||
|
||||
s = ip->samples;
|
||||
sp = ip->sample;
|
||||
|
||||
if (s == 1)
|
||||
{
|
||||
voice[v].sample = sp;
|
||||
return;
|
||||
}
|
||||
|
||||
f = voice[v].orig_frequency;
|
||||
for (i = 0; i < s; i++)
|
||||
{
|
||||
if (sp->low_vel <= vel && sp->high_vel >= vel &&
|
||||
sp->low_freq <= f && sp->high_freq >= f)
|
||||
{
|
||||
voice[v].sample = sp;
|
||||
return;
|
||||
}
|
||||
sp++;
|
||||
}
|
||||
|
||||
/*
|
||||
No suitable sample found! We'll select the sample whose root
|
||||
frequency is closest to the one we want. (Actually we should
|
||||
probably convert the low, high, and root frequencies to MIDI note
|
||||
values and compare those.) */
|
||||
|
||||
cdiff = 1e10;
|
||||
closest = sp = ip->sample;
|
||||
for (i = 0; i < s; i++)
|
||||
{
|
||||
diff = fabs(sp->root_freq - f);
|
||||
if (diff < cdiff)
|
||||
{
|
||||
cdiff = diff;
|
||||
closest = sp;
|
||||
}
|
||||
sp++;
|
||||
}
|
||||
voice[v].sample = closest;
|
||||
return;
|
||||
}
|
||||
|
||||
void Renderer::recompute_freq(int v)
|
||||
{
|
||||
Channel *ch = &channel[voice[v].channel];
|
||||
|
@ -210,37 +159,59 @@ void Renderer::recompute_amp(Voice *v)
|
|||
int chanvol = chan->volume;
|
||||
int chanexpr = chan->expression;
|
||||
|
||||
v->attenuation = (vol_table[(chanvol * chanexpr) / 2113407] * vol_table[v->velocity]) * ((127 + 64) / 12419775.f);
|
||||
}
|
||||
|
||||
void Renderer::compute_pan(int panning, float &left_offset, float &right_offset)
|
||||
{
|
||||
// Round the left- and right-most positions to their extremes, since
|
||||
// most songs only do coarse panning.
|
||||
if (panning < 128)
|
||||
if (v->sample->type == INST_GUS)
|
||||
{
|
||||
panning = 0;
|
||||
}
|
||||
else if (panning > 127*128)
|
||||
{
|
||||
panning = 32767;
|
||||
}
|
||||
|
||||
if (panning == 0)
|
||||
{
|
||||
left_offset = 0;
|
||||
right_offset = (float)-HUGE_VAL;
|
||||
}
|
||||
else if (panning == 32767)
|
||||
{
|
||||
left_offset = (float)-HUGE_VAL;
|
||||
right_offset = 0;
|
||||
v->attenuation = (vol_table[(chanvol * chanexpr) / 127] * vol_table[v->velocity]) * ((127 + 64) / 12419775.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
double pan = panning * (1 / 32767.0);
|
||||
right_offset = (float)(log(pan) * (1 / (log_of_2 * 32)));
|
||||
left_offset = (float)(log(1 - pan) * (1 / (log_of_2 * 32)));
|
||||
// Implicit modulators from SF2 spec
|
||||
double velatten, cc7atten, cc11atten;
|
||||
|
||||
velatten = log10(127.0 / v->velocity);
|
||||
cc7atten = log10(127.0 / chanvol);
|
||||
cc11atten = log10(127.0 / chanexpr);
|
||||
v->attenuation = float(400 * (velatten + cc7atten + cc11atten)) + v->sample->initial_attenuation;
|
||||
}
|
||||
}
|
||||
|
||||
// Pan must be in the range [0,1]
|
||||
void Renderer::compute_pan(double pan, int type, float &left_offset, float &right_offset)
|
||||
{
|
||||
if (pan <= 0)
|
||||
{
|
||||
left_offset = 1;
|
||||
right_offset = 0;
|
||||
}
|
||||
else if (pan >= 127/128.0)
|
||||
{
|
||||
left_offset = 0;
|
||||
right_offset = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == INST_GUS)
|
||||
{
|
||||
/* Original amp equation looks like this:
|
||||
* calc_gf1_amp(atten + offset)
|
||||
* which expands to:
|
||||
* 2^(16*(atten + offset) - 16)
|
||||
* Keeping in mind that 2^(x + y) == 2^x * 2^y, we can
|
||||
* rewrite this to avoid doing two pows in GF1Envelope::ApplyToAmp():
|
||||
* 2^(16*atten + 16*offset - 16)
|
||||
* 2^(16*atten - 16 + 16 * offset + 16 - 16)
|
||||
* 2^(16*atten - 16) * 2^(16*offset + 16 - 16)
|
||||
* 2^(16*atten - 16) * 2^(16*(offset + 1) - 16)
|
||||
* calc_gf1_amp(atten) * calc_gf1_amp(offset + 1)
|
||||
*/
|
||||
right_offset = (float)calc_gf1_amp((log(pan) * (1 / (log_of_2 * 32))) + 1);
|
||||
left_offset = (float)calc_gf1_amp((log(1 - pan) * (1 / (log_of_2 * 32))) + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
left_offset = (float)db_to_amp(-20 * log10(sqrt(1 - pan)));
|
||||
right_offset = (float)db_to_amp(-20 * log10(sqrt(pan)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,17 +235,112 @@ void Renderer::kill_key_group(int i)
|
|||
|
||||
float Renderer::calculate_scaled_frequency(Sample *sp, int note)
|
||||
{
|
||||
double scalednote = (note - sp->scale_note) * sp->scale_factor / 1024.0 + sp->scale_note;
|
||||
double scalednote = (note - sp->scale_note) * sp->scale_factor / 1024.0 + sp->scale_note + sp->tune * 0.01;
|
||||
return (float)note_to_freq(scalednote);
|
||||
}
|
||||
|
||||
void Renderer::start_note(int chan, int note, int vel, int i)
|
||||
bool Renderer::start_region(int chan, int note, int vel, Sample *sp, float f)
|
||||
{
|
||||
int voicenum;
|
||||
Voice *v;
|
||||
|
||||
voicenum = allocate_voice();
|
||||
if (voicenum < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
v = &voice[voicenum];
|
||||
v->sample = sp;
|
||||
|
||||
if (sp->type == INST_GUS)
|
||||
{
|
||||
v->orig_frequency = f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sp->scale_factor != 1024)
|
||||
{
|
||||
v->orig_frequency = calculate_scaled_frequency(sp, note);
|
||||
}
|
||||
else if (sp->tune != 0)
|
||||
{
|
||||
v->orig_frequency = note_to_freq(note + sp->tune * 0.01);
|
||||
}
|
||||
else
|
||||
{
|
||||
v->orig_frequency = note_to_freq(note);
|
||||
}
|
||||
}
|
||||
|
||||
v->status = VOICE_RUNNING;
|
||||
v->channel = chan;
|
||||
v->note = note;
|
||||
v->velocity = vel;
|
||||
v->sample_offset = 0;
|
||||
v->sample_increment = 0; /* make sure it isn't negative */
|
||||
v->sample_count = 0;
|
||||
|
||||
v->tremolo_phase = 0;
|
||||
v->tremolo_phase_increment = v->sample->tremolo_phase_increment;
|
||||
v->tremolo_sweep = v->sample->tremolo_sweep_increment;
|
||||
v->tremolo_sweep_position = 0;
|
||||
|
||||
v->vibrato_sweep = v->sample->vibrato_sweep_increment;
|
||||
v->vibrato_sweep_position = 0;
|
||||
v->vibrato_control_ratio = v->sample->vibrato_control_ratio;
|
||||
v->vibrato_control_counter = v->vibrato_phase = 0;
|
||||
|
||||
kill_key_group(voicenum);
|
||||
|
||||
memset(v->vibrato_sample_increment, 0, sizeof(v->vibrato_sample_increment));
|
||||
|
||||
if (sp->type == INST_SF2)
|
||||
{
|
||||
// Channel pan is added to instrument pan.
|
||||
double pan;
|
||||
if (channel[chan].panning == NO_PANNING)
|
||||
{
|
||||
pan = (sp->panning + 500) / 1000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pan = channel[chan].panning / 128.0 + sp->panning / 1000.0;
|
||||
}
|
||||
compute_pan(pan, sp->type, v->left_offset, v->right_offset);
|
||||
}
|
||||
else if (channel[chan].panning != NO_PANNING)
|
||||
{
|
||||
compute_pan(channel[chan].panning / 128.0, sp->type, v->left_offset, v->right_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
v->left_offset = v->sample->left_offset;
|
||||
v->right_offset = v->sample->right_offset;
|
||||
}
|
||||
|
||||
recompute_freq(voicenum);
|
||||
recompute_amp(v);
|
||||
v->control_counter = 0;
|
||||
|
||||
v->eg1.Init(this, v);
|
||||
|
||||
if (v->sample->modes & PATCH_LOOPEN)
|
||||
{
|
||||
v->status |= VOICE_LPE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::start_note(int chan, int note, int vel)
|
||||
{
|
||||
Instrument *ip;
|
||||
Sample *sp;
|
||||
int bank = channel[chan].bank;
|
||||
int prog = channel[chan].program;
|
||||
Voice *v = &voice[i];
|
||||
int i;
|
||||
float f;
|
||||
|
||||
note &= 0x7f;
|
||||
if (ISDRUMCHANNEL(chan))
|
||||
{
|
||||
if (NULL == drumset[bank] || NULL == (ip = drumset[bank]->instrument[note]))
|
||||
|
@ -282,7 +348,12 @@ void Renderer::start_note(int chan, int note, int vel, int i)
|
|||
if (!(ip = drumset[0]->instrument[note]))
|
||||
return; /* No instrument? Then we can't play. */
|
||||
}
|
||||
if (ip->type == INST_GUS && ip->samples != 1)
|
||||
assert(ip != MAGIC_LOAD_INSTRUMENT);
|
||||
if (ip == MAGIC_LOAD_INSTRUMENT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (ip->samples != 1 && ip->sample->type == INST_GUS)
|
||||
{
|
||||
cmsg(CMSG_WARNING, VERB_VERBOSE,
|
||||
"Strange: percussion instrument with %d samples!", ip->samples);
|
||||
|
@ -299,62 +370,85 @@ void Renderer::start_note(int chan, int note, int vel, int i)
|
|||
if (NULL == (ip = tonebank[0]->instrument[prog]))
|
||||
return; /* No instrument? Then we can't play. */
|
||||
}
|
||||
}
|
||||
if (ip->sample->scale_factor != 1024)
|
||||
assert(ip != MAGIC_LOAD_INSTRUMENT);
|
||||
if (ip == MAGIC_LOAD_INSTRUMENT)
|
||||
{
|
||||
v->orig_frequency = calculate_scaled_frequency(ip->sample, note & 0x7F);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == ip->sample || ip->samples == 0)
|
||||
return; /* No samples? Then nothing to play. */
|
||||
|
||||
// For GF1 patches, scaling is based solely on the first
|
||||
// waveform in this layer.
|
||||
if (ip->sample->type == INST_GUS && ip->sample->scale_factor != 1024)
|
||||
{
|
||||
f = calculate_scaled_frequency(ip->sample, note);
|
||||
}
|
||||
else
|
||||
{
|
||||
v->orig_frequency = note_to_freq(note & 0x7F);
|
||||
f = note_to_freq(note);
|
||||
}
|
||||
select_sample(i, ip, vel);
|
||||
|
||||
v->status = VOICE_RUNNING;
|
||||
v->channel = chan;
|
||||
v->note = note;
|
||||
v->velocity = vel;
|
||||
v->sample_offset = 0;
|
||||
v->sample_increment = 0; /* make sure it isn't negative */
|
||||
|
||||
v->tremolo_phase = 0;
|
||||
v->tremolo_phase_increment = voice[i].sample->tremolo_phase_increment;
|
||||
v->tremolo_sweep = voice[i].sample->tremolo_sweep_increment;
|
||||
v->tremolo_sweep_position = 0;
|
||||
|
||||
v->vibrato_sweep = voice[i].sample->vibrato_sweep_increment;
|
||||
v->vibrato_sweep_position = 0;
|
||||
v->vibrato_control_ratio = voice[i].sample->vibrato_control_ratio;
|
||||
v->vibrato_control_counter = voice[i].vibrato_phase = 0;
|
||||
|
||||
kill_key_group(i);
|
||||
|
||||
memset(v->vibrato_sample_increment, 0, sizeof(v->vibrato_sample_increment));
|
||||
|
||||
if (channel[chan].panning != NO_PANNING)
|
||||
if (ip->sample->type == INST_GUS)
|
||||
{
|
||||
v->left_offset = channel[chan].left_offset;
|
||||
v->right_offset = channel[chan].right_offset;
|
||||
/* We're more lenient with matching ranges for GUS patches, since the
|
||||
* official Gravis ones don't cover the full range of possible
|
||||
* frequencies for every instrument.
|
||||
*/
|
||||
if (ip->samples == 1)
|
||||
{ // If there's only one sample, definitely play it.
|
||||
start_region(chan, note, vel, ip->sample, f);
|
||||
}
|
||||
for (i = ip->samples, sp = ip->sample; i != 0; --i, ++sp)
|
||||
{
|
||||
// GUS patches don't have velocity ranges, so no need to compare against them.
|
||||
if (sp->low_freq <= f && sp->high_freq >= f)
|
||||
{
|
||||
if (i > 1 && (sp + 1)->low_freq <= f && (sp + 1)->high_freq >= f)
|
||||
{ /* If there is a range of contiguous regions that match our
|
||||
* desired frequency, the last one in that block is used.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
start_region(chan, note, vel, sp, f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 0)
|
||||
{ /* Found nothing. Try again, but look for the one with the closest root frequency.
|
||||
* As per the suggestion in the original TiMidity function, this search uses
|
||||
* note values rather than raw frequencies.
|
||||
*/
|
||||
double cdiff = 1e10;
|
||||
double want_note = freq_to_note(f);
|
||||
Sample *closest = sp = ip->sample;
|
||||
for (i = ip->samples; i != 0; --i, ++sp)
|
||||
{
|
||||
double diff = fabs(freq_to_note(sp->root_freq) - want_note);
|
||||
if (diff < cdiff)
|
||||
{
|
||||
cdiff = diff;
|
||||
closest = sp;
|
||||
}
|
||||
}
|
||||
start_region(chan, note, vel, closest, f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
v->left_offset = v->sample->left_offset;
|
||||
v->right_offset = v->sample->right_offset;
|
||||
}
|
||||
|
||||
recompute_freq(i);
|
||||
recompute_amp(v);
|
||||
|
||||
/* Ramp up from 0 */
|
||||
v->envelope_stage = ATTACK;
|
||||
v->envelope_volume = 0;
|
||||
v->control_counter = 0;
|
||||
recompute_envelope(v);
|
||||
apply_envelope_to_amp(v);
|
||||
|
||||
if (v->sample->modes & PATCH_LOOPEN)
|
||||
for (i = ip->samples, sp = ip->sample; i != 0; --i, ++sp)
|
||||
{
|
||||
v->status |= VOICE_LPE;
|
||||
if ((sp->low_vel <= vel && sp->high_vel >= vel &&
|
||||
sp->low_freq <= f && sp->high_freq >= f))
|
||||
{
|
||||
if (!start_region(chan, note, vel, sp, f))
|
||||
{ // Ran out of voices
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,47 +463,22 @@ void Renderer::kill_note(int i)
|
|||
}
|
||||
}
|
||||
|
||||
/* Only one instance of a note can be playing on a single channel. */
|
||||
void Renderer::note_on(int chan, int note, int vel)
|
||||
int Renderer::allocate_voice()
|
||||
{
|
||||
if (vel == 0)
|
||||
{
|
||||
note_off(chan, note, 0);
|
||||
return;
|
||||
}
|
||||
int i, lowest;
|
||||
float lv, v;
|
||||
|
||||
int i = voices, lowest = -1;
|
||||
float lv = 1e10, v;
|
||||
|
||||
while (i--)
|
||||
for (i = 0; i < voices; ++i)
|
||||
{
|
||||
if (!(voice[i].status & VOICE_RUNNING))
|
||||
{
|
||||
lowest = i; /* Can't get a lower volume than silence */
|
||||
return i; /* Can't get a lower volume than silence */
|
||||
}
|
||||
else if (voice[i].channel == chan && ((voice[i].note == note && !voice[i].sample->self_nonexclusive) || channel[chan].mono))
|
||||
{
|
||||
if (channel[chan].mono)
|
||||
{
|
||||
kill_note(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
finish_note(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lowest != -1)
|
||||
{
|
||||
/* Found a free voice. */
|
||||
start_note(chan, note, vel, lowest);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Look for the decaying note with the lowest volume */
|
||||
if (lowest == -1)
|
||||
{
|
||||
lowest = -1;
|
||||
lv = 1e10;
|
||||
i = voices;
|
||||
while (i--)
|
||||
{
|
||||
|
@ -423,9 +492,8 @@ void Renderer::note_on(int chan, int note, int vel)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lowest != -1)
|
||||
if (lowest >= 0)
|
||||
{
|
||||
/* This can still cause a click, but if we had a free voice to
|
||||
spare for ramping down this note, we wouldn't need to kill it
|
||||
|
@ -434,12 +502,41 @@ void Renderer::note_on(int chan, int note, int vel)
|
|||
|
||||
cut_notes++;
|
||||
voice[lowest].status = 0;
|
||||
start_note(chan, note, vel, lowest);
|
||||
}
|
||||
else
|
||||
{
|
||||
lost_notes++;
|
||||
}
|
||||
return lowest;
|
||||
}
|
||||
|
||||
void Renderer::note_on(int chan, int note, int vel)
|
||||
{
|
||||
if (vel == 0)
|
||||
{
|
||||
note_off(chan, note, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int i = voices;
|
||||
|
||||
/* Only one instance of a note can be playing on a single channel. */
|
||||
while (i--)
|
||||
{
|
||||
if (voice[i].channel == chan && ((voice[i].note == note && !voice[i].sample->self_nonexclusive) || channel[chan].mono))
|
||||
{
|
||||
if (channel[chan].mono)
|
||||
{
|
||||
kill_note(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
finish_note(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start_note(chan, note, vel);
|
||||
}
|
||||
|
||||
void Renderer::finish_note(int i)
|
||||
|
@ -455,23 +552,8 @@ void Renderer::finish_note(int i)
|
|||
{
|
||||
v->status &= ~VOICE_LPE; /* sampled release */
|
||||
}
|
||||
if (!(v->sample->modes & PATCH_NO_SRELEASE) || (v->sample->modes & PATCH_FAST_REL))
|
||||
{
|
||||
/* ramp out to minimum volume with rate from final release stage */
|
||||
v->envelope_stage = RELEASEC;
|
||||
recompute_envelope(v);
|
||||
// Get rate from the final release ramp, but force the target to 0.
|
||||
v->envelope_target = 0;
|
||||
v->envelope_increment = -v->sample->envelope_rate[RELEASEC];
|
||||
}
|
||||
else if (v->sample->modes & PATCH_SUSTAIN)
|
||||
{
|
||||
if (v->envelope_stage < RELEASE)
|
||||
{
|
||||
v->envelope_stage = RELEASE;
|
||||
}
|
||||
recompute_envelope(v);
|
||||
}
|
||||
v->eg1.Release(v);
|
||||
v->eg2.Release(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,15 +636,19 @@ void Renderer::adjust_pressure(int chan, int note, int amount)
|
|||
void Renderer::adjust_panning(int chan)
|
||||
{
|
||||
Channel *chanp = &channel[chan];
|
||||
compute_pan(chanp->panning, chanp->left_offset, chanp->right_offset);
|
||||
int i = voices;
|
||||
while (i--)
|
||||
{
|
||||
if ((voice[i].channel == chan) && (voice[i].status & VOICE_RUNNING))
|
||||
Voice *v = &voice[i];
|
||||
if ((v->channel == chan) && (v->status & VOICE_RUNNING))
|
||||
{
|
||||
voice[i].left_offset = chanp->left_offset;
|
||||
voice[i].right_offset = chanp->right_offset;
|
||||
apply_envelope_to_amp(&voice[i]);
|
||||
double pan = chanp->panning / 128.0;
|
||||
if (v->sample->type == INST_SF2)
|
||||
{ // Add instrument pan to channel pan.
|
||||
pan += v->sample->panning / 500.0;
|
||||
}
|
||||
compute_pan(pan, v->sample->type, v->left_offset, v->right_offset);
|
||||
apply_envelope_to_amp(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -674,32 +760,17 @@ void Renderer::HandleController(int chan, int ctrl, int val)
|
|||
break;
|
||||
|
||||
case CTRL_VOLUME:
|
||||
channel[chan].volume = (channel[chan].volume & 0x007F) | (val << 7);
|
||||
adjust_volume(chan);
|
||||
break;
|
||||
|
||||
case CTRL_VOLUME+32:
|
||||
channel[chan].volume = (channel[chan].volume & 0x3F80) | (val);
|
||||
channel[chan].volume = val;
|
||||
adjust_volume(chan);
|
||||
break;
|
||||
|
||||
case CTRL_EXPRESSION:
|
||||
channel[chan].expression = (channel[chan].expression & 0x007F) | (val << 7);
|
||||
adjust_volume(chan);
|
||||
break;
|
||||
|
||||
case CTRL_EXPRESSION+32:
|
||||
channel[chan].expression = (channel[chan].expression & 0x3F80) | (val);
|
||||
channel[chan].expression = val;
|
||||
adjust_volume(chan);
|
||||
break;
|
||||
|
||||
case CTRL_PAN:
|
||||
channel[chan].panning = (channel[chan].panning & 0x007F) | (val << 7);
|
||||
adjust_panning(chan);
|
||||
break;
|
||||
|
||||
case CTRL_PAN+32:
|
||||
channel[chan].panning = (channel[chan].panning & 0x3F80) | (val);
|
||||
channel[chan].panning = val;
|
||||
adjust_panning(chan);
|
||||
break;
|
||||
|
||||
|
|
|
@ -509,6 +509,14 @@ sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr)
|
|||
/* Need to resample. Use the proper function. */
|
||||
modes = vp->sample->modes;
|
||||
|
||||
if (vp->status & VOICE_LPE)
|
||||
{
|
||||
if (vp->sample->loop_end - vp->sample->loop_start < 2)
|
||||
{ // Loop is too short; turn it off.
|
||||
vp->status &= ~VOICE_LPE;
|
||||
}
|
||||
}
|
||||
|
||||
if (vp->vibrato_control_ratio)
|
||||
{
|
||||
if (vp->status & VOICE_LPE)
|
||||
|
|
318
src/timidity/sf2.h
Normal file
318
src/timidity/sf2.h
Normal file
|
@ -0,0 +1,318 @@
|
|||
typedef WORD SFGenerator;
|
||||
|
||||
struct SFRange
|
||||
{
|
||||
BYTE Lo;
|
||||
BYTE Hi;
|
||||
};
|
||||
|
||||
struct SFPreset
|
||||
{
|
||||
char Name[21];
|
||||
BYTE LoadOrder:7;
|
||||
BYTE bHasGlobalZone:1;
|
||||
WORD Program;
|
||||
WORD Bank;
|
||||
WORD BagIndex;
|
||||
/* Don't care about library, genre, and morphology */
|
||||
};
|
||||
|
||||
struct SFBag
|
||||
{
|
||||
WORD GenIndex;
|
||||
// WORD ModIndex; // If I am feeling ambitious, I might add support for modulators some day.
|
||||
SFRange KeyRange;
|
||||
SFRange VelRange;
|
||||
int Target; // Either an instrument or sample index
|
||||
};
|
||||
|
||||
struct SFInst
|
||||
{
|
||||
char Name[21];
|
||||
BYTE Pad:7;
|
||||
BYTE bHasGlobalZone:1;
|
||||
WORD BagIndex;
|
||||
};
|
||||
|
||||
struct SFSample
|
||||
{
|
||||
float *InMemoryData;
|
||||
DWORD Start;
|
||||
DWORD End;
|
||||
DWORD StartLoop;
|
||||
DWORD EndLoop;
|
||||
DWORD SampleRate;
|
||||
BYTE OriginalPitch;
|
||||
SBYTE PitchCorrection;
|
||||
WORD SampleLink;
|
||||
WORD SampleType;
|
||||
char Name[21];
|
||||
};
|
||||
|
||||
// Sample type bit fields (all but ROM are mutually exclusive)
|
||||
enum
|
||||
{
|
||||
SFST_Mono = 1,
|
||||
SFST_Right = 2,
|
||||
SFST_Left = 4,
|
||||
SFST_Linked = 8, /* SF2.04 defines this bit but not its function */
|
||||
SFST_Bad = 16384, /* Used internally */
|
||||
SFST_ROM = 32768
|
||||
};
|
||||
|
||||
// Generator definitions
|
||||
|
||||
struct SFGenList
|
||||
{
|
||||
SFGenerator Oper;
|
||||
union
|
||||
{
|
||||
SFRange Range;
|
||||
SWORD Amount;
|
||||
WORD uAmount;
|
||||
};
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GEN_startAddrsOffset,
|
||||
GEN_endAddrsOffset,
|
||||
GEN_startloopAddrsOffset,
|
||||
GEN_endloopAddrsOffset,
|
||||
GEN_startAddrsCoarseOffset,
|
||||
GEN_modLfoToPitch,
|
||||
GEN_vibLfoToPitch,
|
||||
GEN_modEnvToPitch,
|
||||
GEN_initialFilterFC,
|
||||
GEN_initialFilterQ,
|
||||
GEN_modLfoToFilterFc,
|
||||
GEN_modEnvToFilterFc,
|
||||
GEN_endAddrsCoarseOffset,
|
||||
GEN_modLfoToVolume,
|
||||
GEN_unused1,
|
||||
GEN_chorusEffectsSend,
|
||||
GEN_reverbEffectsSend,
|
||||
GEN_pan,
|
||||
GEN_unused2,
|
||||
GEN_unused3,
|
||||
GEN_unused4,
|
||||
GEN_delayModLFO,
|
||||
GEN_freqModLFO,
|
||||
GEN_delayVibLFO,
|
||||
GEN_freqVibLFO,
|
||||
GEN_delayModEnv,
|
||||
GEN_attackModEnv,
|
||||
GEN_holdModEnv,
|
||||
GEN_decayModEnv,
|
||||
GEN_sustainModEnv,
|
||||
GEN_releaseModEnv,
|
||||
GEN_keynumToModEnvHold,
|
||||
GEN_keynumToModEnvDecay,
|
||||
GEN_delayVolEnv,
|
||||
GEN_attackVolEnv,
|
||||
GEN_holdVolEnv,
|
||||
GEN_decayVolEnv,
|
||||
GEN_sustainVolEnv,
|
||||
GEN_releaseVolEnv,
|
||||
GEN_keynumToVolEnvHold,
|
||||
GEN_keynumToVolEnvDecay,
|
||||
GEN_instrument,
|
||||
GEN_reserved1,
|
||||
GEN_keyRange,
|
||||
GEN_velRange,
|
||||
GEN_startloopAddrsCoarseOffset,
|
||||
GEN_keynum,
|
||||
GEN_velocity,
|
||||
GEN_initialAttenuation,
|
||||
GEN_reserved2,
|
||||
GEN_endloopAddrsCoarseOffset,
|
||||
GEN_coarseTune,
|
||||
GEN_fineTune,
|
||||
GEN_sampleID,
|
||||
GEN_sampleModes,
|
||||
GEN_reserved3,
|
||||
GEN_scaleTuning,
|
||||
GEN_exclusiveClass,
|
||||
GEN_overridingRootKey,
|
||||
|
||||
GEN_NumGenerators
|
||||
};
|
||||
|
||||
// Modulator definitions
|
||||
|
||||
struct SFModulator
|
||||
{
|
||||
WORD Index:7;
|
||||
WORD CC:1;
|
||||
WORD Dir:1; /* 0 = min->max, 1 = max->min */
|
||||
WORD Polarity:1; /* 0 = unipolar, 1 = bipolar */
|
||||
WORD Type:6;
|
||||
};
|
||||
|
||||
struct SFModList
|
||||
{
|
||||
SFModulator SrcOper;
|
||||
SFGenerator DestOper;
|
||||
SWORD Amount;
|
||||
SFModulator AmtSrcOper;
|
||||
WORD Transform;
|
||||
};
|
||||
|
||||
// Modulator sources when CC is 0
|
||||
|
||||
enum
|
||||
{
|
||||
SFMod_One = 0, // Psuedo-controller that always has the value 1
|
||||
SFMod_NoteVelocity = 2,
|
||||
SFMod_KeyNumber = 3,
|
||||
SFMod_PolyPressure = 10,
|
||||
SFMod_ChannelPressure = 13,
|
||||
SFMod_PitchWheel = 14,
|
||||
SFMod_PitchSens = 16,
|
||||
SFMod_Link = 127
|
||||
};
|
||||
|
||||
// Modulator types
|
||||
|
||||
enum
|
||||
{
|
||||
SFModType_Linear,
|
||||
SFModType_Concave, // log(fabs(value)/(max value)^2)
|
||||
SFModType_Convex,
|
||||
SFModType_Switch
|
||||
};
|
||||
|
||||
// Modulator transforms
|
||||
|
||||
enum
|
||||
{
|
||||
SFModTrans_Linear = 0,
|
||||
SFModTrans_Abs = 2
|
||||
};
|
||||
|
||||
// All possible generators in a single structure
|
||||
|
||||
struct SFGenComposite
|
||||
{
|
||||
union
|
||||
{
|
||||
SFRange keyRange; // For normal use
|
||||
struct // For intermediate percussion use
|
||||
{
|
||||
BYTE drumset;
|
||||
BYTE key;
|
||||
};
|
||||
};
|
||||
SFRange velRange;
|
||||
union
|
||||
{
|
||||
WORD instrument; // At preset level
|
||||
WORD sampleID; // At instrument level
|
||||
};
|
||||
SWORD modLfoToPitch;
|
||||
SWORD vibLfoToPitch;
|
||||
SWORD modEnvToPitch;
|
||||
SWORD initialFilterFc;
|
||||
SWORD initialFilterQ;
|
||||
SWORD modLfoToFilterFc;
|
||||
SWORD modEnvToFilterFc;
|
||||
SWORD modLfoToVolume;
|
||||
SWORD chorusEffectsSend;
|
||||
SWORD reverbEffectsSend;
|
||||
SWORD pan;
|
||||
SWORD delayModLFO;
|
||||
SWORD freqModLFO;
|
||||
SWORD delayVibLFO;
|
||||
SWORD freqVibLFO;
|
||||
SWORD delayModEnv;
|
||||
SWORD attackModEnv;
|
||||
SWORD holdModEnv;
|
||||
SWORD decayModEnv;
|
||||
SWORD sustainModEnv;
|
||||
SWORD releaseModEnv;
|
||||
SWORD keynumToModEnvHold;
|
||||
SWORD keynumToModEnvDecay;
|
||||
SWORD delayVolEnv;
|
||||
SWORD attackVolEnv;
|
||||
SWORD holdVolEnv;
|
||||
SWORD decayVolEnv;
|
||||
SWORD sustainVolEnv;
|
||||
SWORD releaseVolEnv;
|
||||
SWORD keynumToVolEnvHold;
|
||||
SWORD keynumToVolEnvDecay;
|
||||
SWORD initialAttenuation;
|
||||
SWORD coarseTune;
|
||||
SWORD fineTune;
|
||||
SWORD scaleTuning;
|
||||
|
||||
// The following are only for instruments:
|
||||
SWORD startAddrsOffset, startAddrsCoarseOffset;
|
||||
SWORD endAddrsOffset, endAddrsCoarseOffset;
|
||||
SWORD startLoopAddrsOffset, startLoopAddrsCoarseOffset;
|
||||
SWORD endLoopAddrsOffset, endLoopAddrsCoarseOffset;
|
||||
SWORD keynum;
|
||||
SWORD velocity;
|
||||
WORD sampleModes;
|
||||
SWORD exclusiveClass;
|
||||
SWORD overridingRootKey;
|
||||
};
|
||||
|
||||
// Intermediate percussion representation
|
||||
|
||||
struct SFPerc
|
||||
{
|
||||
SFPreset *Preset;
|
||||
SFGenComposite Generators;
|
||||
BYTE LoadOrder;
|
||||
};
|
||||
|
||||
// Container for all parameters from a SoundFont file
|
||||
|
||||
struct SFFile : public Timidity::FontFile
|
||||
{
|
||||
SFFile(FString filename);
|
||||
~SFFile();
|
||||
Timidity::Instrument *LoadInstrument(struct Timidity::Renderer *song, int drum, int bank, int program);
|
||||
Timidity::Instrument *LoadInstrumentOrder(struct Timidity::Renderer *song, int order, int drum, int bank, int program);
|
||||
void SetOrder(int order, int drum, int bank, int program);
|
||||
void SetAllOrders(int order);
|
||||
|
||||
bool FinalStructureTest();
|
||||
void CheckBags();
|
||||
void CheckZones(int start, int stop, bool instr);
|
||||
void TranslatePercussions();
|
||||
void TranslatePercussionPreset(SFPreset *preset);
|
||||
void TranslatePercussionPresetZone(SFPreset *preset, SFBag *zone);
|
||||
|
||||
void SetInstrumentGenerators(SFGenComposite *composite, int start, int stop);
|
||||
void AddPresetGenerators(SFGenComposite *composite, int start, int stop, SFPreset *preset);
|
||||
void AddPresetGenerators(SFGenComposite *composite, int start, int stop, bool gen_set[GEN_NumGenerators]);
|
||||
|
||||
Timidity::Instrument *LoadPercussion(Timidity::Renderer *song, SFPerc *perc);
|
||||
Timidity::Instrument *LoadPreset(Timidity::Renderer *song, SFPreset *preset);
|
||||
void LoadSample(SFSample *sample);
|
||||
void ApplyGeneratorsToRegion(SFGenComposite *gen, SFSample *sfsamp, Timidity::Renderer *song, Timidity::Sample *sp);
|
||||
|
||||
SFPreset *Presets;
|
||||
SFBag *PresetBags;
|
||||
SFGenList *PresetGenerators;
|
||||
SFInst *Instruments;
|
||||
SFBag *InstrBags;
|
||||
SFGenList *InstrGenerators;
|
||||
SFSample *Samples;
|
||||
TArray<SFPerc> Percussion;
|
||||
int MinorVersion;
|
||||
DWORD SampleDataOffset;
|
||||
DWORD SampleDataLSBOffset;
|
||||
DWORD SizeSampleData;
|
||||
DWORD SizeSampleDataLSB;
|
||||
int NumPresets;
|
||||
int NumPresetBags;
|
||||
int NumPresetGenerators;
|
||||
int NumInstruments;
|
||||
int NumInstrBags;
|
||||
int NumInstrGenerators;
|
||||
int NumSamples;
|
||||
};
|
||||
|
||||
SFFile *ReadSF2(const char *filename, FileReader *f);
|
|
@ -28,6 +28,7 @@
|
|||
#include "m_alloc.h"
|
||||
#include "cmdlib.h"
|
||||
#include "c_cvars.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "i_system.h"
|
||||
#include "files.h"
|
||||
|
||||
|
@ -42,13 +43,10 @@ ToneBank *tonebank[MAXBANK], *drumset[MAXBANK];
|
|||
static FString def_instr_name;
|
||||
int openmode = OM_FILEORLUMP;
|
||||
|
||||
|
||||
#define MAXWORDS 10
|
||||
|
||||
static int read_config_file(const char *name, bool ismain)
|
||||
{
|
||||
FileReader *fp;
|
||||
char tmp[1024], *w[MAXWORDS], *cp;
|
||||
char tmp[1024], *cp;
|
||||
ToneBank *bank = NULL;
|
||||
int i, j, k, line = 0, words;
|
||||
static int rcf_count = 0;
|
||||
|
@ -81,17 +79,29 @@ static int read_config_file(const char *name, bool ismain)
|
|||
while (fp->Gets(tmp, sizeof(tmp)))
|
||||
{
|
||||
line++;
|
||||
w[words = 0] = strtok(tmp, " \t\r\n\240");
|
||||
if (!w[0]) continue;
|
||||
FCommandLine w(tmp, true);
|
||||
words = w.argc();
|
||||
if (words == 0) continue;
|
||||
|
||||
/* Originally the TiMidity++ extensions were prefixed like this */
|
||||
if (strcmp(w[0], "#extension") == 0)
|
||||
words = -1;
|
||||
{
|
||||
w.Shift();
|
||||
words--;
|
||||
}
|
||||
else if (*w[0] == '#')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
while (w[words] && *w[words] != '#' && (words < MAXWORDS))
|
||||
w[++words] = strtok(0, " \t\r\n\240");
|
||||
for (i = 0; i < words; ++i)
|
||||
{
|
||||
if (*w[i] == '#')
|
||||
{
|
||||
words = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TiMidity++ adds a number of extensions to the config file format.
|
||||
|
@ -155,19 +165,93 @@ static int read_config_file(const char *name, bool ismain)
|
|||
*/
|
||||
Printf("FIXME: Implement \"altassign\" in TiMidity config.\n");
|
||||
}
|
||||
else if (!strcmp(w[0], "soundfont") || !strcmp(w[0], "font"))
|
||||
else if (!strcmp(w[0], "soundfont"))
|
||||
{
|
||||
/*
|
||||
* I can't find any documentation for these, but I guess they're
|
||||
* an alternative way of loading/unloading instruments.
|
||||
*
|
||||
* "soundfont" sf_file "remove"
|
||||
* "soundfont" sf_file ["order=" order] ["cutoff=" cutoff]
|
||||
* ["reso=" reso] ["amp=" amp]
|
||||
*/
|
||||
if (words < 2)
|
||||
{
|
||||
Printf("%s: line %d: No soundfont given\n", name, line);
|
||||
delete fp;
|
||||
return -2;
|
||||
}
|
||||
if (words > 2 && !strcmp(w[2], "remove"))
|
||||
{
|
||||
font_remove(w[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
int order = 0;
|
||||
|
||||
for (i = 2; i < words; ++i)
|
||||
{
|
||||
if (!(cp = strchr(w[i], '=')))
|
||||
{
|
||||
Printf("%s: line %d: bad soundfont option %s\n", name, line, w[i]);
|
||||
delete fp;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
font_add(w[1], order);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(w[0], "font"))
|
||||
{
|
||||
/*
|
||||
* "font" "exclude" bank preset keynote
|
||||
* "font" "order" order bank preset keynote
|
||||
*/
|
||||
Printf("FIXME: Implmement \"%s\" in TiMidity config.\n", w[0]);
|
||||
int order, drum = -1, bank = -1, instr = -1;
|
||||
|
||||
if (words < 3)
|
||||
{
|
||||
Printf("%s: line %d: syntax error\n", name, line);
|
||||
delete fp;
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (!strcmp(w[1], "exclude"))
|
||||
{
|
||||
order = 254;
|
||||
i = 2;
|
||||
}
|
||||
else if (!strcmp(w[1], "order"))
|
||||
{
|
||||
order = atoi(w[2]);
|
||||
i = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("%s: line %d: font subcommand must be 'order' or 'exclude'\n", name, line);
|
||||
delete fp;
|
||||
return -2;
|
||||
}
|
||||
if (i < words)
|
||||
{
|
||||
drum = atoi(w[i++]);
|
||||
}
|
||||
if (i < words)
|
||||
{
|
||||
bank = atoi(w[i++]);
|
||||
}
|
||||
if (i < words)
|
||||
{
|
||||
instr = atoi(w[i++]);
|
||||
}
|
||||
if (drum != 128)
|
||||
{
|
||||
instr = bank;
|
||||
bank = drum;
|
||||
drum = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
drum = 1;
|
||||
}
|
||||
font_order(order, drum, bank, instr);
|
||||
}
|
||||
else if (!strcmp(w[0], "progbase"))
|
||||
{
|
||||
|
@ -289,12 +373,34 @@ static int read_config_file(const char *name, bool ismain)
|
|||
delete fp;
|
||||
return -2;
|
||||
}
|
||||
bank->tone[i].name = w[1];
|
||||
bank->tone[i].note = bank->tone[i].amp = bank->tone[i].pan =
|
||||
bank->tone[i].strip_loop = bank->tone[i].strip_envelope =
|
||||
bank->tone[i].strip_tail = -1;
|
||||
bank->tone[i].fontbank = bank->tone[i].fontpreset =
|
||||
bank->tone[i].fontnote = bank->tone[i].strip_loop =
|
||||
bank->tone[i].strip_envelope = bank->tone[i].strip_tail = -1;
|
||||
|
||||
for (j = 2; j<words; j++)
|
||||
if (!strcmp(w[1], "%font"))
|
||||
{
|
||||
bank->tone[i].name = w[2];
|
||||
bank->tone[i].fontbank = atoi(w[3]);
|
||||
bank->tone[i].fontpreset = atoi(w[4]);
|
||||
if (bank->tone[i].fontbank == 128 || (w[5][0] >= '0' && w[5][0] <= '9'))
|
||||
{
|
||||
bank->tone[i].fontnote = atoi(w[5]);
|
||||
j = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
j = 5;
|
||||
}
|
||||
font_add(w[2], 254);
|
||||
}
|
||||
else
|
||||
{
|
||||
bank->tone[i].name = w[1];
|
||||
j = 2;
|
||||
}
|
||||
|
||||
for (; j<words; j++)
|
||||
{
|
||||
if (!(cp=strchr(w[j], '=')))
|
||||
{
|
||||
|
@ -397,6 +503,7 @@ static int read_config_file(const char *name, bool ismain)
|
|||
void FreeAll()
|
||||
{
|
||||
free_instruments();
|
||||
font_freeall();
|
||||
for (int i = 0; i < MAXBANK; ++i)
|
||||
{
|
||||
if (tonebank[i] != NULL)
|
||||
|
|
|
@ -177,6 +177,7 @@ extern void clear_pathlist();
|
|||
extern void *safe_malloc(size_t count);
|
||||
|
||||
FileReader *open_filereader(const char *name, int open, int *plumpnum);
|
||||
extern int openmode;
|
||||
|
||||
/*
|
||||
controls.h
|
||||
|
@ -204,53 +205,6 @@ void cmsg(int type, int verbosity_level, const char *fmt, ...);
|
|||
instrum.h
|
||||
*/
|
||||
|
||||
struct Sample
|
||||
{
|
||||
SDWORD
|
||||
loop_start, loop_end, data_length,
|
||||
sample_rate, low_vel, high_vel, low_freq, high_freq, root_freq;
|
||||
SDWORD
|
||||
envelope_rate[6], envelope_offset[6];
|
||||
float
|
||||
volume;
|
||||
sample_t *data;
|
||||
SDWORD
|
||||
tremolo_sweep_increment, tremolo_phase_increment,
|
||||
vibrato_sweep_increment, vibrato_control_ratio;
|
||||
BYTE
|
||||
tremolo_depth, vibrato_depth,
|
||||
modes;
|
||||
WORD
|
||||
panning, scale_factor;
|
||||
SWORD
|
||||
scale_note;
|
||||
bool
|
||||
self_nonexclusive;
|
||||
BYTE
|
||||
key_group;
|
||||
float
|
||||
left_offset, right_offset;
|
||||
};
|
||||
|
||||
void convert_sample_data(Sample *sample, const void *data);
|
||||
void free_instruments();
|
||||
|
||||
/* Patch definition: */
|
||||
enum
|
||||
{
|
||||
HEADER_SIZE = 12,
|
||||
ID_SIZE = 10,
|
||||
DESC_SIZE = 60,
|
||||
RESERVED_SIZE = 40,
|
||||
PATCH_HEADER_RESERVED_SIZE = 36,
|
||||
LAYER_RESERVED_SIZE = 40,
|
||||
PATCH_DATA_RESERVED_SIZE = 36,
|
||||
INST_NAME_SIZE = 16,
|
||||
ENVELOPES = 6,
|
||||
MAX_LAYERS = 4
|
||||
};
|
||||
#define GF1_HEADER_TEXT "GF1PATCH110"
|
||||
|
||||
enum
|
||||
{
|
||||
PATCH_16 = (1<<0),
|
||||
|
@ -263,80 +217,90 @@ enum
|
|||
PATCH_FAST_REL = (1<<7)
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#define GCC_PACKED
|
||||
#else
|
||||
#define GCC_PACKED __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
struct GF1PatchHeader
|
||||
struct Sample
|
||||
{
|
||||
char Header[HEADER_SIZE];
|
||||
char GravisID[ID_SIZE]; /* Id = "ID#000002" */
|
||||
char Description[DESC_SIZE];
|
||||
BYTE Instruments;
|
||||
BYTE Voices;
|
||||
BYTE Channels;
|
||||
WORD WaveForms;
|
||||
WORD MasterVolume;
|
||||
DWORD DataSize;
|
||||
BYTE Reserved[PATCH_HEADER_RESERVED_SIZE];
|
||||
} GCC_PACKED;
|
||||
SDWORD
|
||||
loop_start, loop_end, data_length,
|
||||
sample_rate;
|
||||
float
|
||||
low_freq, high_freq, root_freq;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
BYTE rate[6], offset[6];
|
||||
} gf1;
|
||||
struct
|
||||
{
|
||||
short delay_vol;
|
||||
short attack_vol;
|
||||
short hold_vol;
|
||||
short decay_vol;
|
||||
short sustain_vol;
|
||||
short release_vol;
|
||||
} sf2;
|
||||
} envelope;
|
||||
float
|
||||
volume;
|
||||
sample_t *data;
|
||||
SDWORD
|
||||
tremolo_sweep_increment, tremolo_phase_increment,
|
||||
vibrato_sweep_increment, vibrato_control_ratio;
|
||||
BYTE
|
||||
tremolo_depth, vibrato_depth,
|
||||
low_vel, high_vel,
|
||||
modes, type;
|
||||
SWORD
|
||||
panning;
|
||||
WORD
|
||||
scale_factor, key_group;
|
||||
SWORD
|
||||
scale_note;
|
||||
bool
|
||||
self_nonexclusive;
|
||||
float
|
||||
left_offset, right_offset;
|
||||
|
||||
struct GF1InstrumentData
|
||||
{
|
||||
WORD Instrument;
|
||||
char InstrumentName[INST_NAME_SIZE];
|
||||
int InstrumentSize;
|
||||
BYTE Layers;
|
||||
BYTE Reserved[RESERVED_SIZE];
|
||||
} GCC_PACKED;
|
||||
// SF2 stuff
|
||||
SWORD tune;
|
||||
SBYTE velocity;
|
||||
|
||||
struct GF1LayerData
|
||||
{
|
||||
BYTE LayerDuplicate;
|
||||
BYTE Layer;
|
||||
int LayerSize;
|
||||
BYTE Samples;
|
||||
BYTE Reserved[LAYER_RESERVED_SIZE];
|
||||
} GCC_PACKED;
|
||||
float initial_attenuation;
|
||||
};
|
||||
|
||||
struct GF1PatchData
|
||||
{
|
||||
char WaveName[7];
|
||||
BYTE Fractions;
|
||||
int WaveSize;
|
||||
int StartLoop;
|
||||
int EndLoop;
|
||||
WORD SampleRate;
|
||||
int LowFrequency;
|
||||
int HighFrequency;
|
||||
int RootFrequency;
|
||||
SWORD Tune;
|
||||
BYTE Balance;
|
||||
BYTE EnvelopeRate[ENVELOPES];
|
||||
BYTE EnvelopeOffset[ENVELOPES];
|
||||
BYTE TremoloSweep;
|
||||
BYTE TremoloRate;
|
||||
BYTE TremoloDepth;
|
||||
BYTE VibratoSweep;
|
||||
BYTE VibratoRate;
|
||||
BYTE VibratoDepth;
|
||||
BYTE Modes;
|
||||
SWORD ScaleFrequency;
|
||||
WORD ScaleFactor; /* From 0 to 2048 or 0 to 2 */
|
||||
BYTE Reserved[PATCH_DATA_RESERVED_SIZE];
|
||||
} GCC_PACKED;
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
#undef GCC_PACKED
|
||||
void convert_sample_data(Sample *sample, const void *data);
|
||||
void free_instruments();
|
||||
|
||||
/* Magic file words */
|
||||
|
||||
#define ID_RIFF MAKE_ID('R','I','F','F')
|
||||
#define ID_LIST MAKE_ID('L','I','S','T')
|
||||
#define ID_INFO MAKE_ID('I','N','F','O')
|
||||
#define ID_sfbk MAKE_ID('s','f','b','k')
|
||||
#define ID_sdta MAKE_ID('s','d','t','a')
|
||||
#define ID_pdta MAKE_ID('p','d','t','a')
|
||||
#define ID_ifil MAKE_ID('i','f','i','l')
|
||||
#define ID_iver MAKE_ID('i','v','e','r')
|
||||
#define ID_irom MAKE_ID('i','r','o','m')
|
||||
#define ID_smpl MAKE_ID('s','m','p','l')
|
||||
#define ID_sm24 MAKE_ID('s','m','2','4')
|
||||
#define ID_phdr MAKE_ID('p','h','d','r')
|
||||
#define ID_pbag MAKE_ID('p','b','a','g')
|
||||
#define ID_pmod MAKE_ID('p','m','o','d')
|
||||
#define ID_pgen MAKE_ID('p','g','e','n')
|
||||
#define ID_inst MAKE_ID('i','n','s','t')
|
||||
#define ID_ibag MAKE_ID('i','b','a','g')
|
||||
#define ID_imod MAKE_ID('i','m','o','d')
|
||||
#define ID_igen MAKE_ID('i','g','e','n')
|
||||
#define ID_shdr MAKE_ID('s','h','d','r')
|
||||
|
||||
/* Instrument definitions */
|
||||
|
||||
enum
|
||||
{
|
||||
INST_GUS,
|
||||
INST_DLS
|
||||
INST_DLS,
|
||||
INST_SF2
|
||||
};
|
||||
|
||||
struct Instrument
|
||||
|
@ -344,7 +308,6 @@ struct Instrument
|
|||
Instrument();
|
||||
~Instrument();
|
||||
|
||||
int type;
|
||||
int samples;
|
||||
Sample *sample;
|
||||
};
|
||||
|
@ -356,11 +319,10 @@ struct ToneBankElement
|
|||
{}
|
||||
|
||||
FString name;
|
||||
int note, amp, pan, strip_loop, strip_envelope, strip_tail;
|
||||
int note, amp, pan, fontbank, fontpreset, fontnote, strip_loop, strip_envelope, strip_tail;
|
||||
};
|
||||
|
||||
/* A hack to delay instrument loading until after reading the
|
||||
entire MIDI file. */
|
||||
/* A hack to delay instrument loading until after reading the entire MIDI file. */
|
||||
#define MAGIC_LOAD_INSTRUMENT ((Instrument *)(-1))
|
||||
|
||||
enum
|
||||
|
@ -381,7 +343,34 @@ struct ToneBank
|
|||
|
||||
#define SPECIAL_PROGRAM -1
|
||||
|
||||
extern void pcmap(int *b, int *v, int *p, int *drums);
|
||||
/*
|
||||
instrum_font.cpp
|
||||
*/
|
||||
|
||||
class FontFile
|
||||
{
|
||||
public:
|
||||
FontFile(FString filename);
|
||||
virtual ~FontFile();
|
||||
|
||||
FString Filename;
|
||||
FontFile *Next;
|
||||
|
||||
virtual Instrument *LoadInstrument(struct Renderer *song, int drum, int bank, int program) = 0;
|
||||
virtual Instrument *LoadInstrumentOrder(struct Renderer *song, int order, int drum, int bank, int program) = 0;
|
||||
virtual void SetOrder(int order, int drum, int bank, int program) = 0;
|
||||
virtual void SetAllOrders(int order) = 0;
|
||||
};
|
||||
|
||||
void font_freeall();
|
||||
FontFile *font_find(const char *filename);
|
||||
void font_add(const char *filename, int load_order);
|
||||
void font_remove(const char *filename);
|
||||
void font_order(int order, int bank, int preset, int keynote);
|
||||
Instrument *load_instrument_font(struct Renderer *song, const char *font, int drum, int bank, int instrument);
|
||||
Instrument *load_instrument_font_order(struct Renderer *song, int order, int drum, int bank, int instrument);
|
||||
|
||||
FontFile *ReadDLS(const char *filename, FileReader *f);
|
||||
|
||||
/*
|
||||
mix.h
|
||||
|
@ -446,9 +435,9 @@ struct Channel
|
|||
bank, program, sustain, pitchbend,
|
||||
mono, /* one note only on this channel */
|
||||
pitchsens;
|
||||
WORD
|
||||
BYTE
|
||||
volume, expression;
|
||||
SWORD
|
||||
SBYTE
|
||||
panning;
|
||||
WORD
|
||||
rpn, nrpn;
|
||||
|
@ -456,13 +445,81 @@ struct Channel
|
|||
nrpn_mode;
|
||||
float
|
||||
pitchfactor; /* precomputed pitch bend factor to save some fdiv's */
|
||||
float
|
||||
left_offset, right_offset; /* precomputed panning values */
|
||||
};
|
||||
|
||||
/* Causes the instrument's default panning to be used. */
|
||||
#define NO_PANNING -1
|
||||
|
||||
struct MinEnvelope
|
||||
{
|
||||
int stage;
|
||||
BYTE bUpdating;
|
||||
};
|
||||
|
||||
struct GF1Envelope : public MinEnvelope
|
||||
{
|
||||
int volume, target, increment;
|
||||
int rate[6], offset[6];
|
||||
|
||||
void Init(struct Renderer *song, Voice *v);
|
||||
bool Update(struct Voice *v);
|
||||
bool Recompute(struct Voice *v);
|
||||
void ApplyToAmp(struct Voice *v);
|
||||
void Release(struct Voice *v);
|
||||
};
|
||||
|
||||
struct SF2Envelope : public MinEnvelope
|
||||
{
|
||||
float volume;
|
||||
float DelayTime; // timecents
|
||||
float AttackTime; // timecents
|
||||
float HoldTime; // timecents
|
||||
float DecayTime; // timecents
|
||||
float SustainLevel; // -0.1%
|
||||
float ReleaseTime; // timecents
|
||||
float SampleRate;
|
||||
int HoldStart;
|
||||
float RateMul;
|
||||
float RateMul_cB;
|
||||
|
||||
void Init(struct Renderer *song, Voice *v);
|
||||
bool Update(struct Voice *v);
|
||||
void ApplyToAmp(struct Voice *v);
|
||||
void Release(struct Voice *v);
|
||||
};
|
||||
|
||||
struct Envelope
|
||||
{
|
||||
union
|
||||
{
|
||||
MinEnvelope env;
|
||||
GF1Envelope gf1;
|
||||
SF2Envelope sf2;
|
||||
};
|
||||
|
||||
BYTE Type;
|
||||
|
||||
void Init(struct Renderer *song, struct Voice *v);
|
||||
bool Update(struct Voice *v)
|
||||
{
|
||||
if (Type == INST_GUS)
|
||||
return gf1.Update(v);
|
||||
return sf2.Update(v);
|
||||
}
|
||||
void ApplyToAmp(struct Voice *v)
|
||||
{
|
||||
if (Type == INST_GUS)
|
||||
return gf1.ApplyToAmp(v);
|
||||
return sf2.ApplyToAmp(v);
|
||||
}
|
||||
void Release(struct Voice *v)
|
||||
{
|
||||
if (Type == INST_GUS)
|
||||
return gf1.Release(v);
|
||||
return sf2.Release(v);
|
||||
}
|
||||
};
|
||||
|
||||
struct Voice
|
||||
{
|
||||
BYTE
|
||||
|
@ -472,11 +529,12 @@ struct Voice
|
|||
orig_frequency, frequency;
|
||||
int
|
||||
sample_offset, sample_increment,
|
||||
envelope_volume, envelope_target, envelope_increment,
|
||||
tremolo_sweep, tremolo_sweep_position,
|
||||
tremolo_phase, tremolo_phase_increment,
|
||||
vibrato_sweep, vibrato_sweep_position;
|
||||
|
||||
Envelope eg1, eg2;
|
||||
|
||||
final_volume_t left_mix, right_mix;
|
||||
|
||||
float
|
||||
|
@ -487,8 +545,10 @@ struct Voice
|
|||
vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS];
|
||||
int
|
||||
vibrato_phase, vibrato_control_ratio, vibrato_control_counter,
|
||||
envelope_stage, control_counter;
|
||||
control_counter;
|
||||
|
||||
int
|
||||
sample_count;
|
||||
};
|
||||
|
||||
/* Voice status options: */
|
||||
|
@ -506,12 +566,23 @@ enum
|
|||
/* Envelope stages: */
|
||||
enum
|
||||
{
|
||||
ATTACK,
|
||||
HOLD,
|
||||
DECAY,
|
||||
RELEASE,
|
||||
RELEASEB,
|
||||
RELEASEC
|
||||
GF1_ATTACK,
|
||||
GF1_HOLD,
|
||||
GF1_DECAY,
|
||||
GF1_RELEASE,
|
||||
GF1_RELEASEB,
|
||||
GF1_RELEASEC
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SF2_DELAY,
|
||||
SF2_ATTACK,
|
||||
SF2_HOLD,
|
||||
SF2_DECAY,
|
||||
SF2_SUSTAIN,
|
||||
SF2_RELEASE,
|
||||
SF2_FINISHED
|
||||
};
|
||||
|
||||
#define ISDRUMCHANNEL(c) ((drumchannels & (1<<(c))))
|
||||
|
@ -527,10 +598,16 @@ extern void pre_resample(struct Renderer *song, Sample *sp);
|
|||
tables.h
|
||||
*/
|
||||
|
||||
const double log_of_2 = 0.69314718055994529;
|
||||
|
||||
#define sine(x) (sin((2*PI/1024.0) * (x)))
|
||||
|
||||
#define note_to_freq(x) (float(8175.7989473096690661233836992789 * pow(2.0, (x) / 12.0)))
|
||||
//#define calc_vol(x) (pow(2.0,((x)*6.0 - 6.0))) // Physically ideal equation
|
||||
#define freq_to_note(x) (log((x) / 8175.7989473096690661233836992789) * (12.0 / log_of_2))
|
||||
|
||||
#define calc_gf1_amp(x) (pow(2.0,((x)*16.0 - 16.0))) // Actual GUS equation
|
||||
#define cb_to_amp(x) (pow(10.0, (x) * (1 / -200.0))) // centibels to amp
|
||||
#define db_to_amp(x) (pow(10.0, (x) * (1 / -20.0))) // decibels to map
|
||||
|
||||
/*
|
||||
timidity.h
|
||||
|
@ -582,7 +659,8 @@ struct Renderer
|
|||
|
||||
void kill_key_group(int voice);
|
||||
float calculate_scaled_frequency(Sample *sample, int note);
|
||||
void start_note(int chan, int note, int vel, int voice);
|
||||
void start_note(int chan, int note, int vel);
|
||||
bool start_region(int chan, int note, int vel, Sample *sp, float freq);
|
||||
|
||||
void note_on(int chan, int note, int vel);
|
||||
void note_off(int chan, int note, int vel);
|
||||
|
@ -598,7 +676,7 @@ struct Renderer
|
|||
void reset_controllers(int chan);
|
||||
void reset_midi();
|
||||
|
||||
void select_sample(int voice, Instrument *instr, int vel);
|
||||
int allocate_voice();
|
||||
|
||||
void kill_note(int voice);
|
||||
void finish_note(int voice);
|
||||
|
@ -608,7 +686,7 @@ struct Renderer
|
|||
void DataEntryCoarseNRPN(int chan, int nrpn, int val);
|
||||
void DataEntryFineNRPN(int chan, int nrpn, int val);
|
||||
|
||||
static void compute_pan(int panning, float &left_offset, float &right_offset);
|
||||
static void compute_pan(double panning, int type, float &left_offset, float &right_offset);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
502
zdoom.vcproj
502
zdoom.vcproj
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Version="8.00"
|
||||
Name="zdoom"
|
||||
ProjectGUID="{8049475B-5C87-46F9-9358-635218A4EF18}"
|
||||
RootNamespace=" zdoom"
|
||||
|
@ -135,112 +135,6 @@
|
|||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory=".\Debug"
|
||||
IntermediateDirectory=".\Debug"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
Description="Checking svnrevision.h..."
|
||||
CommandLine="$(OutDir)\updaterevision.exe src src/svnrevision.h"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
MkTypLibCompatible="true"
|
||||
SuppressStartupBanner="true"
|
||||
TargetEnvironment="1"
|
||||
TypeLibraryName=".\Debug/zdoom.tlb"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;jpeg-6b;snes_spc\snes_spc"
|
||||
PreprocessorDefinitions="WIN32,_DEBUG,_WIN32,_WINDOWS,USEASM,_CRTDBG_MAP_ALLOC,HAVE_STRUPR,HAVE_FILELENGTH"
|
||||
MinimalRebuild="true"
|
||||
RuntimeLibrary="1"
|
||||
EnableFunctionLevelLinking="true"
|
||||
ForceConformanceInForLoopScope="true"
|
||||
PrecompiledHeaderFile=""
|
||||
AssemblerOutput="0"
|
||||
AssemblerListingLocation=".\Debug/"
|
||||
ObjectFile=".\Debug/"
|
||||
ProgramDataBaseFileName=".\Debug/"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="true"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
CompileAs="0"
|
||||
DisableSpecificWarnings="4996"
|
||||
ForcedIncludeFiles=""
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
Culture="1033"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalOptions="/MACHINE:I386"
|
||||
AdditionalDependencies="gdi32.lib user32.lib comctl32.lib shell32.lib advapi32.lib comdlg32.lib ole32.lib dxguid.lib dsound.lib dinput8.lib strmiids.lib wsock32.lib winmm.lib fmodex_vc.lib setupapi.lib ws2_32.lib"
|
||||
OutputFile="../zdoomd.exe"
|
||||
LinkIncremental="2"
|
||||
SuppressStartupBanner="true"
|
||||
AdditionalLibraryDirectories=""
|
||||
IgnoreDefaultLibraryNames="libcmt;msvcrtd;msvcrt"
|
||||
GenerateDebugInformation="true"
|
||||
ProgramDatabaseFile=".\Debug/zdoomd.pdb"
|
||||
SubSystem="2"
|
||||
StackReserveSize="0"
|
||||
TerminalServerAware="2"
|
||||
SetChecksum="false"
|
||||
TargetMachine="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
|
@ -352,6 +246,112 @@
|
|||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory=".\Debug"
|
||||
IntermediateDirectory=".\Debug"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
Description="Checking svnrevision.h..."
|
||||
CommandLine="$(OutDir)\updaterevision.exe src src/svnrevision.h"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
MkTypLibCompatible="true"
|
||||
SuppressStartupBanner="true"
|
||||
TargetEnvironment="1"
|
||||
TypeLibraryName=".\Debug/zdoom.tlb"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;jpeg-6b;snes_spc\snes_spc"
|
||||
PreprocessorDefinitions="WIN32,_DEBUG,_WIN32,_WINDOWS,USEASM,_CRTDBG_MAP_ALLOC,HAVE_STRUPR,HAVE_FILELENGTH"
|
||||
MinimalRebuild="true"
|
||||
RuntimeLibrary="1"
|
||||
EnableFunctionLevelLinking="true"
|
||||
ForceConformanceInForLoopScope="true"
|
||||
PrecompiledHeaderFile=""
|
||||
AssemblerOutput="0"
|
||||
AssemblerListingLocation=".\Debug/"
|
||||
ObjectFile=".\Debug/"
|
||||
ProgramDataBaseFileName=".\Debug/"
|
||||
WarningLevel="3"
|
||||
SuppressStartupBanner="true"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
CompileAs="0"
|
||||
DisableSpecificWarnings="4996"
|
||||
ForcedIncludeFiles=""
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
Culture="1033"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalOptions="/MACHINE:I386"
|
||||
AdditionalDependencies="gdi32.lib user32.lib comctl32.lib shell32.lib advapi32.lib comdlg32.lib ole32.lib dxguid.lib dsound.lib dinput8.lib strmiids.lib wsock32.lib winmm.lib fmodex_vc.lib setupapi.lib ws2_32.lib"
|
||||
OutputFile="../zdoomd.exe"
|
||||
LinkIncremental="2"
|
||||
SuppressStartupBanner="true"
|
||||
AdditionalLibraryDirectories=""
|
||||
IgnoreDefaultLibraryNames="libcmt;msvcrtd;msvcrt"
|
||||
GenerateDebugInformation="true"
|
||||
ProgramDatabaseFile=".\Debug/zdoomd.pdb"
|
||||
SubSystem="2"
|
||||
StackReserveSize="0"
|
||||
TerminalServerAware="2"
|
||||
SetChecksum="false"
|
||||
TargetMachine="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
|
@ -926,16 +926,6 @@
|
|||
Outputs=""src/$(InputName).h""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Creating $(InputName).h from src/$(InputFileName)"
|
||||
CommandLine="tools\re2c\re2c --no-generation-date -s -o "src/$(InputName).h" "src/$(InputFileName)"
"
|
||||
Outputs=""src/$(InputName).h""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
>
|
||||
|
@ -946,6 +936,16 @@
|
|||
Outputs=""src/$(InputName).h""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Creating $(InputName).h from src/$(InputFileName)"
|
||||
CommandLine="tools\re2c\re2c --no-generation-date -s -o "src/$(InputName).h" "src/$(InputFileName)"
"
|
||||
Outputs=""src/$(InputName).h""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
>
|
||||
|
@ -1540,16 +1540,6 @@
|
|||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Assembling $(InputPath)..."
|
||||
CommandLine="nasm -g -o "$(IntDir)\$(InputName).obj" -f win32 "$(InputPath)"
$(OutDir)\fixrtext "$(IntDir)\$(InputName).obj"
"
|
||||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -1561,6 +1551,16 @@
|
|||
Outputs="$(IntDir)/$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Assembling $(InputPath)..."
|
||||
CommandLine="nasm -g -o "$(IntDir)\$(InputName).obj" -f win32 "$(InputPath)"
$(OutDir)\fixrtext "$(IntDir)\$(InputName).obj"
"
|
||||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -1586,16 +1586,6 @@
|
|||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Assembling $(InputPath)..."
|
||||
CommandLine="nasm -g -o "$(IntDir)\$(InputName).obj" -f win32 "$(InputPath)"
$(OutDir)\fixrtext "$(IntDir)\$(InputName).obj"
"
|
||||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -1607,6 +1597,16 @@
|
|||
Outputs="$(IntDir)/$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Assembling $(InputPath)..."
|
||||
CommandLine="nasm -g -o "$(IntDir)\$(InputName).obj" -f win32 "$(InputPath)"
$(OutDir)\fixrtext "$(IntDir)\$(InputName).obj"
"
|
||||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -1632,16 +1632,6 @@
|
|||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Assembling $(InputPath)..."
|
||||
CommandLine="nasm -g -o "$(IntDir)\$(InputName).obj" -f win32 "$(InputPath)"
$(OutDir)\fixrtext "$(IntDir)\$(InputName).obj"
"
|
||||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -1653,6 +1643,16 @@
|
|||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Assembling $(InputPath)..."
|
||||
CommandLine="nasm -g -o "$(IntDir)\$(InputName).obj" -f win32 "$(InputPath)"
$(OutDir)\fixrtext "$(IntDir)\$(InputName).obj"
"
|
||||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -1678,16 +1678,6 @@
|
|||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Assembling $(InputPath)..."
|
||||
CommandLine="nasm -g -o "$(IntDir)\$(InputName).obj" -f win32 "$(InputPath)"
$(OutDir)\fixrtext "$(IntDir)\$(InputName).obj"
"
|
||||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -1699,6 +1689,16 @@
|
|||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Assembling $(InputPath)..."
|
||||
CommandLine="nasm -g -o "$(IntDir)\$(InputName).obj" -f win32 "$(InputPath)"
$(OutDir)\fixrtext "$(IntDir)\$(InputName).obj"
"
|
||||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -1724,16 +1724,6 @@
|
|||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Assembling $(InputPath)..."
|
||||
CommandLine="nasm -g -o "$(IntDir)\$(InputName).obj" -f win32 "$(InputPath)"
$(OutDir)\fixrtext "$(IntDir)\$(InputName).obj"
"
|
||||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -1745,6 +1735,16 @@
|
|||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Assembling $(InputPath)..."
|
||||
CommandLine="nasm -g -o "$(IntDir)\$(InputName).obj" -f win32 "$(InputPath)"
$(OutDir)\fixrtext "$(IntDir)\$(InputName).obj"
"
|
||||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -1910,6 +1910,14 @@
|
|||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
|
@ -1920,14 +1928,6 @@
|
|||
Outputs="$(IntDir)\$(InputName).obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
ExcludedFromBuild="true"
|
||||
|
@ -2785,6 +2785,14 @@
|
|||
AdditionalIncludeDirectories="src\win32;$(NoInherit)"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
AdditionalIncludeDirectories="src\win32;$(NoInherit)"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
|
@ -2794,14 +2802,6 @@
|
|||
AdditionalIncludeDirectories="src\win32;$(NoInherit)"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
AdditionalIncludeDirectories="src\win32;$(NoInherit)"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
>
|
||||
|
@ -2952,9 +2952,32 @@
|
|||
Name="Timidity"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\timidity\common.cpp"
|
||||
RelativePath=".\src\timidity\instrum_font.cpp"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="Docs"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\timidity\CHANGES"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\COPYING"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\FAQ"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\README"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Headers"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\timidity\dls1.h"
|
||||
>
|
||||
|
@ -2963,6 +2986,26 @@
|
|||
RelativePath=".\src\timidity\dls2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\gf1patch.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\sf2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\timidity.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Source"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\timidity\common.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\instrum.cpp"
|
||||
>
|
||||
|
@ -2971,6 +3014,10 @@
|
|||
RelativePath=".\src\timidity\instrum_dls.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\instrum_sf2.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\mix.cpp"
|
||||
>
|
||||
|
@ -3003,29 +3050,6 @@
|
|||
RelativePath=".\src\timidity\timidity.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\timidity.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="Docs"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\timidity\CHANGES"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\COPYING"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\FAQ"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\timidity\README"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Filter>
|
||||
|
@ -3044,7 +3068,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3052,7 +3076,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3084,7 +3108,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3092,7 +3116,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3121,7 +3145,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3130,7 +3154,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3160,7 +3184,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3168,7 +3192,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3197,7 +3221,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3206,7 +3230,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3237,7 +3261,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3246,7 +3270,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3276,7 +3300,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3284,7 +3308,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3313,7 +3337,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3322,7 +3346,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3353,7 +3377,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3362,7 +3386,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3393,7 +3417,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3402,7 +3426,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3432,7 +3456,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3440,7 +3464,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3468,7 +3492,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3476,7 +3500,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3504,7 +3528,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3512,7 +3536,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3540,7 +3564,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3548,7 +3572,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3578,7 +3602,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3588,7 +3612,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3632,7 +3656,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
@ -3640,7 +3664,7 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
|
|
Loading…
Reference in a new issue