2022-03-21 22:34:43 +00:00
/**
* Furnace Tracker - multi - system chiptune tracker
2024-01-17 02:26:57 +00:00
* Copyright ( C ) 2021 - 2024 tildearrow and contributors
2022-03-21 22:34:43 +00:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2022-07-27 06:20:26 +00:00
# define _USE_MATH_DEFINES
2022-03-21 21:34:19 +00:00
# include "gui.h"
# include "plot_nolerp.h"
2022-04-02 23:22:06 +00:00
# include "IconsFontAwesome4.h"
2022-03-21 21:34:19 +00:00
# include "misc/cpp/imgui_stdlib.h"
2022-10-08 22:57:14 +00:00
# include <fmt/printf.h>
2022-07-27 06:20:26 +00:00
# include <math.h>
2022-03-30 05:28:49 +00:00
# include <imgui.h>
2022-03-21 21:34:19 +00:00
2022-07-27 06:20:26 +00:00
const char * waveGenBaseShapes [ 4 ] = {
" Sine " ,
" Triangle " ,
" Saw " ,
" Pulse "
} ;
2022-10-12 19:54:29 +00:00
const char * waveInterpolations [ 4 ] = {
" None " ,
" Linear " ,
" Cosine " ,
" Cubic "
2022-10-03 17:48:07 +00:00
} ;
2023-02-06 06:29:01 +00:00
double sinus ( double x ) {
2023-02-06 06:36:19 +00:00
return sin ( x ) ;
2023-02-06 06:29:01 +00:00
}
double rectSin ( double x ) {
2023-02-06 06:36:19 +00:00
return sin ( x ) > 0 ? sin ( x ) : 0 ;
2023-02-06 06:29:01 +00:00
}
double absSin ( double x ) {
2023-02-06 06:36:19 +00:00
return fabs ( sin ( x ) ) ;
2023-02-06 06:29:01 +00:00
}
double square ( double x ) {
2023-02-06 06:36:19 +00:00
return fmod ( x , ( 2 * M_PI ) ) > = M_PI ? - 1 : 1 ;
2023-02-06 06:29:01 +00:00
}
double rectSquare ( double x ) {
2023-02-06 06:36:19 +00:00
return square ( x ) > 0 ? square ( x ) : 0 ;
2023-02-06 06:29:01 +00:00
}
double quartSin ( double x ) {
2023-02-06 06:36:19 +00:00
return absSin ( x ) * rectSquare ( 2 * x ) ;
2023-02-06 06:29:01 +00:00
}
double squiSin ( double x ) {
2023-02-06 06:36:19 +00:00
return sin ( x ) > = 0 ? sin ( 2 * x ) : 0 ;
2023-02-06 06:29:01 +00:00
}
double squiAbsSin ( double x ) {
2023-02-06 06:36:19 +00:00
return fabs ( squiSin ( x ) ) ;
2023-02-06 06:29:01 +00:00
}
double saw ( double x ) {
2023-02-06 06:36:19 +00:00
return atan ( tan ( x / 2 ) ) / ( M_PI / 2 ) ;
2023-02-06 06:29:01 +00:00
}
double rectSaw ( double x ) {
2023-02-06 06:36:19 +00:00
return saw ( x ) > 0 ? saw ( x ) : 0 ;
2023-02-06 06:29:01 +00:00
}
double absSaw ( double x ) {
2023-02-06 06:36:19 +00:00
return saw ( x ) < 0 ? saw ( x ) + 1 : saw ( x ) ;
2023-02-06 06:29:01 +00:00
}
double cubSaw ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( saw ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double rectCubSaw ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( rectSaw ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double absCubSaw ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( absSaw ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double cubSine ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( sin ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double rectCubSin ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( rectSin ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double absCubSin ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( absSin ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double quartCubSin ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( quartSin ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double squishCubSin ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( squiSin ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double squishAbsCubSin ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( squiAbsSin ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double triangle ( double x ) {
2023-02-06 06:36:19 +00:00
return asin ( sin ( x ) ) / ( M_PI / 2 ) ;
2023-02-06 06:29:01 +00:00
}
double rectTri ( double x ) {
2023-02-06 06:36:19 +00:00
return triangle ( x ) > 0 ? triangle ( x ) : 0 ;
2023-02-06 06:29:01 +00:00
}
double absTri ( double x ) {
2023-02-06 06:36:19 +00:00
return fabs ( triangle ( x ) ) ;
2023-02-06 06:29:01 +00:00
}
double quartTri ( double x ) {
2023-02-06 06:36:19 +00:00
return absTri ( x ) * rectSquare ( 2 * x ) ;
2023-02-06 06:29:01 +00:00
}
double squiTri ( double x ) {
2023-02-06 06:36:19 +00:00
return sin ( x ) > = 0 ? triangle ( 2 * x ) : 0 ;
2023-02-06 06:29:01 +00:00
}
double absSquiTri ( double x ) {
2023-02-06 06:36:19 +00:00
return fabs ( squiTri ( x ) ) ;
2023-02-06 06:29:01 +00:00
}
double cubTriangle ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( triangle ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double cubRectTri ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( rectTri ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double cubAbsTri ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( absTri ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double cubQuartTri ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( quartTri ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double cubSquiTri ( double x ) {
2023-02-06 06:36:19 +00:00
return pow ( squiTri ( x ) , 3 ) ;
2023-02-06 06:29:01 +00:00
}
double absCubSquiTri ( double x ) {
2023-02-06 06:36:19 +00:00
return fabs ( cubSquiTri ( x ) ) ;
2023-02-06 06:29:01 +00:00
}
typedef double ( * WaveFunc ) ( double a ) ;
2023-02-06 06:36:19 +00:00
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
2023-02-06 06:29:01 +00:00
} ;
const char * fmWaveforms [ ] = {
2023-02-06 06:36:19 +00:00
" 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 " ,
2023-02-06 06:29:01 +00:00
} ;
2023-02-06 06:36:19 +00:00
const size_t fmWaveformsLen = sizeof ( fmWaveforms ) / sizeof ( fmWaveforms [ 0 ] ) ;
2022-09-16 07:04:01 +00:00
const float multFactors [ 17 ] = {
2022-09-05 10:48:20 +00:00
M_PI ,
2 * M_PI ,
4 * M_PI ,
6 * M_PI ,
8 * M_PI ,
10 * M_PI ,
12 * M_PI ,
14 * M_PI ,
16 * M_PI ,
18 * M_PI ,
20 * M_PI ,
22 * M_PI ,
24 * M_PI ,
26 * M_PI ,
28 * M_PI ,
30 * M_PI ,
2022-09-16 07:04:01 +00:00
32 * M_PI ,
2022-09-05 10:48:20 +00:00
} ;
2022-07-27 06:20:26 +00:00
void FurnaceGUI : : doGenerateWave ( ) {
float finalResult [ 256 ] ;
if ( curWave < 0 | | curWave > = ( int ) e - > song . wave . size ( ) ) return ;
DivWavetable * wave = e - > song . wave [ curWave ] ;
memset ( finalResult , 0 , sizeof ( float ) * 256 ) ;
2022-07-27 07:23:29 +00:00
if ( wave - > len < 2 ) return ;
2022-07-27 06:20:26 +00:00
if ( waveGenFM ) {
2022-09-09 08:23:18 +00:00
float s0fb0 = 0 ;
float s0fb1 = 0 ;
float s1fb0 = 0 ;
float s1fb1 = 0 ;
float s2fb0 = 0 ;
float s2fb1 = 0 ;
float s3fb0 = 0 ;
float s3fb1 = 0 ;
2023-02-06 06:29:01 +00:00
2023-02-06 06:36:19 +00:00
float s0 = 0 ;
float s1 = 0 ;
float s2 = 0 ;
float s3 = 1 ;
2023-02-06 06:29:01 +00:00
2022-09-05 10:48:20 +00:00
for ( int i = 0 ; i < wave - > len ; i + + ) {
float pos = ( float ) i / ( float ) wave - > len ;
2023-02-06 06:29:01 +00:00
2023-02-06 06:36:19 +00:00
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 ] ;
2022-09-09 08:23:18 +00:00
s0fb0 = s0fb1 ;
s0fb1 = s0 ;
2023-02-06 06:36:19 +00:00
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 ] ;
2023-02-06 06:29:01 +00:00
2022-09-09 08:23:18 +00:00
s1fb0 = s1fb1 ;
s1fb1 = s1 ;
2023-02-06 06:36:19 +00:00
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 ] ;
2023-02-06 06:29:01 +00:00
2022-09-09 08:23:18 +00:00
s2fb0 = s2fb1 ;
s2fb1 = s2 ;
2023-02-06 06:36:19 +00:00
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 ] ;
2023-02-06 06:29:01 +00:00
2022-09-09 08:23:18 +00:00
s3fb0 = s3fb1 ;
s3fb1 = s3 ;
2022-07-27 06:20:26 +00:00
2023-02-06 06:29:01 +00:00
if ( waveGenFMCon0 [ 4 ] ) finalResult [ i ] + = s0 ;
if ( waveGenFMCon1 [ 4 ] ) finalResult [ i ] + = s1 ;
if ( waveGenFMCon2 [ 4 ] ) finalResult [ i ] + = s2 ;
if ( waveGenFMCon3 [ 4 ] ) finalResult [ i ] + = s3 ;
2022-09-05 10:48:20 +00:00
}
2022-07-27 06:20:26 +00:00
} else {
switch ( waveGenBaseShape ) {
case 0 : // sine
for ( int i = 0 ; i < wave - > len ; i + + ) {
2022-07-27 07:23:29 +00:00
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 ;
}
2022-07-27 06:20:26 +00:00
}
break ;
case 1 : // triangle
for ( int i = 0 ; i < wave - > len ; i + + ) {
2022-07-27 07:23:29 +00:00
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 ;
}
2022-07-27 06:20:26 +00:00
}
break ;
case 2 : // saw
for ( int i = 0 ; i < wave - > len ; i + + ) {
2022-07-27 07:23:29 +00:00
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 ;
}
2022-07-27 06:20:26 +00:00
}
break ;
case 3 : // pulse
for ( int i = 0 ; i < wave - > len ; i + + ) {
2022-07-27 07:23:29 +00:00
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 ;
}
2022-07-27 06:20:26 +00:00
}
break ;
}
}
2022-07-27 07:23:29 +00:00
for ( int i = waveGenInvertPoint * wave - > len ; i < wave - > len ; i + + ) {
finalResult [ i ] = - finalResult [ i ] ;
}
2022-07-27 06:20:26 +00:00
for ( int i = 0 ; i < wave - > len ; i + + ) {
2022-07-27 07:23:29 +00:00
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 ;
2022-07-27 06:20:26 +00:00
wave - > data [ i ] = round ( finalResult [ i ] * wave - > max ) ;
}
2022-10-10 08:00:07 +00:00
e - > notifyWaveChange ( curWave ) ;
2022-10-16 23:30:48 +00:00
MARK_MODIFIED ;
2022-07-27 06:20:26 +00:00
}
2022-09-04 09:00:56 +00:00
# define CENTER_TEXT(text) \
ImGui : : SetCursorPosX ( ImGui : : GetCursorPosX ( ) + 0.5 * ( ImGui : : GetContentRegionAvail ( ) . x - ImGui : : CalcTextSize ( text ) . x ) ) ;
2022-03-21 21:34:19 +00:00
void FurnaceGUI : : drawWaveEdit ( ) {
if ( nextWindow = = GUI_WINDOW_WAVE_EDIT ) {
waveEditOpen = true ;
ImGui : : SetNextWindowFocus ( ) ;
nextWindow = GUI_WINDOW_NOTHING ;
}
if ( ! waveEditOpen ) return ;
2022-05-25 17:18:11 +00:00
float wavePreview [ 257 ] ;
2022-09-09 20:31:29 +00:00
if ( mobileUI ) {
2022-10-20 07:34:14 +00:00
patWindowPos = ( portrait ? ImVec2 ( 0.0f , ( mobileMenuPos * - 0.65 * canvasH ) ) : ImVec2 ( ( 0.16 * canvasH ) + 0.5 * canvasW * mobileMenuPos , 0.0f ) ) ;
patWindowSize = ( portrait ? ImVec2 ( canvasW , canvasH - ( 0.16 * canvasW ) - ( pianoOpen ? ( 0.4 * canvasW ) : 0.0f ) ) : ImVec2 ( canvasW - ( 0.16 * canvasH ) , canvasH - ( pianoOpen ? ( 0.3 * canvasH ) : 0.0f ) ) ) ;
2022-09-09 20:31:29 +00:00
ImGui : : SetNextWindowPos ( patWindowPos ) ;
ImGui : : SetNextWindowSize ( patWindowSize ) ;
} else {
2022-10-20 07:34:14 +00:00
ImGui : : SetNextWindowSizeConstraints ( ImVec2 ( 300.0f * dpiScale , 300.0f * dpiScale ) , ImVec2 ( canvasW , canvasH ) ) ;
2022-09-09 20:31:29 +00:00
}
2022-05-19 21:35:00 +00:00
if ( ImGui : : Begin ( " Wavetable Editor " , & waveEditOpen , globalWinFlags | ( settings . allowEditDocking ? 0 : ImGuiWindowFlags_NoDocking ) ) ) {
2022-03-21 21:34:19 +00:00
if ( curWave < 0 | | curWave > = ( int ) e - > song . wave . size ( ) ) {
2022-10-08 22:57:14 +00:00
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) + ( ImGui : : GetContentRegionAvail ( ) . y - ImGui : : GetFrameHeightWithSpacing ( ) * 2.0f ) * 0.5f ) ;
CENTER_TEXT ( " no wavetable selected " ) ;
2022-03-21 21:34:19 +00:00
ImGui : : Text ( " no wavetable selected " ) ;
2022-10-08 22:57:14 +00:00
if ( ImGui : : BeginTable ( " noAssetCenter " , 3 ) ) {
ImGui : : TableSetupColumn ( " c0 " , ImGuiTableColumnFlags_WidthStretch , 0.5f ) ;
ImGui : : TableSetupColumn ( " c1 " , ImGuiTableColumnFlags_WidthFixed ) ;
ImGui : : TableSetupColumn ( " c2 " , ImGuiTableColumnFlags_WidthStretch , 0.5f ) ;
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : TableNextColumn ( ) ;
if ( e - > song . wave . size ( ) > 0 ) {
if ( ImGui : : BeginCombo ( " ##WaveSelect " , " select one... " ) ) {
2022-10-19 18:53:56 +00:00
if ( ImGui : : BeginTable ( " WaveSelCombo " , 1 , ImGuiTableFlags_ScrollY ) ) {
actualWaveList ( ) ;
ImGui : : EndTable ( ) ;
}
2022-10-08 22:57:14 +00:00
ImGui : : EndCombo ( ) ;
}
ImGui : : SameLine ( ) ;
ImGui : : TextUnformatted ( " or " ) ;
ImGui : : SameLine ( ) ;
}
if ( ImGui : : Button ( " Open " ) ) {
doAction ( GUI_ACTION_WAVE_LIST_OPEN ) ;
}
ImGui : : SameLine ( ) ;
ImGui : : TextUnformatted ( " or " ) ;
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Create New " ) ) {
doAction ( GUI_ACTION_WAVE_LIST_ADD ) ;
}
ImGui : : TableNextColumn ( ) ;
ImGui : : EndTable ( ) ;
}
2022-03-21 21:34:19 +00:00
} else {
DivWavetable * wave = e - > song . wave [ curWave ] ;
2022-07-21 07:49:19 +00:00
if ( ImGui : : BeginTable ( " WEProps " , 2 ) ) {
ImGui : : TableSetupColumn ( " c0 " , ImGuiTableColumnFlags_WidthStretch ) ;
ImGui : : TableSetupColumn ( " c1 " , ImGuiTableColumnFlags_WidthFixed ) ;
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( 80.0f * dpiScale ) ;
2023-12-11 23:58:48 +00:00
if ( ImGui : : InputInt ( " ##CurWave " , & curWave , 1 , 10 ) ) {
2022-07-21 07:49:19 +00:00
if ( curWave < 0 ) curWave = 0 ;
if ( curWave > = ( int ) e - > song . wave . size ( ) ) curWave = e - > song . wave . size ( ) - 1 ;
}
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( ICON_FA_FOLDER_OPEN " ##WELoad " ) ) {
2022-08-13 09:17:32 +00:00
doAction ( GUI_ACTION_WAVE_LIST_OPEN_REPLACE ) ;
2022-07-21 07:49:19 +00:00
}
2022-12-10 19:32:51 +00:00
if ( ImGui : : IsItemHovered ( ) ) {
2022-12-11 02:09:13 +00:00
ImGui : : SetTooltip ( " Open " ) ;
2022-12-10 19:32:51 +00:00
}
2022-07-21 07:49:19 +00:00
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( ICON_FA_FLOPPY_O " ##WESave " ) ) {
doAction ( GUI_ACTION_WAVE_LIST_SAVE ) ;
}
2022-12-10 19:32:51 +00:00
if ( ImGui : : IsItemHovered ( ) ) {
ImGui : : SetTooltip ( " Save " ) ;
}
2022-09-04 07:37:43 +00:00
if ( ImGui : : BeginPopupContextItem ( " WaveSaveFormats " , ImGuiMouseButton_Right ) ) {
if ( ImGui : : MenuItem ( " save as .dmw... " ) ) {
doAction ( GUI_ACTION_WAVE_LIST_SAVE_DMW ) ;
}
if ( ImGui : : MenuItem ( " save raw... " ) ) {
doAction ( GUI_ACTION_WAVE_LIST_SAVE_RAW ) ;
}
ImGui : : EndPopup ( ) ;
}
2022-07-21 07:49:19 +00:00
ImGui : : SameLine ( ) ;
if ( ImGui : : RadioButton ( " Steps " , waveEditStyle = = 0 ) ) {
waveEditStyle = 0 ;
}
ImGui : : SameLine ( ) ;
if ( ImGui : : RadioButton ( " Lines " , waveEditStyle = = 1 ) ) {
waveEditStyle = 1 ;
}
ImGui : : TableNextColumn ( ) ;
2022-04-17 01:51:53 +00:00
ImGui : : Text ( " Width " ) ;
if ( ImGui : : IsItemHovered ( ) ) {
2022-10-10 08:02:36 +00:00
ImGui : : SetTooltip ( " use a width of: \n - any on Amiga/N163 \n - 32 on Game Boy, PC Engine, SCC, Konami Bubble System, Namco WSG, Virtual Boy and WonderSwan \n - 64 on FDS \n - 128 on X1-010 \n any other widths will be scaled during playback. " ) ;
2022-04-17 01:51:53 +00:00
}
ImGui : : SameLine ( ) ;
2022-07-21 07:49:19 +00:00
ImGui : : SetNextItemWidth ( 96.0f * dpiScale ) ;
2023-12-11 23:58:48 +00:00
if ( ImGui : : InputInt ( " ##_WTW " , & wave - > len , 1 , 16 ) ) {
2022-04-17 01:51:53 +00:00
if ( wave - > len > 256 ) wave - > len = 256 ;
if ( wave - > len < 1 ) wave - > len = 1 ;
e - > notifyWaveChange ( curWave ) ;
if ( wavePreviewOn ) e - > previewWave ( curWave , wavePreviewNote ) ;
MARK_MODIFIED ;
}
ImGui : : SameLine ( ) ;
ImGui : : Text ( " Height " ) ;
if ( ImGui : : IsItemHovered ( ) ) {
2023-02-06 09:02:29 +00:00
ImGui : : SetTooltip ( " use a height of: \n - 16 for Game Boy, WonderSwan, Namco WSG, Konami Bubble System, X1-010 Envelope shape and N163 \n - 32 for PC Engine \n - 64 for FDS and Virtual Boy \n - 256 for X1-010 and SCC \n any other heights will be scaled during playback. " ) ;
2022-04-17 01:51:53 +00:00
}
ImGui : : SameLine ( ) ;
2022-07-21 07:49:19 +00:00
ImGui : : SetNextItemWidth ( 96.0f * dpiScale ) ;
2023-02-06 09:02:29 +00:00
int realMax = wave - > max + 1 ;
2023-12-11 23:58:48 +00:00
if ( ImGui : : InputInt ( " ##_WTH " , & realMax , 1 , 16 ) ) {
2023-02-06 09:02:29 +00:00
if ( realMax > 256 ) realMax = 256 ;
if ( realMax < 2 ) realMax = 2 ;
wave - > max = realMax - 1 ;
2022-04-17 01:51:53 +00:00
e - > notifyWaveChange ( curWave ) ;
MARK_MODIFIED ;
}
2022-07-21 08:14:52 +00:00
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( waveGenVisible ? ( ICON_FA_CHEVRON_RIGHT " ##WEWaveGen " ) : ( ICON_FA_CHEVRON_LEFT " ##WEWaveGen " ) ) ) {
waveGenVisible = ! waveGenVisible ;
}
2022-07-21 07:49:19 +00:00
ImGui : : EndTable ( ) ;
2022-04-17 01:51:53 +00:00
}
2022-03-21 21:34:19 +00:00
for ( int i = 0 ; i < wave - > len ; i + + ) {
if ( wave - > data [ i ] > wave - > max ) wave - > data [ i ] = wave - > max ;
wavePreview [ i ] = wave - > data [ i ] ;
2022-09-11 03:35:21 +00:00
if ( waveSigned & & ! waveHex ) {
wavePreview [ i ] - = ( int ) ( ( wave - > max + 1 ) / 2 ) ;
}
2022-03-21 21:34:19 +00:00
}
if ( wave - > len > 0 ) wavePreview [ wave - > len ] = wave - > data [ wave - > len - 1 ] ;
2022-07-21 08:14:52 +00:00
if ( ImGui : : BeginTable ( " WEWaveSection " , waveGenVisible ? 2 : 1 ) ) {
ImGui : : TableSetupColumn ( " c0 " , ImGuiTableColumnFlags_WidthStretch ) ;
if ( waveGenVisible ) ImGui : : TableSetupColumn ( " c1 " , ImGuiTableColumnFlags_WidthFixed , 250.0f * dpiScale ) ;
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 0.0f , 0.0f ) ) ;
2022-03-21 21:34:19 +00:00
2022-07-21 08:14:52 +00:00
ImVec2 contentRegion = ImGui : : GetContentRegionAvail ( ) ; // wavetable graph size determined here
contentRegion . y - = ImGui : : GetFrameHeightWithSpacing ( ) + ImGui : : GetStyle ( ) . WindowPadding . y ;
if ( waveEditStyle ) {
2022-09-11 03:35:21 +00:00
PlotNoLerp ( " ##Waveform " , wavePreview , wave - > len + 1 , 0 , NULL , ( waveSigned & & ! waveHex ) ? ( - ( int ) ( ( wave - > max + 1 ) / 2 ) ) : 0 , ( waveSigned & & ! waveHex ) ? ( ( int ) ( wave - > max / 2 ) ) : wave - > max , contentRegion ) ;
2022-07-21 08:14:52 +00:00
} else {
2022-09-11 03:35:21 +00:00
PlotCustom ( " ##Waveform " , wavePreview , wave - > len , 0 , NULL , ( waveSigned & & ! waveHex ) ? ( - ( int ) ( ( wave - > max + 1 ) / 2 ) ) : 0 , ( waveSigned & & ! waveHex ) ? ( ( int ) ( wave - > max / 2 ) ) : wave - > max , contentRegion , sizeof ( float ) , ImVec4 ( 1.0f , 1.0f , 1.0f , 1.0f ) , 0 , NULL , NULL , true ) ;
2022-07-21 08:14:52 +00:00
}
if ( ImGui : : IsItemClicked ( ImGuiMouseButton_Left ) ) {
waveDragStart = ImGui : : GetItemRectMin ( ) ;
waveDragAreaSize = contentRegion ;
waveDragMin = 0 ;
waveDragMax = wave - > max ;
waveDragLen = wave - > len ;
waveDragActive = true ;
waveDragTarget = wave - > data ;
processDrags ( ImGui : : GetMousePos ( ) . x , ImGui : : GetMousePos ( ) . y ) ;
e - > notifyWaveChange ( curWave ) ;
modified = true ;
}
ImGui : : PopStyleVar ( ) ;
if ( waveGenVisible ) {
ImGui : : TableNextColumn ( ) ;
2023-02-06 08:57:46 +00:00
ImVec2 waveGenSize = ImGui : : GetContentRegionAvail ( ) ;
waveGenSize . y = contentRegion . y ;
if ( ImGui : : BeginChild ( " WaveGenView " , waveGenSize ) ) {
if ( ImGui : : BeginTabBar ( " WaveGenOpt " ) ) {
if ( ImGui : : BeginTabItem ( " Shapes " ) ) {
waveGenFM = false ;
2022-07-27 06:20:26 +00:00
if ( waveGenBaseShape < 0 ) waveGenBaseShape = 0 ;
if ( waveGenBaseShape > 3 ) waveGenBaseShape = 3 ;
2022-07-27 07:23:29 +00:00
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
2023-02-06 08:57:46 +00:00
if ( CWSliderInt ( " ##WGShape " , & waveGenBaseShape , 0 , 3 , waveGenBaseShapes [ waveGenBaseShape ] ) ) {
if ( waveGenBaseShape < 0 ) waveGenBaseShape = 0 ;
if ( waveGenBaseShape > 3 ) waveGenBaseShape = 3 ;
2022-07-27 07:23:29 +00:00
doGenerateWave ( ) ;
}
2023-02-06 08:57:46 +00:00
if ( ImGui : : BeginTable ( " WGShapeProps " , 2 ) ) {
ImGui : : TableSetupColumn ( " c0 " , ImGuiTableColumnFlags_WidthFixed ) ;
ImGui : : TableSetupColumn ( " c1 " , ImGuiTableColumnFlags_WidthStretch ) ;
2022-07-27 07:23:29 +00:00
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
2023-08-07 05:47:17 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2023-02-06 08:57:46 +00:00
ImGui : : Text ( " Duty " ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
if ( CWSliderFloat ( " ##WGDuty " , & waveGenDuty , 0.0f , 1.0f ) ) {
doGenerateWave ( ) ;
2023-04-20 08:43:35 +00:00
} rightClickable
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
2023-08-07 05:47:17 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2023-02-06 08:57:46 +00:00
ImGui : : Text ( " Exponent " ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
if ( CWSliderInt ( " ##WGExp " , & waveGenPower , 1 , 8 ) ) {
doGenerateWave ( ) ;
2023-04-20 08:43:35 +00:00
} rightClickable
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
2023-08-07 05:47:17 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2023-02-06 08:57:46 +00:00
ImGui : : Text ( " XOR Point " ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
if ( CWSliderFloat ( " ##WGXOR " , & waveGenInvertPoint , 0.0f , 1.0f ) ) {
doGenerateWave ( ) ;
2023-04-20 08:43:35 +00:00
} rightClickable
2023-02-06 08:57:46 +00:00
ImGui : : EndTable ( ) ;
2022-07-27 07:23:29 +00:00
}
2023-02-06 08:57:46 +00:00
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 ( ) ;
2023-08-07 05:47:17 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2023-02-06 08:57:46 +00:00
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 ( ) ;
2023-04-20 08:43:35 +00:00
} rightClickable
2023-02-06 08:57:46 +00:00
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 ( ) ;
2023-04-20 08:43:35 +00:00
} rightClickable
2023-02-06 08:57:46 +00:00
if ( ImGui : : IsItemClicked ( ImGuiMouseButton_Middle ) ) {
waveGenPhase [ i ] = 0.0f ;
doGenerateWave ( ) ;
}
ImGui : : PopID ( ) ;
}
ImGui : : EndTable ( ) ;
}
ImGui : : TreePop ( ) ;
}
ImGui : : EndTabItem ( ) ;
2022-07-27 07:23:29 +00:00
}
2023-02-06 08:57:46 +00:00
if ( ImGui : : BeginTabItem ( " FM " ) ) {
waveGenFM = true ;
2022-07-27 07:23:29 +00:00
2023-02-06 08:57:46 +00:00
if ( ImGui : : BeginTable ( " WGFMProps " , 4 ) ) {
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 : : TableNextRow ( ImGuiTableRowFlags_Headers ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : Text ( " Op " ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : Text ( " Level " ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : Text ( " Mult " ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : Text ( " FB " ) ;
2022-07-27 07:23:29 +00:00
2023-02-06 08:57:46 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
2022-07-27 07:23:29 +00:00
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
2023-08-07 05:47:17 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2022-07-27 07:23:29 +00:00
ImGui : : Text ( " %d " , i + 1 ) ;
2023-02-06 08:57:46 +00:00
2022-07-27 07:23:29 +00:00
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
2023-02-06 08:57:46 +00:00
ImGui : : PushID ( i ) ;
if ( CWSliderFloat ( " ##WGTL " , & waveGenTL [ i ] , 0.0f , 1.0f ) ) {
2022-07-27 07:23:29 +00:00
doGenerateWave ( ) ;
2023-04-20 08:43:35 +00:00
} rightClickable
2023-02-06 08:57:46 +00:00
ImGui : : PopID ( ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
ImGui : : PushID ( i ) ;
if ( CWSliderInt ( " ##WGMULT " , & waveGenMult [ i ] , 1 , 16 ) ) {
2022-07-27 07:23:29 +00:00
doGenerateWave ( ) ;
2023-04-20 08:43:35 +00:00
} rightClickable
2022-07-27 07:23:29 +00:00
ImGui : : PopID ( ) ;
2023-02-06 08:57:46 +00:00
2022-07-27 07:23:29 +00:00
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
2023-02-06 08:57:46 +00:00
ImGui : : PushID ( i ) ;
if ( CWSliderInt ( " ##WGFB " , & waveGenFB [ i ] , 0 , 7 ) ) {
2022-07-27 07:23:29 +00:00
doGenerateWave ( ) ;
2023-04-20 08:43:35 +00:00
} rightClickable
2023-02-06 08:57:46 +00:00
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 ( ) ;
2023-08-07 05:47:17 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2023-02-06 08:57:46 +00:00
ImGui : : Text ( " %d " , i + 1 ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
ImGui : : PushID ( i ) ;
if ( CWSliderInt ( " ##WGWAVEFORM " , & fmWaveform [ i ] , 0 , fmWaveformsLen - 1 , fmWaveforms [ fmWaveform [ i ] ] ) ) {
2022-07-27 07:23:29 +00:00
doGenerateWave ( ) ;
}
ImGui : : PopID ( ) ;
}
ImGui : : EndTable ( ) ;
}
2023-02-06 08:57:46 +00:00
CENTER_TEXT ( " Connection Diagram " ) ;
ImGui : : Text ( " Connection Diagram " ) ;
if ( ImGui : : BeginTable ( " WGFMCon " , 6 ) ) {
2022-09-04 09:00:56 +00:00
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
2023-02-06 08:57:46 +00:00
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 ( " Out " ) ;
2022-09-04 09:00:56 +00:00
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
2022-09-04 09:00:56 +00:00
ImGui : : TableNextColumn ( ) ;
2023-08-07 05:47:17 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2023-02-06 08:57:46 +00:00
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 ( ) ;
2023-08-07 05:47:17 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2023-02-06 08:57:46 +00:00
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 ] ) ) {
2022-09-04 09:00:56 +00:00
doGenerateWave ( ) ;
}
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
2022-09-04 09:00:56 +00:00
ImGui : : TableNextColumn ( ) ;
2023-08-07 05:47:17 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2023-02-06 08:57:46 +00:00
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 ] ) ) {
2022-09-04 09:00:56 +00:00
doGenerateWave ( ) ;
}
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
2022-09-04 09:00:56 +00:00
ImGui : : TableNextColumn ( ) ;
2023-08-07 05:47:17 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2023-02-06 08:57:46 +00:00
ImGui : : Text ( " 4 " ) ;
ImGui : : TableNextColumn ( ) ;
if ( ImGui : : Checkbox ( " ##Con31 " , & waveGenFMCon3 [ 0 ] ) ) {
2022-09-04 09:00:56 +00:00
doGenerateWave ( ) ;
}
2023-02-06 08:57:46 +00:00
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 ( ) ;
2022-09-04 09:00:56 +00:00
}
2023-02-06 08:57:46 +00:00
ImGui : : EndTabItem ( ) ;
2022-09-04 09:00:56 +00:00
}
2023-02-06 08:57:46 +00:00
if ( ImGui : : BeginTabItem ( " WaveTools " ) ) {
if ( ImGui : : BeginTable ( " WGParamItems " , 2 ) ) {
ImGui : : TableSetupColumn ( " c0 " , ImGuiTableColumnFlags_WidthStretch ) ;
ImGui : : TableSetupColumn ( " c1 " , ImGuiTableColumnFlags_WidthFixed ) ;
2022-09-04 09:00:56 +00:00
2023-02-06 06:36:19 +00:00
ImGui : : TableNextRow ( ) ;
2023-02-06 06:29:01 +00:00
ImGui : : TableNextColumn ( ) ;
2023-02-06 08:57:46 +00:00
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
if ( ImGui : : InputInt ( " ##WGScaleX " , & waveGenScaleX , 1 , 16 ) ) {
if ( waveGenScaleX < 2 ) waveGenScaleX = 2 ;
if ( waveGenScaleX > 256 ) waveGenScaleX = 256 ;
}
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
if ( CWSliderInt ( " ##WGInterpolation " , & waveInterpolation , 0 , 3 , waveInterpolations [ waveInterpolation ] ) ) {
if ( waveInterpolation < 0 ) waveInterpolation = 0 ;
if ( waveInterpolation > 3 ) waveInterpolation = 3 ;
}
ImGui : : TableNextColumn ( ) ;
if ( ImGui : : Button ( " Scale X " ) ) {
if ( waveGenScaleX > 0 & & wave - > len ! = waveGenScaleX ) e - > lockEngine ( [ this , wave ] ( ) {
int origData [ 256 ] ;
// Copy original wave to temp buffer
// If longer than 256 samples, return
if ( wave - > len > 256 ) {
showError ( " wavetable longer than 256 samples! " ) ;
return ;
}
memcpy ( origData , wave - > data , wave - > len * sizeof ( int ) ) ;
float t = 0 ; // Index used into `origData`
for ( int i = 0 ; i < waveGenScaleX ; i + + , t + = ( float ) wave - > len / waveGenScaleX ) {
switch ( waveInterpolation ) {
case 0 : {
wave - > data [ i ] = origData [ i * wave - > len / waveGenScaleX ] ;
break ;
}
case 1 : { // Linear
int idx = t ; // Implicitly floors `t`
int s0 = origData [ ( idx ) % wave - > len ] ;
int s1 = origData [ ( idx + 1 ) % wave - > len ] ;
double mu = ( t - idx ) ;
wave - > data [ i ] = s0 + mu * s1 - ( mu * s0 ) ;
break ;
}
case 2 : { // Cosine
int idx = t ; // Implicitly floors `t`
int s0 = origData [ ( idx ) % wave - > len ] ;
int s1 = origData [ ( idx + 1 ) % wave - > len ] ;
double mu = ( t - idx ) ;
double muCos = ( 1 - cos ( mu * M_PI ) ) / 2 ;
wave - > data [ i ] = s0 + muCos * s1 - ( muCos * s0 ) ;
break ;
}
case 3 : { // Cubic Spline
int idx = t ; // Implicitly floors `t`
int s0 = origData [ ( ( idx - 1 % wave - > len + wave - > len ) % wave - > len ) ] ;
int s1 = origData [ ( idx ) % wave - > len ] ;
int s2 = origData [ ( idx + 1 ) % wave - > len ] ;
int s3 = origData [ ( idx + 2 ) % wave - > len ] ;
double mu = ( t - idx ) ;
double mu2 = mu * mu ;
double a0 = - 0.5 * s0 + 1.5 * s1 - 1.5 * s2 + 0.5 * s3 ;
double a1 = s0 - 2.5 * s1 + 2 * s2 - 0.5 * s3 ;
double a2 = - 0.5 * s0 + 0.5 * s2 ;
double a3 = s1 ;
wave - > data [ i ] = ( a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3 ) ;
break ;
}
default : { // No interpolation
wave - > data [ i ] = origData [ i * wave - > len / waveGenScaleX ] ;
break ;
}
}
}
wave - > len = waveGenScaleX ;
MARK_MODIFIED ;
} ) ;
}
2023-02-06 06:36:19 +00:00
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
2023-02-06 06:29:01 +00:00
ImGui : : TableNextColumn ( ) ;
2023-02-06 06:36:19 +00:00
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
2023-02-06 08:57:46 +00:00
if ( ImGui : : InputInt ( " ##WGScaleY " , & waveGenScaleY , 1 , 16 ) ) {
if ( waveGenScaleY < 2 ) waveGenScaleY = 2 ;
if ( waveGenScaleY > 256 ) waveGenScaleY = 256 ;
}
ImGui : : TableNextColumn ( ) ;
if ( ImGui : : Button ( " Scale Y " ) ) {
if ( waveGenScaleY > 0 & & wave - > max ! = ( waveGenScaleY - 1 ) ) e - > lockEngine ( [ this , wave ] ( ) {
for ( int i = 0 ; i < wave - > len ; i + + ) {
2023-02-06 09:02:29 +00:00
wave - > data [ i ] = ( wave - > data [ i ] * ( waveGenScaleY ) ) / ( wave - > max + 1 ) ;
2023-02-06 08:57:46 +00:00
}
wave - > max = waveGenScaleY - 1 ;
MARK_MODIFIED ;
} ) ;
2023-02-06 06:29:01 +00:00
}
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
if ( ImGui : : InputInt ( " ##WGOffsetX " , & waveGenOffsetX , 1 , 16 ) ) {
if ( waveGenOffsetX < - wave - > len + 1 ) waveGenOffsetX = - wave - > len + 1 ;
if ( waveGenOffsetX > wave - > len - 1 ) waveGenOffsetX = wave - > len - 1 ;
}
ImGui : : TableNextColumn ( ) ;
if ( ImGui : : Button ( " Offset X " ) ) {
if ( waveGenOffsetX ! = 0 & & wave - > len > 0 ) e - > lockEngine ( [ this , wave ] ( ) {
int origData [ 256 ] ;
memcpy ( origData , wave - > data , wave - > len * sizeof ( int ) ) ;
int realOff = - waveGenOffsetX ;
while ( realOff < 0 ) realOff + = wave - > len ;
for ( int i = 0 ; i < wave - > len ; i + + ) {
wave - > data [ i ] = origData [ ( i + realOff ) % wave - > len ] ;
}
MARK_MODIFIED ;
} ) ;
}
2023-02-06 06:29:01 +00:00
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
if ( ImGui : : InputInt ( " ##WGOffsetY " , & waveGenOffsetY , 1 , 16 ) ) {
if ( waveGenOffsetY < - wave - > max ) waveGenOffsetY = - wave - > max ;
if ( waveGenOffsetY > wave - > max ) waveGenOffsetY = wave - > max ;
}
ImGui : : TableNextColumn ( ) ;
if ( ImGui : : Button ( " Offset Y " ) ) {
if ( waveGenOffsetY ! = 0 ) e - > lockEngine ( [ this , wave ] ( ) {
for ( int i = 0 ; i < wave - > len ; i + + ) {
wave - > data [ i ] = CLAMP ( wave - > data [ i ] + waveGenOffsetY , 0 , wave - > max ) ;
}
MARK_MODIFIED ;
} ) ;
}
2023-02-06 06:29:01 +00:00
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
if ( ImGui : : InputInt ( " ##WGSmooth " , & waveGenSmooth , 1 , 4 ) ) {
if ( waveGenSmooth > wave - > len ) waveGenSmooth = wave - > len ;
if ( waveGenSmooth < 1 ) waveGenSmooth = 1 ;
}
ImGui : : TableNextColumn ( ) ;
if ( ImGui : : Button ( " Smooth " ) ) {
if ( waveGenSmooth > 0 ) e - > lockEngine ( [ this , wave ] ( ) {
int origData [ 256 ] ;
memcpy ( origData , wave - > data , wave - > len * sizeof ( int ) ) ;
for ( int i = 0 ; i < wave - > len ; i + + ) {
int dataSum = 0 ;
for ( int j = i ; j < i + waveGenSmooth + 1 ; j + + ) {
int pos = ( j - ( ( waveGenSmooth + 1 ) / 2 ) ) ;
while ( pos < 0 ) pos + = wave - > len ;
dataSum + = origData [ pos % wave - > len ] ;
}
dataSum / = waveGenSmooth + 1 ;
wave - > data [ i ] = dataSum ;
}
MARK_MODIFIED ;
} ) ;
}
2023-02-06 06:29:01 +00:00
2023-02-06 08:57:46 +00:00
ImGui : : TableNextRow ( ) ;
ImGui : : TableNextColumn ( ) ;
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
float amp = waveGenAmplify * 100.0f ;
if ( ImGui : : InputFloat ( " ##WGAmplify " , & amp , 1.0f , 10.0f ) ) {
waveGenAmplify = amp / 100.0f ;
if ( waveGenAmplify < 0.0f ) waveGenAmplify = 0.0f ;
if ( waveGenAmplify > 100.0f ) waveGenAmplify = 100.0f ;
}
ImGui : : TableNextColumn ( ) ;
if ( ImGui : : Button ( " Amplify " ) ) {
if ( waveGenAmplify ! = 1.0f ) e - > lockEngine ( [ this , wave ] ( ) {
for ( int i = 0 ; i < wave - > len ; i + + ) {
wave - > data [ i ] = CLAMP ( round ( ( float ) ( wave - > data [ i ] - ( int ) ( /* Clang can you stop complaining */ ( int ) ( wave - > max + 1 ) / ( int ) 2 ) ) * waveGenAmplify ) , ( int ) ( - ( ( wave - > max + 1 ) / 2 ) ) , ( int ) ( wave - > max / 2 ) ) + ( int ) ( ( wave - > max + 1 ) / 2 ) ;
}
MARK_MODIFIED ;
} ) ;
}
2022-09-10 21:01:22 +00:00
2023-02-06 08:57:46 +00:00
ImGui : : EndTable ( ) ;
2022-10-03 17:48:07 +00:00
}
2022-10-12 19:54:29 +00:00
2023-02-06 08:57:46 +00:00
ImVec2 buttonSize = ImGui : : GetContentRegionAvail ( ) ;
buttonSize . y = 0.0f ;
ImVec2 buttonSizeHalf = buttonSize ;
buttonSizeHalf . x - = ImGui : : GetStyle ( ) . ItemSpacing . x ;
buttonSizeHalf . x * = 0.5 ;
2022-10-12 19:54:29 +00:00
2023-02-06 08:57:46 +00:00
if ( ImGui : : Button ( " Normalize " , buttonSize ) ) {
e - > lockEngine ( [ this , wave ] ( ) {
// find lowest point
int lowest = wave - > max ;
for ( int i = 0 ; i < wave - > len ; i + + ) {
if ( wave - > data [ i ] < lowest ) lowest = wave - > data [ i ] ;
2022-10-12 19:54:29 +00:00
}
2022-09-10 21:01:22 +00:00
2023-02-06 08:57:46 +00:00
// find highest point
int highest = 0 ;
2022-09-11 00:35:50 +00:00
for ( int i = 0 ; i < wave - > len ; i + + ) {
2023-02-06 08:57:46 +00:00
if ( wave - > data [ i ] > highest ) highest = wave - > data [ i ] ;
2022-09-11 00:35:50 +00:00
}
2022-09-10 21:01:22 +00:00
2023-02-06 08:57:46 +00:00
// abort if lowest and highest points are equal
if ( lowest = = highest ) return ;
2022-09-11 00:35:50 +00:00
2023-02-06 08:57:46 +00:00
// abort if lowest and highest points already span the entire height
if ( lowest = = wave - > max & & highest = = 0 ) return ;
2022-09-10 21:01:22 +00:00
2023-02-06 08:57:46 +00:00
// apply offset
2022-09-11 00:35:50 +00:00
for ( int i = 0 ; i < wave - > len ; i + + ) {
2023-02-06 08:57:46 +00:00
wave - > data [ i ] - = lowest ;
2022-09-11 00:35:50 +00:00
}
2023-02-06 08:57:46 +00:00
highest - = lowest ;
2022-09-10 21:01:22 +00:00
2023-02-06 08:57:46 +00:00
// scale
for ( int i = 0 ; i < wave - > len ; i + + ) {
wave - > data [ i ] = ( wave - > data [ i ] * wave - > max ) / highest ;
2022-09-11 03:12:03 +00:00
}
MARK_MODIFIED ;
} ) ;
}
2023-08-20 06:41:01 +00:00
if ( ImGui : : Button ( " Invert " , buttonSizeHalf ) ) {
2023-02-06 08:57:46 +00:00
e - > lockEngine ( [ this , wave ] ( ) {
2022-09-11 00:35:50 +00:00
for ( int i = 0 ; i < wave - > len ; i + + ) {
2023-02-06 08:57:46 +00:00
wave - > data [ i ] = wave - > max - wave - > data [ i ] ;
2022-09-11 00:35:50 +00:00
}
MARK_MODIFIED ;
} ) ;
}
2023-08-20 06:41:01 +00:00
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Reverse " , buttonSizeHalf ) ) {
e - > lockEngine ( [ this , wave ] ( ) {
int origData [ 256 ] ;
memcpy ( origData , wave - > data , wave - > len * sizeof ( int ) ) ;
for ( int i = 0 ; i < wave - > len ; i + + ) {
wave - > data [ i ] = origData [ wave - > len - 1 - i ] ;
}
MARK_MODIFIED ;
} ) ;
}
2022-09-10 21:01:22 +00:00
2023-02-06 08:57:46 +00:00
if ( ImGui : : Button ( " Half " , buttonSizeHalf ) ) {
int origData [ 256 ] ;
memcpy ( origData , wave - > data , wave - > len * sizeof ( int ) ) ;
2022-09-11 03:12:03 +00:00
for ( int i = 0 ; i < wave - > len ; i + + ) {
2023-02-06 08:57:46 +00:00
wave - > data [ i ] = origData [ i > > 1 ] ;
2022-09-11 03:12:03 +00:00
}
MARK_MODIFIED ;
2023-02-06 08:57:46 +00:00
}
ImGui : : SameLine ( ) ;
if ( ImGui : : Button ( " Double " , buttonSizeHalf ) ) {
int origData [ 256 ] ;
memcpy ( origData , wave - > data , wave - > len * sizeof ( int ) ) ;
2022-09-11 00:35:50 +00:00
for ( int i = 0 ; i < wave - > len ; i + + ) {
2023-02-06 08:57:46 +00:00
wave - > data [ i ] = origData [ ( i * 2 ) % wave - > len ] ;
2022-09-11 00:35:50 +00:00
}
MARK_MODIFIED ;
2022-09-11 03:12:03 +00:00
}
2023-02-06 08:57:46 +00:00
if ( ImGui : : Button ( " Convert Signed/Unsigned " , buttonSize ) ) {
if ( wave - > max > 0 ) e - > lockEngine ( [ this , wave ] ( ) {
for ( int i = 0 ; i < wave - > len ; i + + ) {
if ( wave - > data [ i ] > ( wave - > max / 2 ) ) {
wave - > data [ i ] - = ( wave - > max + 1 ) / 2 ;
} else {
wave - > data [ i ] + = ( wave - > max + 1 ) / 2 ;
}
}
MARK_MODIFIED ;
} ) ;
2022-09-11 03:12:03 +00:00
}
2023-02-06 08:57:46 +00:00
if ( ImGui : : Button ( " Randomize " , buttonSize ) ) {
if ( wave - > max > 0 ) e - > lockEngine ( [ this , wave ] ( ) {
for ( int i = 0 ; i < wave - > len ; i + + ) {
wave - > data [ i ] = rand ( ) % ( wave - > max + 1 ) ;
2022-09-11 00:35:50 +00:00
}
2023-02-06 08:57:46 +00:00
MARK_MODIFIED ;
} ) ;
}
ImGui : : EndTabItem ( ) ;
2022-09-11 00:35:50 +00:00
}
2023-02-06 08:57:46 +00:00
ImGui : : EndTabBar ( ) ;
2022-07-21 08:14:52 +00:00
}
}
2023-02-06 08:57:46 +00:00
ImGui : : EndChild ( ) ;
2022-07-21 08:14:52 +00:00
}
ImGui : : EndTable ( ) ;
2022-03-21 21:34:19 +00:00
}
2022-07-21 07:49:19 +00:00
if ( ImGui : : RadioButton ( " Dec " , ! waveHex ) ) {
waveHex = false ;
}
ImGui : : SameLine ( ) ;
if ( ImGui : : RadioButton ( " Hex " , waveHex ) ) {
waveHex = true ;
}
ImGui : : SameLine ( ) ;
2022-09-11 03:35:21 +00:00
if ( ! waveHex ) if ( ImGui : : Button ( waveSigned ? " ±##WaveSign " : " +##WaveSign " , ImVec2 ( ImGui : : GetFrameHeight ( ) , ImGui : : GetFrameHeight ( ) ) ) ) {
waveSigned = ! waveSigned ;
}
if ( ImGui : : IsItemHovered ( ) ) {
ImGui : : SetTooltip ( " Signed/Unsigned " ) ;
}
ImGui : : SameLine ( ) ;
2022-07-21 07:49:19 +00:00
ImGui : : SetNextItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ; // wavetable text input size found here
if ( ImGui : : InputText ( " ##MMLWave " , & mmlStringW ) ) {
2022-09-11 03:35:21 +00:00
int actualData [ 256 ] ;
decodeMMLStrW ( mmlStringW , actualData , wave - > len , ( waveSigned & & ! waveHex ) ? ( - ( ( wave - > max + 1 ) / 2 ) ) : 0 , ( waveSigned & & ! waveHex ) ? ( wave - > max / 2 ) : wave - > max , waveHex ) ;
2022-10-16 23:30:48 +00:00
MARK_MODIFIED ;
2022-09-11 03:35:21 +00:00
if ( waveSigned & & ! waveHex ) {
for ( int i = 0 ; i < wave - > len ; i + + ) {
actualData [ i ] + = ( wave - > max + 1 ) / 2 ;
}
}
memcpy ( wave - > data , actualData , wave - > len * sizeof ( int ) ) ;
2022-07-21 07:49:19 +00:00
}
if ( ! ImGui : : IsItemActive ( ) ) {
2022-09-11 03:35:21 +00:00
int actualData [ 256 ] ;
memcpy ( actualData , wave - > data , 256 * sizeof ( int ) ) ;
if ( waveSigned & & ! waveHex ) {
for ( int i = 0 ; i < wave - > len ; i + + ) {
actualData [ i ] - = ( wave - > max + 1 ) / 2 ;
}
}
encodeMMLStr ( mmlStringW , actualData , wave - > len , - 1 , - 1 , waveHex ) ;
2022-07-21 07:49:19 +00:00
}
2022-03-21 21:34:19 +00:00
}
}
if ( ImGui : : IsWindowFocused ( ImGuiFocusedFlags_ChildWindows ) ) curWindow = GUI_WINDOW_WAVE_EDIT ;
ImGui : : End ( ) ;
2022-05-19 21:35:00 +00:00
}