mirror of
https://github.com/vsariola/sointu.git
synced 2025-05-28 03:10:24 -04:00
3480 lines
100 KiB
C++
3480 lines
100 KiB
C++
#include "Go4kVSTiCore.h"
|
|
|
|
#include <math.h>
|
|
|
|
#include "Go4kVSTiGUI.h"
|
|
#include "resource.h"
|
|
#include <stdio.h>
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <list>
|
|
#include <string>
|
|
|
|
DWORD versiontag10 = 0x30316b34; // 4k10
|
|
DWORD versiontag11 = 0x31316b34; // 4k11
|
|
DWORD versiontag12 = 0x32316b34; // 4k12
|
|
DWORD versiontag13 = 0x33316b34; // 4k13
|
|
DWORD versiontag = 0x34316b34; // 4k14
|
|
|
|
static SynthObject SynthObj;
|
|
|
|
extern "C" void __stdcall go4kENV_func();
|
|
extern "C" void __stdcall go4kVCO_func();
|
|
extern "C" void __stdcall go4kVCF_func();
|
|
extern "C" void __stdcall go4kDST_func();
|
|
extern "C" void __stdcall go4kDLL_func();
|
|
extern "C" void __stdcall go4kFOP_func();
|
|
extern "C" void __stdcall go4kFST_func();
|
|
extern "C" void __stdcall go4kPAN_func();
|
|
extern "C" void __stdcall go4kOUT_func();
|
|
extern "C" void __stdcall go4kACC_func();
|
|
extern "C" void __stdcall go4kFLD_func();
|
|
extern "C" void __stdcall go4kGLITCH_func();
|
|
extern "C" DWORD go4k_delay_buffer_ofs;
|
|
extern "C" float go4k_delay_buffer;
|
|
extern "C" WORD go4k_delay_times;
|
|
extern "C" float LFO_NORMALIZE;
|
|
|
|
typedef void (__stdcall *go4kFunc)(void);
|
|
|
|
void __stdcall NULL_func()
|
|
{
|
|
};
|
|
|
|
static go4kFunc SynthFuncs[] =
|
|
{
|
|
NULL_func,
|
|
go4kENV_func,
|
|
go4kVCO_func,
|
|
go4kVCF_func,
|
|
go4kDST_func,
|
|
go4kDLL_func,
|
|
go4kFOP_func,
|
|
go4kFST_func,
|
|
go4kPAN_func,
|
|
go4kOUT_func,
|
|
go4kACC_func,
|
|
go4kFLD_func,
|
|
go4kGLITCH_func
|
|
};
|
|
|
|
static float BeatsPerMinute = 120.0f;
|
|
|
|
// solo mode handling
|
|
static int SoloChannel = 0;
|
|
static int Solo = 0;
|
|
|
|
// stream structures for recording sound
|
|
static DWORD samplesProcessed = 0;
|
|
static bool Recording = false;
|
|
static bool RecordingNoise = true;
|
|
static bool FirstRecordingEvent = false;
|
|
static DWORD PatternSize = 16;
|
|
static float SamplesPerTick;
|
|
static float TickScaler = 1.0f;
|
|
static DWORD MaxTicks;
|
|
static int InstrumentOn[MAX_INSTRUMENTS];
|
|
static std::vector<int> InstrumentRecord[MAX_INSTRUMENTS];
|
|
static std::vector<int> ReducedPatterns;
|
|
static std::vector<int> PatternIndices[MAX_INSTRUMENTS];
|
|
static int NumReducedPatterns = 0;
|
|
|
|
// init synth
|
|
void Go4kVSTi_Init()
|
|
{
|
|
static bool initialized = false;
|
|
// do one time initialisation here (e.g. wavtable generation ...)
|
|
if (!initialized)
|
|
{
|
|
memset(&SynthObj, 0, sizeof(SynthObj));
|
|
BeatsPerMinute = 120.0f;
|
|
SoloChannel = 0;
|
|
Solo = 0;
|
|
Go4kVSTi_ResetPatch();
|
|
initialized = true;
|
|
}
|
|
}
|
|
|
|
// reset synth
|
|
|
|
void Go4kVSTi_ClearInstrumentSlot(char channel, int slot)
|
|
{
|
|
memset(SynthObj.InstrumentValues[channel][slot], 0, MAX_UNIT_SLOTS);
|
|
for (int i = 0; i < MAX_POLYPHONY; i++)
|
|
{
|
|
float* w = &(SynthObj.InstrumentWork[channel*MAX_POLYPHONY+i].workspace[slot*MAX_UNIT_SLOTS]);
|
|
memset(w, 0, MAX_UNIT_SLOTS*4);
|
|
}
|
|
}
|
|
|
|
void Go4kVSTi_ClearInstrumentWorkspace(char channel)
|
|
{
|
|
// clear workspace
|
|
InstrumentWorkspace* w = &(SynthObj.InstrumentWork[channel*MAX_POLYPHONY]);
|
|
memset(w, 0, sizeof(InstrumentWorkspace)*MAX_POLYPHONY);
|
|
}
|
|
|
|
void Go4kVSTi_ResetInstrument(char channel)
|
|
{
|
|
char name[128];
|
|
sprintf(name, "Instrument %d", channel+1);
|
|
memcpy(SynthObj.InstrumentNames[channel], name, strlen(name));
|
|
|
|
// clear values
|
|
BYTE* v = SynthObj.InstrumentValues[channel][0];
|
|
memset(v, 0, MAX_UNITS*MAX_UNIT_SLOTS);
|
|
|
|
// clear workspace
|
|
InstrumentWorkspace* w = &(SynthObj.InstrumentWork[channel*MAX_POLYPHONY]);
|
|
memset(w, 0, sizeof(InstrumentWorkspace)*MAX_POLYPHONY);
|
|
|
|
// set default units
|
|
Go4kVSTi_InitSlot(SynthObj.InstrumentValues[channel][0], channel, M_ENV);
|
|
Go4kVSTi_InitSlot(SynthObj.InstrumentValues[channel][1], channel, M_VCO);
|
|
Go4kVSTi_InitSlot(SynthObj.InstrumentValues[channel][2], channel, M_FOP); ((FOP_valP)(SynthObj.InstrumentValues[channel][2]))->flags = FOP_MULP;
|
|
Go4kVSTi_InitSlot(SynthObj.InstrumentValues[channel][3], channel, M_DLL);
|
|
Go4kVSTi_InitSlot(SynthObj.InstrumentValues[channel][4], channel, M_PAN);
|
|
Go4kVSTi_InitSlot(SynthObj.InstrumentValues[channel][5], channel, M_OUT);
|
|
|
|
SynthObj.HighestSlotIndex[channel] = 5;
|
|
SynthObj.InstrumentSignalValid[channel] = 1;
|
|
SynthObj.SignalTrace[channel] = 0.0f;
|
|
SynthObj.ControlInstrument[channel] = 0;
|
|
SynthObj.VoiceIndex[channel] = 0;
|
|
|
|
|
|
Go4kVSTi_ClearDelayLines();
|
|
}
|
|
|
|
void Go4kVSTi_ClearGlobalSlot(int slot)
|
|
{
|
|
memset(SynthObj.GlobalValues[slot], 0, MAX_UNIT_SLOTS);
|
|
float* w = &(SynthObj.GlobalWork.workspace[slot*MAX_UNIT_SLOTS]);
|
|
memset(w, 0, MAX_UNIT_SLOTS*4);
|
|
}
|
|
|
|
void Go4kVSTi_ClearGlobalWorkspace()
|
|
{
|
|
// clear workspace
|
|
memset(&(SynthObj.GlobalWork), 0, sizeof(InstrumentWorkspace));
|
|
}
|
|
|
|
void Go4kVSTi_ResetGlobal()
|
|
{
|
|
// clear values
|
|
memset(SynthObj.GlobalValues, 0, MAX_UNITS*MAX_UNIT_SLOTS);
|
|
|
|
// clear workspace
|
|
memset(&(SynthObj.GlobalWork), 0, sizeof(InstrumentWorkspace));
|
|
|
|
// set default units
|
|
Go4kVSTi_InitSlot(SynthObj.GlobalValues[0], 16, M_ACC); ((ACC_valP)(SynthObj.GlobalValues[0]))->flags = ACC_AUX;
|
|
Go4kVSTi_InitSlot(SynthObj.GlobalValues[1], 16, M_DLL);
|
|
((DLL_valP)(SynthObj.GlobalValues[1]))->reverb = 1;
|
|
((DLL_valP)(SynthObj.GlobalValues[1]))->leftreverb = 1;
|
|
((DLL_valP)(SynthObj.GlobalValues[1]))->feedback = 125;
|
|
((DLL_valP)(SynthObj.GlobalValues[1]))->pregain = 40;
|
|
Go4kVSTi_InitSlot(SynthObj.GlobalValues[2], 16, M_FOP); ((FOP_valP)(SynthObj.GlobalValues[2]))->flags = FOP_XCH;
|
|
Go4kVSTi_InitSlot(SynthObj.GlobalValues[3], 16, M_DLL);
|
|
((DLL_valP)(SynthObj.GlobalValues[3]))->reverb = 1;
|
|
((DLL_valP)(SynthObj.GlobalValues[3]))->leftreverb = 0;
|
|
((DLL_valP)(SynthObj.GlobalValues[3]))->feedback = 125;
|
|
((DLL_valP)(SynthObj.GlobalValues[3]))->pregain = 40;
|
|
Go4kVSTi_InitSlot(SynthObj.GlobalValues[4], 16, M_FOP); ((FOP_valP)(SynthObj.GlobalValues[4]))->flags = FOP_XCH;
|
|
Go4kVSTi_InitSlot(SynthObj.GlobalValues[5], 16, M_ACC);
|
|
Go4kVSTi_InitSlot(SynthObj.GlobalValues[6], 16, M_FOP); ((FOP_valP)(SynthObj.GlobalValues[6]))->flags = FOP_ADDP2;
|
|
Go4kVSTi_InitSlot(SynthObj.GlobalValues[7], 16, M_OUT);
|
|
|
|
SynthObj.HighestSlotIndex[16] = 7;
|
|
SynthObj.GlobalSignalValid = 1;
|
|
|
|
PatternSize = 16;
|
|
|
|
Go4kVSTi_ClearDelayLines();
|
|
}
|
|
|
|
// reset synth
|
|
void Go4kVSTi_ResetPatch()
|
|
{
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i ++)
|
|
{
|
|
Go4kVSTi_ResetInstrument(i);
|
|
}
|
|
// reset global settings
|
|
Go4kVSTi_ResetGlobal();
|
|
|
|
SynthObj.Polyphony = 1;
|
|
}
|
|
|
|
void Go4kVSTi_FlipInstrumentSlots(char channel, int a, int b)
|
|
{
|
|
int s = a;
|
|
if (b > a)
|
|
s = b;
|
|
if (s >= SynthObj.HighestSlotIndex[channel])
|
|
SynthObj.HighestSlotIndex[channel] = s;
|
|
|
|
DWORD temp[MAX_UNIT_SLOTS];
|
|
BYTE* v1 = SynthObj.InstrumentValues[channel][a];
|
|
BYTE* v2 = SynthObj.InstrumentValues[channel][b];
|
|
memcpy(temp, v2, MAX_UNIT_SLOTS);
|
|
memcpy(v2, v1, MAX_UNIT_SLOTS);
|
|
memcpy(v1, temp, MAX_UNIT_SLOTS);
|
|
for (int i = 0; i < MAX_POLYPHONY; i++)
|
|
{
|
|
float* w1 = &(SynthObj.InstrumentWork[channel*MAX_POLYPHONY+i].workspace[a*MAX_UNIT_SLOTS]);
|
|
float* w2 = &(SynthObj.InstrumentWork[channel*MAX_POLYPHONY+i].workspace[b*MAX_UNIT_SLOTS]);
|
|
memcpy(temp, w2, MAX_UNIT_SLOTS*4);
|
|
memcpy(w2, w1, MAX_UNIT_SLOTS*4);
|
|
memcpy(w1, temp, MAX_UNIT_SLOTS*4);
|
|
}
|
|
// reset dll workspaces, they are invalid now
|
|
if ((v1[0] == M_DLL || v1[0] == M_GLITCH) && (v2[0] == M_DLL || v2[0] == M_GLITCH))
|
|
{
|
|
Go4kVSTi_ClearDelayLines();
|
|
Go4kVSTi_UpdateDelayTimes();
|
|
}
|
|
}
|
|
|
|
void Go4kVSTi_FlipGlobalSlots(int a, int b)
|
|
{
|
|
int s = a;
|
|
if (b > a)
|
|
s = b;
|
|
if (s >= SynthObj.HighestSlotIndex[16])
|
|
SynthObj.HighestSlotIndex[16] = s;
|
|
|
|
DWORD temp[MAX_UNIT_SLOTS];
|
|
BYTE* v1 = SynthObj.GlobalValues[a];
|
|
BYTE* v2 = SynthObj.GlobalValues[b];
|
|
memcpy(temp, v2, MAX_UNIT_SLOTS);
|
|
memcpy(v2, v1, MAX_UNIT_SLOTS);
|
|
memcpy(v1, temp, MAX_UNIT_SLOTS);
|
|
for (int i = 0; i < MAX_POLYPHONY; i++)
|
|
{
|
|
float* w1 = &(SynthObj.GlobalWork.workspace[a*MAX_UNIT_SLOTS]);
|
|
float* w2 = &(SynthObj.GlobalWork.workspace[b*MAX_UNIT_SLOTS]);
|
|
memcpy(temp, w2, MAX_UNIT_SLOTS*4);
|
|
memcpy(w2, w1, MAX_UNIT_SLOTS*4);
|
|
memcpy(w1, temp, MAX_UNIT_SLOTS*4);
|
|
}
|
|
// reset dll workspaces, they are invalid now
|
|
if ((v1[0] == M_DLL || v1[0] == M_GLITCH) && (v2[0] == M_DLL || v2[0] == M_GLITCH))
|
|
{
|
|
Go4kVSTi_ClearDelayLines();
|
|
Go4kVSTi_UpdateDelayTimes();
|
|
}
|
|
}
|
|
|
|
// init a unit slot
|
|
void Go4kVSTi_InitSlot(BYTE* slot, int channel, int type)
|
|
{
|
|
// set default values
|
|
slot[0] = type;
|
|
if (type == M_ENV)
|
|
{
|
|
ENV_valP v = (ENV_valP)slot;
|
|
v->attac = 64;
|
|
v->decay = 64;
|
|
v->sustain = 64;
|
|
v->release = 64;
|
|
v->gain = 128;
|
|
}
|
|
if (type == M_VCO)
|
|
{
|
|
VCO_valP v = (VCO_valP)slot;
|
|
v->transpose = 64;
|
|
v->detune = 64;
|
|
v->phaseofs = 0;
|
|
v->gain =0x55;
|
|
v->color = 64;
|
|
v->shape = 64;
|
|
v->gain = 128;
|
|
v->flags = VCO_SINE;
|
|
}
|
|
if (type == M_VCF)
|
|
{
|
|
VCF_valP v = (VCF_valP)slot;
|
|
v->freq = 64;
|
|
v->res = 64;
|
|
v->type = VCF_LOWPASS;
|
|
}
|
|
if (type == M_DST)
|
|
{
|
|
DST_valP v = (DST_valP)slot;
|
|
v->drive = 64;
|
|
v->snhfreq = 128;
|
|
v->stereo = 0;
|
|
}
|
|
if (type == M_DLL)
|
|
{
|
|
DLL_valP v = (DLL_valP)slot;
|
|
v->reverb = 0;
|
|
v->delay = 0;
|
|
v->count = 1;
|
|
v->pregain = 64;
|
|
v->dry = 128;
|
|
v->feedback = 64;
|
|
v->damp = 64;
|
|
v->guidelay = 40;
|
|
v->synctype = 1;
|
|
v->leftreverb = 0;
|
|
v->depth = 0;
|
|
v->freq = 0;
|
|
}
|
|
if (type == M_FOP)
|
|
{
|
|
FOP_valP v = (FOP_valP)slot;
|
|
v->flags = FOP_MULP;
|
|
}
|
|
if (type == M_FST)
|
|
{
|
|
FST_valP v = (FST_valP)slot;
|
|
v->amount = 64;
|
|
v->type = FST_SET;
|
|
v->dest_stack = -1;
|
|
v->dest_unit = -1;
|
|
v->dest_slot = -1;
|
|
v->dest_id = -1;
|
|
}
|
|
if (type == M_PAN)
|
|
{
|
|
PAN_valP v = (PAN_valP)slot;
|
|
v->panning = 64;
|
|
}
|
|
if (type == M_OUT)
|
|
{
|
|
OUT_valP v = (OUT_valP)slot;
|
|
v->gain = 64;
|
|
v->auxsend = 0;
|
|
}
|
|
if (type == M_ACC)
|
|
{
|
|
ACC_valP v = (ACC_valP)slot;
|
|
v->flags = ACC_OUT;
|
|
}
|
|
if (type == M_FLD)
|
|
{
|
|
FLD_valP v = (FLD_valP)slot;
|
|
v->value = 64;
|
|
}
|
|
if (type == M_GLITCH)
|
|
{
|
|
GLITCH_valP v = (GLITCH_valP)slot;
|
|
v->active = 0;
|
|
v->dry = 0;
|
|
v->dsize = 64;
|
|
v->dpitch = 64;
|
|
v->guidelay = 40;
|
|
}
|
|
}
|
|
|
|
// init a instrument slot
|
|
void Go4kVSTi_InitInstrumentSlot(char channel, int s, int type)
|
|
{
|
|
if (s >= SynthObj.HighestSlotIndex[channel])
|
|
SynthObj.HighestSlotIndex[channel] = s;
|
|
// clear values and workspace
|
|
Go4kVSTi_ClearInstrumentSlot(channel, s);
|
|
// init with default values
|
|
Go4kVSTi_InitSlot(SynthObj.InstrumentValues[channel][s], channel, type);
|
|
if (type == M_DLL || type == M_GLITCH)
|
|
{
|
|
Go4kVSTi_ClearDelayLines();
|
|
Go4kVSTi_UpdateDelayTimes();
|
|
}
|
|
}
|
|
|
|
// init a global slot
|
|
void Go4kVSTi_InitGlobalSlot(int s, int type)
|
|
{
|
|
if (s >= SynthObj.HighestSlotIndex[16])
|
|
SynthObj.HighestSlotIndex[16] = s;
|
|
// clear values and workspace
|
|
Go4kVSTi_ClearGlobalSlot(s);
|
|
// init with default values
|
|
Go4kVSTi_InitSlot(SynthObj.GlobalValues[s], 16, type);
|
|
if (type == M_DLL || type == M_GLITCH)
|
|
{
|
|
Go4kVSTi_ClearDelayLines();
|
|
Go4kVSTi_UpdateDelayTimes();
|
|
}
|
|
}
|
|
|
|
// panic
|
|
void Go4kVSTi_Panic()
|
|
{
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
// clear workspace
|
|
InstrumentWorkspace* w = &(SynthObj.InstrumentWork[i*MAX_POLYPHONY]);
|
|
memset(w, 0, sizeof(InstrumentWorkspace)*MAX_POLYPHONY);
|
|
SynthObj.SignalTrace[i] = 0.0f;
|
|
}
|
|
// clear workspace
|
|
memset(&(SynthObj.GlobalWork), 0, sizeof(InstrumentWorkspace));
|
|
Go4kVSTi_ClearDelayLines();
|
|
}
|
|
|
|
static float delayTimeFraction[33] =
|
|
{
|
|
4.0f * (1.0f/32.0f) * (2.0f/3.0f),
|
|
4.0f * (1.0f/32.0f),
|
|
4.0f * (1.0f/32.0f) * (3.0f/2.0f),
|
|
4.0f * (1.0f/16.0f) * (2.0f/3.0f),
|
|
4.0f * (1.0f/16.0f),
|
|
4.0f * (1.0f/16.0f) * (3.0f/2.0f),
|
|
4.0f * (1.0f/8.0f) * (2.0f/3.0f),
|
|
4.0f * (1.0f/8.0f),
|
|
4.0f * (1.0f/8.0f) * (3.0f/2.0f),
|
|
4.0f * (1.0f/4.0f) * (2.0f/3.0f),
|
|
4.0f * (1.0f/4.0f),
|
|
4.0f * (1.0f/4.0f) * (3.0f/2.0f),
|
|
4.0f * (1.0f/2.0f) * (2.0f/3.0f),
|
|
4.0f * (1.0f/2.0f),
|
|
4.0f * (1.0f/2.0f) * (3.0f/2.0f),
|
|
4.0f * (1.0f) * (2.0f/3.0f),
|
|
4.0f * (1.0f),
|
|
4.0f * (1.0f) * (3.0f/2.0f),
|
|
4.0f * (2.0f) * (2.0f/3.0f),
|
|
4.0f * (2.0f),
|
|
4.0f * (2.0f) * (3.0f/2.0f),
|
|
4.0f * (3.0f/8.0f),
|
|
4.0f * (5.0f/8.0f),
|
|
4.0f * (7.0f/8.0f),
|
|
4.0f * (9.0f/8.0f),
|
|
4.0f * (11.0f/8.0f),
|
|
4.0f * (13.0f/8.0f),
|
|
4.0f * (15.0f/8.0f),
|
|
4.0f * (3.0f/4.0f),
|
|
4.0f * (5.0f/4.0f),
|
|
4.0f * (7.0f/4.0f),
|
|
4.0f * (3.0f/2.0f),
|
|
4.0f * (3.0f/2.0f),
|
|
};
|
|
|
|
void Go4kVSTi_UpdateDelayTimes()
|
|
{
|
|
int delayindex = 17;
|
|
for (int i = 0; i <= MAX_INSTRUMENTS; i++)
|
|
{
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
DLL_valP v;
|
|
if (i < MAX_INSTRUMENTS)
|
|
v = (DLL_valP)(SynthObj.InstrumentValues[i][u]);
|
|
else
|
|
v = (DLL_valP)(SynthObj.GlobalValues[u]);
|
|
|
|
if (v->id == M_DLL)
|
|
{
|
|
//DLL_valP v = (DLL_valP)(SynthObj.InstrumentValues[i][u]);
|
|
if (v->reverb)
|
|
{
|
|
if (v->leftreverb)
|
|
{
|
|
v->delay = 1;
|
|
v->count = 8;
|
|
}
|
|
else
|
|
{
|
|
v->delay = 9;
|
|
v->count = 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int delay;
|
|
if (v->synctype == 2)
|
|
{
|
|
(&go4k_delay_times)[delayindex] = 0; // added for debug. doesnt hurt though
|
|
v->delay = 0;
|
|
v->count = 1;
|
|
}
|
|
else
|
|
{
|
|
if (v->synctype == 1)
|
|
{
|
|
float ftime;
|
|
float quarterlength = 60.0f/Go4kVSTi_GetBPM();
|
|
ftime = quarterlength*delayTimeFraction[v->guidelay>>2];
|
|
delay = 44100.0f*ftime;
|
|
if (delay >= 65536)
|
|
delay = 65535;
|
|
}
|
|
else
|
|
{
|
|
delay = v->guidelay*16;
|
|
}
|
|
(&go4k_delay_times)[delayindex] = delay;
|
|
v->delay = delayindex;
|
|
v->count = 1;
|
|
}
|
|
delayindex++;
|
|
}
|
|
}
|
|
|
|
if (v->id == M_GLITCH)
|
|
{
|
|
GLITCH_valP v2 = (GLITCH_valP)(v);
|
|
int delay;
|
|
float ftime;
|
|
float quarterlength = 60.0f/Go4kVSTi_GetBPM();
|
|
ftime = quarterlength*delayTimeFraction[v2->guidelay>>2];
|
|
delay = 44100.0f*ftime*0.25; // slice time is in fractions per beat (therefore / 4)
|
|
if (delay >= 65536)
|
|
delay = 65535;
|
|
(&go4k_delay_times)[delayindex] = delay;
|
|
v2->delay = delayindex;
|
|
|
|
delayindex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// clear delay lines
|
|
void Go4kVSTi_ClearDelayLines()
|
|
{
|
|
memset((&go4k_delay_buffer), 0, 16*16*((65536+5)*4));
|
|
}
|
|
|
|
// set global bpm
|
|
void Go4kVSTi_SetBPM(float bpm)
|
|
{
|
|
BeatsPerMinute = bpm;
|
|
LFO_NORMALIZE = bpm/(44100.0*60.0);
|
|
Go4kVSTi_UpdateDelayTimes();
|
|
}
|
|
|
|
// get bpm
|
|
float Go4kVSTi_GetBPM()
|
|
{
|
|
return BeatsPerMinute;
|
|
}
|
|
|
|
// enable solo mode for a single channel only
|
|
void Go4kVSTi_Solo(int channel, int solo)
|
|
{
|
|
if (solo)
|
|
{
|
|
SoloChannel = channel;
|
|
Solo = true;
|
|
}
|
|
else
|
|
{
|
|
Solo = false;
|
|
}
|
|
}
|
|
|
|
// sample times tick the whole synth pipeline. results are left and right output sample
|
|
|
|
void Go4kVSTi_Tick(float *oleft, float *oright, int samples)
|
|
{
|
|
if (Recording)
|
|
{
|
|
samplesProcessed += samples;
|
|
|
|
if (RecordingNoise)
|
|
{
|
|
// send a stayalive signal to the host
|
|
for (int i = 0; i < samples; i++)
|
|
{
|
|
float signal = 0.03125*((float)(i & 255) / 128.0f - 1.0f);
|
|
*oleft++ = signal;
|
|
*oright++ = signal;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// do as many samples as requested
|
|
int s = 0;
|
|
while (s < samples)
|
|
{
|
|
float left=0.0f;
|
|
float right=0.0f;
|
|
|
|
go4k_delay_buffer_ofs = (DWORD)(&go4k_delay_buffer);
|
|
// loop all instruments
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
// solo mode and not the channel we want?
|
|
if (Solo && i != SoloChannel)
|
|
{
|
|
// loop all voices and clear outputs
|
|
for (int p = 0; p < SynthObj.Polyphony; p++)
|
|
{
|
|
InstrumentWorkspaceP iwork = &(SynthObj.InstrumentWork[i*MAX_POLYPHONY+p]);
|
|
iwork->dlloutl = 0.0f;
|
|
iwork->dlloutr = 0.0f;
|
|
iwork->outl = 0.0f;
|
|
iwork->outr = 0.0f;
|
|
}
|
|
// adjust delay index
|
|
for (int s = 0; s < MAX_UNITS; s++)
|
|
{
|
|
BYTE* val = SynthObj.InstrumentValues[i][s];
|
|
if (val[0] == M_DLL || val[0] == M_GLITCH)
|
|
go4k_delay_buffer_ofs += (5+65536)*4*SynthObj.Polyphony;
|
|
}
|
|
// go to next instrument
|
|
continue;
|
|
}
|
|
// if the instrument signal stack is valid and we still got a signal from that instrument
|
|
if (SynthObj.InstrumentSignalValid[i] && (fabs(SynthObj.SignalTrace[i]) > 0.00001f))
|
|
{
|
|
float sumSignals = 0.0f;
|
|
// loop all voices
|
|
for (int p = 0; p < SynthObj.Polyphony; p++)
|
|
{
|
|
InstrumentWorkspaceP iwork = &(SynthObj.InstrumentWork[i*MAX_POLYPHONY+p]);
|
|
float *lwrk = iwork->workspace;
|
|
DWORD inote = iwork->note;
|
|
// loop each slot
|
|
for (int s = 0; s <= SynthObj.HighestSlotIndex[i]; s++)
|
|
{
|
|
BYTE* val = SynthObj.InstrumentValues[i][s];
|
|
float *wrk = &(iwork->workspace[s*MAX_UNIT_SLOTS]);
|
|
if (val[0] == M_FST)
|
|
{
|
|
FST_valP v = (FST_valP)val;
|
|
// if a target slot is set
|
|
if (v->dest_slot != -1)
|
|
{
|
|
InstrumentWorkspaceP mwork;
|
|
int polyphonicStore = SynthObj.Polyphony;
|
|
int stack = v->dest_stack;
|
|
// local storage?
|
|
if (stack == -1 || stack == i)
|
|
{
|
|
// only store the sample in the current workspace
|
|
polyphonicStore = 1;
|
|
mwork = iwork;
|
|
}
|
|
else if (stack == MAX_INSTRUMENTS)
|
|
mwork = &(SynthObj.GlobalWork);
|
|
else
|
|
mwork = &(SynthObj.InstrumentWork[stack*MAX_POLYPHONY]);
|
|
|
|
float* mdest = &(mwork->workspace[v->dest_unit*MAX_UNIT_SLOTS + v->dest_slot]);
|
|
float amount = (2.0f*v->amount - 128.0f)*0.0078125f;
|
|
int storetype = v->type;
|
|
for (int stc = 0; stc < polyphonicStore; stc++)
|
|
{
|
|
__asm
|
|
{
|
|
push eax
|
|
push ebx
|
|
|
|
mov eax, mdest
|
|
mov ebx, storetype
|
|
|
|
fld amount
|
|
fmul st(0), st(1)
|
|
|
|
// test ebx, FST_MUL
|
|
// jz store_func_add
|
|
// fmul dword ptr [eax]
|
|
// jmp store_func_set
|
|
//store_func_add:
|
|
test ebx, FST_ADD
|
|
jz store_func_set
|
|
fadd dword ptr [eax]
|
|
store_func_set:
|
|
fstp dword ptr [eax]
|
|
store_func_done:
|
|
pop ebx
|
|
pop eax
|
|
}
|
|
mdest += sizeof(InstrumentWorkspace)/4;
|
|
}
|
|
// remove signal on pop flag
|
|
if (storetype & FST_POP)
|
|
{
|
|
_asm fstp st(0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// only process if note active or dll unit
|
|
if (val[0])
|
|
{
|
|
// set up and call synth core func
|
|
__asm
|
|
{
|
|
pushad
|
|
xor eax, eax
|
|
mov esi, val
|
|
lodsb
|
|
mov eax, dword ptr [SynthFuncs+eax*4]
|
|
mov ebx, inote
|
|
mov ecx, lwrk
|
|
mov ebp, wrk
|
|
call eax
|
|
popad
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// check for end of note
|
|
DWORD envstate = *((BYTE*)(lwrk));
|
|
if (envstate == ENV_STATE_OFF)
|
|
{
|
|
iwork->note = 0;
|
|
}
|
|
sumSignals += fabsf(iwork->outl) + fabsf(iwork->outr) + fabsf(iwork->dlloutl) + fabsf(iwork->dlloutr);
|
|
}
|
|
// update envelope follower only for non control instruments. (1s attack rate) for total instrument signal
|
|
if (SynthObj.ControlInstrument[i])
|
|
SynthObj.SignalTrace[i] = 1.0f;
|
|
else
|
|
SynthObj.SignalTrace[i] = sumSignals + 0.999977324f * ( SynthObj.SignalTrace[i] - sumSignals );
|
|
}
|
|
// instrument stack invalid
|
|
else
|
|
{
|
|
// adjust delay index
|
|
for (int s = 0; s < MAX_UNITS; s++)
|
|
{
|
|
BYTE* val = SynthObj.InstrumentValues[i][s];
|
|
if (val[0] == M_DLL || val[0] == M_GLITCH)
|
|
go4k_delay_buffer_ofs += (5+65536)*4*SynthObj.Polyphony;
|
|
}
|
|
// loop all voices
|
|
for (int p = 0; p < SynthObj.Polyphony; p++)
|
|
{
|
|
InstrumentWorkspaceP iwork = &(SynthObj.InstrumentWork[i*MAX_POLYPHONY+p]);
|
|
iwork->dlloutl = 0.0f;
|
|
iwork->dlloutr = 0.0f;
|
|
iwork->outl = 0.0f;
|
|
iwork->outr = 0.0f;
|
|
}
|
|
}
|
|
}
|
|
// if the global stack is valid
|
|
if (SynthObj.GlobalSignalValid)
|
|
{
|
|
InstrumentWorkspaceP gwork = &(SynthObj.GlobalWork);
|
|
float *lwrk = gwork->workspace;
|
|
DWORD gnote = 1;
|
|
gwork->note = 1;
|
|
// loop all global slots
|
|
for (int s = 0; s <= SynthObj.HighestSlotIndex[16]; s++)
|
|
{
|
|
BYTE* val = SynthObj.GlobalValues[s];
|
|
float *wrk = &(lwrk[s*MAX_UNIT_SLOTS]);
|
|
// manually accumulate signals
|
|
float ACCL = 0.0f;
|
|
float ACCR = 0.0f;
|
|
if (val[0] == M_ACC)
|
|
{
|
|
ACC_valP av = (ACC_valP)val;
|
|
if (av->flags == ACC_OUT)
|
|
{
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
for (int p = 0; p < SynthObj.Polyphony; p++)
|
|
{
|
|
ACCL += SynthObj.InstrumentWork[i*MAX_POLYPHONY+p].outl;
|
|
ACCR += SynthObj.InstrumentWork[i*MAX_POLYPHONY+p].outr;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
for (int p = 0; p < SynthObj.Polyphony; p++)
|
|
{
|
|
ACCL += SynthObj.InstrumentWork[i*MAX_POLYPHONY+p].dlloutl;
|
|
ACCR += SynthObj.InstrumentWork[i*MAX_POLYPHONY+p].dlloutr;
|
|
}
|
|
}
|
|
}
|
|
// push the accumulated signals on the fp stack
|
|
__asm
|
|
{
|
|
fld ACCR
|
|
fld ACCL
|
|
}
|
|
}
|
|
// no ACC unit, check store
|
|
else if (val[0] == M_FST)
|
|
{
|
|
FST_valP v = (FST_valP)val;
|
|
// if a target slot is set
|
|
if (v->dest_slot != -1)
|
|
{
|
|
InstrumentWorkspaceP mwork;
|
|
int polyphonicStore = SynthObj.Polyphony;
|
|
int stack = v->dest_stack;
|
|
// local storage?
|
|
if (stack == -1 || stack == MAX_INSTRUMENTS)
|
|
{
|
|
// only store the sample in the current workspace
|
|
polyphonicStore = 1;
|
|
mwork = &(SynthObj.GlobalWork);
|
|
}
|
|
else
|
|
mwork = &(SynthObj.InstrumentWork[stack*MAX_POLYPHONY]);
|
|
|
|
float* mdest = &(mwork->workspace[v->dest_unit*MAX_UNIT_SLOTS + v->dest_slot]);
|
|
float amount = (2.0f*v->amount - 128.0f)*0.0078125f;;
|
|
int storetype = v->type;
|
|
for (int stc = 0; stc < polyphonicStore; stc++)
|
|
{
|
|
__asm
|
|
{
|
|
push eax
|
|
push ebx
|
|
|
|
mov eax, mdest
|
|
mov ebx, storetype
|
|
|
|
fld amount
|
|
fmul st(0), st(1)
|
|
|
|
// test ebx, FST_MUL
|
|
// jz gstore_func_add
|
|
// fmul dword ptr [eax]
|
|
// jmp gstore_func_set
|
|
//gstore_func_add:
|
|
test ebx, FST_ADD
|
|
jz gstore_func_set
|
|
fadd dword ptr [eax]
|
|
gstore_func_set:
|
|
fstp dword ptr [eax]
|
|
gstore_func_done:
|
|
pop ebx
|
|
pop eax
|
|
}
|
|
mdest += sizeof(InstrumentWorkspace)/4;
|
|
}
|
|
// remove signal on pop flag
|
|
if (storetype & FST_POP)
|
|
{
|
|
_asm fstp st(0);
|
|
}
|
|
}
|
|
}
|
|
// just call synth core func
|
|
else
|
|
{
|
|
if (val[0])
|
|
{
|
|
__asm
|
|
{
|
|
pushad
|
|
xor eax, eax
|
|
mov esi, val
|
|
lodsb
|
|
mov eax, dword ptr [SynthFuncs+eax*4]
|
|
mov ebx, gnote
|
|
mov ecx, lwrk
|
|
mov ebp, wrk
|
|
call eax
|
|
popad
|
|
}
|
|
}
|
|
}
|
|
}
|
|
left = gwork->outl;
|
|
right = gwork->outr;
|
|
}
|
|
|
|
// clip
|
|
if (left < -1.0f)
|
|
left = -1.0f;
|
|
if (left > 1.0f)
|
|
left = 1.0f;
|
|
if (right < -1.0f)
|
|
right = -1.0f;
|
|
if (right > 1.0f)
|
|
right = 1.0f;
|
|
|
|
*(oleft++) = left;
|
|
*(oright++) = right;
|
|
|
|
s++;
|
|
} // end sample loop
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Synth input processing
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// prepare for recording the midi stream
|
|
void Go4kVSTi_Record(bool record, bool recordingNoise, int patternsize, float patternquant)
|
|
{
|
|
Recording = record;
|
|
RecordingNoise = recordingNoise;
|
|
// if we started recording, clear all record streams
|
|
if (Recording)
|
|
{
|
|
TickScaler = patternquant;
|
|
PatternSize = (int)(patternsize*TickScaler);
|
|
// set first recording event variable to true to enable start time reset on the first occuring event
|
|
FirstRecordingEvent = true;
|
|
// clear all buffers
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
InstrumentOn[i] = -1;
|
|
InstrumentRecord[i].clear();
|
|
for (int j = 0; j < 256*256; j++)
|
|
InstrumentRecord[i].push_back(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// nothing recorded?
|
|
if (FirstRecordingEvent == true)
|
|
return;
|
|
Recording = true;
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
Go4kVSTi_StopVoice(i, 0);
|
|
Recording = false;
|
|
// how many ticks did we record?
|
|
MaxTicks = (int)(0.5f+((float)samplesProcessed/SamplesPerTick));
|
|
int remainder = MaxTicks % 16;
|
|
MaxTicks += remainder;
|
|
// fold patterns if TickScaler < 1, this is needed because directly recording at half samplerate leads to information loss
|
|
if (TickScaler < 1.0f)
|
|
{
|
|
MaxTicks = (int)((float)MaxTicks*TickScaler);
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
for (int j = 0; j < (int)(256*256*TickScaler); j++)
|
|
InstrumentRecord[i][j] = InstrumentRecord[i][(int)(j/TickScaler)];
|
|
}
|
|
}
|
|
// open file dialog and save if desired ...
|
|
// the save function called from this one is GoSynth_SaveByteStream
|
|
GetStreamFileName();
|
|
}
|
|
}
|
|
|
|
// add a voice with given parameters to synth
|
|
void Go4kVSTi_AddVoice(int channel, int note)
|
|
{
|
|
// record song
|
|
if (Recording)
|
|
{
|
|
// check for the first recording event
|
|
if (FirstRecordingEvent)
|
|
{
|
|
FirstRecordingEvent = false;
|
|
// reset time stamp for very first event
|
|
samplesProcessed = 0;
|
|
// Set samples per tick for this recording
|
|
if (TickScaler >= 1.0f)
|
|
SamplesPerTick = 44100.0f*4.0f*60.0f/(BeatsPerMinute*16*TickScaler);
|
|
else
|
|
SamplesPerTick = 44100.0f*4.0f*60.0f/(BeatsPerMinute*16);
|
|
}
|
|
int CurrentTick = (int)(0.5f+((float)samplesProcessed/SamplesPerTick));
|
|
if (InstrumentOn[channel] >= 0)
|
|
{
|
|
for (int i = CurrentTick-1; i > InstrumentOn[channel]; i--)
|
|
{
|
|
if (!InstrumentRecord[channel][i])
|
|
InstrumentRecord[channel][i] = -1;
|
|
}
|
|
}
|
|
if (!InstrumentRecord[channel][CurrentTick])
|
|
{
|
|
InstrumentRecord[channel][CurrentTick] = note;
|
|
InstrumentOn[channel] = CurrentTick;
|
|
}
|
|
|
|
// no signals to synth when using recording noise
|
|
if (RecordingNoise == true)
|
|
return;
|
|
}
|
|
|
|
InstrumentWorkspaceP work,work2;
|
|
work = &(SynthObj.InstrumentWork[channel*MAX_POLYPHONY+0]);
|
|
work->release = 1;
|
|
work2 = &(SynthObj.InstrumentWork[channel*MAX_POLYPHONY+1]);
|
|
work2->release = 1;
|
|
// filp worspace
|
|
if (SynthObj.Polyphony > 1)
|
|
{
|
|
work = &(SynthObj.InstrumentWork[channel*MAX_POLYPHONY+SynthObj.VoiceIndex[channel]]);
|
|
SynthObj.VoiceIndex[channel] = SynthObj.VoiceIndex[channel] ^ 0x1;
|
|
}
|
|
// add new note
|
|
memset(work, 0, (2+MAX_UNITS*MAX_UNIT_SLOTS)*4);
|
|
work->note = note;
|
|
SynthObj.SignalTrace[channel] = 1.0f;
|
|
// check if its a controll instrument which is played
|
|
SynthObj.ControlInstrument[channel] = 1;
|
|
for (int i = 0; i < MAX_UNITS; i++)
|
|
{
|
|
if (SynthObj.InstrumentValues[channel][i][0] == M_OUT)
|
|
{
|
|
SynthObj.ControlInstrument[channel] = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// stop a voice with given parameters in synth
|
|
void Go4kVSTi_StopVoice(int channel, int note)
|
|
{
|
|
// record song
|
|
if (Recording)
|
|
{
|
|
int CurrentTick = (int)(0.5f+((float)samplesProcessed/SamplesPerTick));
|
|
if (InstrumentOn[channel] >= 0)
|
|
{
|
|
for (int i = CurrentTick-1; i > InstrumentOn[channel]; i--)
|
|
{
|
|
if (!InstrumentRecord[channel][i])
|
|
InstrumentRecord[channel][i] = -1;
|
|
}
|
|
}
|
|
// if (!InstrumentRecord[channel][CurrentTick])
|
|
InstrumentOn[channel] = -1;
|
|
|
|
// no signals to synth when only using recording noise
|
|
if (RecordingNoise == true)
|
|
return;
|
|
}
|
|
|
|
InstrumentWorkspaceP work,work2;
|
|
// release notes
|
|
work = &(SynthObj.InstrumentWork[channel*MAX_POLYPHONY+0]);
|
|
work->release = 1;
|
|
work2 = &(SynthObj.InstrumentWork[channel*MAX_POLYPHONY+1]);
|
|
work2->release = 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// convenience functions for loading and storing patches and instruments
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
void FlipSlotModulations(int stack, int unit1, int unit2)
|
|
{
|
|
// look in all instruments if a store unit had its target on one of the changed units
|
|
for (int i = 0; i <= MAX_INSTRUMENTS; i++)
|
|
{
|
|
BYTE* values;
|
|
if (i < MAX_INSTRUMENTS)
|
|
values = SynthObj.InstrumentValues[i][0];
|
|
else
|
|
values = SynthObj.GlobalValues[0];
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
if (values[u*MAX_UNIT_SLOTS+0] == M_FST)
|
|
{
|
|
FST_valP v = (FST_valP)(&values[u*MAX_UNIT_SLOTS+0]);
|
|
|
|
int target_inst;
|
|
if (v->dest_stack == -1)
|
|
target_inst = i;
|
|
else
|
|
target_inst = v->dest_stack;
|
|
|
|
// the store points to another stack, so continue
|
|
if (target_inst != stack)
|
|
continue;
|
|
|
|
// a up/down process
|
|
if (unit2 != -1)
|
|
{
|
|
// if the target unit was unit1 or unit2 realign target unit
|
|
if (v->dest_unit == unit1)
|
|
{
|
|
v->dest_unit = unit2;
|
|
}
|
|
else if (v->dest_unit == unit2)
|
|
{
|
|
v->dest_unit = unit1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// autoconvert 1.0 instrument stacks
|
|
bool Autoconvert10(int stack)
|
|
{
|
|
// get desired stack
|
|
BYTE* values;
|
|
if (stack < MAX_INSTRUMENTS)
|
|
values = SynthObj.InstrumentValues[stack][0];
|
|
else
|
|
values = SynthObj.GlobalValues[0];
|
|
|
|
// replace the delay with the new one
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
if (values[u*MAX_UNIT_SLOTS+0] == M_DLL)
|
|
{
|
|
DLL10_val ov;
|
|
memcpy(&ov, &values[u*MAX_UNIT_SLOTS+0], sizeof(DLL10_val));
|
|
DLL_valP nv = (DLL_valP)(&values[u*MAX_UNIT_SLOTS+0]);
|
|
nv->id = ov.id;
|
|
nv->pregain = ov.pregain;
|
|
nv->dry = ov.dry;
|
|
nv->feedback = ov.feedback;
|
|
nv->damp = ov.damp;
|
|
nv->freq = 0;
|
|
nv->depth = 0;
|
|
nv->guidelay = ov.guidelay;
|
|
nv->synctype = ov.synctype;
|
|
nv->leftreverb = ov.leftreverb;
|
|
nv->reverb = ov.reverb;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// autoconvert 1.1 instrument stacks
|
|
bool Autoconvert11(int stack)
|
|
{
|
|
// get desired stack
|
|
BYTE* values;
|
|
if (stack < MAX_INSTRUMENTS)
|
|
values = SynthObj.InstrumentValues[stack][0];
|
|
else
|
|
values = SynthObj.GlobalValues[0];
|
|
|
|
// replace the osc with the new one
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
if (values[u*MAX_UNIT_SLOTS+0] == M_VCO)
|
|
{
|
|
VCO11_val ov;
|
|
memcpy(&ov, &values[u*MAX_UNIT_SLOTS+0], sizeof(VCO11_val));
|
|
VCO_valP nv = (VCO_valP)(&values[u*MAX_UNIT_SLOTS+0]);
|
|
nv->id = ov.id;
|
|
nv->transpose = ov.transpose;
|
|
nv->detune = ov.detune;
|
|
nv->phaseofs = ov.phaseofs;
|
|
nv->gate = 0x55;
|
|
nv->color = ov.color;
|
|
nv->shape = ov.shape;
|
|
nv->gain = ov.gain;
|
|
nv->flags = ov.flags;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// autoconvert 1.3 instrument stacks
|
|
bool Autoconvert13(int stack)
|
|
{
|
|
// get desired stack
|
|
BYTE* values;
|
|
if (stack < MAX_INSTRUMENTS)
|
|
values = SynthObj.InstrumentValues[stack][0];
|
|
else
|
|
values = SynthObj.GlobalValues[0];
|
|
|
|
// replace the osc with the new one
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
if (values[u*MAX_UNIT_SLOTS+0] == M_VCO)
|
|
{
|
|
VCO_valP nv = (VCO_valP)(&values[u*MAX_UNIT_SLOTS+0]);
|
|
// correct sine color as it has a meaning now in 1.4 format
|
|
if (nv->flags & VCO_SINE)
|
|
nv->color = 128;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
// load patch data
|
|
void Go4kVSTi_LoadPatch(char *filename)
|
|
{
|
|
Go4kVSTi_ResetPatch();
|
|
FILE *file = fopen(filename, "rb");
|
|
if (file)
|
|
{
|
|
DWORD version;
|
|
bool version10 = false;
|
|
bool version11 = false;
|
|
bool version12 = false;
|
|
bool version13 = false;
|
|
fread(&version, 1, 4, file);
|
|
if (versiontag != version)
|
|
{
|
|
// version 1.3 file
|
|
if (version == versiontag13)
|
|
{
|
|
// only mulp2 unit added and layout for instruments changed, no need for message
|
|
//MessageBox(0,"Autoconvert. Please save file again", "1.3 File Format", MB_OK | MB_SETFOREGROUND);
|
|
version13 = true;
|
|
}
|
|
// version 1.2 file
|
|
else if (version == versiontag12)
|
|
{
|
|
// only fld unit added, no need for message
|
|
//MessageBox(0,"Autoconvert. Please save file again", "1.2 File Format", MB_OK | MB_SETFOREGROUND);
|
|
version12 = true;
|
|
version13 = true;
|
|
}
|
|
// version 1.1 file
|
|
else if (version == versiontag11)
|
|
{
|
|
MessageBox(0,"Autoconvert. Please save file again", "1.1 File Format", MB_OK | MB_SETFOREGROUND);
|
|
version11 = true;
|
|
version12 = true;
|
|
version13 = true;
|
|
}
|
|
// version 1.0 file
|
|
else if (version == versiontag10)
|
|
{
|
|
MessageBox(0,"Autoconvert. Please save file again", "1.0 File Format", MB_OK | MB_SETFOREGROUND);
|
|
version10 = true;
|
|
version11 = true;
|
|
version12 = true;
|
|
version13 = true;
|
|
}
|
|
// newer format than supported
|
|
else
|
|
{
|
|
MessageBox(0,"The file was created with a newer version of 4klang.", "File Format Error", MB_ICONERROR | MB_SETFOREGROUND);
|
|
fclose(file);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// read data
|
|
fread(&(SynthObj.Polyphony), 1, 4, file);
|
|
fread(SynthObj.InstrumentNames, 1, MAX_INSTRUMENTS*64, file);
|
|
for (int i=0; i<MAX_INSTRUMENTS; i++)
|
|
{
|
|
if (version13)
|
|
{
|
|
BYTE dummyBuf[16];
|
|
for (int j = 0; j < 32; j++) // 1.3 format had 32 units
|
|
{
|
|
fread(SynthObj.InstrumentValues[i][j], 1, 16, file); // 1.3 format had 32 unit slots, but not fully used
|
|
fread(dummyBuf, 1, 16, file); // 1.3 read remaining block to dummy
|
|
}
|
|
}
|
|
else
|
|
fread(SynthObj.InstrumentValues[i], 1, MAX_UNITS*MAX_UNIT_SLOTS, file);
|
|
}
|
|
if (version13)
|
|
{
|
|
BYTE dummyBuf[16];
|
|
for (int j = 0; j < 32; j++) // 1.3 format had 32 units
|
|
{
|
|
fread(SynthObj.GlobalValues[j], 1, 16, file); // 1.3 format had 32 unit slots, but not fully used
|
|
fread(dummyBuf, 1, 16, file); // 1.3 read remaining block to dummy
|
|
}
|
|
}
|
|
else
|
|
fread(SynthObj.GlobalValues, 1, MAX_UNITS*MAX_UNIT_SLOTS, file);
|
|
fclose(file);
|
|
|
|
// convert 1.0 file format
|
|
if (version10)
|
|
{
|
|
// convert all instruments
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
if (!Autoconvert10(i))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Instrument %d could not be converted", i+1);
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
// convert global
|
|
if (!Autoconvert10(MAX_INSTRUMENTS))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Global could not be converted");
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
// convert 1.1 file format
|
|
if (version11)
|
|
{
|
|
// convert all instruments
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
if (!Autoconvert11(i))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Instrument %d could not be converted", i+1);
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
// convert global
|
|
if (!Autoconvert11(MAX_INSTRUMENTS))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Global could not be converted");
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
// convert 1.2 file format
|
|
if (version12)
|
|
{
|
|
// nothing to do, only fld unit added at the end
|
|
}
|
|
// version 1.3 file format
|
|
if (version13)
|
|
{
|
|
// convert all instruments
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
if (!Autoconvert13(i))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Instrument %d could not be converted", i+1);
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
// convert global
|
|
if (!Autoconvert13(MAX_INSTRUMENTS))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Global could not be converted");
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
}
|
|
Go4kVSTi_UpdateDelayTimes();
|
|
}
|
|
|
|
// save patch data
|
|
void Go4kVSTi_SavePatch(char *filename)
|
|
{
|
|
FILE *file = fopen(filename, "wb");
|
|
if (file)
|
|
{
|
|
fwrite(&versiontag, 1, 4, file);
|
|
fwrite(&(SynthObj.Polyphony), 1, 4, file);
|
|
fwrite(SynthObj.InstrumentNames, 1, MAX_INSTRUMENTS*64, file);
|
|
fwrite(SynthObj.InstrumentValues, 1, MAX_INSTRUMENTS*MAX_UNITS*MAX_UNIT_SLOTS, file);
|
|
fwrite(SynthObj.GlobalValues, 1, MAX_UNITS*MAX_UNIT_SLOTS, file);
|
|
fclose(file);
|
|
}
|
|
}
|
|
|
|
// load instrumen data to specified channel
|
|
void Go4kVSTi_LoadInstrument(char* filename, char channel)
|
|
{
|
|
FILE *file = fopen(filename, "rb");
|
|
if (file)
|
|
{
|
|
DWORD version;
|
|
bool version10 = false;
|
|
bool version11 = false;
|
|
bool version12 = false;
|
|
bool version13 = false;
|
|
fread(&version, 1, 4, file);
|
|
if (versiontag != version) // 4k10
|
|
{
|
|
// version 1.3 file
|
|
if (version == versiontag13)
|
|
{
|
|
// only mulp2 unit added and layout for instruments changed, no need for message
|
|
//MessageBox(0,"Autoconvert. Please save file again", "1.3 File Format", MB_OK | MB_SETFOREGROUND);
|
|
version13 = true;
|
|
}
|
|
// version 1.2 file
|
|
else if (version == versiontag12)
|
|
{
|
|
// only fld unit added, no need for message
|
|
//MessageBox(0,"Autoconvert. Please save file again", "1.2 File Format", MB_OK | MB_SETFOREGROUND);
|
|
version12 = true;
|
|
version13 = true;
|
|
}
|
|
// version 1.1 file
|
|
else if (version == versiontag11)
|
|
{
|
|
MessageBox(0,"Autoconvert. Please save file again", "1.1 File Format", MB_OK | MB_SETFOREGROUND);
|
|
version11 = true;
|
|
version12 = true;
|
|
version13 = true;
|
|
}
|
|
// version 1.0 file
|
|
else if (version == versiontag10)
|
|
{
|
|
MessageBox(0,"Autoconvert. Please save file again", "1.0 File Format", MB_OK | MB_SETFOREGROUND);
|
|
version10 = true;
|
|
version11 = true;
|
|
version12 = true;
|
|
version13 = true;
|
|
}
|
|
// newer format than supported
|
|
else
|
|
{
|
|
MessageBox(0,"The file was created with a newer version of 4klang.", "File Format Error", MB_ICONERROR | MB_SETFOREGROUND);
|
|
fclose(file);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (channel < 16)
|
|
{
|
|
Go4kVSTi_ResetInstrument(channel);
|
|
fread(SynthObj.InstrumentNames[channel], 1, 64, file);
|
|
if (version13)
|
|
{
|
|
BYTE dummyBuf[16];
|
|
for (int j = 0; j < 32; j++) // 1.3 format had 32 units
|
|
{
|
|
fread(SynthObj.InstrumentValues[channel][j], 1, 16, file); // 1.3 format had 32 unit slots, but not fully used
|
|
fread(dummyBuf, 1, 16, file); // 1.3 read remaining block to dummy
|
|
}
|
|
}
|
|
else
|
|
fread(SynthObj.InstrumentValues[channel], 1, MAX_UNITS*MAX_UNIT_SLOTS, file);
|
|
}
|
|
else
|
|
{
|
|
Go4kVSTi_ResetGlobal();
|
|
// read the instrument name in a dummy buffer, as global section doesnt have an own name
|
|
BYTE dummyNameBuf[64];
|
|
fread(dummyNameBuf, 1, 64, file);
|
|
if (version13)
|
|
{
|
|
BYTE dummyBuf[16];
|
|
for (int j = 0; j < 32; j++) // 1.3 format had 32 units
|
|
{
|
|
fread(SynthObj.GlobalValues[j], 1, 16, file); // 1.3 format had 32 unit slots, but not fully used
|
|
fread(dummyBuf, 1, 16, file); // 1.3 read remaining block to dummy
|
|
}
|
|
}
|
|
else
|
|
fread(SynthObj.GlobalValues, 1, MAX_UNITS*MAX_UNIT_SLOTS, file);
|
|
}
|
|
fclose(file);
|
|
// convert 1.0 file format
|
|
if (version10)
|
|
{
|
|
// convert instruments
|
|
if (channel < 16)
|
|
{
|
|
if (!Autoconvert10(channel))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Instrument %d could not be converted", channel+1);
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
// convert global
|
|
else
|
|
{
|
|
if (!Autoconvert10(MAX_INSTRUMENTS))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Global could not be converted");
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
}
|
|
// convert 1.1 file format
|
|
if (version11)
|
|
{
|
|
// convert instruments
|
|
if (channel < 16)
|
|
{
|
|
if (!Autoconvert11(channel))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Instrument %d could not be converted", channel+1);
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
// convert global
|
|
else
|
|
{
|
|
if (!Autoconvert11(MAX_INSTRUMENTS))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Global could not be converted");
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
}
|
|
// convert 1.2 file format
|
|
if (version12)
|
|
{
|
|
// nothing to do, only fld unit added at the end
|
|
}
|
|
// version 1.3 file format
|
|
if (version13)
|
|
{
|
|
// convert instruments
|
|
if (channel < 16)
|
|
{
|
|
if (!Autoconvert13(channel))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Instrument %d could not be converted", channel+1);
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
// convert global
|
|
else
|
|
{
|
|
if (!Autoconvert13(MAX_INSTRUMENTS))
|
|
{
|
|
char errmsg[64];
|
|
sprintf(errmsg, "Global could not be converted");
|
|
MessageBox(0, errmsg, "Error", MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Go4kVSTi_UpdateDelayTimes();
|
|
}
|
|
|
|
// save instrument data from current channel
|
|
void Go4kVSTi_SaveInstrument(char* filename, char channel)
|
|
{
|
|
FILE *file = fopen(filename, "wb");
|
|
if (file)
|
|
{
|
|
fwrite(&versiontag, 1, 4, file);
|
|
if (channel < 16)
|
|
{
|
|
fwrite(SynthObj.InstrumentNames[channel], 1, 64, file);
|
|
fwrite(SynthObj.InstrumentValues[channel], 1, MAX_UNITS*MAX_UNIT_SLOTS, file);
|
|
}
|
|
else
|
|
{
|
|
// write a dummy name for global section as it doesnt have an own name
|
|
fwrite("GlobalUnitsStoredAs.4ki ", 1, 64, file);
|
|
fwrite(SynthObj.GlobalValues, 1, MAX_UNITS*MAX_UNIT_SLOTS, file);
|
|
}
|
|
fclose(file);
|
|
}
|
|
}
|
|
|
|
// load unit data into specified slot
|
|
void Go4kVSTi_LoadUnit(char* filename, BYTE* slot)
|
|
{
|
|
FILE *file = fopen(filename, "rb");
|
|
if (file)
|
|
{
|
|
fread(slot, 1, MAX_UNIT_SLOTS, file);
|
|
fclose(file);
|
|
if (slot[0] == M_DLL || slot[0] == M_GLITCH)
|
|
{
|
|
Go4kVSTi_ClearDelayLines();
|
|
Go4kVSTi_UpdateDelayTimes();
|
|
}
|
|
}
|
|
}
|
|
|
|
// save unit date from specified slot
|
|
void Go4kVSTi_SaveUnit(char* filename, BYTE* slot)
|
|
{
|
|
FILE *file = fopen(filename, "wb");
|
|
if (file)
|
|
{
|
|
fwrite(slot, 1, MAX_UNIT_SLOTS, file);
|
|
fclose(file);
|
|
}
|
|
}
|
|
|
|
int GetShift2(int in)
|
|
{
|
|
int ret = 0;
|
|
while (in = (in >> 1))
|
|
{
|
|
ret++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
struct SynthUses
|
|
{
|
|
bool env_gm;
|
|
bool env_adrm;
|
|
|
|
bool vco_phaseofs;
|
|
bool vco_shape;
|
|
bool vco_fm;
|
|
bool vco_pm;
|
|
bool vco_tm;
|
|
bool vco_dm;
|
|
bool vco_cm;
|
|
bool vco_gm;
|
|
bool vco_sm;
|
|
bool vco_gate;
|
|
bool vco_stereo;
|
|
|
|
bool vcf_fm;
|
|
bool vcf_rm;
|
|
bool vcf_stereo;
|
|
|
|
bool dst_use;
|
|
bool dst_snh;
|
|
bool dst_dm;
|
|
bool dst_sm;
|
|
bool dst_stereo;
|
|
|
|
bool dll_use;
|
|
bool dll_notesync;
|
|
bool dll_damp;
|
|
bool dll_chorus;
|
|
bool dll_use_mod;
|
|
bool dll_pm;
|
|
bool dll_fm;
|
|
bool dll_im;
|
|
bool dll_dm;
|
|
bool dll_sm;
|
|
bool dll_am;
|
|
|
|
bool pan_use;
|
|
bool pan_pm;
|
|
|
|
bool fstg_use;
|
|
|
|
bool out_am;
|
|
bool out_gm;
|
|
|
|
bool fld_use;
|
|
bool fld_vm;
|
|
|
|
bool glitch_use;
|
|
};
|
|
|
|
void GetUses(SynthUses *uses, bool InstrumentUsed[])
|
|
{
|
|
for (int i = 0; i <= MAX_INSTRUMENTS; i++)
|
|
{
|
|
// skip usage checks for non used instruments
|
|
if (i < MAX_INSTRUMENTS)
|
|
if (!InstrumentUsed[i])
|
|
continue;
|
|
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
BYTE *v;
|
|
if (i < MAX_INSTRUMENTS)
|
|
v = SynthObj.InstrumentValues[i][u];
|
|
else
|
|
v = SynthObj.GlobalValues[u];
|
|
|
|
if (v[0] == M_VCO)
|
|
{
|
|
if (((VCO_valP)v)->phaseofs != 0)
|
|
uses->vco_phaseofs = true;
|
|
if (((VCO_valP)v)->shape != 64)
|
|
uses->vco_shape = true;
|
|
if (((VCO_valP)v)->flags & VCO_GATE)
|
|
uses->vco_gate = true;
|
|
if (((VCO_valP)v)->flags & VCO_STEREO)
|
|
uses->vco_stereo = true;
|
|
}
|
|
if (v[0] == M_VCF)
|
|
{
|
|
if (((VCF_valP)v)->type & VCF_STEREO)
|
|
uses->vcf_stereo = true;
|
|
}
|
|
if (v[0] == M_DST)
|
|
{
|
|
uses->dst_use = true;
|
|
if (((DST_valP)v)->snhfreq != 128)
|
|
uses->dst_snh = true;
|
|
if (((DST_valP)v)->stereo & VCF_STEREO)
|
|
uses->dst_stereo = true;
|
|
}
|
|
if (v[0] == M_DLL)
|
|
{
|
|
uses->dll_use = true;
|
|
if (((DLL_valP)v)->synctype == 2)
|
|
uses->dll_notesync = true;
|
|
if (((DLL_valP)v)->damp > 0)
|
|
uses->dll_damp = true;
|
|
if ((((DLL_valP)v)->freq > 0) && (((DLL_valP)v)->depth > 0))
|
|
uses->dll_chorus = true;
|
|
}
|
|
if (v[0] == M_PAN)
|
|
{
|
|
if (((PAN_valP)v)->panning != 64)
|
|
uses->pan_use = true;
|
|
}
|
|
if (v[0] == M_FLD)
|
|
{
|
|
uses->fld_use = true;
|
|
}
|
|
if (v[0] == M_GLITCH)
|
|
{
|
|
uses->glitch_use = true;
|
|
}
|
|
if (v[0] == M_FST)
|
|
{
|
|
if ((((FST_valP)v)->dest_stack != -1) && (((FST_valP)v)->dest_stack != i))
|
|
uses->fstg_use = true;
|
|
|
|
InstrumentWorkspaceP mwork;
|
|
int stack = ((FST_valP)v)->dest_stack;
|
|
int unit = ((FST_valP)v)->dest_unit;
|
|
int slot = ((FST_valP)v)->dest_slot;
|
|
// local storage?
|
|
if (stack == -1 || stack == i)
|
|
{
|
|
stack = i;
|
|
}
|
|
else
|
|
{
|
|
uses->fstg_use = true;
|
|
}
|
|
BYTE *v2;
|
|
if (stack < MAX_INSTRUMENTS)
|
|
v2 = SynthObj.InstrumentValues[stack][unit];
|
|
else
|
|
v2 = SynthObj.GlobalValues[unit];
|
|
|
|
if (v2[0] == M_ENV)
|
|
{
|
|
if (slot == 2)
|
|
uses->env_gm = true;
|
|
if (slot == 3)
|
|
uses->env_adrm = true;
|
|
if (slot == 4)
|
|
uses->env_adrm = true;
|
|
if (slot == 6)
|
|
uses->env_adrm = true;
|
|
}
|
|
if (v2[0] == M_VCO)
|
|
{
|
|
if (slot == 1)
|
|
uses->vco_tm = true;
|
|
if (slot == 2)
|
|
uses->vco_dm = true;
|
|
if (slot == 3)
|
|
uses->vco_fm = true;
|
|
if (slot == 4)
|
|
uses->vco_pm = true;
|
|
if (slot == 5)
|
|
uses->vco_cm = true;
|
|
if (slot == 6)
|
|
uses->vco_sm = true;
|
|
if (slot == 7)
|
|
uses->vco_gm = true;
|
|
}
|
|
if (v2[0] == M_VCF)
|
|
{
|
|
if (slot == 4)
|
|
uses->vcf_fm = true;
|
|
if (slot == 5)
|
|
uses->vcf_rm = true;
|
|
}
|
|
if (v2[0] == M_DST)
|
|
{
|
|
if (slot == 2)
|
|
uses->dst_dm = true;
|
|
if (slot == 3)
|
|
uses->dst_sm = true;
|
|
}
|
|
if (v2[0] == M_DLL)
|
|
{
|
|
if (slot == 0)
|
|
{
|
|
uses->dll_pm = true;
|
|
uses->dll_use_mod = true;
|
|
}
|
|
if (slot == 1)
|
|
{
|
|
uses->dll_fm = true;
|
|
uses->dll_use_mod = true;
|
|
}
|
|
if (slot == 2)
|
|
{
|
|
uses->dll_im = true;
|
|
uses->dll_use_mod = true;
|
|
}
|
|
if (slot == 3)
|
|
{
|
|
uses->dll_dm = true;
|
|
uses->dll_damp = true;
|
|
uses->dll_use_mod = true;
|
|
}
|
|
if (slot == 4)
|
|
{
|
|
uses->dll_sm = true;
|
|
uses->dll_use_mod = true;
|
|
}
|
|
if (slot == 5)
|
|
{
|
|
uses->dll_am = true;
|
|
uses->dll_use_mod = true;
|
|
}
|
|
}
|
|
if (v2[0] == M_PAN)
|
|
{
|
|
if (slot == 0)
|
|
uses->pan_pm = true;
|
|
}
|
|
if (v2[0] == M_OUT)
|
|
{
|
|
if (slot == 0)
|
|
uses->out_am = true;
|
|
if (slot == 1)
|
|
uses->out_gm = true;
|
|
}
|
|
if (v2[0] == M_FLD)
|
|
{
|
|
if (slot == 0)
|
|
uses->fld_vm = true;
|
|
}
|
|
// if (v2[0] == M_GLITCH)
|
|
// {
|
|
// if (slot == 0)
|
|
// uses->glitch_am = true;
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Go4kVSTi_SaveByteStream(HINSTANCE hInst, char* filename, int useenvlevels, int useenotevalues, int clipoutput, int undenormalize, int objformat, int output16)
|
|
{
|
|
std::string incfile = filename;
|
|
// extract path
|
|
std::string fpath = filename;
|
|
int sp = fpath.find_last_of("/");
|
|
int bp = fpath.find_last_of("\\");
|
|
if (sp < bp)
|
|
sp = bp;
|
|
std::string storePath = fpath.substr(0, sp);
|
|
|
|
SynthUses mergeUses;
|
|
memset(&mergeUses, 0, sizeof(SynthUses));
|
|
int mergeMaxInst = 0;
|
|
int mergeMaxPatterns = 0;
|
|
int mergeNumReducedPatterns = 0;
|
|
std::vector<int> mergePatternIndices[MAX_INSTRUMENTS];
|
|
std::string mergeCommandString;
|
|
std::string mergeValueString;
|
|
int mergeDelayTimes = 0;
|
|
std::vector<WORD> mergeDelays;
|
|
|
|
#ifndef _8KLANG
|
|
// init reduced patterns for primary plugin
|
|
ReducedPatterns.clear();
|
|
NumReducedPatterns = 0;
|
|
// add NULL pattern
|
|
for (int i = 0; i < PatternSize; i++)
|
|
{
|
|
ReducedPatterns.push_back(0);
|
|
}
|
|
#else
|
|
// load merge info if available
|
|
std::string mergefile = storePath + "/8klang.merge";
|
|
FILE *mfile = fopen(mergefile.c_str(), "rb");
|
|
if (mfile)
|
|
{
|
|
// read unit usage info block for primary plugin
|
|
fread(&mergeUses, sizeof(SynthUses), 1, mfile);
|
|
// read number of instruments for primary plugin
|
|
fread(&mergeMaxInst, 4, 1, mfile);
|
|
// read max number of used patterns for primary plugin
|
|
fread(&mergeMaxPatterns, 4, 1, mfile);
|
|
// read and add reduced patterns from primary plugin
|
|
fread(&mergeNumReducedPatterns, 4, 1, mfile);
|
|
for (int i = 0; i < mergeNumReducedPatterns*PatternSize; i++)
|
|
{
|
|
int rpv = 0;
|
|
fread(&rpv, 4, 1, mfile);
|
|
ReducedPatterns.push_back(rpv);
|
|
}
|
|
// read pattern list for primary plugin
|
|
for (int i = 0; i < mergeMaxInst; i++)
|
|
{
|
|
for (int j = 0; j < mergeMaxPatterns; j++)
|
|
{
|
|
int pi = 0;
|
|
fread(&pi, 4, 1, mfile);
|
|
mergePatternIndices[i].push_back(pi);
|
|
}
|
|
}
|
|
char c;
|
|
// read command strings
|
|
while (true)
|
|
{
|
|
fread(&c, 1, 1, mfile);
|
|
if (c == 0)
|
|
break;
|
|
mergeCommandString += c;
|
|
};
|
|
// read value strings
|
|
while (true)
|
|
{
|
|
fread(&c, 1, 1, mfile);
|
|
if (c == 0)
|
|
break;
|
|
mergeValueString += c;
|
|
};
|
|
|
|
|
|
fread(&mergeDelayTimes, 4, 1, mfile);
|
|
for (int i = 0; i < mergeDelayTimes; i++)
|
|
{
|
|
int delaytime;
|
|
fread(&delaytime, 4, 1, mfile);
|
|
mergeDelays.push_back(delaytime);
|
|
}
|
|
|
|
fclose(mfile);
|
|
}
|
|
#endif
|
|
|
|
std::string pfilepath = storePath + "/patterns.dbg";
|
|
FILE *pfile = fopen(pfilepath.c_str(), "wb");
|
|
// now add minimal reduced instrument patterns
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
fprintf(pfile, "Instrument%d:\n", i);
|
|
PatternIndices[i].clear();
|
|
// loop all patterns
|
|
for (int j = 0; j < MaxTicks/PatternSize; j++)
|
|
{
|
|
for (int l = 0; l < PatternSize; l++)
|
|
{
|
|
char bv = InstrumentRecord[i][j*PatternSize+l];
|
|
if (bv >= 0)
|
|
fprintf(pfile, "%d, ", bv);
|
|
else
|
|
fprintf(pfile, "HLD, ", bv);
|
|
}
|
|
fprintf(pfile, "\n");
|
|
|
|
int pindex = j;
|
|
bool found = false;
|
|
// compare each tick of the current pattern to all already reduced patterns
|
|
for (int k = 0; k < ReducedPatterns.size()/PatternSize; k++)
|
|
{
|
|
bool patternMatch = true;
|
|
for (int l = 0; l < PatternSize; l++)
|
|
{
|
|
if (InstrumentRecord[i][j*PatternSize+l] != ReducedPatterns[k*PatternSize+l])
|
|
{
|
|
patternMatch = false;
|
|
break;
|
|
}
|
|
}
|
|
if (patternMatch)
|
|
{
|
|
NumReducedPatterns++;
|
|
pindex = k;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
// add new pattern if necessary
|
|
if (!found)
|
|
{
|
|
for (int k = 0; k < PatternSize; k++)
|
|
{
|
|
ReducedPatterns.push_back(InstrumentRecord[i][j*PatternSize+k]);
|
|
}
|
|
pindex = (ReducedPatterns.size()/PatternSize)-1;
|
|
}
|
|
// add new pattern index
|
|
PatternIndices[i].push_back(pindex);
|
|
}
|
|
}
|
|
fclose(pfile);
|
|
|
|
int maxinst = 0;
|
|
FILE *file = fopen(incfile.c_str(), "w");
|
|
if (file)
|
|
{
|
|
bool InstrumentUsed[MAX_INSTRUMENTS];
|
|
// determine max instrument count
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
InstrumentUsed[i] = false;
|
|
for (int j = 0; j < PatternIndices[i].size(); j++)
|
|
{
|
|
if (PatternIndices[i][j])
|
|
{
|
|
InstrumentUsed[i] = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// determine max instrument count and create a mapping instrument index -> used instrument index
|
|
int InstrumentIndex[MAX_INSTRUMENTS];
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
// dummy init
|
|
InstrumentIndex[i] = -1;
|
|
if (InstrumentUsed[i])
|
|
{
|
|
InstrumentIndex[i] = maxinst;
|
|
maxinst++;
|
|
}
|
|
|
|
}
|
|
std::vector<WORD> delay_times;
|
|
std::vector<int> delay_indices;
|
|
bool hasReverb = false;
|
|
bool hasNoteSync = false;
|
|
#ifdef _8KLANG
|
|
//m get delaytimes and index from primary plugin
|
|
for (int i = 0; i < mergeDelayTimes; i++)
|
|
{
|
|
delay_times.push_back(mergeDelays[i]);
|
|
if (i < 17)
|
|
delay_indices.push_back(i);
|
|
}
|
|
#else
|
|
// add notesync and reverb times
|
|
for (int i = 0; i < 17; i++)
|
|
{
|
|
DWORD times = (&go4k_delay_times)[i];
|
|
delay_times.push_back(times);
|
|
delay_indices.push_back(i);
|
|
}
|
|
delay_times[0] = 0;
|
|
#endif
|
|
for (int i = 0; i <= MAX_INSTRUMENTS; i++)
|
|
{
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
// // used instrument or global?
|
|
if (InstrumentUsed[i] || i == MAX_INSTRUMENTS)
|
|
{
|
|
DLL_valP v;
|
|
if (i < MAX_INSTRUMENTS)
|
|
v = (DLL_valP)(SynthObj.InstrumentValues[i][u]);
|
|
else
|
|
v = (DLL_valP)(SynthObj.GlobalValues[u]);
|
|
|
|
if (v->id == M_DLL)
|
|
{
|
|
if (!v->reverb)
|
|
{
|
|
// if not notesync
|
|
if (v->synctype != 2)
|
|
{
|
|
DWORD times = (&go4k_delay_times)[delay_indices.size()];
|
|
// check if indexed value already existed
|
|
int found = -1;
|
|
for (int j = 17; j < delay_times.size(); j++)
|
|
{
|
|
if (delay_times[j] == times)
|
|
{
|
|
found = j;
|
|
break;
|
|
}
|
|
}
|
|
if (found != -1)
|
|
{
|
|
// already in list, so let index point to that one
|
|
delay_indices.push_back(found);
|
|
}
|
|
else
|
|
{
|
|
// new value, so push it
|
|
delay_times.push_back(times);
|
|
delay_indices.push_back(delay_times.size()-1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hasNoteSync = true;
|
|
delay_indices.push_back(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hasReverb = true;
|
|
}
|
|
}
|
|
if (v->id == M_GLITCH)
|
|
{
|
|
DWORD times = (&go4k_delay_times)[delay_indices.size()];
|
|
// check if indexed value already existed
|
|
int found = -1;
|
|
for (int j = 17; j < delay_times.size(); j++)
|
|
{
|
|
if (delay_times[j] == times)
|
|
{
|
|
found = j;
|
|
break;
|
|
}
|
|
}
|
|
if (found != -1)
|
|
{
|
|
// already in list, so let index point to that one
|
|
delay_indices.push_back(found);
|
|
}
|
|
else
|
|
{
|
|
// new value, so push it
|
|
delay_times.push_back(times);
|
|
delay_indices.push_back(delay_times.size()-1);
|
|
}
|
|
}
|
|
}
|
|
// no used instrument
|
|
else
|
|
{
|
|
DLL_valP v;
|
|
v = (DLL_valP)(SynthObj.InstrumentValues[i][u]);
|
|
if (v->id == M_DLL)
|
|
{
|
|
if (!v->reverb)
|
|
{
|
|
// just push a dummy index
|
|
delay_indices.push_back(-1);
|
|
}
|
|
}
|
|
if (v->id == M_GLITCH)
|
|
{
|
|
// just push a dummy index
|
|
delay_indices.push_back(-1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// rarely needed anyway
|
|
#if 0
|
|
// if we dont have reverb, remove values and adjust indices
|
|
if (!hasReverb)
|
|
{
|
|
// move values
|
|
for (int i = 17; i < delay_times.size(); i++)
|
|
{
|
|
delay_times[i-16] = delay_times[i];
|
|
}
|
|
// remove obsolete values
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
delay_times.pop_back();
|
|
}
|
|
// adjust indices
|
|
for (int i = 0; i < delay_indices.size(); i++)
|
|
{
|
|
if (delay_indices[i] != 0)
|
|
delay_indices[i] -= 16;
|
|
}
|
|
}
|
|
// if we dont have notesync, remove values and adjust indices
|
|
if (!hasNoteSync)
|
|
{
|
|
// move values
|
|
for (int i = 1; i < delay_times.size(); i++)
|
|
{
|
|
delay_times[i-1] = delay_times[i];
|
|
}
|
|
// remove obsolete values
|
|
delay_times.pop_back();
|
|
// adjust indices
|
|
for (int i = 0; i < delay_indices.size(); i++)
|
|
{
|
|
delay_indices[i] -= 1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
SynthUses uses;
|
|
#ifndef _8KLANG
|
|
memset(&uses, 0, sizeof(SynthUses));
|
|
#else
|
|
memcpy(&uses, &mergeUses, sizeof(SynthUses));
|
|
#endif
|
|
GetUses(&uses, InstrumentUsed);
|
|
|
|
// write inc file
|
|
fprintf(file, "%%macro export_func 1\n");
|
|
// fprintf(file, " %%define %%1 _%%1\n");
|
|
fprintf(file, " global _%%1\n");
|
|
fprintf(file, " _%%1:\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
|
|
// fprintf(file, "%%macro export_dword_array 2\n");
|
|
// fprintf(file, " %%define %%1 _%%1\n");
|
|
// fprintf(file, " global %%1\n");
|
|
// fprintf(file, " %%1 resd %%2\n");
|
|
// fprintf(file, "%%endmacro\n");
|
|
|
|
/* if (objformat == 0)
|
|
MessageBox(0,"WINDOWS","",MB_OK);
|
|
if (objformat == 1)
|
|
MessageBox(0,"LINUX","",MB_OK);
|
|
if (objformat == 2)
|
|
MessageBox(0,"MACOSX","",MB_OK);
|
|
*/
|
|
|
|
if (objformat == 0) // 0:windows, 1:linux, 2:osx
|
|
{
|
|
// use sections only for windows,
|
|
// linux doesnt have any crinkler like packer to take advantage of multiple sections
|
|
// and osx export has a bug in current nasm and is not able to export custom sections
|
|
fprintf(file, "%%define USE_SECTIONS\n");
|
|
}
|
|
|
|
fprintf(file, "%%define SAMPLE_RATE %d\n", 44100);
|
|
fprintf(file, "%%define MAX_INSTRUMENTS %d\n", maxinst + mergeMaxInst);
|
|
fprintf(file, "%%define MAX_VOICES %d\n", SynthObj.Polyphony);
|
|
fprintf(file, "%%define HLD 1\n");
|
|
fprintf(file, "%%define BPM %f\n", BeatsPerMinute);
|
|
fprintf(file, "%%define MAX_PATTERNS %d\n", mergeMaxPatterns > PatternIndices[0].size() ? mergeMaxPatterns : PatternIndices[0].size());
|
|
fprintf(file, "%%define PATTERN_SIZE_SHIFT %d\n", GetShift2(PatternSize));
|
|
fprintf(file, "%%define PATTERN_SIZE (1 << PATTERN_SIZE_SHIFT)\n");
|
|
fprintf(file, "%%define MAX_TICKS (MAX_PATTERNS*PATTERN_SIZE)\n");
|
|
fprintf(file, "%%define SAMPLES_PER_TICK %d\n", (int)(44100.0f*4.0f*60.0f/(BeatsPerMinute*16*TickScaler)));
|
|
fprintf(file, "%%define DEF_LFO_NORMALIZE %.10f\n", LFO_NORMALIZE);
|
|
fprintf(file, "%%define MAX_SAMPLES (SAMPLES_PER_TICK*MAX_TICKS)\n");
|
|
fprintf(file, "%s%%define GO4K_USE_16BIT_OUTPUT\n",output16?"":";");
|
|
fprintf(file, ";%%define GO4K_USE_GROOVE_PATTERN\n");
|
|
fprintf(file, "%s%%define GO4K_USE_ENVELOPE_RECORDINGS\n",useenvlevels?"":";");
|
|
fprintf(file, "%s%%define GO4K_USE_NOTE_RECORDINGS\n",useenotevalues?"":";");
|
|
if (undenormalize)
|
|
fprintf(file, "%%define GO4K_USE_UNDENORMALIZE\n");
|
|
if (clipoutput)
|
|
fprintf(file, "%%define GO4K_CLIP_OUTPUT\n");
|
|
if (uses.dst_use)
|
|
fprintf(file, "%%define GO4K_USE_DST\n");
|
|
if (uses.dll_use)
|
|
fprintf(file, "%%define GO4K_USE_DLL\n");
|
|
if (uses.pan_use)
|
|
fprintf(file, "%%define GO4K_USE_PAN\n");
|
|
fprintf(file, "%%define GO4K_USE_GLOBAL_DLL\n");
|
|
if (uses.fstg_use)
|
|
fprintf(file, "%%define GO4K_USE_FSTG\n");
|
|
if (uses.fld_use)
|
|
fprintf(file, "%%define GO4K_USE_FLD\n");
|
|
if (uses.glitch_use)
|
|
fprintf(file, "%%define GO4K_USE_GLITCH\n");
|
|
fprintf(file, "%%define GO4K_USE_ENV_CHECK\n");
|
|
if (uses.env_gm)
|
|
fprintf(file, "%%define GO4K_USE_ENV_MOD_GM\n");
|
|
if (uses.env_adrm)
|
|
fprintf(file, "%%define GO4K_USE_ENV_MOD_ADR\n");
|
|
fprintf(file, "%%define GO4K_USE_VCO_CHECK\n");
|
|
if (uses.vco_phaseofs)
|
|
fprintf(file, "%%define GO4K_USE_VCO_PHASE_OFFSET\n");
|
|
if (uses.vco_shape)
|
|
fprintf(file, "%%define GO4K_USE_VCO_SHAPE\n");
|
|
if (uses.vco_gate)
|
|
fprintf(file, "%%define GO4K_USE_VCO_GATE\n");
|
|
if (uses.vco_fm)
|
|
fprintf(file, "%%define GO4K_USE_VCO_MOD_FM\n");
|
|
if (uses.vco_pm)
|
|
fprintf(file, "%%define GO4K_USE_VCO_MOD_PM\n");
|
|
if (uses.vco_tm)
|
|
fprintf(file, "%%define GO4K_USE_VCO_MOD_TM\n");
|
|
if (uses.vco_dm)
|
|
fprintf(file, "%%define GO4K_USE_VCO_MOD_DM\n");
|
|
if (uses.vco_cm)
|
|
fprintf(file, "%%define GO4K_USE_VCO_MOD_CM\n");
|
|
if (uses.vco_gm)
|
|
fprintf(file, "%%define GO4K_USE_VCO_MOD_GM\n");
|
|
if (uses.vco_sm)
|
|
fprintf(file, "%%define GO4K_USE_VCO_MOD_SM\n");
|
|
if (uses.vco_stereo)
|
|
fprintf(file, "%%define GO4K_USE_VCO_STEREO\n");
|
|
fprintf(file, "%%define GO4K_USE_VCF_CHECK\n");
|
|
if (uses.vcf_fm)
|
|
fprintf(file, "%%define GO4K_USE_VCF_MOD_FM\n");
|
|
if (uses.vcf_rm)
|
|
fprintf(file, "%%define GO4K_USE_VCF_MOD_RM\n");
|
|
fprintf(file, "%%define GO4K_USE_VCF_HIGH\n");
|
|
fprintf(file, "%%define GO4K_USE_VCF_BAND\n");
|
|
fprintf(file, "%%define GO4K_USE_VCF_PEAK\n");
|
|
if (uses.vcf_stereo)
|
|
fprintf(file, "%%define GO4K_USE_VCF_STEREO\n");
|
|
fprintf(file, "%%define GO4K_USE_DST_CHECK\n");
|
|
if (uses.dst_snh)
|
|
fprintf(file, "%%define GO4K_USE_DST_SH\n");
|
|
if (uses.dst_dm)
|
|
fprintf(file, "%%define GO4K_USE_DST_MOD_DM\n");
|
|
if (uses.dst_sm)
|
|
fprintf(file, "%%define GO4K_USE_DST_MOD_SH\n");
|
|
if (uses.dst_stereo)
|
|
fprintf(file, "%%define GO4K_USE_DST_STEREO\n");
|
|
if (uses.dll_notesync)
|
|
fprintf(file, "%%define GO4K_USE_DLL_NOTE_SYNC\n");
|
|
if (uses.dll_chorus)
|
|
fprintf(file, "%%define GO4K_USE_DLL_CHORUS\n");
|
|
fprintf(file, "%%define GO4K_USE_DLL_CHORUS_CLAMP\n");
|
|
if (uses.dll_damp)
|
|
fprintf(file, "%%define GO4K_USE_DLL_DAMP\n");
|
|
fprintf(file, "%%define GO4K_USE_DLL_DC_FILTER\n");
|
|
fprintf(file, "%%define GO4K_USE_FSTG_CHECK\n");
|
|
if (uses.pan_pm)
|
|
fprintf(file, "%%define GO4K_USE_PAN_MOD\n");
|
|
if (uses.out_am)
|
|
fprintf(file, "%%define GO4K_USE_OUT_MOD_AM\n");
|
|
if (uses.out_gm)
|
|
fprintf(file, "%%define GO4K_USE_OUT_MOD_GM\n");
|
|
fprintf(file, "%%define GO4K_USE_WAVESHAPER_CLIP\n");
|
|
if (uses.fld_vm)
|
|
fprintf(file, "%%define GO4K_USE_FLD_MOD_VM\n");
|
|
if (uses.dll_use_mod)
|
|
fprintf(file, "%%define GO4K_USE_DLL_MOD\n");
|
|
if (uses.dll_pm)
|
|
fprintf(file, "%%define GO4K_USE_DLL_MOD_PM\n");
|
|
if (uses.dll_fm)
|
|
fprintf(file, "%%define GO4K_USE_DLL_MOD_FM\n");
|
|
if (uses.dll_im)
|
|
fprintf(file, "%%define GO4K_USE_DLL_MOD_IM\n");
|
|
if (uses.dll_dm)
|
|
fprintf(file, "%%define GO4K_USE_DLL_MOD_DM\n");
|
|
if (uses.dll_sm)
|
|
fprintf(file, "%%define GO4K_USE_DLL_MOD_SM\n");
|
|
if (uses.dll_am)
|
|
fprintf(file, "%%define GO4K_USE_DLL_MOD_AM\n");
|
|
|
|
fprintf(file, "%%define MAX_DELAY 65536\n");
|
|
fprintf(file, "%%define MAX_UNITS 64\n");
|
|
fprintf(file, "%%define MAX_UNIT_SLOTS 16\n");
|
|
fprintf(file, "%%define GO4K_BEGIN_CMDDEF(def_name)\n");
|
|
fprintf(file, "%%define GO4K_END_CMDDEF db 0\n");
|
|
fprintf(file, "%%define GO4K_BEGIN_PARAMDEF(def_name)\n");
|
|
fprintf(file, "%%define GO4K_END_PARAMDEF\n");
|
|
|
|
fprintf(file, "GO4K_ENV_ID equ 1\n");
|
|
fprintf(file, "%%macro GO4K_ENV 5\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, " db %%2\n");
|
|
fprintf(file, " db %%3\n");
|
|
fprintf(file, " db %%4\n");
|
|
fprintf(file, " db %%5\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define ATTAC(val) val \n");
|
|
fprintf(file, "%%define DECAY(val) val \n");
|
|
fprintf(file, "%%define SUSTAIN(val) val \n");
|
|
fprintf(file, "%%define RELEASE(val) val \n");
|
|
fprintf(file, "%%define GAIN(val) val \n");
|
|
fprintf(file, "struc go4kENV_val\n");
|
|
fprintf(file, " .attac resd 1\n");
|
|
fprintf(file, " .decay resd 1\n");
|
|
fprintf(file, " .sustain resd 1\n");
|
|
fprintf(file, " .release resd 1\n");
|
|
fprintf(file, " .gain resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kENV_wrk\n");
|
|
fprintf(file, " .state resd 1\n");
|
|
fprintf(file, " .level resd 1\n");
|
|
fprintf(file, " .gm resd 1\n");
|
|
fprintf(file, " .am resd 1\n");
|
|
fprintf(file, " .dm resd 1\n");
|
|
fprintf(file, " .sm resd 1\n");
|
|
fprintf(file, " .rm resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "%%define ENV_STATE_ATTAC 0\n");
|
|
fprintf(file, "%%define ENV_STATE_DECAY 1\n");
|
|
fprintf(file, "%%define ENV_STATE_SUSTAIN 2\n");
|
|
fprintf(file, "%%define ENV_STATE_RELEASE 3\n");
|
|
fprintf(file, "%%define ENV_STATE_OFF 4\n");
|
|
|
|
fprintf(file, "GO4K_VCO_ID equ 2\n");
|
|
fprintf(file, "%%macro GO4K_VCO 8\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, " db %%2\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_VCO_PHASE_OFFSET \n");
|
|
fprintf(file, " db %%3\n");
|
|
fprintf(file, "%%endif \n");
|
|
fprintf(file, "%%ifdef GO4K_USE_VCO_GATE \n");
|
|
fprintf(file, " db %%4\n");
|
|
fprintf(file, "%%endif \n");
|
|
fprintf(file, " db %%5\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_VCO_SHAPE \n");
|
|
fprintf(file, " db %%6\n");
|
|
fprintf(file, "%%endif \n");
|
|
fprintf(file, " db %%7\n");
|
|
fprintf(file, " db %%8\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define TRANSPOSE(val) val \n");
|
|
fprintf(file, "%%define DETUNE(val) val \n");
|
|
fprintf(file, "%%define PHASE(val) val \n");
|
|
fprintf(file, "%%define GATES(val) val \n");
|
|
fprintf(file, "%%define COLOR(val) val \n");
|
|
fprintf(file, "%%define SHAPE(val) val \n");
|
|
fprintf(file, "%%define FLAGS(val) val \n");
|
|
fprintf(file, "%%define SINE 0x01\n");
|
|
fprintf(file, "%%define TRISAW 0x02\n");
|
|
fprintf(file, "%%define PULSE 0x04\n");
|
|
fprintf(file, "%%define NOISE 0x08\n");
|
|
fprintf(file, "%%define LFO 0x10\n");
|
|
fprintf(file, "%%define GATE 0x20\n");
|
|
fprintf(file, "%%define VCO_STEREO 0x40\n");
|
|
fprintf(file, "struc go4kVCO_val\n");
|
|
fprintf(file, " .transpose resd 1\n");
|
|
fprintf(file, " .detune resd 1\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_VCO_PHASE_OFFSET \n");
|
|
fprintf(file, " .phaseofs resd 1\n");
|
|
fprintf(file, "%%endif \n");
|
|
fprintf(file, "%%ifdef GO4K_USE_VCO_GATE \n");
|
|
fprintf(file, " .gate resd 1\n");
|
|
fprintf(file, "%%endif \n");
|
|
fprintf(file, " .color resd 1\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_VCO_SHAPE \n");
|
|
fprintf(file, " .shape resd 1\n");
|
|
fprintf(file, "%%endif \n");
|
|
fprintf(file, " .gain resd 1\n");
|
|
fprintf(file, " .flags resd 1 \n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kVCO_wrk\n");
|
|
fprintf(file, " .phase resd 1\n");
|
|
fprintf(file, " .tm resd 1\n");
|
|
fprintf(file, " .dm resd 1\n");
|
|
fprintf(file, " .fm resd 1\n");
|
|
fprintf(file, " .pm resd 1\n");
|
|
fprintf(file, " .cm resd 1\n");
|
|
fprintf(file, " .sm resd 1\n");
|
|
fprintf(file, " .gm resd 1\n");
|
|
fprintf(file, " .phase2 resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
fprintf(file, "GO4K_VCF_ID equ 3\n");
|
|
fprintf(file, "%%macro GO4K_VCF 3\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, " db %%2\n");
|
|
fprintf(file, " db %%3\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define LOWPASS 0x1\n");
|
|
fprintf(file, "%%define HIGHPASS 0x2\n");
|
|
fprintf(file, "%%define BANDPASS 0x4\n");
|
|
fprintf(file, "%%define BANDSTOP 0x3\n");
|
|
fprintf(file, "%%define ALLPASS 0x7\n");
|
|
fprintf(file, "%%define PEAK 0x8\n");
|
|
fprintf(file, "%%define STEREO 0x10\n");
|
|
fprintf(file, "%%define FREQUENCY(val) val\n");
|
|
fprintf(file, "%%define RESONANCE(val) val\n");
|
|
fprintf(file, "%%define VCFTYPE(val) val\n");
|
|
fprintf(file, "struc go4kVCF_val\n");
|
|
fprintf(file, " .freq resd 1\n");
|
|
fprintf(file, " .res resd 1\n");
|
|
fprintf(file, " .type resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kVCF_wrk\n");
|
|
fprintf(file, " .low resd 1\n");
|
|
fprintf(file, " .high resd 1\n");
|
|
fprintf(file, " .band resd 1\n");
|
|
fprintf(file, " .freq resd 1\n");
|
|
fprintf(file, " .fm resd 1\n");
|
|
fprintf(file, " .rm resd 1\n");
|
|
fprintf(file, " .low2 resd 1\n");
|
|
fprintf(file, " .high2 resd 1\n");
|
|
fprintf(file, " .band2 resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
fprintf(file, "GO4K_DST_ID equ 4\n");
|
|
fprintf(file, "%%macro GO4K_DST 3\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_DST_SH\n");
|
|
fprintf(file, " db %%2\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_DST_STEREO\n");
|
|
fprintf(file, " db %%3\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, "%%else\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_DST_STEREO\n");
|
|
fprintf(file, " db %%3\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define DRIVE(val) val\n");
|
|
fprintf(file, "%%define SNHFREQ(val) val\n");
|
|
fprintf(file, "%%define FLAGS(val) val\n");
|
|
fprintf(file, "struc go4kDST_val\n");
|
|
fprintf(file, " .drive resd 1\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_DST_SH \n");
|
|
fprintf(file, " .snhfreq resd 1\n");
|
|
fprintf(file, "%%endif \n");
|
|
fprintf(file, " .flags resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kDST_wrk\n");
|
|
fprintf(file, " .out resd 1\n");
|
|
fprintf(file, " .snhphase resd 1\n");
|
|
fprintf(file, " .dm resd 1\n");
|
|
fprintf(file, " .sm resd 1\n");
|
|
fprintf(file, " .out2 resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
fprintf(file, "GO4K_DLL_ID equ 5\n");
|
|
fprintf(file, "%%macro GO4K_DLL 8\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, " db %%2\n");
|
|
fprintf(file, " db %%3\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_DLL_DAMP \n");
|
|
fprintf(file, " db %%4\n");
|
|
fprintf(file, "%%endif \n");
|
|
fprintf(file, "%%ifdef GO4K_USE_DLL_CHORUS \n");
|
|
fprintf(file, " db %%5\n");
|
|
fprintf(file, " db %%6\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, " db %%7\n");
|
|
fprintf(file, " db %%8\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define PREGAIN(val) val\n");
|
|
fprintf(file, "%%define DRY(val) val\n");
|
|
fprintf(file, "%%define FEEDBACK(val) val\n");
|
|
fprintf(file, "%%define DEPTH(val) val\n");
|
|
fprintf(file, "%%define DAMP(val) val\n");
|
|
fprintf(file, "%%define DELAY(val) val\n");
|
|
fprintf(file, "%%define COUNT(val) val\n");
|
|
fprintf(file, "struc go4kDLL_val\n");
|
|
fprintf(file, " .pregain resd 1\n");
|
|
fprintf(file, " .dry resd 1\n");
|
|
fprintf(file, " .feedback resd 1\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_DLL_DAMP \n");
|
|
fprintf(file, " .damp resd 1 \n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_DLL_CHORUS\n");
|
|
fprintf(file, " .freq resd 1\n");
|
|
fprintf(file, " .depth\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, " .delay resd 1\n");
|
|
fprintf(file, " .count resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kDLL_wrk\n");
|
|
fprintf(file, " .index resd 1\n");
|
|
fprintf(file, " .store resd 1\n");
|
|
fprintf(file, " .dcin resd 1\n");
|
|
fprintf(file, " .dcout resd 1\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_DLL_CHORUS\n");
|
|
fprintf(file, " .phase resd 1\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, " .buffer resd MAX_DELAY\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kDLL_wrk2\n");
|
|
fprintf(file, " .pm resd 1\n");
|
|
fprintf(file, " .fm resd 1\n");
|
|
fprintf(file, " .im resd 1\n");
|
|
fprintf(file, " .dm resd 1\n");
|
|
fprintf(file, " .sm resd 1\n");
|
|
fprintf(file, " .am resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
fprintf(file, "GO4K_FOP_ID equ 6\n");
|
|
fprintf(file, "%%macro GO4K_FOP 1\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define OP(val) val\n");
|
|
fprintf(file, "%%define FOP_POP 0x1\n");
|
|
fprintf(file, "%%define FOP_ADDP 0x2\n");
|
|
fprintf(file, "%%define FOP_MULP 0x3\n");
|
|
fprintf(file, "%%define FOP_PUSH 0x4\n");
|
|
fprintf(file, "%%define FOP_XCH 0x5\n");
|
|
fprintf(file, "%%define FOP_ADD 0x6\n");
|
|
fprintf(file, "%%define FOP_MUL 0x7\n");
|
|
fprintf(file, "%%define FOP_ADDP2 0x8\n");
|
|
fprintf(file, "%%define FOP_LOADNOTE 0x9\n");
|
|
fprintf(file, "%%define FOP_MULP2 0xa\n");
|
|
fprintf(file, "struc go4kFOP_val\n");
|
|
fprintf(file, " .flags resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kFOP_wrk\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
fprintf(file, "GO4K_FST_ID equ 7\n");
|
|
fprintf(file, "%%macro GO4K_FST 2\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, " dw %%2\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define AMOUNT(val) val\n");
|
|
fprintf(file, "%%define DEST(val) val\n");
|
|
fprintf(file, "%%define FST_SET 0x0000\n");
|
|
fprintf(file, "%%define FST_ADD 0x4000\n");
|
|
fprintf(file, "%%define FST_POP 0x8000\n");
|
|
fprintf(file, "struc go4kFST_val\n");
|
|
fprintf(file, " .amount resd 1\n");
|
|
fprintf(file, " .op1 resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kFST_wrk\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
fprintf(file, "GO4K_PAN_ID equ 8\n");
|
|
fprintf(file, "%%macro GO4K_PAN 1\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_PAN\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define PANNING(val) val\n");
|
|
fprintf(file, "struc go4kPAN_val\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_PAN\n");
|
|
fprintf(file, " .panning resd 1\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kPAN_wrk\n");
|
|
fprintf(file, " .pm resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
fprintf(file, "GO4K_OUT_ID equ 9\n");
|
|
fprintf(file, "%%macro GO4K_OUT 2\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_GLOBAL_DLL \n");
|
|
fprintf(file, " db %%2\n");
|
|
fprintf(file, "%%endif \n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define AUXSEND(val) val\n");
|
|
fprintf(file, "struc go4kOUT_val\n");
|
|
fprintf(file, " .gain resd 1\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_GLOBAL_DLL \n");
|
|
fprintf(file, " .auxsend resd 1\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kOUT_wrk\n");
|
|
fprintf(file, " .am resd 1\n");
|
|
fprintf(file, " .gm resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
fprintf(file, "GO4K_ACC_ID equ 10\n");
|
|
fprintf(file, "%%macro GO4K_ACC 1\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define OUTPUT 0\n");
|
|
fprintf(file, "%%define AUX 8\n");
|
|
fprintf(file, "%%define ACCTYPE(val) val\n");
|
|
fprintf(file, "struc go4kACC_val\n");
|
|
fprintf(file, " .acctype resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kACC_wrk\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
fprintf(file, "%%ifdef GO4K_USE_FLD\n");
|
|
fprintf(file, "GO4K_FLD_ID equ 11\n");
|
|
fprintf(file, "%%macro GO4K_FLD 1\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define VALUE(val) val\n");
|
|
fprintf(file, "struc go4kFLD_val\n");
|
|
fprintf(file, " .value resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kFLD_wrk\n");
|
|
fprintf(file, " .vm resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "%%endif\n");
|
|
|
|
fprintf(file, "%%ifdef GO4K_USE_GLITCH\n");
|
|
fprintf(file, "GO4K_GLITCH_ID equ 12\n");
|
|
fprintf(file, "%%macro GO4K_GLITCH 5\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, " db %%2\n");
|
|
fprintf(file, " db %%3\n");
|
|
fprintf(file, " db %%4\n");
|
|
fprintf(file, " db %%5\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "%%define ACTIVE(val) val\n");
|
|
fprintf(file, "%%define SLICEFACTOR(val)val\n");
|
|
fprintf(file, "%%define PITCHFACTOR(val)val\n");
|
|
fprintf(file, "%%define SLICESIZE(val) val\n");
|
|
fprintf(file, "struc go4kGLITCH_val\n");
|
|
fprintf(file, " .active resd 1\n");
|
|
fprintf(file, " .dry resd 1\n");
|
|
fprintf(file, " .dsize resd 1\n");
|
|
fprintf(file, " .dpitch resd 1\n");
|
|
fprintf(file, " .slicesize resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kGLITCH_wrk\n");
|
|
fprintf(file, " .index resd 1\n");
|
|
fprintf(file, " .store resd 1\n");
|
|
fprintf(file, " .slizesize resd 1\n");
|
|
fprintf(file, " .slicepitch resd 1\n");
|
|
fprintf(file, " .unused resd 1\n");
|
|
fprintf(file, " .buffer resd MAX_DELAY\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kGLITCH_wrk2\n");
|
|
fprintf(file, " .am resd 1\n");
|
|
fprintf(file, " .dm resd 1\n");
|
|
fprintf(file, " .sm resd 1\n");
|
|
fprintf(file, " .pm resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "%%endif\n");
|
|
|
|
fprintf(file, "%%ifdef GO4K_USE_FSTG\n");
|
|
fprintf(file, "GO4K_FSTG_ID equ %d\n", uses.glitch_use ? 13 : 12);
|
|
fprintf(file, "%%macro GO4K_FSTG 2\n");
|
|
fprintf(file, " db %%1\n");
|
|
fprintf(file, " dw %%2\n");
|
|
fprintf(file, "%%endmacro\n");
|
|
fprintf(file, "struc go4kFSTG_val\n");
|
|
fprintf(file, " .amount resd 1\n");
|
|
fprintf(file, " .op1 resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "struc go4kFSTG_wrk\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
fprintf(file, "%%endif\n");
|
|
|
|
fprintf(file, "struc go4k_instrument\n");
|
|
fprintf(file, " .release resd 1\n");
|
|
fprintf(file, " .note resd 1\n");
|
|
fprintf(file, " .workspace resd MAX_UNITS*MAX_UNIT_SLOTS\n");
|
|
fprintf(file, " .dlloutl resd 1\n");
|
|
fprintf(file, " .dlloutr resd 1\n");
|
|
fprintf(file, " .outl resd 1\n");
|
|
fprintf(file, " .outr resd 1\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
fprintf(file, "struc go4k_synth\n");
|
|
fprintf(file, " .instruments resb go4k_instrument.size * MAX_INSTRUMENTS * MAX_VOICES\n");
|
|
fprintf(file, " .global resb go4k_instrument.size * MAX_VOICES\n");
|
|
fprintf(file, " .size\n");
|
|
fprintf(file, "endstruc\n");
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// the patterns
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
fprintf(file, "%%ifdef USE_SECTIONS\n");
|
|
fprintf(file, "section .g4kmuc1 data align=1\n");
|
|
fprintf(file, "%%else\n");
|
|
fprintf(file, "section .data align=1\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, "go4k_patterns\n");
|
|
for (int i = 0; i < ReducedPatterns.size()/PatternSize; i++)
|
|
{
|
|
fprintf(file, "\tdb\t");
|
|
for (int j = 0; j < PatternSize; j++)
|
|
{
|
|
if (ReducedPatterns[i*PatternSize+j] >= 0)
|
|
fprintf(file, "%d, ", ReducedPatterns[i*PatternSize+j]);
|
|
else
|
|
fprintf(file, "HLD, ");
|
|
}
|
|
fprintf(file, "\n");
|
|
}
|
|
fprintf(file, "go4k_patterns_end\n");
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// the pattern indices
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
fprintf(file, "%%ifdef USE_SECTIONS\n");
|
|
fprintf(file, "section .g4kmuc2 data align=1\n");
|
|
fprintf(file, "%%else\n");
|
|
fprintf(file, "section .data\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, "go4k_pattern_lists\n");
|
|
#ifdef _8KLANG
|
|
// write primary plugins pattern indices
|
|
for (int i = 0; i < mergeMaxInst; i++)
|
|
{
|
|
fprintf(file, "Instrument%dList\t\tdb\t", i);
|
|
for (int j = 0; j < mergeMaxPatterns; j++)
|
|
{
|
|
fprintf(file, "%d, ", mergePatternIndices[i][j]);
|
|
}
|
|
// fill up with 0 indices when secondary plugin has more patterns
|
|
for (int j = mergeMaxPatterns; j < PatternIndices[0].size(); j++)
|
|
{
|
|
fprintf(file, "0, ");
|
|
}
|
|
fprintf(file, "\n");
|
|
}
|
|
#endif
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
if (!InstrumentUsed[i]) continue;
|
|
fprintf(file, "Instrument%dList\t\tdb\t", i + mergeMaxInst);
|
|
for (int j = 0; j < PatternIndices[i].size(); j++)
|
|
{
|
|
fprintf(file, "%d, ", PatternIndices[i][j]);
|
|
}
|
|
// fill up with 0 indices when primary plugin had more patterns
|
|
for (int j = PatternIndices[0].size(); j < mergeMaxPatterns; j++)
|
|
{
|
|
fprintf(file, "0, ");
|
|
}
|
|
fprintf(file, "\n");
|
|
}
|
|
|
|
fprintf(file, "go4k_pattern_lists_end\n");
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// the instrument commands
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
fprintf(file, "%%ifdef USE_SECTIONS\n");
|
|
fprintf(file, "section .g4kmuc3 data align=1\n");
|
|
fprintf(file, "%%else\n");
|
|
fprintf(file, "section .data\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, "go4k_synth_instructions\n");
|
|
char comstr[1024];
|
|
std::string CommandString;
|
|
|
|
#ifdef _8KLANG
|
|
// add primary plugin commands first
|
|
fprintf(file, "%s", mergeCommandString.c_str());
|
|
#endif
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
if (!InstrumentUsed[i]) continue;
|
|
sprintf(comstr, "GO4K_BEGIN_CMDDEF(Instrument%d)\n", i + mergeMaxInst); CommandString += comstr;
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
comstr[0] = 0;
|
|
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_ENV)
|
|
sprintf(comstr, "\tdb GO4K_ENV_ID\n");
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_VCO)
|
|
sprintf(comstr, "\tdb GO4K_VCO_ID\n");
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_VCF)
|
|
sprintf(comstr, "\tdb GO4K_VCF_ID\n");
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_DST)
|
|
sprintf(comstr, "\tdb GO4K_DST_ID\n");
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_DLL)
|
|
sprintf(comstr, "\tdb GO4K_DLL_ID\n");
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_FOP)
|
|
sprintf(comstr, "\tdb GO4K_FOP_ID\n");
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_FST)
|
|
{
|
|
FST_valP v = (FST_valP)(SynthObj.InstrumentValues[i][u]);
|
|
// local storage
|
|
if (v->dest_stack == -1 || v->dest_stack == i)
|
|
sprintf(comstr, "\tdb GO4K_FST_ID\n");
|
|
// global storage
|
|
else
|
|
sprintf(comstr, "\tdb GO4K_FSTG_ID\n");
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_PAN)
|
|
sprintf(comstr, "\tdb GO4K_PAN_ID\n");
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_OUT)
|
|
sprintf(comstr, "\tdb GO4K_OUT_ID\n");
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_ACC)
|
|
sprintf(comstr, "\tdb GO4K_ACC_ID\n");
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_FLD)
|
|
sprintf(comstr, "\tdb GO4K_FLD_ID\n");
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_GLITCH)
|
|
sprintf(comstr, "\tdb GO4K_GLITCH_ID\n");
|
|
|
|
CommandString += comstr;
|
|
}
|
|
sprintf(comstr, "GO4K_END_CMDDEF\n"); CommandString += comstr;
|
|
};
|
|
fprintf(file, "%s", CommandString.c_str());
|
|
|
|
fprintf(file, "GO4K_BEGIN_CMDDEF(Global)\n");
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
if (SynthObj.GlobalValues[u][0] == M_ENV)
|
|
fprintf(file, "\tdb GO4K_ENV_ID\n");
|
|
if (SynthObj.GlobalValues[u][0] == M_VCO)
|
|
fprintf(file, "\tdb GO4K_VCO_ID\n");
|
|
if (SynthObj.GlobalValues[u][0] == M_VCF)
|
|
fprintf(file, "\tdb GO4K_VCF_ID\n");
|
|
if (SynthObj.GlobalValues[u][0] == M_DST)
|
|
fprintf(file, "\tdb GO4K_DST_ID\n");
|
|
if (SynthObj.GlobalValues[u][0] == M_DLL)
|
|
fprintf(file, "\tdb GO4K_DLL_ID\n");
|
|
if (SynthObj.GlobalValues[u][0] == M_FOP)
|
|
fprintf(file, "\tdb GO4K_FOP_ID\n");
|
|
if (SynthObj.GlobalValues[u][0] == M_FST)
|
|
{
|
|
FST_valP v = (FST_valP)(SynthObj.GlobalValues[u]);
|
|
// local storage
|
|
if (v->dest_stack == -1 || v->dest_stack == MAX_INSTRUMENTS)
|
|
fprintf(file, "\tdb GO4K_FST_ID\n");
|
|
// global storage
|
|
else
|
|
fprintf(file, "\tdb GO4K_FSTG_ID\n");
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_PAN)
|
|
fprintf(file, "\tdb GO4K_PAN_ID\n");
|
|
if (SynthObj.GlobalValues[u][0] == M_OUT)
|
|
fprintf(file, "\tdb GO4K_OUT_ID\n");
|
|
if (SynthObj.GlobalValues[u][0] == M_ACC)
|
|
fprintf(file, "\tdb GO4K_ACC_ID\n");
|
|
if (SynthObj.GlobalValues[u][0] == M_FLD)
|
|
fprintf(file, "\tdb GO4K_FLD_ID\n");
|
|
if (SynthObj.GlobalValues[u][0] == M_GLITCH)
|
|
fprintf(file, "\tdb GO4K_GLITCH_ID\n");
|
|
}
|
|
fprintf(file, "GO4K_END_CMDDEF\n");
|
|
fprintf(file, "go4k_synth_instructions_end\n");
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// the instrument data
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
fprintf(file, "%%ifdef USE_SECTIONS\n");
|
|
fprintf(file, "section .g4kmuc4 data align=1\n");
|
|
fprintf(file, "%%else\n");
|
|
fprintf(file, "section .data\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, "go4k_synth_parameter_values\n");
|
|
int delayindex = 0;
|
|
char valstr[1024];
|
|
std::string ValueString;
|
|
#ifdef _8KLANG
|
|
// add primary plugin values first
|
|
fprintf(file, "%s", mergeValueString.c_str());
|
|
#endif
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
if (!InstrumentUsed[i]) continue;
|
|
sprintf(valstr, "GO4K_BEGIN_PARAMDEF(Instrument%d)\n", i + mergeMaxInst); ValueString += valstr;
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
valstr[0] = 0;
|
|
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_ENV)
|
|
{
|
|
ENV_valP v = (ENV_valP)(SynthObj.InstrumentValues[i][u]);
|
|
sprintf(valstr, "\tGO4K_ENV\tATTAC(%d),DECAY(%d),SUSTAIN(%d),RELEASE(%d),GAIN(%d)\n", v->attac, v->decay, v->sustain, v->release, v->gain);
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_VCO)
|
|
{
|
|
VCO_valP v = (VCO_valP)(SynthObj.InstrumentValues[i][u]);
|
|
char type[16]; type[0] = 0;
|
|
char lfo[16]; lfo[0] = 0;
|
|
char stereo[16]; stereo[0] = 0;
|
|
if (v->flags & VCO_SINE)
|
|
sprintf(type, "SINE");
|
|
if (v->flags & VCO_TRISAW)
|
|
sprintf(type, "TRISAW");
|
|
if (v->flags & VCO_PULSE)
|
|
sprintf(type, "PULSE");
|
|
if (v->flags & VCO_NOISE)
|
|
sprintf(type, "NOISE");
|
|
if (v->flags & VCO_GATE)
|
|
sprintf(type, "GATE");
|
|
if (v->flags & VCO_LFO)
|
|
sprintf(lfo, "|LFO");
|
|
if (v->flags & VCO_STEREO)
|
|
sprintf(stereo, "|VCO_STEREO");
|
|
sprintf(valstr, "\tGO4K_VCO\tTRANSPOSE(%d),DETUNE(%d),PHASE(%d),GATES(%d),COLOR(%d),SHAPE(%d),GAIN(%d),FLAGS(%s%s%s)\n", v->transpose, v->detune, v->phaseofs, v->gate, v->color, v->shape, v->gain, type, lfo, stereo);
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_VCF)
|
|
{
|
|
VCF_valP v = (VCF_valP)(SynthObj.InstrumentValues[i][u]);
|
|
char type[16]; type[0] = 0;
|
|
char stereo[16]; stereo[0] = 0;
|
|
int t = v->type & ~VCF_STEREO;
|
|
if (t == VCF_LOWPASS)
|
|
sprintf(type, "LOWPASS");
|
|
if (t == VCF_HIGHPASS)
|
|
sprintf(type, "HIGHPASS");
|
|
if (t == VCF_BANDPASS)
|
|
sprintf(type, "BANDPASS");
|
|
if (t == VCF_BANDSTOP)
|
|
sprintf(type, "BANDSTOP");
|
|
if (t == VCF_ALLPASS)
|
|
sprintf(type, "ALLPASS");
|
|
if (t == VCF_PEAK)
|
|
sprintf(type, "PEAK");
|
|
if (v->type & VCF_STEREO)
|
|
sprintf(stereo, "|STEREO");
|
|
sprintf(valstr, "\tGO4K_VCF\tFREQUENCY(%d),RESONANCE(%d),VCFTYPE(%s%s)\n", v->freq, v->res, type, stereo);
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_DST)
|
|
{
|
|
DST_valP v = (DST_valP)(SynthObj.InstrumentValues[i][u]);
|
|
sprintf(valstr, "\tGO4K_DST\tDRIVE(%d), SNHFREQ(%d), FLAGS(%s)\n", v->drive, v->snhfreq, v->stereo & VCF_STEREO ? "STEREO" : "0");
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_DLL)
|
|
{
|
|
DLL_valP v = (DLL_valP)(SynthObj.InstrumentValues[i][u]);
|
|
if (v->delay < delay_indices.size())
|
|
{
|
|
sprintf(valstr, "\tGO4K_DLL\tPREGAIN(%d),DRY(%d),FEEDBACK(%d),DAMP(%d),FREQUENCY(%d),DEPTH(%d),DELAY(%d),COUNT(%d)\n",
|
|
v->pregain, v->dry, v->feedback, v->damp, v->freq, v->depth, delay_indices[v->delay], v->count);
|
|
}
|
|
// error handling in case indices are fucked up
|
|
else
|
|
{
|
|
sprintf(valstr, "\tGO4K_DLL\tPREGAIN(%d),DRY(%d),FEEDBACK(%d),DAMP(%d),FREQUENCY(%d),DEPTH(%d),DELAY(%d),COUNT(%d) ; ERROR\n",
|
|
v->pregain, v->dry, v->feedback, v->damp, v->freq, v->depth, v->delay, v->count);
|
|
}
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_FOP)
|
|
{
|
|
FOP_valP v = (FOP_valP)(SynthObj.InstrumentValues[i][u]);
|
|
char type[16]; type[0] = 0;
|
|
if (v->flags == FOP_POP)
|
|
sprintf(type, "FOP_POP");
|
|
if (v->flags == FOP_PUSH)
|
|
sprintf(type, "FOP_PUSH");
|
|
if (v->flags == FOP_XCH)
|
|
sprintf(type, "FOP_XCH");
|
|
if (v->flags == FOP_ADD)
|
|
sprintf(type, "FOP_ADD");
|
|
if (v->flags == FOP_ADDP)
|
|
sprintf(type, "FOP_ADDP");
|
|
if (v->flags == FOP_MUL)
|
|
sprintf(type, "FOP_MUL");
|
|
if (v->flags == FOP_MULP)
|
|
sprintf(type, "FOP_MULP");
|
|
if (v->flags == FOP_ADDP2)
|
|
sprintf(type, "FOP_ADDP2");
|
|
if (v->flags == FOP_LOADNOTE)
|
|
sprintf(type, "FOP_LOADNOTE");
|
|
if (v->flags == FOP_MULP2)
|
|
sprintf(type, "FOP_MULP2");
|
|
sprintf(valstr, "\tGO4K_FOP\tOP(%s)\n", type);
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_FST)
|
|
{
|
|
FST_valP v = (FST_valP)(SynthObj.InstrumentValues[i][u]);
|
|
// local storage
|
|
if (v->dest_stack == -1 || v->dest_stack == i)
|
|
{
|
|
// skip empty units on the way to target
|
|
int emptySkip = 0;
|
|
for (int e = 0; e < v->dest_unit; e++)
|
|
{
|
|
if (SynthObj.InstrumentValues[i][e][0] == M_NONE)
|
|
emptySkip++;
|
|
}
|
|
std::string modes;
|
|
modes = "FST_SET";
|
|
if (v->type & FST_ADD)
|
|
modes = "FST_ADD";
|
|
//if (v->type & FST_MUL)
|
|
// modes = "FST_MUL";
|
|
if (v->type & FST_POP)
|
|
modes += "+FST_POP";
|
|
sprintf(valstr, "\tGO4K_FST\tAMOUNT(%d),DEST(%d*MAX_UNIT_SLOTS+%d+%s)\n", v->amount, v->dest_unit-emptySkip, v->dest_slot, modes.c_str() );
|
|
}
|
|
// global storage
|
|
else
|
|
{
|
|
int storestack;
|
|
if (v->dest_stack == MAX_INSTRUMENTS)
|
|
storestack = maxinst;
|
|
else
|
|
storestack = InstrumentIndex[v->dest_stack] + mergeMaxInst;
|
|
// skip empty units on the way to target
|
|
int emptySkip = 0;
|
|
for (int e = 0; e < v->dest_unit; e++)
|
|
{
|
|
if (v->dest_stack == MAX_INSTRUMENTS)
|
|
{
|
|
if (SynthObj.GlobalValues[e][0] == M_NONE)
|
|
emptySkip++;
|
|
}
|
|
else
|
|
{
|
|
if (SynthObj.InstrumentValues[v->dest_stack][e][0] == M_NONE)
|
|
emptySkip++;
|
|
}
|
|
}
|
|
// invalid store target, possibly due non usage of the target instrument
|
|
if (storestack == -1)
|
|
{
|
|
sprintf(valstr, "\tGO4K_FSTG\tAMOUNT(0),DEST(7*4+go4k_instrument.workspace)\n");
|
|
}
|
|
else
|
|
{
|
|
std::string modes;
|
|
modes = "FST_SET";
|
|
if (v->type & FST_ADD)
|
|
modes = "FST_ADD";
|
|
//if (v->type & FST_MUL)
|
|
// modes = "FST_MUL";
|
|
if (v->type & FST_POP)
|
|
modes += "+FST_POP";
|
|
sprintf(valstr, "\tGO4K_FSTG\tAMOUNT(%d),DEST((%d*go4k_instrument.size*MAX_VOICES/4)+(%d*MAX_UNIT_SLOTS+%d)+(go4k_instrument.workspace/4)+%s)\n", v->amount, storestack, v->dest_unit-emptySkip, v->dest_slot, modes.c_str());
|
|
}
|
|
}
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_PAN)
|
|
{
|
|
PAN_valP v = (PAN_valP)(SynthObj.InstrumentValues[i][u]);
|
|
sprintf(valstr, "\tGO4K_PAN\tPANNING(%d)\n", v->panning);
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_OUT)
|
|
{
|
|
OUT_valP v = (OUT_valP)(SynthObj.InstrumentValues[i][u]);
|
|
sprintf(valstr, "\tGO4K_OUT\tGAIN(%d), AUXSEND(%d)\n", v->gain, v->auxsend);
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_ACC)
|
|
{
|
|
ACC_valP v = (ACC_valP)(SynthObj.InstrumentValues[i][u]);
|
|
if (v->flags == ACC_OUT)
|
|
sprintf(valstr, "\tGO4K_ACC\tACCTYPE(OUTPUT)\n");
|
|
else
|
|
sprintf(valstr, "\tGO4K_ACC\tACCTYPE(AUX)\n");
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_FLD)
|
|
{
|
|
FLD_valP v = (FLD_valP)(SynthObj.InstrumentValues[i][u]);
|
|
sprintf(valstr, "\tGO4K_FLD\tVALUE(%d)\n", v->value);
|
|
}
|
|
if (SynthObj.InstrumentValues[i][u][0] == M_GLITCH)
|
|
{
|
|
GLITCH_valP v = (GLITCH_valP)(SynthObj.InstrumentValues[i][u]);
|
|
if (v->delay < delay_indices.size())
|
|
{
|
|
sprintf(valstr, "\tGO4K_GLITCH\tACTIVE(%d),DRY(%d),SLICEFACTOR(%d),PITCHFACTOR(%d),SLICESIZE(%d)\n",
|
|
v->active, v->dry, v->dsize, v->dpitch, delay_indices[v->delay]);
|
|
}
|
|
// error handling in case indices are fucked up
|
|
else
|
|
{
|
|
sprintf(valstr, "\tGO4K_GLITCH\tACTIVE(%d),DRY(%d),SLICEFACTOR(%d),PITCHFACTOR(%d),SLICESIZE(%d) ; ERROR\n",
|
|
v->active, v->dry, v->dsize, v->dpitch, v->delay);
|
|
}
|
|
}
|
|
|
|
ValueString += valstr;
|
|
}
|
|
sprintf(valstr, "GO4K_END_PARAMDEF\n"); ValueString += valstr;
|
|
}
|
|
fprintf(file, "%s", ValueString.c_str());
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// the global data
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
{
|
|
fprintf(file, "GO4K_BEGIN_PARAMDEF(Global)\n");
|
|
for (int u = 0; u < MAX_UNITS; u++)
|
|
{
|
|
if (SynthObj.GlobalValues[u][0] == M_ENV)
|
|
{
|
|
ENV_valP v = (ENV_valP)(SynthObj.GlobalValues[u]);
|
|
fprintf(file, "\tGO4K_ENV\tATTAC(%d),DECAY(%d),SUSTAIN(%d),RELEASE(%d),GAIN(%d)\n", v->attac, v->decay, v->sustain, v->release, v->gain);
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_VCO)
|
|
{
|
|
VCO_valP v = (VCO_valP)(SynthObj.GlobalValues[u]);
|
|
char type[16]; type[0] = 0;
|
|
char lfo[16]; lfo[0] = 0;
|
|
char stereo[16]; stereo[0] = 0;
|
|
if (v->flags & VCO_SINE)
|
|
sprintf(type, "SINE");
|
|
if (v->flags & VCO_TRISAW)
|
|
sprintf(type, "TRISAW");
|
|
if (v->flags & VCO_PULSE)
|
|
sprintf(type, "PULSE");
|
|
if (v->flags & VCO_NOISE)
|
|
sprintf(type, "NOISE");
|
|
if (v->flags & VCO_GATE)
|
|
sprintf(type, "GATE");
|
|
if (v->flags & VCO_LFO)
|
|
sprintf(lfo, "|LFO");
|
|
if (v->flags & VCO_STEREO)
|
|
sprintf(stereo, "|VCO_STEREO");
|
|
fprintf(file, "\tGO4K_VCO\tTRANSPOSE(%d),DETUNE(%d),PHASE(%d),GATES(%d),COLOR(%d),SHAPE(%d),GAIN(%d),FLAGS(%s%s%s)\n", v->transpose, v->detune, v->phaseofs, v->gate, v->color, v->shape, v->gain, type, lfo, stereo);
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_VCF)
|
|
{
|
|
VCF_valP v = (VCF_valP)(SynthObj.GlobalValues[u]);
|
|
char type[16]; type[0] = 0;
|
|
char stereo[16]; stereo[0] = 0;
|
|
int t = v->type & ~VCF_STEREO;
|
|
if (t == VCF_LOWPASS)
|
|
sprintf(type, "LOWPASS");
|
|
if (t == VCF_HIGHPASS)
|
|
sprintf(type, "HIGHPASS");
|
|
if (t == VCF_BANDPASS)
|
|
sprintf(type, "BANDPASS");
|
|
if (t == VCF_BANDSTOP)
|
|
sprintf(type, "BANDSTOP");
|
|
if (t == VCF_ALLPASS)
|
|
sprintf(type, "ALLPASS");
|
|
if (t == VCF_PEAK)
|
|
sprintf(type, "PEAK");
|
|
if (v->type & VCF_STEREO)
|
|
sprintf(stereo, "|STEREO");
|
|
fprintf(file, "\tGO4K_VCF\tFREQUENCY(%d),RESONANCE(%d),VCFTYPE(%s%s)\n", v->freq, v->res, type, stereo);
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_DST)
|
|
{
|
|
DST_valP v = (DST_valP)(SynthObj.GlobalValues[u]);
|
|
fprintf(file, "\tGO4K_DST\tDRIVE(%d), SNHFREQ(%d), FLAGS(%s)\n", v->drive, v->snhfreq, v->stereo & VCF_STEREO ? "STEREO" : "0");
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_DLL)
|
|
{
|
|
DLL_valP v = (DLL_valP)(SynthObj.GlobalValues[u]);
|
|
if (v->delay < delay_indices.size())
|
|
{
|
|
fprintf(file, "\tGO4K_DLL\tPREGAIN(%d),DRY(%d),FEEDBACK(%d),DAMP(%d),FREQUENCY(%d),DEPTH(%d),DELAY(%d),COUNT(%d)\n",
|
|
v->pregain, v->dry, v->feedback, v->damp, v->freq, v->depth, delay_indices[v->delay], v->count);
|
|
}
|
|
// error handling in case indices are fucked up
|
|
else
|
|
{
|
|
fprintf(file, "\tGO4K_DLL\tPREGAIN(%d),DRY(%d),FEEDBACK(%d),DAMP(%d),FREQUENCY(%d),DEPTH(%d),DELAY(%d),COUNT(%d) ; ERROR\n",
|
|
v->pregain, v->dry, v->feedback, v->damp, v->freq, v->depth, v->delay, v->count);
|
|
}
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_FOP)
|
|
{
|
|
FOP_valP v = (FOP_valP)(SynthObj.GlobalValues[u]);
|
|
char type[16]; type[0] = 0;
|
|
if (v->flags == FOP_POP)
|
|
sprintf(type, "FOP_POP");
|
|
if (v->flags == FOP_PUSH)
|
|
sprintf(type, "FOP_PUSH");
|
|
if (v->flags == FOP_XCH)
|
|
sprintf(type, "FOP_XCH");
|
|
if (v->flags == FOP_ADD)
|
|
sprintf(type, "FOP_ADD");
|
|
if (v->flags == FOP_ADDP)
|
|
sprintf(type, "FOP_ADDP");
|
|
if (v->flags == FOP_MUL)
|
|
sprintf(type, "FOP_MUL");
|
|
if (v->flags == FOP_MULP)
|
|
sprintf(type, "FOP_MULP");
|
|
if (v->flags == FOP_ADDP2)
|
|
sprintf(type, "FOP_ADDP2");
|
|
if (v->flags == FOP_LOADNOTE)
|
|
sprintf(type, "FOP_LOADNOTE");
|
|
if (v->flags == FOP_MULP2)
|
|
sprintf(type, "FOP_MULP2");
|
|
fprintf(file, "\tGO4K_FOP\tOP(%s)\n", type);
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_FST)
|
|
{
|
|
FST_valP v = (FST_valP)(SynthObj.GlobalValues[u]);
|
|
// local storage
|
|
if (v->dest_stack == -1 || v->dest_stack == MAX_INSTRUMENTS)
|
|
{
|
|
// skip empty units on the way to target
|
|
int emptySkip = 0;
|
|
for (int e = 0; e < v->dest_unit; e++)
|
|
{
|
|
if (SynthObj.GlobalValues[e][0] == M_NONE)
|
|
emptySkip++;
|
|
}
|
|
std::string modes;
|
|
modes = "FST_SET";
|
|
if (v->type & FST_ADD)
|
|
modes = "FST_ADD";
|
|
//if (v->type & FST_MUL)
|
|
// modes = "FST_MUL";
|
|
if (v->type & FST_POP)
|
|
modes += "+FST_POP";
|
|
fprintf(file, "\tGO4K_FST\tAMOUNT(%d),DEST(%d*MAX_UNIT_SLOTS+%d+%s)\n", v->amount, v->dest_unit-emptySkip, v->dest_slot, modes.c_str());
|
|
}
|
|
// global storage
|
|
else
|
|
{
|
|
int storestack = InstrumentIndex[v->dest_stack] + mergeMaxInst;
|
|
// skip empty units on the way to target
|
|
int emptySkip = 0;
|
|
for (int e = 0; e < v->dest_unit; e++)
|
|
{
|
|
if (SynthObj.InstrumentValues[v->dest_stack][e][0] == M_NONE)
|
|
emptySkip++;
|
|
}
|
|
// invalid store target, possibly due non usage of the target instrument
|
|
if (storestack == -1)
|
|
{
|
|
fprintf(file, "\tGO4K_FSTG\tAMOUNT(0),DEST(7*4+go4k_instrument.workspace)\n");
|
|
}
|
|
else
|
|
{
|
|
std::string modes;
|
|
modes = "FST_SET";
|
|
if (v->type & FST_ADD)
|
|
modes = "FST_ADD";
|
|
//if (v->type & FST_MUL)
|
|
// modes = "FST_MUL";
|
|
if (v->type & FST_POP)
|
|
modes += "+FST_POP";
|
|
fprintf(file, "\tGO4K_FSTG\tAMOUNT(%d),DEST((%d*go4k_instrument.size*MAX_VOICES/4)+(%d*MAX_UNIT_SLOTS+%d)+(go4k_instrument.workspace/4)+%s)\n", v->amount, storestack, v->dest_unit-emptySkip, v->dest_slot, modes.c_str() );
|
|
}
|
|
}
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_PAN)
|
|
{
|
|
PAN_valP v = (PAN_valP)(SynthObj.GlobalValues[u]);
|
|
fprintf(file, "\tGO4K_PAN\tPANNING(%d)\n", v->panning);
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_OUT)
|
|
{
|
|
OUT_valP v = (OUT_valP)(SynthObj.GlobalValues[u]);
|
|
fprintf(file, "\tGO4K_OUT\tGAIN(%d), AUXSEND(%d)\n", v->gain, v->auxsend);
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_ACC)
|
|
{
|
|
ACC_valP v = (ACC_valP)(SynthObj.GlobalValues[u]);
|
|
if (v->flags == ACC_OUT)
|
|
fprintf(file, "\tGO4K_ACC\tACCTYPE(OUTPUT)\n");
|
|
else
|
|
fprintf(file, "\tGO4K_ACC\tACCTYPE(AUX)\n");
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_FLD)
|
|
{
|
|
FLD_valP v = (FLD_valP)(SynthObj.GlobalValues[u]);
|
|
fprintf(file, "\tGO4K_FLD\tVALUE(%d)\n", v->value);
|
|
}
|
|
if (SynthObj.GlobalValues[u][0] == M_GLITCH)
|
|
{
|
|
GLITCH_valP v = (GLITCH_valP)(SynthObj.GlobalValues[u]);
|
|
if (v->delay < delay_indices.size())
|
|
{
|
|
fprintf(file, "\tGO4K_GLITCH\tACTIVE(%d),DRY(%d),SLICEFACTOR(%d),PITCHFACTOR(%d),SLICESIZE(%d)\n",
|
|
v->active, v->dry, v->dsize, v->dpitch, delay_indices[v->delay]);
|
|
}
|
|
// error handling in case indices are fucked up
|
|
else
|
|
{
|
|
fprintf(file, "\tGO4K_GLITCH\tACTIVE(%d),DRY(%d),SLICEFACTOR(%d),PITCHFACTOR(%d),SLICESIZE(%d) ; ERROR\n",
|
|
v->active, v->dry, v->dsize, v->dpitch, v->delay);
|
|
}
|
|
}
|
|
}
|
|
fprintf(file, "GO4K_END_PARAMDEF\n");
|
|
}
|
|
fprintf(file, "go4k_synth_parameter_values_end\n");
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// delay line times
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TODO: Reduction here
|
|
fprintf(file, "%%ifdef USE_SECTIONS\n");
|
|
fprintf(file, "section .g4kmuc5 data align=1\n");
|
|
fprintf(file, "%%else\n");
|
|
fprintf(file, "section .data\n");
|
|
fprintf(file, "%%endif\n");
|
|
fprintf(file, "%%ifdef GO4K_USE_DLL\n");
|
|
fprintf(file, "global _go4k_delay_times\n");
|
|
fprintf(file, "_go4k_delay_times\n");
|
|
for (int i = 0; i < delay_times.size(); i++)
|
|
{
|
|
fprintf(file, "\tdw %d\n", delay_times[i]);
|
|
}
|
|
fprintf(file, "%%endif\n");
|
|
|
|
fclose(file);
|
|
|
|
|
|
// save additional info for primary plugin so secondary can merge
|
|
#ifndef _8KLANG
|
|
std::string mergefile = storePath + "/8klang.merge";
|
|
FILE *mfile = fopen(mergefile.c_str(), "wb");
|
|
// write unit usage info block for primary plugin
|
|
fwrite(&uses, sizeof(SynthUses), 1, mfile);
|
|
// write number of instruments for primary plugin
|
|
fwrite(&maxinst, 4, 1, mfile);
|
|
// write max number of used patterns for primary plugin
|
|
int maxpatterns = PatternIndices[0].size();
|
|
fwrite(&maxpatterns, 4, 1, mfile);
|
|
// write reduced patterns for primary plugin
|
|
int numreducedpatterns = ReducedPatterns.size()/PatternSize;
|
|
fwrite(&numreducedpatterns, 4, 1, mfile);
|
|
for (int i = 0; i < ReducedPatterns.size(); i++)
|
|
{
|
|
int rpv = ReducedPatterns[i];
|
|
fwrite(&rpv, 4, 1, mfile);
|
|
}
|
|
// write pattern list for primary plugin
|
|
for (int i = 0; i < MAX_INSTRUMENTS; i++)
|
|
{
|
|
if (!InstrumentUsed[i]) continue;
|
|
for (int j = 0; j < PatternIndices[i].size(); j++)
|
|
{
|
|
int pi = PatternIndices[i][j];
|
|
fwrite(&pi, 4, 1, mfile);
|
|
}
|
|
}
|
|
// write command strings
|
|
const char* cstr = CommandString.c_str();
|
|
fwrite(cstr, 1, CommandString.size()+1, mfile);
|
|
// write value strings
|
|
const char* vstr = ValueString.c_str();
|
|
fwrite(vstr, 1, ValueString.size()+1, mfile);
|
|
|
|
// write delay times
|
|
int delaytimes = delay_times.size();
|
|
fwrite(&delaytimes, 4, 1, mfile);
|
|
for (int i = 0; i < delay_times.size(); i++)
|
|
{
|
|
delaytimes = delay_times[i];
|
|
fwrite(&delaytimes, 4, 1, mfile);
|
|
}
|
|
|
|
fclose(mfile);
|
|
#endif
|
|
|
|
}
|
|
|
|
// write song info file
|
|
std::string infofile;
|
|
if (objformat != 0) // not windows obj
|
|
infofile = incfile.substr(0, incfile.size()-1) + "h";
|
|
else
|
|
infofile = incfile.substr(0, incfile.size()-3) + "h";
|
|
FILE *fnfofile = fopen(infofile.c_str(), "w");
|
|
fprintf(fnfofile, "// some useful song defines for 4klang\n");
|
|
fprintf(fnfofile, "#define SAMPLE_RATE %d\n", 44100);
|
|
fprintf(fnfofile, "#define BPM %f\n", BeatsPerMinute);
|
|
fprintf(fnfofile, "#define MAX_INSTRUMENTS %d\n", maxinst + mergeMaxInst);
|
|
fprintf(fnfofile, "#define MAX_PATTERNS %d\n", mergeMaxPatterns > PatternIndices[0].size() ? mergeMaxPatterns : PatternIndices[0].size());
|
|
fprintf(fnfofile, "#define PATTERN_SIZE_SHIFT %d\n", GetShift2(PatternSize));
|
|
fprintf(fnfofile, "#define PATTERN_SIZE (1 << PATTERN_SIZE_SHIFT)\n");
|
|
fprintf(fnfofile, "#define MAX_TICKS (MAX_PATTERNS*PATTERN_SIZE)\n");
|
|
fprintf(fnfofile, "#define SAMPLES_PER_TICK %d\n", ((int)(44100.0f*4.0f*60.0f/(BeatsPerMinute*16.0f*TickScaler))));
|
|
fprintf(fnfofile, "#define MAX_SAMPLES (SAMPLES_PER_TICK*MAX_TICKS)\n");
|
|
fprintf(fnfofile, "#define POLYPHONY %d\n", SynthObj.Polyphony);
|
|
if (output16)
|
|
{
|
|
fprintf(fnfofile, "#define INTEGER_16BIT\n");
|
|
fprintf(fnfofile, "#define SAMPLE_TYPE short\n");
|
|
}
|
|
else
|
|
{
|
|
fprintf(fnfofile, "#define FLOAT_32BIT\n");
|
|
fprintf(fnfofile, "#define SAMPLE_TYPE float\n");
|
|
}
|
|
if (objformat == 0)
|
|
{
|
|
fprintf(fnfofile, "\n#define WINDOWS_OBJECT\n\n");
|
|
fprintf(fnfofile, "// declaration of the external synth render function, you'll always need that\n");
|
|
fprintf(fnfofile, "extern \"C\" void __stdcall _4klang_render(void*);\n");
|
|
fprintf(fnfofile, "// declaration of the external envelope buffer. access only if you're song was exported with that option\n");
|
|
fprintf(fnfofile, "extern \"C\" float _4klang_envelope_buffer;\n");
|
|
fprintf(fnfofile, "// declaration of the external note buffer. access only if you're song was exported with that option\n");
|
|
fprintf(fnfofile, "extern \"C\" int _4klang_note_buffer;\n");
|
|
}
|
|
if (objformat == 1)
|
|
{
|
|
fprintf(fnfofile, "\n#define LINUX_OBJECT\n\n");
|
|
fprintf(fnfofile, "// declaration of the external synth render function, you'll always need that\n");
|
|
fprintf(fnfofile, "extern void* __4klang_render(void*);\n");
|
|
fprintf(fnfofile, "// declaration of the external envelope buffer. access only if you're song was exported with that option\n");
|
|
fprintf(fnfofile, "extern float __4klang_envelope_buffer;\n");
|
|
fprintf(fnfofile, "// declaration of the external note buffer. access only if you're song was exported with that option\n");
|
|
fprintf(fnfofile, "extern int __4klang_note_buffer;\n");
|
|
}
|
|
if (objformat == 2)
|
|
{
|
|
fprintf(fnfofile, "\n#define MACOSX_OBJECT\n\n");
|
|
fprintf(fnfofile, "// declaration of the external synth render function, you'll always need that\n");
|
|
fprintf(fnfofile, "extern void* _4klang_render(void*);\n");
|
|
fprintf(fnfofile, "// declaration of the external envelope buffer. access only if you're song was exported with that option\n");
|
|
fprintf(fnfofile, "extern float _4klang_envelope_buffer;\n");
|
|
fprintf(fnfofile, "// declaration of the external note buffer. access only if you're song was exported with that option\n");
|
|
fprintf(fnfofile, "extern int _4klang_note_buffer;\n");
|
|
}
|
|
|
|
fclose(fnfofile);
|
|
}
|
|
|
|
SynthObjectP Go4kVSTi_GetSynthObject()
|
|
{
|
|
return &SynthObj;
|
|
} |