fix tuner, spectrum, vertical mixer layout
This commit is contained in:
parent
8626937f89
commit
242af1d5f8
11 changed files with 648 additions and 208 deletions
|
|
@ -1000,6 +1000,7 @@ src/gui/scaling.cpp
|
|||
src/gui/settings.cpp
|
||||
src/gui/songInfo.cpp
|
||||
src/gui/songNotes.cpp
|
||||
src/gui/spectrum.cpp
|
||||
src/gui/speed.cpp
|
||||
src/gui/spoiler.cpp
|
||||
src/gui/stats.cpp
|
||||
|
|
|
|||
|
|
@ -321,6 +321,9 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_WINDOW_TUNER:
|
||||
nextWindow = GUI_WINDOW_TUNER;
|
||||
break;
|
||||
case GUI_ACTION_WINDOW_SPECTRUM:
|
||||
nextWindow = GUI_WINDOW_SPECTRUM;
|
||||
break;
|
||||
case GUI_ACTION_WINDOW_CHANNELS:
|
||||
nextWindow=GUI_WINDOW_CHANNELS;
|
||||
break;
|
||||
|
|
@ -429,9 +432,6 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_WINDOW_NOTES:
|
||||
notesOpen=false;
|
||||
break;
|
||||
case GUI_WINDOW_TUNER:
|
||||
notesOpen = false;
|
||||
break;
|
||||
case GUI_WINDOW_CHANNELS:
|
||||
channelsOpen=false;
|
||||
break;
|
||||
|
|
@ -470,6 +470,13 @@ void FurnaceGUI::doAction(int what) {
|
|||
break;
|
||||
case GUI_WINDOW_USER_PRESETS:
|
||||
userPresetsOpen=false;
|
||||
break;
|
||||
case GUI_WINDOW_TUNER:
|
||||
tunerOpen=false;
|
||||
break;
|
||||
case GUI_WINDOW_SPECTRUM:
|
||||
spectrumOpen=false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3839,6 +3839,7 @@ bool FurnaceGUI::loop() {
|
|||
DECLARE_METRIC(piano)
|
||||
DECLARE_METRIC(notes)
|
||||
DECLARE_METRIC(tuner)
|
||||
DECLARE_METRIC(spectrum)
|
||||
DECLARE_METRIC(channels)
|
||||
DECLARE_METRIC(patManager)
|
||||
DECLARE_METRIC(sysManager)
|
||||
|
|
@ -4443,6 +4444,7 @@ bool FurnaceGUI::loop() {
|
|||
IMPORT_CLOSE(pianoOpen);
|
||||
IMPORT_CLOSE(notesOpen);
|
||||
IMPORT_CLOSE(tunerOpen);
|
||||
IMPORT_CLOSE(spectrumOpen);
|
||||
IMPORT_CLOSE(channelsOpen);
|
||||
IMPORT_CLOSE(regViewOpen);
|
||||
IMPORT_CLOSE(logOpen);
|
||||
|
|
@ -4809,6 +4811,7 @@ bool FurnaceGUI::loop() {
|
|||
if (ImGui::MenuItem(_("oscilloscope (X-Y)"),BIND_FOR(GUI_ACTION_WINDOW_XY_OSC),xyOscOpen)) xyOscOpen=!xyOscOpen;
|
||||
if (ImGui::MenuItem(_("volume meter"),BIND_FOR(GUI_ACTION_WINDOW_VOL_METER),volMeterOpen)) volMeterOpen=!volMeterOpen;
|
||||
if (ImGui::MenuItem(_("tuner"), BIND_FOR(GUI_ACTION_WINDOW_TUNER), tunerOpen)) tunerOpen = !tunerOpen;
|
||||
if (ImGui::MenuItem(_("spectrum"), BIND_FOR(GUI_ACTION_WINDOW_SPECTRUM), spectrumOpen)) spectrumOpen = !spectrumOpen;
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu(_("tempo"))) {
|
||||
|
|
@ -5089,6 +5092,7 @@ bool FurnaceGUI::loop() {
|
|||
MEASURE(piano,drawPiano());
|
||||
MEASURE(notes,drawNotes());
|
||||
MEASURE(tuner,drawTuner());
|
||||
MEASURE(spectrum, drawSpectrum());
|
||||
MEASURE(channels,drawChannels());
|
||||
MEASURE(patManager,drawPatManager());
|
||||
MEASURE(sysManager,drawSysManager());
|
||||
|
|
@ -8213,6 +8217,7 @@ void FurnaceGUI::syncState() {
|
|||
#endif
|
||||
notesOpen=e->getConfBool("notesOpen",false);
|
||||
tunerOpen=e->getConfBool("tunerOpen",false);
|
||||
spectrumOpen=e->getConfBool("spectrumOpen", false);
|
||||
channelsOpen=e->getConfBool("channelsOpen",false);
|
||||
patManagerOpen=e->getConfBool("patManagerOpen",false);
|
||||
sysManagerOpen=e->getConfBool("sysManagerOpen",false);
|
||||
|
|
@ -8273,6 +8278,12 @@ void FurnaceGUI::syncState() {
|
|||
oscZoomSlider=e->getConfBool("oscZoomSlider",false);
|
||||
oscWindowSize=e->getConfFloat("oscWindowSize",20.0f);
|
||||
|
||||
spectrum.bins=e->getConfInt("spectrumBins",2048);
|
||||
spectrum.xZoom=e->getConfFloat("spectrumxZoom",1.0f);
|
||||
spectrum.xOffset=e->getConfFloat("spectrumxOffset",0);
|
||||
spectrum.yOffset=e->getConfFloat("spectrumyOffset",0);
|
||||
spectrum.mono=e->getConfBool("spectrumMono",false);
|
||||
|
||||
pianoOctaves=e->getConfInt("pianoOctaves",pianoOctaves);
|
||||
pianoOctavesEdit=e->getConfInt("pianoOctavesEdit",pianoOctavesEdit);
|
||||
pianoOptions=e->getConfBool("pianoOptions",pianoOptions);
|
||||
|
|
@ -8374,6 +8385,7 @@ void FurnaceGUI::commitState(DivConfig& conf) {
|
|||
conf.set("pianoOpen",pianoOpen);
|
||||
conf.set("notesOpen",notesOpen);
|
||||
conf.set("tunerOpen",tunerOpen);
|
||||
conf.set("spectrumOpen",spectrumOpen);
|
||||
conf.set("channelsOpen",channelsOpen);
|
||||
conf.set("patManagerOpen",patManagerOpen);
|
||||
conf.set("sysManagerOpen",sysManagerOpen);
|
||||
|
|
@ -8428,6 +8440,13 @@ void FurnaceGUI::commitState(DivConfig& conf) {
|
|||
conf.set("oscZoomSlider",oscZoomSlider);
|
||||
conf.set("oscWindowSize",oscWindowSize);
|
||||
|
||||
// commit spectrum state
|
||||
conf.set("spectrumBins",spectrum.bins);
|
||||
conf.set("spectrumxZoom",spectrum.xZoom);
|
||||
conf.set("spectrumxOffset",spectrum.xOffset);
|
||||
conf.set("spectrumyOffset",spectrum.yOffset);
|
||||
conf.set("spectrumMono",spectrum.mono);
|
||||
|
||||
// commit piano state
|
||||
conf.set("pianoOctaves",pianoOctaves);
|
||||
conf.set("pianoOctavesEdit",pianoOctavesEdit);
|
||||
|
|
@ -8544,14 +8563,17 @@ bool FurnaceGUI::finish(bool saveConfig) {
|
|||
fftw_free(tunerFFTOutBuf);
|
||||
tunerFFTOutBuf=NULL;
|
||||
}
|
||||
if (spectrumPlan) {
|
||||
fftw_free(spectrumPlan);
|
||||
spectrumPlan=NULL;
|
||||
}
|
||||
if (tunerPlan) {
|
||||
fftw_free(tunerPlan);
|
||||
tunerPlan=NULL;
|
||||
}
|
||||
if (spectrum.in) {
|
||||
delete[] spectrum.in;
|
||||
spectrum.in=NULL;
|
||||
}
|
||||
if (spectrum.buffer) {
|
||||
fftw_free(spectrum.buffer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -9092,9 +9114,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
xyOscDecayTime(10.0f),
|
||||
xyOscIntensity(2.0f),
|
||||
xyOscThickness(2.0f),
|
||||
spectrumPlan(NULL),
|
||||
tunerPlan(NULL),
|
||||
spectrumBins(2048),
|
||||
followLog(true),
|
||||
#ifdef IS_MOBILE
|
||||
pianoOctaves(7),
|
||||
|
|
|
|||
|
|
@ -517,6 +517,10 @@ enum FurnaceGUIColors {
|
|||
GUI_COLOR_MEMORY_BANK6,
|
||||
GUI_COLOR_MEMORY_BANK7,
|
||||
|
||||
GUI_COLOR_TUNER_NEEDLE,
|
||||
GUI_COLOR_TUNER_SCALE_LOW,
|
||||
GUI_COLOR_TUNER_SCALE_HIGH,
|
||||
|
||||
GUI_COLOR_LOGLEVEL_ERROR,
|
||||
GUI_COLOR_LOGLEVEL_WARNING,
|
||||
GUI_COLOR_LOGLEVEL_INFO,
|
||||
|
|
@ -552,6 +556,7 @@ enum FurnaceGUIWindows {
|
|||
GUI_WINDOW_PIANO,
|
||||
GUI_WINDOW_NOTES,
|
||||
GUI_WINDOW_TUNER,
|
||||
GUI_WINDOW_SPECTRUM,
|
||||
GUI_WINDOW_CHANNELS,
|
||||
GUI_WINDOW_PAT_MANAGER,
|
||||
GUI_WINDOW_SYS_MANAGER,
|
||||
|
|
@ -758,6 +763,7 @@ enum FurnaceGUIActions {
|
|||
GUI_ACTION_WINDOW_PIANO,
|
||||
GUI_ACTION_WINDOW_NOTES,
|
||||
GUI_ACTION_WINDOW_TUNER,
|
||||
GUI_ACTION_WINDOW_SPECTRUM,
|
||||
GUI_ACTION_WINDOW_CHANNELS,
|
||||
GUI_ACTION_WINDOW_PAT_MANAGER,
|
||||
GUI_ACTION_WINDOW_SYS_MANAGER,
|
||||
|
|
@ -2065,6 +2071,7 @@ class FurnaceGUI {
|
|||
int rackShowLEDs;
|
||||
int sampleImportInstDetune;
|
||||
int mixerStyle;
|
||||
int mixerLayout;
|
||||
String mainFontPath;
|
||||
String headFontPath;
|
||||
String patFontPath;
|
||||
|
|
@ -2319,6 +2326,7 @@ class FurnaceGUI {
|
|||
rackShowLEDs(1),
|
||||
sampleImportInstDetune(0),
|
||||
mixerStyle(1),
|
||||
mixerLayout(0),
|
||||
mainFontPath(""),
|
||||
headFontPath(""),
|
||||
patFontPath(""),
|
||||
|
|
@ -2392,7 +2400,7 @@ class FurnaceGUI {
|
|||
bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen;
|
||||
bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen;
|
||||
bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen;
|
||||
bool pianoOpen, notesOpen, tunerOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen;
|
||||
bool pianoOpen, notesOpen, tunerOpen, spectrumOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen;
|
||||
bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen, clockOpen, speedOpen;
|
||||
bool groovesOpen, xyOscOpen, memoryOpen, csPlayerOpen, cvOpen, userPresetsOpen;
|
||||
|
||||
|
|
@ -2734,8 +2742,34 @@ class FurnaceGUI {
|
|||
// spectrum and tuner
|
||||
double* tunerFFTInBuf;
|
||||
fftw_complex* tunerFFTOutBuf;
|
||||
fftw_plan spectrumPlan, tunerPlan;
|
||||
int spectrumBins;
|
||||
fftw_plan tunerPlan;
|
||||
struct SpectrumSettings {
|
||||
int bins;
|
||||
float xZoom, xOffset;
|
||||
float yOffset;
|
||||
fftw_plan plan;
|
||||
fftw_complex* buffer;
|
||||
double* in;
|
||||
ImVec2* plot;
|
||||
std::vector<int> frequencies;
|
||||
bool update, running, mono;
|
||||
bool showXGrid, showYGrid, showXScale, showYScale;
|
||||
SpectrumSettings():
|
||||
bins(2048),
|
||||
xZoom(1.0f),
|
||||
xOffset(0.0f),
|
||||
yOffset(0.0f),
|
||||
buffer(NULL),
|
||||
in(NULL),
|
||||
frequencies({}),
|
||||
update(true),
|
||||
running(false),
|
||||
mono(false),
|
||||
showXGrid(true),
|
||||
showYGrid(true),
|
||||
showXScale(true),
|
||||
showYScale(true) {}
|
||||
} spectrum;
|
||||
|
||||
// visualizer
|
||||
float keyHit[DIV_MAX_CHANS];
|
||||
|
|
@ -2980,6 +3014,7 @@ class FurnaceGUI {
|
|||
void drawPiano();
|
||||
void drawNotes(bool asChild=false);
|
||||
void drawTuner();
|
||||
void drawSpectrum();
|
||||
void drawChannels();
|
||||
void drawPatManager();
|
||||
void drawSysManager();
|
||||
|
|
|
|||
|
|
@ -28,6 +28,22 @@ const int opOrder[4]={
|
|||
0, 2, 1, 3
|
||||
};
|
||||
|
||||
const float topKeyStarts[5]={
|
||||
0.9f/7.0f, 2.1f/7.0f, 3.9f/7.0f, 5.0f/7.0f, 6.1f/7.0f
|
||||
};
|
||||
|
||||
const int topKeyNotes[5]={
|
||||
1, 3, 6, 8, 10
|
||||
};
|
||||
|
||||
const int bottomKeyNotes[7]={
|
||||
0, 2, 4, 5, 7, 9, 11
|
||||
};
|
||||
|
||||
const bool isTopKey[12]={
|
||||
false, true, false, true, false, false, true, false, true, false, true, false
|
||||
};
|
||||
|
||||
const char* noteNames[180]={
|
||||
"c_5", "c+5", "d_5", "d+5", "e_5", "f_5", "f+5", "g_5", "g+5", "a_5", "a+5", "b_5",
|
||||
"c_4", "c+4", "d_4", "d+4", "e_4", "f_4", "f+4", "g_4", "g+4", "a_4", "a+4", "b_4",
|
||||
|
|
@ -642,6 +658,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
|||
D("WINDOW_PIANO", _N("Piano"), 0),
|
||||
D("WINDOW_NOTES", _N("Song Comments"), 0),
|
||||
D("WINDOW_TUNER", _N("Tuner"), 0),
|
||||
D("WINDOW_SPECTRUM", _N("Spectrum"), 0),
|
||||
D("WINDOW_CHANNELS", _N("Channels"), 0),
|
||||
D("WINDOW_PAT_MANAGER", _N("Pattern Manager"), 0),
|
||||
D("WINDOW_SYS_MANAGER", _N("Chip Manager"), 0),
|
||||
|
|
@ -1214,6 +1231,10 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
|||
D(GUI_COLOR_MEMORY_BANK6,"",ImVec4(0.5f,0.1f,1.0f,1.0f)),
|
||||
D(GUI_COLOR_MEMORY_BANK7,"",ImVec4(1.0f,0.1f,1.0f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_TUNER_NEEDLE,"",ImVec4(0.1f,0.5f,0.9f,1.0f)),
|
||||
D(GUI_COLOR_TUNER_SCALE_LOW,"",ImVec4(0.1f,1.0f,0.2f,1.0f)),
|
||||
D(GUI_COLOR_TUNER_SCALE_HIGH,"",ImVec4(0.9f,0.1f,0.1f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_LOGLEVEL_ERROR,"",ImVec4(1.0f,0.2f,0.2f,1.0f)),
|
||||
D(GUI_COLOR_LOGLEVEL_WARNING,"",ImVec4(1.0f,1.0f,0.2f,1.0f)),
|
||||
D(GUI_COLOR_LOGLEVEL_INFO,"",ImVec4(0.4f,1.0f,0.4f,1.0f)),
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ struct FurnaceGUIColorDef {
|
|||
};
|
||||
|
||||
extern const int opOrder[4];
|
||||
extern const float topKeyStarts[5];
|
||||
extern const int topKeyNotes[5];
|
||||
extern const int bottomKeyNotes[7];
|
||||
extern const bool isTopKey[12];
|
||||
extern const char* noteNames[180];
|
||||
extern const char* noteNamesG[180];
|
||||
extern const char* noteNamesF[180];
|
||||
|
|
|
|||
|
|
@ -226,55 +226,84 @@ void FurnaceGUI::drawMixer() {
|
|||
if (ImGui::Begin("Mixer",&mixerOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking),_("Mixer"))) {
|
||||
if (ImGui::BeginTabBar("MixerView")) {
|
||||
if (ImGui::BeginTabItem(_("Mixer"))) {
|
||||
float maxY=ImGui::GetContentRegionAvail().y;
|
||||
VerticalText(maxY,true,_("Master Volume"));
|
||||
ImGui::SameLine();
|
||||
if (settings.mixerStyle==2) {
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos();
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(40*dpiScale,maxY)),peak,e->getAudioDescGot().outChans,false);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,127<<IM_COL32_A_SHIFT);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,0);
|
||||
}
|
||||
if (ImGui::VSliderFloat("##mixerMaster",ImVec2(40*dpiScale,maxY),&e->song.masterVol,0,3,"%.2fx")) {
|
||||
if (e->song.masterVol<0) e->song.masterVol=0;
|
||||
if (e->song.masterVol>3) e->song.masterVol=3;
|
||||
MARK_MODIFIED;
|
||||
} rightClickable
|
||||
ImGui::SameLine();
|
||||
if (settings.mixerStyle==2) {
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopStyleVar();
|
||||
} else if (settings.mixerStyle==1) {
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos();
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(40*dpiScale,maxY)),peak,e->getAudioDescGot().outChans,false);
|
||||
ImGui::Dummy(ImVec2(40*dpiScale,maxY));
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
const float itemWidth=60*dpiScale;
|
||||
// figure out if we need to cut the height for the scrollbar
|
||||
float itemCalcWidth=
|
||||
itemWidth+
|
||||
1.5f*ImGui::GetStyle().FramePadding.x+
|
||||
4*ImGui::GetStyle().FramePadding.x+
|
||||
dpiScale+ // separator
|
||||
(settings.mixerStyle==1?(itemWidth-ImGui::GetFontSize()-ImGui::GetStyle().FramePadding.x):0)
|
||||
;
|
||||
float realwidth=ImGui::GetWindowWidth()-ImGui::GetCursorPosX();
|
||||
if ((itemCalcWidth*e->song.systemLen)>realwidth) maxY-=ImGui::GetStyle().ScrollbarSize;
|
||||
float maxY=ImGui::GetContentRegionAvail().y;
|
||||
if (settings.mixerLayout) {
|
||||
ImGui::TextUnformatted(_("Master Volume"));
|
||||
if (settings.mixerStyle==2) {
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos(),
|
||||
size=ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetFontSize()+ImGui::GetStyle().FramePadding.y*2.0f);
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+size),peak,e->getAudioDescGot().outChans,true);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,127<<IM_COL32_A_SHIFT);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,0);
|
||||
}
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::SliderFloat("##mixerMaster",&e->song.masterVol,0,3,"%.2fx")) {
|
||||
if (e->song.masterVol<0) e->song.masterVol=0;
|
||||
if (e->song.masterVol>3) e->song.masterVol=3;
|
||||
MARK_MODIFIED;
|
||||
} rightClickable
|
||||
if (settings.mixerStyle==2) {
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopStyleVar();
|
||||
} else if (settings.mixerStyle==1) {
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos(),
|
||||
size=ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetFontSize()+ImGui::GetStyle().FramePadding.y*2.0f);
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+size),peak,e->getAudioDescGot().outChans,true);
|
||||
ImGui::Dummy(size);
|
||||
}
|
||||
} else {
|
||||
VerticalText(maxY,true,_("Master Volume"));
|
||||
ImGui::SameLine();
|
||||
if (settings.mixerStyle==2) {
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos();
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(40*dpiScale,maxY)),peak,e->getAudioDescGot().outChans,false);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,127<<IM_COL32_A_SHIFT);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,0);
|
||||
}
|
||||
if (ImGui::VSliderFloat("##mixerMaster",ImVec2(40*dpiScale,maxY),&e->song.masterVol,0,3,"%.2fx")) {
|
||||
if (e->song.masterVol<0) e->song.masterVol=0;
|
||||
if (e->song.masterVol>3) e->song.masterVol=3;
|
||||
MARK_MODIFIED;
|
||||
} rightClickable
|
||||
ImGui::SameLine();
|
||||
if (settings.mixerStyle==2) {
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopStyleVar();
|
||||
} else if (settings.mixerStyle==1) {
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos();
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(40*dpiScale,maxY)),peak,e->getAudioDescGot().outChans,false);
|
||||
ImGui::Dummy(ImVec2(40*dpiScale,maxY));
|
||||
ImGui::SameLine();
|
||||
}
|
||||
// figure out if we need to cut the height for the scrollbar
|
||||
float itemCalcWidth=
|
||||
itemWidth+
|
||||
1.5f*ImGui::GetStyle().FramePadding.x+
|
||||
4*ImGui::GetStyle().FramePadding.x+
|
||||
dpiScale+ // separator
|
||||
(settings.mixerStyle==1?(itemWidth-ImGui::GetFontSize()-ImGui::GetStyle().FramePadding.x):0)
|
||||
;
|
||||
float realwidth=ImGui::GetWindowWidth()-ImGui::GetCursorPosX();
|
||||
if ((itemCalcWidth*e->song.systemLen)>realwidth) maxY-=ImGui::GetStyle().ScrollbarSize;
|
||||
}
|
||||
if (ImGui::BeginChild("##mixerPerChipContainer",ImVec2(0,0),0,ImGuiWindowFlags_HorizontalScrollbar)) {
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
ImGui::GetWindowDrawList()->AddRectFilled(
|
||||
ImGui::GetCursorScreenPos(),
|
||||
ImGui::GetCursorScreenPos()+ImVec2(dpiScale,maxY),
|
||||
ImGui::GetColorU32(ImGuiCol_Separator)
|
||||
);
|
||||
ImGui::Dummy(ImVec2(dpiScale,maxY));
|
||||
ImGui::SameLine();
|
||||
if (settings.mixerLayout==0) {
|
||||
ImGui::GetWindowDrawList()->AddRectFilled(
|
||||
ImGui::GetCursorScreenPos(),
|
||||
ImGui::GetCursorScreenPos()+ImVec2(dpiScale,maxY),
|
||||
ImGui::GetColorU32(ImGuiCol_Separator)
|
||||
);
|
||||
ImGui::Dummy(ImVec2(dpiScale,maxY));
|
||||
ImGui::SameLine();
|
||||
}
|
||||
if (chipMixer(i,ImVec2(itemWidth,maxY))) MARK_MODIFIED;
|
||||
ImGui::SameLine();
|
||||
if (settings.mixerLayout==0) ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
|
@ -452,76 +481,154 @@ bool FurnaceGUI::chipMixer(int which, ImVec2 size) {
|
|||
|
||||
float vol=fabs(e->song.systemVol[which]);
|
||||
bool doInvert=e->song.systemVol[which]<0;
|
||||
if (ImGui::Checkbox("##ChipInvert",&doInvert)) {
|
||||
e->song.systemVol[which]=doInvert?-vol:vol;
|
||||
ret=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("Invert"));
|
||||
}
|
||||
// hack to get the same line from here
|
||||
ImGui::SameLine();
|
||||
ImVec2 curPos=ImGui::GetCursorPos();
|
||||
ImGui::NewLine();
|
||||
|
||||
float volSliderHeight=size.y-ImGui::GetStyle().FramePadding.y*7-textHeight*2;
|
||||
|
||||
VerticalText(volSliderHeight-(ImGui::GetCursorPosY()-curPos.y),true,"%s",e->getSystemName(e->song.system[which]));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
float vTextWidth=textHeight+2*ImGui::GetStyle().FramePadding.x;
|
||||
|
||||
ImGui::SetCursorPos(curPos);
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos();
|
||||
if (settings.mixerStyle==2) {
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(size.x-vTextWidth,volSliderHeight)),e->chipPeak[which],e->getDispatch(which)->getOutputCount(),false);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,127<<IM_COL32_A_SHIFT);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,0);
|
||||
}
|
||||
if (ImGui::VSliderFloat("##ChipVol",ImVec2(size.x-vTextWidth,volSliderHeight),&vol,0.0f,2.0f)) {
|
||||
if (doInvert) {
|
||||
if (vol<0.0001) vol=0.0001;
|
||||
if (settings.mixerLayout) {
|
||||
if (ImGui::BeginTable("mixerVectRow1", 2)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(e->getSystemName(e->song.system[which]));
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Checkbox("##ChipInvert",&doInvert)) {
|
||||
e->song.systemVol[which]=doInvert?-vol:vol;
|
||||
ret=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("Invert"));
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
if (vol<0) vol=0;
|
||||
if (vol>10) vol=10;
|
||||
e->song.systemVol[which]=doInvert?-vol:vol;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Volume"));
|
||||
}
|
||||
if (settings.mixerStyle==2) {
|
||||
ImGui::PopStyleVar(1);
|
||||
ImGui::PopStyleColor(3);
|
||||
} else if (settings.mixerStyle==1) {
|
||||
ImGui::SetCursorPos(curPos+ImVec2(size.x-vTextWidth+ImGui::GetStyle().FramePadding.x,0));
|
||||
pos=ImGui::GetCursorScreenPos();
|
||||
ImGui::Dummy(ImVec2(size.x-vTextWidth,volSliderHeight));
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(size.x-vTextWidth,volSliderHeight)),e->chipPeak[which],e->getDispatch(which)->getOutputCount(),false);
|
||||
}
|
||||
float panSliderWidth=size.x+1.5f*ImGui::GetStyle().FramePadding.x+((settings.mixerStyle!=1)?0:size.x-vTextWidth+ImGui::GetStyle().FramePadding.x);
|
||||
ImGui::SetNextItemWidth(panSliderWidth);
|
||||
if (ImGui::SliderFloat("##ChipPan",&e->song.systemPan[which],-1.0f,1.0f)) {
|
||||
if (e->song.systemPan[which]<-1.0f) e->song.systemPan[which]=-1.0f;
|
||||
if (e->song.systemPan[which]>1.0f) e->song.systemPan[which]=1.0f;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Panning"));
|
||||
}
|
||||
if (settings.mixerStyle==2) {
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos(),
|
||||
posMax=pos+ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetFontSize()+ImGui::GetStyle().FramePadding.y*2.0f);
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,posMax),e->chipPeak[which],e->getDispatch(which)->getOutputCount(),true);
|
||||
|
||||
ImGui::SetNextItemWidth(panSliderWidth);
|
||||
if (ImGui::SliderFloat("##ChipPanFR",&e->song.systemPanFR[which],-1.0f,1.0f)) {
|
||||
if (e->song.systemPanFR[which]<-1.0f) e->song.systemPanFR[which]=-1.0f;
|
||||
if (e->song.systemPanFR[which]>1.0f) e->song.systemPanFR[which]=1.0f;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Front/Rear"));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,127<<IM_COL32_A_SHIFT);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,0);
|
||||
}
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::SliderFloat("##ChipVol",&vol,0.0f,2.0f)) {
|
||||
if (doInvert) {
|
||||
if (vol<0.0001) vol=0.0001;
|
||||
}
|
||||
if (vol<0) vol=0;
|
||||
if (vol>10) vol=10;
|
||||
e->song.systemVol[which]=doInvert?-vol:vol;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Volume"));
|
||||
}
|
||||
if (settings.mixerStyle==2) {
|
||||
ImGui::PopStyleVar(1);
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
if (ImGui::BeginTable("mixerVectRow3", 2)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::SliderFloat("##ChipPan",&e->song.systemPan[which],-1.0f,1.0f)) {
|
||||
if (e->song.systemPan[which]<-1.0f) e->song.systemPan[which]=-1.0f;
|
||||
if (e->song.systemPan[which]>1.0f) e->song.systemPan[which]=1.0f;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Panning"));
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::SliderFloat("##ChipPanFR",&e->song.systemPanFR[which],-1.0f,1.0f)) {
|
||||
if (e->song.systemPanFR[which]<-1.0f) e->song.systemPanFR[which]=-1.0f;
|
||||
if (e->song.systemPanFR[which]>1.0f) e->song.systemPanFR[which]=1.0f;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Front/Rear"));
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
if (settings.mixerStyle==1) {
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos(),
|
||||
size=ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetFontSize()+ImGui::GetStyle().FramePadding.y*2.0f);
|
||||
ImGui::Dummy(size);
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+size),e->chipPeak[which],e->getDispatch(which)->getOutputCount(),true);
|
||||
}
|
||||
} else {
|
||||
if (ImGui::Checkbox("##ChipInvert",&doInvert)) {
|
||||
e->song.systemVol[which]=doInvert?-vol:vol;
|
||||
ret=true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(_("Invert"));
|
||||
}
|
||||
// hack to get the same line from here
|
||||
ImGui::SameLine();
|
||||
ImVec2 curPos=ImGui::GetCursorPos();
|
||||
ImGui::NewLine();
|
||||
|
||||
float volSliderHeight=size.y-ImGui::GetStyle().FramePadding.y*7-textHeight*2;
|
||||
|
||||
VerticalText(volSliderHeight-(ImGui::GetCursorPosY()-curPos.y),true,"%s",e->getSystemName(e->song.system[which]));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
float vTextWidth=textHeight+2*ImGui::GetStyle().FramePadding.x;
|
||||
|
||||
ImGui::SetCursorPos(curPos);
|
||||
ImVec2 pos=ImGui::GetCursorScreenPos();
|
||||
if (settings.mixerStyle==2) {
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(size.x-vTextWidth,volSliderHeight)),e->chipPeak[which],e->getDispatch(which)->getOutputCount(),false);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive,0);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,127<<IM_COL32_A_SHIFT);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,0);
|
||||
}
|
||||
if (ImGui::VSliderFloat("##ChipVol",ImVec2(size.x-vTextWidth,volSliderHeight),&vol,0.0f,2.0f)) {
|
||||
if (doInvert) {
|
||||
if (vol<0.0001) vol=0.0001;
|
||||
}
|
||||
if (vol<0) vol=0;
|
||||
if (vol>10) vol=10;
|
||||
e->song.systemVol[which]=doInvert?-vol:vol;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Volume"));
|
||||
}
|
||||
if (settings.mixerStyle==2) {
|
||||
ImGui::PopStyleVar(1);
|
||||
ImGui::PopStyleColor(3);
|
||||
} else if (settings.mixerStyle==1) {
|
||||
ImGui::SetCursorPos(curPos+ImVec2(size.x-vTextWidth+ImGui::GetStyle().FramePadding.x,0));
|
||||
pos=ImGui::GetCursorScreenPos();
|
||||
ImGui::Dummy(ImVec2(size.x-vTextWidth,volSliderHeight));
|
||||
drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(size.x-vTextWidth,volSliderHeight)),e->chipPeak[which],e->getDispatch(which)->getOutputCount(),false);
|
||||
}
|
||||
float panSliderWidth=size.x+1.5f*ImGui::GetStyle().FramePadding.x+((settings.mixerStyle!=1)?0:size.x-vTextWidth+ImGui::GetStyle().FramePadding.x);
|
||||
ImGui::SetNextItemWidth(panSliderWidth);
|
||||
if (ImGui::SliderFloat("##ChipPan",&e->song.systemPan[which],-1.0f,1.0f)) {
|
||||
if (e->song.systemPan[which]<-1.0f) e->song.systemPan[which]=-1.0f;
|
||||
if (e->song.systemPan[which]>1.0f) e->song.systemPan[which]=1.0f;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Panning"));
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(panSliderWidth);
|
||||
if (ImGui::SliderFloat("##ChipPanFR",&e->song.systemPanFR[which],-1.0f,1.0f)) {
|
||||
if (e->song.systemPanFR[which]<-1.0f) e->song.systemPanFR[which]=-1.0f;
|
||||
if (e->song.systemPanFR[which]>1.0f) e->song.systemPanFR[which]=1.0f;
|
||||
ret=true;
|
||||
} rightClickable
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) {
|
||||
ImGui::SetTooltip(_("Front/Rear"));
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
|
|
|||
|
|
@ -24,22 +24,6 @@
|
|||
#include <fmt/printf.h>
|
||||
#include "IconsFontAwesome4.h"
|
||||
|
||||
const float topKeyStarts[5]={
|
||||
0.9f/7.0f, 2.1f/7.0f, 3.9f/7.0f, 5.0f/7.0f, 6.1f/7.0f
|
||||
};
|
||||
|
||||
const int topKeyNotes[5]={
|
||||
1, 3, 6, 8, 10
|
||||
};
|
||||
|
||||
const int bottomKeyNotes[7]={
|
||||
0, 2, 4, 5, 7, 9, 11
|
||||
};
|
||||
|
||||
const bool isTopKey[12]={
|
||||
false, true, false, true, false, false, true, false, true, false, true, false
|
||||
};
|
||||
|
||||
#define VALUE_DIGIT(x,label) \
|
||||
if (ImGui::Button(label,buttonSize)) { \
|
||||
if (curWindow==GUI_WINDOW_ORDERS && orderEditMode>0) { \
|
||||
|
|
|
|||
|
|
@ -3871,13 +3871,24 @@ void FurnaceGUI::drawSettings() {
|
|||
|
||||
// SUBSECTION MIXER
|
||||
CONFIG_SUBSECTION(_("Mixer"))
|
||||
ImGui::Text(_("Mixer layout:"));
|
||||
ImGui::Indent();
|
||||
if (ImGui::RadioButton(_("Horizontal##mixl0"),settings.mixerLayout==0)) {
|
||||
settings.mixerLayout=0;
|
||||
settingsChanged=true;
|
||||
}
|
||||
if (ImGui::RadioButton(_("Vertical##mixl1"),settings.mixerLayout==1)) {
|
||||
settings.mixerLayout=1;
|
||||
settingsChanged=true;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
ImGui::Text(_("Mixer style:"));
|
||||
ImGui::Indent();
|
||||
if (ImGui::RadioButton(_("No volume meters"),settings.mixerStyle==0)) {
|
||||
settings.mixerStyle=0;
|
||||
settingsChanged=true;
|
||||
}
|
||||
if (ImGui::RadioButton(_("Volume meters to the side"),settings.mixerStyle==1)) {
|
||||
if (ImGui::RadioButton(_("Volume meters separate"),settings.mixerStyle==1)) {
|
||||
settings.mixerStyle=1;
|
||||
settingsChanged=true;
|
||||
}
|
||||
|
|
@ -4394,6 +4405,12 @@ void FurnaceGUI::drawSettings() {
|
|||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode(_("Tuner"))) {
|
||||
UI_COLOR_CONFIG(GUI_COLOR_TUNER_NEEDLE,_("Needle##tuner"));
|
||||
UI_COLOR_CONFIG(GUI_COLOR_TUNER_SCALE_LOW,_("Scale center"));
|
||||
UI_COLOR_CONFIG(GUI_COLOR_TUNER_SCALE_HIGH,_("Scale edges"));
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode(_("Log Viewer"))) {
|
||||
UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_ERROR,_("Log level: Error"));
|
||||
UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_WARNING,_("Log level: Warning"));
|
||||
|
|
@ -5075,6 +5092,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
settings.rackShowLEDs=conf.getInt("rackShowLEDs",1);
|
||||
|
||||
settings.mixerStyle=conf.getInt("mixerStyle",1);
|
||||
settings.mixerLayout=conf.getInt("mixerLayout",1);
|
||||
|
||||
settings.channelColors=conf.getInt("channelColors",1);
|
||||
settings.channelTextColors=conf.getInt("channelTextColors",0);
|
||||
|
|
@ -5414,6 +5432,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
clampSetting(settings.songNotesWrap,0,1);
|
||||
clampSetting(settings.rackShowLEDs,0,1);
|
||||
clampSetting(settings.mixerStyle,0,2);
|
||||
clampSetting(settings.mixerLayout,0,1);
|
||||
clampSetting(settings.cursorWheelStep,0,2);
|
||||
clampSetting(settings.vsync,0,4);
|
||||
clampSetting(settings.frameRateLimit,0,1000);
|
||||
|
|
@ -5663,6 +5682,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
conf.set("rackShowLEDs",settings.rackShowLEDs);
|
||||
|
||||
conf.set("mixerStyle",settings.mixerStyle);
|
||||
conf.set("mixerLayout",settings.mixerLayout);
|
||||
|
||||
conf.set("channelColors",settings.channelColors);
|
||||
conf.set("channelTextColors",settings.channelTextColors);
|
||||
|
|
|
|||
218
src/gui/spectrum.cpp
Normal file
218
src/gui/spectrum.cpp
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2025 tildearrow and contributors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// bulk of the code is from https://github.com/Eknous-P/unscope/blob/spectrum/src/gui/wins/spectrum.cpp
|
||||
|
||||
#include "gui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include <IconsFontAwesome4.h>
|
||||
#include <fftw3.h>
|
||||
#include <math.h> // fmod
|
||||
|
||||
inline float scaleFuncLog(float x) {
|
||||
constexpr float base=100;
|
||||
return log((base-1)*x+1.0f)/log(base);
|
||||
}
|
||||
|
||||
inline float scaleFuncDb(float y) {
|
||||
return log10(y)*20.0f/70.0f+1;
|
||||
}
|
||||
|
||||
void FurnaceGUI::drawSpectrum() {
|
||||
if (nextWindow==GUI_WINDOW_SPECTRUM) {
|
||||
spectrumOpen=true;
|
||||
ImGui::SetNextWindowFocus();
|
||||
nextWindow=GUI_WINDOW_NOTHING;
|
||||
}
|
||||
if (!spectrumOpen) return;
|
||||
if (ImGui::Begin("Spectrum",&spectrumOpen,globalWinFlags,_("Spectrum"))) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0.0f,0.0f));
|
||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||
ImVec2 origin=ImGui::GetWindowPos(), size=ImGui::GetWindowSize();
|
||||
float titleBar=ImGui::GetCurrentWindow()->TitleBarHeight;
|
||||
origin.y+=titleBar;
|
||||
size.y-=titleBar;
|
||||
// x scale labels (precalc)
|
||||
if (spectrum.showXScale) size.y-=ImGui::GetFontSize();
|
||||
// v scale labels
|
||||
if (spectrum.showYScale) {
|
||||
float padding=ImGui::GetStyle().FramePadding.x;
|
||||
ImVec2 p1, textSize;
|
||||
char buf[16];
|
||||
textSize=ImGui::CalcTextSize("-100");
|
||||
textSize.x+=5.f;
|
||||
int lineOffset=spectrum.yOffset*8;
|
||||
for (int z=lineOffset; z<=7+lineOffset; z++) {
|
||||
p1.y=origin.y+size.y*((z+1)/8.f-spectrum.yOffset)-textSize.y/2.0f;
|
||||
p1.x=origin.x+padding;
|
||||
snprintf(buf,16,"-%2d",(z+1)*10);
|
||||
dl->AddText(p1,ImGui::GetColorU32(ImGuiCol_Text),buf);
|
||||
}
|
||||
origin.x+=textSize.x+padding;
|
||||
size.x-=textSize.x+padding;
|
||||
}
|
||||
// y grid
|
||||
if (spectrum.showYGrid) {
|
||||
int lines=((size.y>450)?16:8);
|
||||
float offset=fmod(spectrum.yOffset*lines,1.0f)/lines;
|
||||
for (unsigned char z=1; z<=lines; z++) {
|
||||
dl->AddLine(
|
||||
origin+ImVec2(0,size.y*((float)z/lines-offset)),
|
||||
origin+ImVec2(size.x,size.y*((float)z/lines-offset)),
|
||||
0x55ffffff);
|
||||
}
|
||||
}
|
||||
// x grid
|
||||
if (spectrum.showXGrid || spectrum.showXScale) {
|
||||
char buf[16];
|
||||
float pos=0, prevPos=0, i;
|
||||
for (size_t j=0; j<spectrum.frequencies.size(); j++) {
|
||||
i=spectrum.frequencies[j];
|
||||
ImU32 color=0x22ffffff;
|
||||
pos=spectrum.xZoom*size.x*(scaleFuncLog(i/(e->getAudioDescGot().rate/2.0f))-spectrum.xOffset);
|
||||
if (pos>size.x) break;
|
||||
if (j%9==0) color=0x55ffffff;
|
||||
if (spectrum.showXScale) {
|
||||
if (i>=1000) {
|
||||
snprintf(buf,16,"%dk",(int)i/1000);
|
||||
} else {
|
||||
snprintf(buf,16,"%d",(int)i);
|
||||
}
|
||||
float x=ImGui::CalcTextSize(buf).x;
|
||||
if (pos-prevPos>x || j%9==0) dl->AddText(
|
||||
origin+ImVec2(pos-x/2,size.y),
|
||||
ImGui::GetColorU32(ImGuiCol_Text),
|
||||
buf
|
||||
);
|
||||
}
|
||||
if (spectrum.showXGrid) dl->AddLine(
|
||||
origin+ImVec2(pos,0),
|
||||
origin+ImVec2(pos,size.y),
|
||||
color);
|
||||
prevPos=pos;
|
||||
}
|
||||
}
|
||||
int chans=e->getAudioDescGot().outChans;
|
||||
if (spectrum.update) {
|
||||
spectrum.update=false;
|
||||
spectrum.running=true;
|
||||
if (spectrum.buffer) {
|
||||
fftw_free(spectrum.buffer);
|
||||
spectrum.buffer=NULL;
|
||||
}
|
||||
if (spectrum.in) {
|
||||
delete[] spectrum.in;
|
||||
spectrum.in=NULL;
|
||||
}
|
||||
if (spectrum.plot) {
|
||||
delete[] spectrum.plot;
|
||||
spectrum.plot=NULL;
|
||||
}
|
||||
spectrum.buffer=(fftw_complex*)fftw_malloc(sizeof(fftw_complex)*spectrum.bins);
|
||||
if (!spectrum.buffer) spectrum.running=false;
|
||||
spectrum.in=new double[spectrum.bins];
|
||||
if (!spectrum.in) spectrum.running=false;
|
||||
spectrum.plot=new ImVec2[spectrum.bins/2];
|
||||
if (!spectrum.plot) spectrum.running=false;
|
||||
spectrum.plan=fftw_plan_dft_r2c_1d(spectrum.bins,spectrum.in,spectrum.buffer,FFTW_ESTIMATE);
|
||||
spectrum.frequencies.clear();
|
||||
float freq;
|
||||
float maxRate=e->getAudioDescGot().rate/2;
|
||||
for (int j=10; j<maxRate; j*=10) {
|
||||
for (int i=1; i<10; i++) {
|
||||
freq = i*j;
|
||||
if (freq>maxRate) break;
|
||||
spectrum.frequencies.push_back((int)freq);
|
||||
}
|
||||
if (freq>maxRate) break;
|
||||
}
|
||||
if (spectrum.running) logV("spectrum ready!");
|
||||
}
|
||||
if (spectrum.running) {
|
||||
for (int z=spectrum.mono?0:(chans-1); z>=0; z--) {
|
||||
// get buffer
|
||||
memset(spectrum.in, 0, sizeof(double)*spectrum.bins);
|
||||
int needle=e->oscReadPos-spectrum.bins;
|
||||
|
||||
for (int j=0; j<spectrum.bins; j++) {
|
||||
int pos=(needle+j)&0x7fff;
|
||||
double sample=0.0;
|
||||
if (spectrum.mono) {
|
||||
for (int i=0; i<chans; i++) {
|
||||
sample+=e->oscBuf[i][pos];
|
||||
}
|
||||
sample/=chans;
|
||||
} else {
|
||||
sample+=e->oscBuf[z][pos];
|
||||
}
|
||||
spectrum.in[j]=sample*(0.5*(1.0-cos(2.0*M_PI*j/(spectrum.bins-1))));
|
||||
}
|
||||
fftw_execute(spectrum.plan);
|
||||
unsigned int count=0;
|
||||
float mag=0.0f, x=0.0f, y=0.0f;
|
||||
count=spectrum.bins/2;
|
||||
for (unsigned int i=0; i<count; i++) {
|
||||
x=spectrum.xZoom*size.x*(scaleFuncLog((float)i/count)-spectrum.xOffset);
|
||||
mag=2.0f*sqrt(spectrum.buffer[i][0]*spectrum.buffer[i][0]+spectrum.buffer[i][1]*spectrum.buffer[i][1])/count;
|
||||
y=1.0-scaleFuncDb(mag);
|
||||
spectrum.plot[i].x=origin.x+x;
|
||||
spectrum.plot[i].y=origin.y+size.y*(y-spectrum.yOffset);
|
||||
}
|
||||
ImGui::PushClipRect(origin, origin+size, true);
|
||||
dl->AddPolyline(spectrum.plot, count, ImGui::GetColorU32(uiColors[spectrum.mono?GUI_COLOR_OSC_WAVE:GUI_COLOR_OSC_WAVE_CH0+z]), 0, 1.0f);
|
||||
dl->PathFillConcave(ImGui::GetColorU32(uiColors[spectrum.mono?GUI_COLOR_OSC_WAVE:GUI_COLOR_OSC_WAVE_CH0+z]));
|
||||
ImGui::PopClipRect();
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsWindowHovered()) {
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowSize().x-ImGui::GetStyle().ItemSpacing.x-ImGui::CalcTextSize(ICON_FA_BARS).x);
|
||||
ImGui::TextUnformatted(ICON_FA_BARS "##spectrumSettings");
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("spectrumSettingsPopup",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
ImGui::Checkbox(_("Mono##spec"), &spectrum.mono);
|
||||
if (ImGui::InputScalar("Bins",ImGuiDataType_U32,&spectrum.bins)) {
|
||||
if (spectrum.bins<32) spectrum.bins=32;
|
||||
if (spectrum.bins>32768) spectrum.bins=32768;
|
||||
spectrum.update=true;
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::SliderFloat("X Zoom", &spectrum.xZoom, 1.0f, 10.0f)) {
|
||||
if (spectrum.xZoom<1.0f) spectrum.xZoom=1.0f;
|
||||
if (spectrum.xZoom>10.0f) spectrum.xZoom=10.0f;
|
||||
}
|
||||
if (ImGui::SliderFloat("X Offset", &spectrum.xOffset, 0.0f, 1.0f)) {
|
||||
if (spectrum.xOffset<0.0f) spectrum.xOffset=0.0f;
|
||||
if (spectrum.xOffset>1.0f) spectrum.xOffset=1.0f;
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::SliderFloat("Y Offset", &spectrum.yOffset, 0.0f, 1.0f)) {
|
||||
if (spectrum.yOffset<0.0f) spectrum.yOffset=0.0f;
|
||||
if (spectrum.yOffset>1.0f) spectrum.yOffset=1.0f;
|
||||
}
|
||||
ImGui::Separator();
|
||||
ImGui::Checkbox(_("Show X Grid"), &spectrum.showXGrid);
|
||||
ImGui::Checkbox(_("Show Y Grid"), &spectrum.showYGrid);
|
||||
ImGui::Checkbox(_("Show X Scale"), &spectrum.showXScale);
|
||||
ImGui::Checkbox(_("Show Y Scale"), &spectrum.showYScale);
|
||||
}
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SPECTRUM;
|
||||
ImGui::End();
|
||||
}
|
||||
|
|
@ -19,22 +19,22 @@
|
|||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include "gui.h"
|
||||
#include "guiConst.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "misc/cpp/imgui_stdlib.h"
|
||||
|
||||
#define FURNACE_TUNER_FFT_SIZE 8192
|
||||
#define FURNACE_TUNER_FFT_SIZE 16384
|
||||
|
||||
void FurnaceGUI::drawTuner() {
|
||||
if (nextWindow == GUI_WINDOW_TUNER) {
|
||||
tunerOpen = true;
|
||||
if (nextWindow==GUI_WINDOW_TUNER) {
|
||||
tunerOpen=true;
|
||||
ImGui::SetNextWindowFocus();
|
||||
nextWindow = GUI_WINDOW_NOTHING;
|
||||
nextWindow=GUI_WINDOW_NOTHING;
|
||||
}
|
||||
if (!tunerOpen) return;
|
||||
if (ImGui::Begin("Tuner", &tunerOpen, globalWinFlags, _("Tuner"))) {
|
||||
|
||||
//fft buffer
|
||||
if (ImGui::Begin("Tuner",&tunerOpen,globalWinFlags,_("Tuner"))) {
|
||||
// fft buffer
|
||||
if (!tunerFFTInBuf) tunerFFTInBuf=new double[FURNACE_TUNER_FFT_SIZE];
|
||||
if (!tunerFFTOutBuf) tunerFFTOutBuf=(fftw_complex*)fftw_malloc(sizeof(fftw_complex)*FURNACE_TUNER_FFT_SIZE);
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ void FurnaceGUI::drawTuner() {
|
|||
int needle=e->oscReadPos;
|
||||
|
||||
for (int j=0; j<FURNACE_TUNER_FFT_SIZE; j++) {
|
||||
int pos=(needle-FURNACE_TUNER_FFT_SIZE+j) & 0x7fff;
|
||||
int pos=(needle-FURNACE_TUNER_FFT_SIZE+j)&0x7fff;
|
||||
double sample=0.0;
|
||||
for (int ch=0; ch<chans; ch++) {
|
||||
sample+=e->oscBuf[ch][pos];
|
||||
|
|
@ -59,95 +59,118 @@ void FurnaceGUI::drawTuner() {
|
|||
fftw_execute(tunerPlan);
|
||||
|
||||
std::vector<double> mag(FURNACE_TUNER_FFT_SIZE/2);
|
||||
for (int k=0; k < FURNACE_TUNER_FFT_SIZE / 2; k++) {
|
||||
mag[0]=0;mag[1]=0;mag[2]=0;mag[3]=0; // skip some of the low frequencies
|
||||
for (int k=4; k<FURNACE_TUNER_FFT_SIZE/2; k++) {
|
||||
mag[k]=sqrt(tunerFFTOutBuf[k][0]*tunerFFTOutBuf[k][0]+tunerFFTOutBuf[k][1]*tunerFFTOutBuf[k][1]);
|
||||
}
|
||||
|
||||
//harmonic product spectrum
|
||||
int harmonics=2;
|
||||
// harmonic product spectrum
|
||||
int harmonics=1; // disabled for now...
|
||||
for (int h=2; h<=harmonics; h++) {
|
||||
for (int k=0; k<FURNACE_TUNER_FFT_SIZE/(2*h); k++) {
|
||||
for (int k=8; k<FURNACE_TUNER_FFT_SIZE/(2*h); k++) {
|
||||
mag[k]*=mag[k*h];
|
||||
}
|
||||
}
|
||||
|
||||
//peak with interpolation
|
||||
int peakIndex = std::distance(mag.begin(), std::max_element(mag.begin(), mag.end()));
|
||||
double sampleRate = e->getAudioDescGot().rate;
|
||||
double sampleRate=e->getAudioDescGot().rate;
|
||||
// peak with interpolation
|
||||
int peakIndex=std::distance(mag.begin(),std::max_element(mag.begin(),mag.end()));
|
||||
|
||||
double freq = 0.0;
|
||||
if (peakIndex > 0 && peakIndex < (int)mag.size() - 1) {
|
||||
double alpha = mag[peakIndex - 1];
|
||||
double beta = mag[peakIndex];
|
||||
double gamma = mag[peakIndex + 1];
|
||||
double p = 0.5 * (alpha - gamma) / (alpha - 2.0 * beta + gamma);
|
||||
freq = (peakIndex + p) * (sampleRate / (double)FURNACE_TUNER_FFT_SIZE);
|
||||
}
|
||||
else {
|
||||
freq = (double)peakIndex * (sampleRate / (double)FURNACE_TUNER_FFT_SIZE);
|
||||
double freq=0.0;
|
||||
if (peakIndex>0 && peakIndex<(int)mag.size()-1) {
|
||||
double alpha=mag[peakIndex-1];
|
||||
double beta=mag[peakIndex];
|
||||
double gamma=mag[peakIndex+1];
|
||||
double p=0.5*(alpha-gamma)/(alpha-2.0*beta+gamma);
|
||||
freq=(peakIndex+p)*(sampleRate/(double)FURNACE_TUNER_FFT_SIZE);
|
||||
} else {
|
||||
freq=(double)peakIndex*(sampleRate/(double)FURNACE_TUNER_FFT_SIZE);
|
||||
}
|
||||
|
||||
|
||||
//tuning formulas
|
||||
double noteExact=0;
|
||||
// tuning formulas
|
||||
double noteExact=0.0;
|
||||
int noteRounded=0;
|
||||
double cents=0.0f;
|
||||
if (freq > 0 && freq < 5000.0) {
|
||||
noteExact=CLAMP(log2(freq / e->song.tuning) * 12.0 + 117.0,0,180);
|
||||
String noteText="---", subtext="";
|
||||
if (freq>0 && freq<5000.0) {
|
||||
noteExact=CLAMP(log2(freq/e->song.tuning)*12.0+117.0,0,180);
|
||||
noteRounded=round(noteExact);
|
||||
cents=noteExact-noteRounded;
|
||||
cents=(noteExact-noteRounded);
|
||||
noteText=fmt::sprintf("%s",noteName(noteRounded));
|
||||
subtext=fmt::sprintf("%3.3f Hz %dc", freq, (int)(cents*100.0f));
|
||||
}
|
||||
String noteText=fmt::sprintf("%s",(freq > 0 && freq < 5000.0)?noteName(noteExact):"---");
|
||||
ImGui::Text("Note: %s", noteText.c_str());
|
||||
ImGui::Text("Freq: %f Hz", freq);
|
||||
ImGui::Text("Cents: %f ", cents*100.0f);
|
||||
|
||||
{
|
||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||
ImVec2 origin=ImGui::GetWindowPos();
|
||||
ImVec2 size=ImGui::GetWindowSize();
|
||||
float titleBar = ImGui::GetCurrentWindow()->TitleBarHeight;
|
||||
float titleBar=ImGui::GetCurrentWindow()->TitleBarHeight;
|
||||
origin.y+=titleBar;
|
||||
size.y-=titleBar;
|
||||
// debug stuff
|
||||
ImVec2* plot=new ImVec2[FURNACE_TUNER_FFT_SIZE];
|
||||
for (size_t i=0; i<FURNACE_TUNER_FFT_SIZE; i++) {
|
||||
plot[i].x=origin.x+size.x*((float)i/FURNACE_TUNER_FFT_SIZE);
|
||||
plot[i].y=origin.y+size.y-size.y*(tunerFFTInBuf[i]+1.0f)/2.0f;
|
||||
}
|
||||
dl->AddPolyline(plot, FURNACE_TUNER_FFT_SIZE, 0xff00ff00, 0, 1.0f);
|
||||
for (size_t i=0; i<mag.size(); i++) {
|
||||
plot[i].x=origin.x+size.x*((float)i/mag.size());
|
||||
plot[i].y=origin.y+size.y-size.y*mag[i]/FURNACE_TUNER_FFT_SIZE;
|
||||
}
|
||||
dl->AddPolyline(plot, mag.size(), 0xffffffff, 0, 1.0f);
|
||||
delete[] plot;
|
||||
ImVec2 needleCenter=origin+ImVec2(size.x/2,size.y/4*3);
|
||||
float needleLength = (size.x/2)*0.9f;
|
||||
const float halfSpan=0.7; // radians
|
||||
const float trim=.2;
|
||||
float angle=cents*halfSpan;
|
||||
ImVec2 needleTip = needleCenter + ImVec2(
|
||||
needleLength*sin(angle),
|
||||
-needleLength*cos(angle)
|
||||
);
|
||||
// ImVec2* plot=new ImVec2[FURNACE_TUNER_FFT_SIZE];
|
||||
// for (size_t i=0; i<FURNACE_TUNER_FFT_SIZE; i++) {
|
||||
// plot[i].x=origin.x+size.x*(float)i/FURNACE_TUNER_FFT_SIZE;
|
||||
// plot[i].y=origin.y+size.y-size.y*(tunerFFTInBuf[i]+1.0f)/2.0f;
|
||||
// }
|
||||
// dl->AddPolyline(plot, FURNACE_TUNER_FFT_SIZE, 0xff00ff00, 0, 1.0f);
|
||||
// for (size_t i=0; i<mag.size(); i++) {
|
||||
// plot[i].x=origin.x+size.x*scaleFuncLog((float)i/mag.size());
|
||||
// plot[i].y=origin.y+size.y-size.y*(mag[i]/FURNACE_TUNER_FFT_SIZE);
|
||||
// }
|
||||
// dl->AddPolyline(plot, mag.size(), 0xffffffff, 0, 1.0f);
|
||||
// dl->AddLine(origin+ImVec2(size.x*scaleFuncLog((double)peakIndex/(mag.size()-1)),0),origin+ImVec2(size.x*scaleFuncLog((double)peakIndex/(mag.size()-1)),size.y), 0xff000fff);
|
||||
// delete[] plot;
|
||||
const float boxHeight=20.0f*dpiScale;
|
||||
const float needleHeight=18.0f*dpiScale;
|
||||
ImU32 lowColor=ImGui::GetColorU32(uiColors[GUI_COLOR_TUNER_SCALE_LOW]);
|
||||
ImU32 highColor=ImGui::GetColorU32(uiColors[GUI_COLOR_TUNER_SCALE_HIGH]);
|
||||
|
||||
ImGui::Dummy(ImVec2(size.x,boxHeight));
|
||||
dl->AddRectFilledMultiColor(origin,origin+ImVec2(size.x/2.0f,boxHeight),highColor,lowColor,lowColor,highColor);
|
||||
dl->AddRectFilledMultiColor(origin+ImVec2(size.x/2.0f,0),origin+ImVec2(size.x,boxHeight),lowColor,highColor,highColor,lowColor);
|
||||
dl->AddLine(origin+ImVec2(size.x/2.0f,0),origin+ImVec2(size.x/2.0f,boxHeight),ImGui::GetColorU32(uiColors[GUI_COLOR_TUNER_NEEDLE]),2.0f*dpiScale);
|
||||
|
||||
float needleX=size.x*(0.5f+cents);
|
||||
dl->AddLine(origin+ImVec2(needleX, boxHeight-needleHeight),origin+ImVec2(needleX,needleHeight),ImGui::GetColorU32(uiColors[GUI_COLOR_TUNER_NEEDLE]),4.0f*dpiScale);
|
||||
// text
|
||||
ImGui::PushFont(bigFont);
|
||||
ImVec2 textSize=ImGui::CalcTextSize(noteText.c_str());
|
||||
dl->AddText(needleCenter-ImVec2(textSize.x/2.0f,textSize.y/2.0f),ImGui::ColorConvertFloat4ToU32(uiColors[GUI_COLOR_TEXT]),noteText.c_str());
|
||||
ImGui::SetCursorPosX((size.x-textSize.x)/2.0f);
|
||||
ImGui::TextUnformatted(noteText.c_str());
|
||||
ImGui::PopFont();
|
||||
// needle
|
||||
needleCenter = needleCenter+ImVec2(
|
||||
needleLength*sin(angle)*trim,
|
||||
-needleLength*cos(angle)*trim
|
||||
);
|
||||
|
||||
dl->AddLine(needleCenter, needleTip, 0xff00ffff, 2.0f);
|
||||
textSize=ImGui::CalcTextSize(subtext.c_str());
|
||||
ImGui::SetCursorPosX((size.x-textSize.x)/2.0f);
|
||||
ImGui::TextUnformatted(subtext.c_str());
|
||||
// piano
|
||||
int noteMod=noteRounded%12;
|
||||
ImVec2 pianoPos=ImGui::GetCursorScreenPos();
|
||||
pianoPos.x=ImGui::GetWindowPos().x;
|
||||
ImVec2 pianoSize=ImVec2(ImGui::GetWindowSize().x,40.0f);
|
||||
float keySize=pianoSize.x/7.0f;
|
||||
for (int i=0; i<7; i++) {
|
||||
dl->AddRectFilled(
|
||||
pianoPos+ImVec2(keySize*i,0),
|
||||
pianoPos+ImVec2(keySize*(i+1),pianoSize.y),
|
||||
ImGui::GetColorU32(uiColors[bottomKeyNotes[i]==noteMod?GUI_COLOR_PIANO_KEY_BOTTOM_HIT:GUI_COLOR_PIANO_KEY_BOTTOM]));
|
||||
dl->AddLine(
|
||||
pianoPos+ImVec2(keySize*i,0),
|
||||
pianoPos+ImVec2(keySize*i,pianoSize.y),
|
||||
ImGui::GetColorU32(uiColors[GUI_COLOR_PIANO_BACKGROUND]),
|
||||
dpiScale);
|
||||
}
|
||||
for (int i=0; i<5; i++) {
|
||||
dl->AddRectFilled(
|
||||
pianoPos+ImVec2(pianoSize.x*topKeyStarts[i]-keySize/3.0f,0),
|
||||
pianoPos+ImVec2(pianoSize.x*topKeyStarts[i]+keySize/3.0f,2.0f*pianoSize.y/3.0f),
|
||||
ImGui::GetColorU32(uiColors[topKeyNotes[i]==noteMod?GUI_COLOR_PIANO_KEY_TOP_HIT:GUI_COLOR_PIANO_KEY_TOP]));
|
||||
}
|
||||
ImGui::Dummy(pianoSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
|
||||
curWindow = GUI_WINDOW_TUNER;
|
||||
curWindow=GUI_WINDOW_TUNER;
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue