Some improvements to the FM Wavetable editor (More waveforms, full modulation matrix) (Take 495, I hope SDL is fine now) (#935)

* Added more waveforms to the FM wavetable editor (Finally Sine isn't the only option anymore!)

* fixed quarter waveforms

* Complete modulation matrix with cross modulation. Also, now X axis modulates Y axis (it was Y modulating X before)

* I really hope it will work this time bruh

* Update gui.cpp

Fixed a programming error that can potentially lead to a SEGFAULT (Core dumped) because I was writing out of bounds of an array

---------

Co-authored-by: System64MC <nicolas1811.jans@gmail.com>
This commit is contained in:
System64 2023-02-06 07:29:01 +01:00 committed by GitHub
parent cdc472dace
commit 056c895c69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 499 additions and 82 deletions

View File

@ -6226,19 +6226,32 @@ FurnaceGUI::FurnaceGUI():
waveGenTL[1]=0.0f;
waveGenTL[2]=0.0f;
waveGenTL[3]=1.0f;
fmWaveform[0]=0;
fmWaveform[1]=0;
fmWaveform[2]=0;
fmWaveform[3]=0;
waveGenMult[0]=1;
waveGenMult[1]=1;
waveGenMult[2]=1;
waveGenMult[3]=1;
memset(waveGenFB,0,sizeof(int)*4);
memset(waveGenFMCon1,0,sizeof(bool)*4);
memset(waveGenFMCon2,0,sizeof(bool)*3);
memset(waveGenFMCon3,0,sizeof(bool)*2);
memset(waveGenFMCon0,0,sizeof(bool)*5);
memset(waveGenFMCon1,0,sizeof(bool)*5);
memset(waveGenFMCon2,0,sizeof(bool)*5);
memset(waveGenFMCon3, 0, sizeof(bool) * 5);
memset(waveGenFMCon4,0,sizeof(bool)*5);
waveGenAmp[0]=1.0f;
waveGenFMCon1[0]=true;
waveGenFMCon2[0]=true;
waveGenFMCon3[0]=true;
waveGenFMCon0[0]=false;
waveGenFMCon1[0]= true;
waveGenFMCon2[1]= true;
waveGenFMCon3[2] = true;
waveGenFMCon4[0]= false;
waveGenFMCon0[4] = false;
waveGenFMCon1[4] = false;
waveGenFMCon2[4] = false;
waveGenFMCon3[4] = true;
memset(keyHit,0,sizeof(float)*DIV_MAX_CHANS);
memset(keyHit1,0,sizeof(float)*DIV_MAX_CHANS);

View File

@ -1765,13 +1765,16 @@ class FurnaceGUI {
float waveGenAmp[16];
float waveGenPhase[16];
float waveGenTL[4];
int fmWaveform[4];
int waveGenMult[4];
int waveGenFB[4];
int waveGenScaleX, waveGenScaleY, waveGenOffsetX, waveGenOffsetY, waveGenSmooth;
float waveGenAmplify;
bool waveGenFMCon1[4];
bool waveGenFMCon2[3];
bool waveGenFMCon3[2];
bool waveGenFMCon0[5];
bool waveGenFMCon1[5];
bool waveGenFMCon2[5];
bool waveGenFMCon3[5];
bool waveGenFMCon4[5];
bool waveGenFM;
void drawSSGEnv(unsigned char type, const ImVec2& size);

View File

@ -40,6 +40,209 @@ const char* waveInterpolations[4]={
"Cubic"
};
double sinus(double x) {
return sin(x);
}
double rectSin(double x) {
return sin(x) > 0 ? sin(x) : 0;
}
double absSin(double x) {
return abs(sin(x));
}
double square(double x) {
return fmod(x, (2 * M_PI)) >= M_PI ? -1 : 1;
}
double rectSquare(double x) {
return square(x) > 0 ? square(x) : 0;
}
double quartSin(double x) {
//if (x < M_PI / 2 || (x >= M_PI && x < (M_PI + M_PI / 2)))
// return absSin(x);
//return 0;
return absSin(x) * rectSquare(2 * x);
}
double squiSin(double x) {
return sin(x) >= 0 ? sin(2 * x) : 0;
}
double squiAbsSin(double x) {
return abs(squiSin(x));
}
double saw(double x) {
return atan(tan(x / 2)) / (M_PI / 2);
}
double rectSaw(double x) {
return saw(x) > 0 ? saw(x) : 0;
}
double absSaw(double x) {
return saw(x) < 0 ? saw(x) + 1 : saw(x);
}
double cubSaw(double x) {
return pow(saw(x), 3);
}
double rectCubSaw(double x) {
return pow(rectSaw(x), 3);
}
double absCubSaw(double x) {
return pow(absSaw(x), 3);
}
double cubSine(double x) {
return pow(sin(x), 3);
}
double rectCubSin(double x) {
return pow(rectSin(x), 3);
}
double absCubSin(double x) {
return pow(absSin(x), 3);
}
double quartCubSin(double x) {
return pow(quartSin(x), 3);
}
double squishCubSin(double x) {
return pow(squiSin(x), 3);
}
double squishAbsCubSin(double x) {
return pow(squiAbsSin(x), 3);
}
double triangle(double x) {
return asin(sin(x)) / (M_PI / 2);
}
double rectTri(double x) {
return triangle(x) > 0 ? triangle(x) : 0;
}
double absTri(double x) {
return abs(triangle(x));
}
double quartTri(double x) {
//if (x < M_PI / 2 || (x >= M_PI && x < (M_PI + M_PI / 2)))
// return absTri(x);
//return 0;
return absTri(x) * rectSquare(2 * x);
}
double squiTri(double x) {
return sin(x) >= 0 ? triangle(2 * x) : 0;
}
double absSquiTri(double x) {
return abs(squiTri(x));
}
double cubTriangle(double x) {
return pow(triangle(x), 3);
}
double cubRectTri(double x) {
return pow(rectTri(x), 3);
}
double cubAbsTri(double x) {
return pow(absTri(x), 3);
}
double cubQuartTri(double x) {
return pow(quartTri(x), 3);
}
double cubSquiTri(double x) {
return pow(squiTri(x), 3);
}
double absCubSquiTri(double x) {
return abs(cubSquiTri(x));
}
typedef double (*WaveFunc) (double a);
WaveFunc waveFuncs[] = {
sinus,
rectSin,
absSin,
quartSin,
squiSin,
squiAbsSin,
square,
rectSquare,
saw,
rectSaw,
absSaw,
cubSaw,
rectCubSaw,
absCubSaw,
cubSine,
rectCubSin,
absCubSin,
quartCubSin,
squishCubSin,
squishAbsCubSin,
triangle,
rectTri,
absTri,
quartTri,
squiTri,
absSquiTri,
cubTriangle,
cubRectTri,
cubAbsTri,
cubQuartTri,
cubSquiTri,
absCubSquiTri
};
const char* fmWaveforms[] = {
"Sine",
"Rect. Sine",
"Abs. Sine",
"Quart. Sine",
"Squish. Sine",
"Abs. Squish. Sine",
"Square",
"rectSquare",
"Saw",
"Rect. Saw",
"Abs. Saw",
"Cubed Saw",
"Rect. Cubed Saw",
"Abs. Cubed Saw",
"Cubed Sine",
"Rect. Cubed Sine",
"Abs. Cubed Sine",
"Quart. Cubed Sine",
"Squish. Cubed Sine",
"Squish. Abs. Cub. Sine",
"Triangle",
"Rect. Triangle",
"Abs. Triangle",
"Quart. Triangle",
"Squish. Triangle",
"Abs. Squish. Triangle",
"Cubed Triangle",
"Rect. Cubed Triangle",
"Abs. Cubed Triangle",
"Quart. Cubed Triangle",
"Squish. Cubed Triangle",
"Squish. Abs. Cub. Triangle",
};
const float multFactors[17]={
M_PI,
2*M_PI,
@ -60,6 +263,8 @@ const float multFactors[17]={
32*M_PI,
};
void FurnaceGUI::doGenerateWave() {
float finalResult[256];
if (curWave<0 || curWave>=(int)e->song.wave.size()) return;
@ -78,28 +283,63 @@ void FurnaceGUI::doGenerateWave() {
float s2fb1=0;
float s3fb0=0;
float s3fb1=0;
float s0 = 0;
float s1 = 0;
float s2 = 0;
float s3 = 1;
for (int i=0; i<wave->len; i++) {
float pos=(float)i/(float)wave->len;
float s0=sin((pos+(waveGenFB[0]?((s0fb0+s0fb1)*pow(2.0f,waveGenFB[0]-8)):0.0f))*multFactors[waveGenMult[0]])*waveGenTL[0];
s0 = waveFuncs[fmWaveform[0]]((pos +
(waveGenFB[0] ? ((s0fb0 + s0fb1) * pow(2.0f, waveGenFB[0] - 8)) : 0.0f) +
(waveGenFMCon0[3] ? s3 : 0.0f) +
(waveGenFMCon0[2] ? s2 : 0.0f) +
(waveGenFMCon0[1] ? s1 : 0.0f) +
(waveGenFMCon0[0] ? s0 : 0.0f))* multFactors[waveGenMult[0]]) * waveGenTL[0];
s0fb0=s0fb1;
s0fb1=s0;
float s1=sin((pos+(waveGenFB[1]?((s1fb0+s1fb1)*pow(2.0f,waveGenFB[1]-8)):0.0f)+(waveGenFMCon1[0]?s0:0.0f))*multFactors[waveGenMult[1]])*waveGenTL[1];
s1 = waveFuncs[fmWaveform[1]]((pos +
(waveGenFB[1] ? ((s1fb0 + s1fb1) * pow(2.0f, waveGenFB[1] - 8)) : 0.0f) +
(waveGenFMCon1[3] ? s3 : 0.0f) +
(waveGenFMCon1[2] ? s2 : 0.0f) +
(waveGenFMCon1[1] ? s1 : 0.0f) +
(waveGenFMCon1[0] ? s0 : 0.0f))* multFactors[waveGenMult[1]]) * waveGenTL[1];
s1fb0=s1fb1;
s1fb1=s1;
float s2=sin((pos+(waveGenFB[2]?((s2fb0+s2fb1)*pow(2.0f,waveGenFB[2]-8)):0.0f)+(waveGenFMCon1[1]?s0:0.0f)+(waveGenFMCon2[0]?s1:0.0f))*multFactors[waveGenMult[2]])*waveGenTL[2];
s2 = waveFuncs[fmWaveform[2]]((pos +
(waveGenFB[2] ? ((s2fb0 + s2fb1) * pow(2.0f, waveGenFB[2] - 8)) : 0.0f) +
(waveGenFMCon2[3] ? s3 : 0.0f) +
(waveGenFMCon2[2] ? s2 : 0.0f) +
(waveGenFMCon2[1] ? s1 : 0.0f) +
(waveGenFMCon2[0] ? s0 : 0.0f))* multFactors[waveGenMult[2]]) * waveGenTL[2];
s2fb0=s2fb1;
s2fb1=s2;
float s3=sin((pos+(waveGenFB[3]?((s3fb0+s3fb1)*pow(2.0f,waveGenFB[3]-8)):0.0f)+(waveGenFMCon1[2]?s0:0.0f)+(waveGenFMCon2[1]?s1:0.0f)+(waveGenFMCon3[0]?s2:0.0f))*multFactors[waveGenMult[3]])*waveGenTL[3];
s3 = waveFuncs[fmWaveform[3]]((pos +
(waveGenFB[3] ? ((s3fb0 + s3fb1) * pow(2.0f, waveGenFB[3] - 8)) : 0.0f) +
(waveGenFMCon3[3] ? s3 : 0.0f) +
(waveGenFMCon3[2] ? s2 : 0.0f) +
(waveGenFMCon3[1] ? s1 : 0.0f) +
(waveGenFMCon3[0] ? s0 : 0.0f)) * multFactors[waveGenMult[3]])* waveGenTL[3];
s3fb0=s3fb1;
s3fb1=s3;
if (waveGenFMCon1[3]) finalResult[i]+=s0;
if (waveGenFMCon2[2]) finalResult[i]+=s1;
if (waveGenFMCon3[1]) finalResult[i]+=s2;
finalResult[i]+=s3;
if (waveGenFMCon0[4]) finalResult[i]+=s0;
if (waveGenFMCon1[4]) finalResult[i]+=s1;
if (waveGenFMCon2[4]) finalResult[i]+=s2;
if (waveGenFMCon3[4]) finalResult[i]+=s3;
//finalResult[i]+=s3;
}
} else {
switch (waveGenBaseShape) {
@ -165,9 +405,15 @@ void FurnaceGUI::doGenerateWave() {
MARK_MODIFIED;
}
#define CENTER_TEXT(text) \
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+0.5*(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(text).x));
//int lengthArray()
void FurnaceGUI::drawWaveEdit() {
if (nextWindow==GUI_WINDOW_WAVE_EDIT) {
waveEditOpen=true;
@ -441,7 +687,7 @@ void FurnaceGUI::drawWaveEdit() {
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize("Op").x);
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5);
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.25);
ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.25);
ImGui::TableSetupColumn("c3", ImGuiTableColumnFlags_WidthStretch, 0.25);
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
@ -480,84 +726,239 @@ void FurnaceGUI::drawWaveEdit() {
if (CWSliderInt("##WGFB",&waveGenFB[i],0,7)) {
doGenerateWave();
}
ImGui::PopID();
}
ImGui::EndTable();
}
if (ImGui::BeginTable("WGFMWAVE", 2)) {
ImGui::TableSetupColumn("c0", ImGuiTableColumnFlags_WidthFixed, ImGui::CalcTextSize("Op").x);
ImGui::TableSetupColumn("c1", ImGuiTableColumnFlags_WidthStretch, 1);
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::Text("Op");
ImGui::TableNextColumn();
ImGui::Text("Waveform");
for (int i = 0; i < 4; i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%d", i + 1);
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::PushID(i);
if (CWSliderInt("##WGWAVEFORM", &fmWaveform[i], 0, _countof(fmWaveforms)-1, fmWaveforms[fmWaveform[i]])) {
doGenerateWave();
}
ImGui::PopID();
}
ImGui::EndTable();
}
CENTER_TEXT("Connection Diagram");
ImGui::Text("Connection Diagram");
if (ImGui::BeginTable("WGFMCon",5)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text(">>");
ImGui::TableNextColumn();
ImGui::Text("2");
ImGui::TableNextColumn();
ImGui::Text("3");
ImGui::TableNextColumn();
ImGui::Text("4");
ImGui::TableNextColumn();
ImGui::Text("Out");
//if (ImGui::BeginTable("WGFMCon",5)) {
// ImGui::TableNextRow();
// ImGui::TableNextColumn();
// ImGui::Text(">>");
// ImGui::TableNextColumn();
// ImGui::Text("2");
// ImGui::TableNextColumn();
// ImGui::Text("3");
// ImGui::TableNextColumn();
// ImGui::Text("4");
// ImGui::TableNextColumn();
// ImGui::Text("Out");
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("1");
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con12",&waveGenFMCon1[0])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con13",&waveGenFMCon1[1])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con14",&waveGenFMCon1[2])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con1O",&waveGenFMCon1[3])) {
doGenerateWave();
}
// ImGui::TableNextRow();
// ImGui::TableNextColumn();
// ImGui::Text("1");
// ImGui::TableNextColumn();
// if (ImGui::Checkbox("##Con12",&waveGenFMCon1[0])) {
// doGenerateWave();
// }
// ImGui::TableNextColumn();
// if (ImGui::Checkbox("##Con13",&waveGenFMCon1[1])) {
// doGenerateWave();
// }
// ImGui::TableNextColumn();
// if (ImGui::Checkbox("##Con14",&waveGenFMCon1[2])) {
// doGenerateWave();
// }
// ImGui::TableNextColumn();
// if (ImGui::Checkbox("##Con1O",&waveGenFMCon1[3])) {
// doGenerateWave();
// }
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("2");
ImGui::TableNextColumn();
// blank
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con23",&waveGenFMCon2[0])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con24",&waveGenFMCon2[1])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con2O",&waveGenFMCon2[2])) {
doGenerateWave();
}
// ImGui::TableNextRow();
// ImGui::TableNextColumn();
// ImGui::Text("2");
// ImGui::TableNextColumn();
// // blank
// ImGui::TableNextColumn();
// if (ImGui::Checkbox("##Con23",&waveGenFMCon2[0])) {
// doGenerateWave();
// }
// ImGui::TableNextColumn();
// if (ImGui::Checkbox("##Con24",&waveGenFMCon2[1])) {
// doGenerateWave();
// }
// ImGui::TableNextColumn();
// if (ImGui::Checkbox("##Con2O",&waveGenFMCon2[2])) {
// doGenerateWave();
// }
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("3");
ImGui::TableNextColumn();
// blank
ImGui::TableNextColumn();
// blank
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con34",&waveGenFMCon3[0])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con3O",&waveGenFMCon3[1])) {
doGenerateWave();
}
// ImGui::TableNextRow();
// ImGui::TableNextColumn();
// ImGui::Text("3");
// ImGui::TableNextColumn();
// // blank
// ImGui::TableNextColumn();
// // blank
// ImGui::TableNextColumn();
// if (ImGui::Checkbox("##Con34",&waveGenFMCon3[0])) {
// doGenerateWave();
// }
// ImGui::TableNextColumn();
// if (ImGui::Checkbox("##Con3O",&waveGenFMCon3[1])) {
// doGenerateWave();
// }
ImGui::EndTable();
// ImGui::EndTable();
//}
if (ImGui::BeginTable("WGFMCon", 6)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text(">>");
ImGui::TableNextColumn();
ImGui::Text("1");
ImGui::TableNextColumn();
ImGui::Text("2");
ImGui::TableNextColumn();
ImGui::Text("3");
ImGui::TableNextColumn();
ImGui::Text("4");
ImGui::TableNextColumn();
//ImGui::Text("4");
//ImGui::TableNextColumn();
ImGui::Text("Out");
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("1");
ImGui::TableNextColumn();
if (ImGui::Checkbox("##ConO1", &waveGenFMCon0[0])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##ConO2", &waveGenFMCon0[1])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##ConO3", &waveGenFMCon0[2])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##ConO4", &waveGenFMCon0[3])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##ConOO", &waveGenFMCon0[4])) {
doGenerateWave();
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("2");
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con11", &waveGenFMCon1[0])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con12", &waveGenFMCon1[1])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con13", &waveGenFMCon1[2])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con14", &waveGenFMCon1[3])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con1O", &waveGenFMCon1[4])) {
doGenerateWave();
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("3");
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con21", &waveGenFMCon2[0])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con22", &waveGenFMCon2[1])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con23", &waveGenFMCon2[2])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con24", &waveGenFMCon2[3])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con2O", &waveGenFMCon2[4])) {
doGenerateWave();
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("4");
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con31", &waveGenFMCon3[0])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con32", &waveGenFMCon3[1])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con33", &waveGenFMCon3[2])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con34", &waveGenFMCon3[3])) {
doGenerateWave();
}
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con3O", &waveGenFMCon3[4])) {
doGenerateWave();
}
ImGui::EndTable();
}
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("WaveTools")) {