From 693d457fffb8447727503dd42dee58e2d672f22a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 27 Jul 2022 02:23:29 -0500 Subject: [PATCH] GUI: wave generator, part 2 --- src/gui/gui.cpp | 6 +-- src/gui/gui.h | 4 +- src/gui/waveEdit.cpp | 114 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 116 insertions(+), 8 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 565ff7db5..ab4b3d63c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4718,9 +4718,9 @@ FurnaceGUI::FurnaceGUI(): #endif hasACED(false), waveGenBaseShape(0), - waveGenDuty(0.0f), - waveGenPower(0.0f), - waveGenInvertPoint(0.0f), + waveGenDuty(0.5f), + waveGenPower(1), + waveGenInvertPoint(1.0f), waveGenFM(false) { // value keys valueKeys[SDLK_0]=0; diff --git a/src/gui/gui.h b/src/gui/gui.h index df3dcd16d..30113953f 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1468,7 +1468,9 @@ class FurnaceGUI { // wave generator int waveGenBaseShape; - float waveGenDuty, waveGenPower, waveGenInvertPoint; + float waveGenDuty; + int waveGenPower; + float waveGenInvertPoint; float waveGenAmp[16]; float waveGenPhase[16]; float waveGenTL[4]; diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 0d65f5e68..5dd9b1ccf 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -39,34 +39,67 @@ void FurnaceGUI::doGenerateWave() { DivWavetable* wave=e->song.wave[curWave]; memset(finalResult,0,sizeof(float)*256); + if (wave->len<2) return; + if (waveGenFM) { } else { switch (waveGenBaseShape) { case 0: // sine for (int i=0; ilen; i++) { - finalResult[i]=0.5*(1.0+sin(i*2.0*M_PI/(double)wave->len)); + for (int j=0; j<16; j++) { + float pos=fmod((waveGenPhase[j]*wave->len)+(i*(j+1)),wave->len); + float partial=sin((0.5+pos)*2.0*M_PI/(double)wave->len); + partial=pow(partial,waveGenPower); + partial*=waveGenAmp[j]; + finalResult[i]+=partial; + } } break; case 1: // triangle for (int i=0; ilen; i++) { - finalResult[i]=2.0*(0.5-fabs(0.5-(i/(double)(wave->len-1)))); + for (int j=0; j<16; j++) { + float pos=fmod((waveGenPhase[j]*wave->len)+(i*(j+1)),wave->len); + float partial=4.0*(0.5-fabs(0.5-(pos/(double)(wave->len-1))))-1.0; + partial=pow(partial,waveGenPower); + partial*=waveGenAmp[j]; + finalResult[i]+=partial; + } } break; case 2: // saw for (int i=0; ilen; i++) { - finalResult[i]=i/(double)(wave->len-1); + for (int j=0; j<16; j++) { + float pos=fmod((waveGenPhase[j]*wave->len)+(i*(j+1)),wave->len); + float partial=((2*pos)/(double)(wave->len-1))-1.0; + partial=pow(partial,waveGenPower); + partial*=waveGenAmp[j]; + finalResult[i]+=partial; + } } break; case 3: // pulse for (int i=0; ilen; i++) { - finalResult[i]=(i>=(wave->len/2))?1:0; + for (int j=0; j<16; j++) { + float pos=fmod((waveGenPhase[j]*wave->len)+(i*(j+1)),wave->len); + float partial=(pos>=(waveGenDuty*wave->len))?1:-1; + partial=pow(partial,waveGenPower); + partial*=waveGenAmp[j]; + finalResult[i]+=partial; + } } break; } } + for (int i=waveGenInvertPoint*wave->len; ilen; i++) { + finalResult[i]=-finalResult[i]; + } + for (int i=0; ilen; i++) { + finalResult[i]=(1.0+finalResult[i])*0.5; + if (finalResult[i]<0.0f) finalResult[i]=0.0f; + if (finalResult[i]>1.0f) finalResult[i]=1.0f; wave->data[i]=round(finalResult[i]*wave->max); } } @@ -202,6 +235,79 @@ void FurnaceGUI::drawWaveEdit() { if (waveGenBaseShape>3) waveGenBaseShape=3; doGenerateWave(); } + + if (ImGui::BeginTable("WGShapeProps",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Duty"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderFloat("##WGDuty",&waveGenDuty,0.0f,1.0f)) { + doGenerateWave(); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Exponent"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##WGExp",&waveGenPower,1,8)) { + doGenerateWave(); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("XOR Point"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderFloat("##WGXOR",&waveGenInvertPoint,0.0f,1.0f)) { + doGenerateWave(); + } + + ImGui::EndTable(); + } + + if (ImGui::TreeNode("Amplitude/Phase")) { + if (ImGui::BeginTable("WGShapeProps",3)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.6f); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.4f); + + for (int i=0; i<16; i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%d",i+1); + ImGui::TableNextColumn(); + ImGui::PushID(140+i); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderFloat("##WGAmp",&waveGenAmp[i],-1.0f,1.0f)) { + doGenerateWave(); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { + waveGenAmp[i]=0.0f; + doGenerateWave(); + } + ImGui::PopID(); + ImGui::TableNextColumn(); + ImGui::PushID(140+i); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderFloat("##WGPhase",&waveGenPhase[i],0.0f,1.0f)) { + doGenerateWave(); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { + waveGenPhase[i]=0.0f; + doGenerateWave(); + } + ImGui::PopID(); + } + + ImGui::EndTable(); + } + ImGui::TreePop(); + } ImGui::EndTabItem(); } if (ImGui::BeginTabItem("FM")) {