diff --git a/modules/radio/src/main.cpp b/modules/radio/src/main.cpp index 29caf395..61e091c9 100644 --- a/modules/radio/src/main.cpp +++ b/modules/radio/src/main.cpp @@ -3,13 +3,18 @@ #include #include -#define CONCAT(a, b) ((std::string(a) + b).c_str()) +#define CONCAT(a, b) ((std::string(a) + b).c_str()) +#define DEEMP_LIST "50µS\00075µS\000none\000" mod::API_t* API; struct RadioContext_t { std::string name; int demod = 1; + int deemp = 0; + int bandWidth; + int bandWidthMin; + int bandWidthMax; SigPath sigPath; }; @@ -17,6 +22,9 @@ MOD_EXPORT void* _INIT_(mod::API_t* _API, ImGuiContext* imctx, std::string _name API = _API; RadioContext_t* ctx = new RadioContext_t; ctx->name = _name; + ctx->bandWidth = 200000; + ctx->bandWidthMin = 100000; + ctx->bandWidthMax = 200000; ctx->sigPath.init(_name, 200000, 1000, API->registerVFO(_name, mod::API_t::REF_CENTER, 0, 200000, 200000, 1000)); ctx->sigPath.start(); ImGui::SetCurrentContext(imctx); @@ -28,41 +36,63 @@ MOD_EXPORT void _NEW_FRAME_(RadioContext_t* ctx) { } MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) { + float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); + ImGui::BeginGroup(); + // TODO: Change VFO ref in signal path + ImGui::Columns(4, CONCAT("RadioModeColumns##_", ctx->name), false); if (ImGui::RadioButton(CONCAT("NFM##_", ctx->name), ctx->demod == 0) && ctx->demod != 0) { - ctx->sigPath.setDemodulator(SigPath::DEMOD_NFM); - ctx->demod = 0; + ctx->demod = 0; + ctx->bandWidth = 16000; + ctx->bandWidthMin = 8000; + ctx->bandWidthMax = 16000; + ctx->sigPath.setDemodulator(SigPath::DEMOD_NFM, ctx->bandWidth); API->setVFOReference(ctx->name, mod::API_t::REF_CENTER); } - if (ImGui::RadioButton(CONCAT("WFM##_", ctx->name), ctx->demod == 1) && ctx->demod != 1) { - ctx->sigPath.setDemodulator(SigPath::DEMOD_FM); - ctx->demod = 1; + if (ImGui::RadioButton(CONCAT("WFM##_", ctx->name), ctx->demod == 1) && ctx->demod != 1) { + ctx->demod = 1; + ctx->bandWidth = 200000; + ctx->bandWidthMin = 100000; + ctx->bandWidthMax = 200000; + ctx->sigPath.setDemodulator(SigPath::DEMOD_FM, ctx->bandWidth); API->setVFOReference(ctx->name, mod::API_t::REF_CENTER); } ImGui::NextColumn(); - if (ImGui::RadioButton(CONCAT("AM##_", ctx->name), ctx->demod == 2) && ctx->demod != 2) { - ctx->sigPath.setDemodulator(SigPath::DEMOD_AM); - ctx->demod = 2; + if (ImGui::RadioButton(CONCAT("AM##_", ctx->name), ctx->demod == 2) && ctx->demod != 2) { + ctx->demod = 2; + ctx->bandWidth = 12500; + ctx->bandWidthMin = 6250; + ctx->bandWidthMax = 12500; + ctx->sigPath.setDemodulator(SigPath::DEMOD_AM, ctx->bandWidth); API->setVFOReference(ctx->name, mod::API_t::REF_CENTER); } - if (ImGui::RadioButton(CONCAT("DSB##_", ctx->name), ctx->demod == 3) && ctx->demod != 3) { - ctx->sigPath.setDemodulator(SigPath::DEMOD_DSB); - ctx->demod = 3; + if (ImGui::RadioButton(CONCAT("DSB##_", ctx->name), ctx->demod == 3) && ctx->demod != 3) { + ctx->demod = 3; + ctx->bandWidth = 6000; + ctx->bandWidthMin = 3000; + ctx->bandWidthMax = 6000; + ctx->sigPath.setDemodulator(SigPath::DEMOD_DSB, ctx->bandWidth); API->setVFOReference(ctx->name, mod::API_t::REF_CENTER); } ImGui::NextColumn(); - if (ImGui::RadioButton(CONCAT("USB##_", ctx->name), ctx->demod == 4) && ctx->demod != 4) { - ctx->sigPath.setDemodulator(SigPath::DEMOD_USB); - ctx->demod = 4; + if (ImGui::RadioButton(CONCAT("USB##_", ctx->name), ctx->demod == 4) && ctx->demod != 4) { + ctx->demod = 4; + ctx->bandWidth = 3000; + ctx->bandWidthMin = 1500; + ctx->bandWidthMax = 3000; + ctx->sigPath.setDemodulator(SigPath::DEMOD_USB, ctx->bandWidth); API->setVFOReference(ctx->name, mod::API_t::REF_LOWER); } if (ImGui::RadioButton(CONCAT("CW##_", ctx->name), ctx->demod == 5) && ctx->demod != 5) { ctx->demod = 5; }; ImGui::NextColumn(); if (ImGui::RadioButton(CONCAT("LSB##_", ctx->name), ctx->demod == 6) && ctx->demod != 6) { - ctx->sigPath.setDemodulator(SigPath::DEMOD_LSB); ctx->demod = 6; + ctx->bandWidth = 3000; + ctx->bandWidthMin = 1500; + ctx->bandWidthMax = 3000; + ctx->sigPath.setDemodulator(SigPath::DEMOD_LSB, ctx->bandWidth); API->setVFOReference(ctx->name, mod::API_t::REF_UPPER); } if (ImGui::RadioButton(CONCAT("RAW##_", ctx->name), ctx->demod == 7) && ctx->demod != 7) { ctx->demod = 7; }; @@ -70,7 +100,22 @@ MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) { ImGui::EndGroup(); - ImGui::Checkbox(CONCAT("Deemphasis##_", ctx->name), &ctx->sigPath.deemp.bypass); + ImGui::Text("WFM Deemphasis"); + ImGui::SameLine(); + ImGui::PushItemWidth(menuColumnWidth - ImGui::GetCursorPosX()); + if (ImGui::Combo(CONCAT("##_deemp_select_", ctx->name), &ctx->deemp, DEEMP_LIST)) { + ctx->sigPath.setDeemphasis(ctx->deemp); + } + ImGui::PopItemWidth(); + + ImGui::Text("Bandwidth"); + ImGui::SameLine(); + ImGui::PushItemWidth(menuColumnWidth - ImGui::GetCursorPosX()); + if (ImGui::InputInt(CONCAT("##_bw_select_", ctx->name), &ctx->bandWidth, 100, 1000)) { + ctx->bandWidth = std::clamp(ctx->bandWidth, ctx->bandWidthMin, ctx->bandWidthMax); + ctx->sigPath.setBandwidth(ctx->bandWidth); + } + ImGui::PopItemWidth(); } MOD_EXPORT void _HANDLE_EVENT_(RadioContext_t* ctx, int eventId) { diff --git a/modules/radio/src/path.cpp b/modules/radio/src/path.cpp index 2dbb99b2..4338980b 100644 --- a/modules/radio/src/path.cpp +++ b/modules/radio/src/path.cpp @@ -10,7 +10,6 @@ int SigPath::sampleRateChangeHandler(void* ctx, float sampleRate) { _this->audioResamp.stop(); _this->deemp.stop(); float bw = std::min(_this->bandwidth, sampleRate / 2.0f); - spdlog::warn("New bandwidth: {0}", bw); _this->audioResamp.setOutputSampleRate(sampleRate, bw, bw); _this->deemp.setBlockSize(_this->audioResamp.getOutputBlockSize()); _this->deemp.setSamplerate(sampleRate); @@ -25,6 +24,7 @@ void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize, dsp: this->vfoName = vfoName; _demod = DEMOD_FM; + _deemp = DEEMP_50US; bandwidth = 200000; // TODO: Set default VFO options @@ -38,17 +38,17 @@ void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize, dsp: outputSampleRate = API->registerMonoStream(&deemp.output, vfoName, vfoName, sampleRateChangeHandler, this); API->setBlockSize(vfoName, audioResamp.getOutputBlockSize()); - setDemodulator(_demod); + setDemodulator(_demod, bandwidth); } void SigPath::setSampleRate(float sampleRate) { this->sampleRate = sampleRate; // Reset the demodulator and audio systems - setDemodulator(_demod); + setDemodulator(_demod, bandwidth); } -void SigPath::setDemodulator(int demId) { +void SigPath::setDemodulator(int demId, float bandWidth) { if (demId < 0 || demId >= _DEMOD_COUNT) { return; } @@ -56,6 +56,8 @@ void SigPath::setDemodulator(int demId) { audioResamp.stop(); deemp.stop(); + bandwidth = bandWidth; + // Stop current demodulator if (_demod == DEMOD_FM) { demod.stop(); @@ -72,76 +74,80 @@ void SigPath::setDemodulator(int demId) { else if (_demod == DEMOD_LSB) { ssbDemod.stop(); } + else if (_demod == DEMOD_DSB) { + ssbDemod.stop(); + } + else { + spdlog::error("UNIMPLEMENTED DEMODULATOR IN SigPath::setDemodulator (stop)"); + } _demod = demId; // Set input of the audio resampler + // TODO: Set bandwidth from argument if (demId == DEMOD_FM) { - API->setVFOSampleRate(vfoName, 200000, 200000); - bandwidth = 15000; + API->setVFOSampleRate(vfoName, 200000, bandwidth); demod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); demod.setSampleRate(200000); - demod.setDeviation(100000); + demod.setDeviation(bandwidth / 2.0f); audioResamp.setInput(&demod.output); - float audioBw = std::min(bandwidth, outputSampleRate / 2.0f); + audioBw = std::min(bandwidth, outputSampleRate / 2.0f); audioResamp.setInputSampleRate(200000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); - deemp.bypass = false; + deemp.bypass = (_deemp == DEEMP_NONE); demod.start(); } if (demId == DEMOD_NFM) { - API->setVFOSampleRate(vfoName, 16000, 16000); - bandwidth = 8000; + API->setVFOSampleRate(vfoName, 16000, bandwidth); demod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); demod.setSampleRate(16000); - demod.setDeviation(8000); + demod.setDeviation(bandwidth / 2.0f); audioResamp.setInput(&demod.output); - float audioBw = std::min(bandwidth, outputSampleRate / 2.0f); + audioBw = std::min(bandwidth, outputSampleRate / 2.0f); audioResamp.setInputSampleRate(16000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); deemp.bypass = true; demod.start(); } else if (demId == DEMOD_AM) { - API->setVFOSampleRate(vfoName, 12500, 12500); - bandwidth = 6250; + API->setVFOSampleRate(vfoName, 12500, bandwidth); amDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); audioResamp.setInput(&amDemod.output); - float audioBw = std::min(bandwidth, outputSampleRate / 2.0f); + audioBw = std::min(bandwidth, outputSampleRate / 2.0f); audioResamp.setInputSampleRate(12500, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); deemp.bypass = true; amDemod.start(); } else if (demId == DEMOD_USB) { - API->setVFOSampleRate(vfoName, 6000, 3000); - bandwidth = 3000; + API->setVFOSampleRate(vfoName, 6000, bandwidth); ssbDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); ssbDemod.setMode(dsp::SSBDemod::MODE_USB); audioResamp.setInput(&ssbDemod.output); - float audioBw = std::min(bandwidth, outputSampleRate / 2.0f); + audioBw = std::min(bandwidth, outputSampleRate / 2.0f); audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); deemp.bypass = true; ssbDemod.start(); } else if (demId == DEMOD_LSB) { - API->setVFOSampleRate(vfoName, 6000, 3000); - bandwidth = 3000; + API->setVFOSampleRate(vfoName, 6000, bandwidth); ssbDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); ssbDemod.setMode(dsp::SSBDemod::MODE_LSB); audioResamp.setInput(&ssbDemod.output); - float audioBw = std::min(bandwidth, outputSampleRate / 2.0f); + audioBw = std::min(bandwidth, outputSampleRate / 2.0f); audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); deemp.bypass = true; ssbDemod.start(); } else if (demId == DEMOD_DSB) { - API->setVFOSampleRate(vfoName, 6000, 6000); - bandwidth = 3000; + API->setVFOSampleRate(vfoName, 6000, bandwidth); ssbDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); ssbDemod.setMode(dsp::SSBDemod::MODE_DSB); audioResamp.setInput(&ssbDemod.output); - float audioBw = std::min(bandwidth, outputSampleRate / 2.0f); + audioBw = std::min(bandwidth, outputSampleRate / 2.0f); audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); deemp.bypass = true; ssbDemod.start(); } + else { + spdlog::error("UNIMPLEMENTED DEMODULATOR IN SigPath::setDemodulator (start)"); + } deemp.setBlockSize(audioResamp.getOutputBlockSize()); @@ -150,7 +156,67 @@ void SigPath::setDemodulator(int demId) { } void SigPath::updateBlockSize() { - setDemodulator(_demod); + setDemodulator(_demod, bandwidth); +} + +void SigPath::setDeemphasis(int deemph) { + _deemp = deemph; + deemp.stop(); + if (_deemp == DEEMP_NONE) { + deemp.bypass = true; + } + else if (_deemp == DEEMP_50US) { + deemp.bypass = false; + deemp.setTau(50e-6); + } + else if (_deemp == DEEMP_75US) { + deemp.bypass = false; + deemp.setTau(75e-6); + } + deemp.start(); +} + +void SigPath::setBandwidth(float bandWidth) { + bandwidth = bandWidth; + API->setVFOBandwidth(vfoName, bandwidth); + if (_demod == DEMOD_FM) { + demod.stop(); + demod.setDeviation(bandwidth / 2.0f); + demod.start(); + } + else if (_demod == DEMOD_NFM) { + demod.stop(); + demod.setDeviation(bandwidth / 2.0f); + demod.start(); + } + else if (_demod == DEMOD_AM) { + // Notbing to change + } + else if (_demod == DEMOD_USB) { + ssbDemod.stop(); + ssbDemod.setBandwidth(bandwidth); + ssbDemod.start(); + } + else if (_demod == DEMOD_LSB) { + ssbDemod.stop(); + ssbDemod.setBandwidth(bandwidth); + ssbDemod.start(); + } + else if (_demod == DEMOD_DSB) { + ssbDemod.stop(); + ssbDemod.setBandwidth(bandwidth); + ssbDemod.start(); + } + else { + spdlog::error("UNIMPLEMENTED DEMODULATOR IN SigPath::setBandwidth"); + } + float _audioBw = std::min(bandwidth, outputSampleRate / 2.0f); + if (audioBw != _audioBw) { + audioBw = _audioBw; + audioResamp.stop(); + audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); + audioResamp.start(); + } } void SigPath::start() { diff --git a/modules/radio/src/path.h b/modules/radio/src/path.h index f28f32e2..cac98247 100644 --- a/modules/radio/src/path.h +++ b/modules/radio/src/path.h @@ -17,12 +17,11 @@ public: void init(std::string vfoName, uint64_t sampleRate, int blockSize, dsp::stream* input); void start(); void setSampleRate(float sampleRate); - void setVFOFrequency(uint64_t frequency); - void updateBlockSize(); - - void setDemodulator(int demod); + void setDemodulator(int demod, float bandWidth); + void setDeemphasis(int deemph); + void setBandwidth(float bandWidth); enum { DEMOD_FM, @@ -34,6 +33,14 @@ public: _DEMOD_COUNT }; + enum { + DEEMP_50US, + DEEMP_75US, + DEEMP_NONE, + _DEEMP_COUNT + }; + + dsp::FMDeemphasis deemp; private: @@ -56,4 +63,6 @@ private: float outputSampleRate; int blockSize; int _demod; + int _deemp; + float audioBw; }; \ No newline at end of file diff --git a/modules/recorder/src/main.cpp b/modules/recorder/src/main.cpp index 950620ea..3bd4655b 100644 --- a/modules/recorder/src/main.cpp +++ b/modules/recorder/src/main.cpp @@ -106,7 +106,7 @@ MOD_EXPORT void _DRAW_MENU_(RecorderContext_t* ctx) { ImGui::PushItemWidth(menuColumnWidth); if (!ctx->recording) { if (ImGui::Combo(CONCAT("##_strea_select_", ctx->name), &ctx->selectedStreamId, nameList.c_str())) { - ctx->selectedStreamName = nameList[ctx->selectedStreamId]; + ctx->selectedStreamName = streamNames[ctx->selectedStreamId]; } } else { diff --git a/res/icons/menu.png b/res/icons/menu.png new file mode 100644 index 00000000..317cfdee Binary files /dev/null and b/res/icons/menu.png differ diff --git a/res/icons/menu_raw.png b/res/icons/menu_raw.png new file mode 100644 index 00000000..f1c132e0 Binary files /dev/null and b/res/icons/menu_raw.png differ diff --git a/src/audio.cpp b/src/audio.cpp index 65eb3c45..18acf105 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -77,16 +77,12 @@ namespace audio { return; } if (astr->type == STREAM_TYPE_MONO) { - spdlog::warn("=> Stopping monoDynSplit"); astr->monoDynSplit->stop(); } else { - spdlog::warn("=> Stopping stereoDynSplit"); astr->stereoDynSplit->stop(); } - spdlog::warn("=> Stopping audio"); astr->audio->stop(); - spdlog::warn("=> Done"); astr->running = false; } diff --git a/src/dsp/demodulator.h b/src/dsp/demodulator.h index 7d5f4353..5c865590 100644 --- a/src/dsp/demodulator.h +++ b/src/dsp/demodulator.h @@ -265,6 +265,16 @@ namespace dsp { } } + void setBandwidth(float bandwidth) { + _bandWidth = bandwidth; + if (_mode == MODE_USB) { + lo.setFrequency(_bandWidth / 2.0f); + } + else if (_mode == MODE_LSB) { + lo.setFrequency(-_bandWidth / 2.0f); + } + } + stream output; enum { diff --git a/src/dsp/filter.h b/src/dsp/filter.h index eab22535..52eda276 100644 --- a/src/dsp/filter.h +++ b/src/dsp/filter.h @@ -25,8 +25,9 @@ namespace dsp { if (_M % 2 == 0) { _M++; } float M = _M; float sum = 0.0f; + float val; for (int i = 0; i < _M; i++) { - float val = (sin(2.0f * M_PI * fc * ((float)i - (M / 2))) / ((float)i - (M / 2))) * (0.42f - (0.5f * cos(2.0f * M_PI / M)) + (0.8f * cos(4.0f * M_PI / M))); + val = (sin(2.0f * M_PI * fc * ((float)i - (M / 2))) / ((float)i - (M / 2))) * (0.42f - (0.5f * cos(2.0f * M_PI / M)) + (0.8f * cos(4.0f * M_PI / M))); taps.push_back(val); sum += val; } @@ -456,8 +457,6 @@ namespace dsp { float dt = 1.0f / _this->_sampleRate; float alpha = dt / (_this->_tau + dt); - spdlog::warn("Deemp filter started: {0}, {1}", _this->_tau * 1000000.0, _this->_sampleRate); - while (true) { if (_this->_in->read(inBuf, count) < 0) { break; }; if (_this->bypass) { diff --git a/src/frequency_select.cpp b/src/frequency_select.cpp index 2115a62c..fbbc3c4f 100644 --- a/src/frequency_select.cpp +++ b/src/frequency_select.cpp @@ -67,9 +67,10 @@ void FrequencySelect::draw() { window = ImGui::GetCurrentWindow(); widgetPos = ImGui::GetWindowContentRegionMin(); widgetEndPos = ImGui::GetWindowContentRegionMax(); - widgetPos.x += window->Pos.x + 255; + ImVec2 cursorPos = ImGui::GetCursorPos(); + widgetPos.x += window->Pos.x + cursorPos.x; widgetPos.y += window->Pos.y - 3; - widgetEndPos.x += window->Pos.x + 255; + widgetEndPos.x += window->Pos.x + cursorPos.x; widgetEndPos.y += window->Pos.y - 3; widgetSize = ImVec2(widgetEndPos.x - widgetPos.x, widgetEndPos.y - widgetPos.y); diff --git a/src/icons.cpp b/src/icons.cpp index 8d60fd6a..d1a93520 100644 --- a/src/icons.cpp +++ b/src/icons.cpp @@ -7,8 +7,7 @@ namespace icons { ImTextureID LOGO; ImTextureID PLAY; ImTextureID STOP; - ImTextureID PLAY_RAW; - ImTextureID STOP_RAW; + ImTextureID MENU; GLuint loadTexture(char* path) { int w,h,n; @@ -28,7 +27,6 @@ namespace icons { LOGO = (ImTextureID)loadTexture("res/icons/sdrpp.png"); PLAY = (ImTextureID)loadTexture("res/icons/play.png"); STOP = (ImTextureID)loadTexture("res/icons/stop.png"); - PLAY_RAW = (ImTextureID)loadTexture("res/icons/play_raw.png"); - STOP_RAW = (ImTextureID)loadTexture("res/icons/stop_raw.png"); + MENU = (ImTextureID)loadTexture("res/icons/menu.png"); } } \ No newline at end of file diff --git a/src/icons.h b/src/icons.h index 92dca23d..2f886d23 100644 --- a/src/icons.h +++ b/src/icons.h @@ -7,8 +7,7 @@ namespace icons { extern ImTextureID LOGO; extern ImTextureID PLAY; extern ImTextureID STOP; - extern ImTextureID PLAY_RAW; - extern ImTextureID STOP_RAW; + extern ImTextureID MENU; GLuint loadTexture(char* path); void load(); diff --git a/src/io/audio.h b/src/io/audio.h index d6c520ff..6527e45f 100644 --- a/src/io/audio.h +++ b/src/io/audio.h @@ -187,11 +187,8 @@ namespace io { else { _stereoInput->stopReader(); } - spdlog::warn("==> Pa_StopStream"); Pa_StopStream(stream); - spdlog::warn("==> Pa_CloseStream"); Pa_CloseStream(stream); - spdlog::warn("==> Done"); if (streamType == MONO) { _monoInput->clearReadStop(); } diff --git a/src/main.cpp b/src/main.cpp index 8d62635f..a77d9c1d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,6 +22,7 @@ #endif bool maximized = false; +bool fullScreen = false; static void glfw_error_callback(int error, const char* description) { spdlog::error("Glfw Error {0}: {1}", error, description); @@ -64,6 +65,7 @@ int main() { maximized = config::config["maximized"]; // Create window with graphics context + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); GLFWwindow* window = glfwCreateWindow(winWidth, winHeight, "SDR++ v" VERSION_STR " (Built at " __TIME__ ", " __DATE__ ")", NULL, NULL); if (window == NULL) return 1; @@ -135,6 +137,7 @@ int main() { spdlog::info("Ready."); bool _maximized = maximized; + int fsWidth, fsHeight, fsPosX, fsPosY; // Main loop while (!glfwWindowShouldClose(window)) { @@ -154,9 +157,27 @@ int main() { } } + + int _winWidth, _winHeight; glfwGetWindowSize(window, &_winWidth, &_winHeight); + if (ImGui::IsKeyPressed(GLFW_KEY_F11)) { + fullScreen = !fullScreen; + if (fullScreen) { + spdlog::info("Fullscreen: ON"); + fsWidth = _winWidth; + fsHeight = _winHeight; + glfwGetWindowPos(window, &fsPosX, &fsPosY); + const GLFWvidmode * mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); + glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, 0); + } + else { + spdlog::info("Fullscreen: OFF"); + glfwSetWindowMonitor(window, nullptr, fsPosX, fsPosY, fsWidth, fsHeight, 0); + } + } + if ((_winWidth != winWidth || _winHeight != winHeight) && !maximized && _winWidth > 0 && _winHeight > 0) { winWidth = _winWidth; winHeight = _winHeight; diff --git a/src/main_window.cpp b/src/main_window.cpp index 3dacf205..63d8f601 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -62,6 +62,7 @@ bool grabbingMenu = false; int newWidth = 300; bool showWaterfall = true; int fftHeight = 300; +bool showMenu = true; void saveCurrentSource() { int i = 0; @@ -227,7 +228,6 @@ void windowInit() { auto _bandplanIt = bandplan::bandplans.find(bandPlanName); if (_bandplanIt != bandplan::bandplans.end()) { bandplanId.val = std::distance(bandplan::bandplans.begin(), bandplan::bandplans.find(bandPlanName)); - spdlog::warn("{0} => {1}", bandplanId.val, bandPlanName); if (bandPlanEnabled.val) { wtf.bandplan = &bandplan::bandplans[bandPlanName]; @@ -444,6 +444,12 @@ void drawWindow() { } // To Bar + if (ImGui::ImageButton(icons::MENU, ImVec2(40, 40), ImVec2(0, 0), ImVec2(1, 1), 0)) { + showMenu = !showMenu; + } + + ImGui::SameLine(); + if (playing) { if (ImGui::ImageButton(icons::STOP, ImVec2(40, 40), ImVec2(0, 0), ImVec2(1, 1), 0)) { soapy.stop(); @@ -465,6 +471,8 @@ void drawWindow() { if (ImGui::SliderFloat("##_2_", volume, 0.0f, 1.0f, "")) { if (audioStreamName != "") { audio::streams[audioStreamName]->audio->setVolume(*volume); + config::config["audio"][audioStreamName]["volume"] = *volume; + config::configModified = true; } } @@ -514,224 +522,229 @@ void drawWindow() { config::configModified = true; } - ImGui::Columns(3, "WindowColumns", false); - ImGui::SetColumnWidth(0, menuWidth); - ImGui::SetColumnWidth(1, winSize.x - menuWidth - 60); - ImGui::SetColumnWidth(2, 60); - // Left Column - ImGui::BeginChild("Left Column"); - float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); - if (ImGui::CollapsingHeader("Source", ImGuiTreeNodeFlags_DefaultOpen)) { - if (playing) { style::beginDisabled(); }; + if (showMenu) { + ImGui::Columns(3, "WindowColumns", false); + ImGui::SetColumnWidth(0, menuWidth); + ImGui::SetColumnWidth(1, winSize.x - menuWidth - 60); + ImGui::SetColumnWidth(2, 60); + ImGui::BeginChild("Left Column"); + float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); - ImGui::PushItemWidth(menuColumnWidth); - if (ImGui::Combo("##_0_", &devId, soapy.txtDevList.c_str())) { - spdlog::info("Changed input device: {0}", devId); - sourceName = soapy.devNameList[devId]; - soapy.setDevice(soapy.devList[devId]); + if (ImGui::CollapsingHeader("Source", ImGuiTreeNodeFlags_DefaultOpen)) { + if (playing) { style::beginDisabled(); }; - if (config::config["sourceSettings"].contains(sourceName)) { - loadSourceConfig(sourceName); + ImGui::PushItemWidth(menuColumnWidth); + if (ImGui::Combo("##_0_", &devId, soapy.txtDevList.c_str())) { + spdlog::info("Changed input device: {0}", devId); + sourceName = soapy.devNameList[devId]; + soapy.setDevice(soapy.devList[devId]); + + if (config::config["sourceSettings"].contains(sourceName)) { + loadSourceConfig(sourceName); + } + else { + srId = 0; + sampleRate = soapy.getSampleRate(); + bw.val = sampleRate; + wtf.setBandwidth(sampleRate); + wtf.setViewBandwidth(sampleRate); + sigPath.setSampleRate(sampleRate); + + if (soapy.gainList.size() >= 0) { + delete[] uiGains; + uiGains = new float[soapy.gainList.size()]; + for (int i = 0; i < soapy.gainList.size(); i++) { + uiGains[i] = soapy.currentGains[i]; + } + } + } + setVFO(fSel.frequency); + config::config["source"] = sourceName; + config::configModified = true; } - else { - srId = 0; - sampleRate = soapy.getSampleRate(); - bw.val = sampleRate; + ImGui::PopItemWidth(); + + if (ImGui::Combo("##_1_", &srId, soapy.txtSampleRateList.c_str())) { + spdlog::info("Changed sample rate: {0}", srId); + sampleRate = soapy.sampleRates[srId]; + soapy.setSampleRate(sampleRate); wtf.setBandwidth(sampleRate); wtf.setViewBandwidth(sampleRate); sigPath.setSampleRate(sampleRate); + bw.val = sampleRate; - if (soapy.gainList.size() >= 0) { - delete[] uiGains; - uiGains = new float[soapy.gainList.size()]; - for (int i = 0; i < soapy.gainList.size(); i++) { - uiGains[i] = soapy.currentGains[i]; + if (!config::config["sourceSettings"].contains(sourceName)) { + saveCurrentSource(); + } + config::config["sourceSettings"][sourceName]["sampleRate"] = sampleRate; + config::configModified = true; + } + + ImGui::SameLine(); + bool noDevice = (soapy.devList.size() == 0); + if (ImGui::Button("Refresh", ImVec2(menuColumnWidth - ImGui::GetCursorPosX(), 0.0f))) { + soapy.refresh(); + if (noDevice && soapy.devList.size() > 0) { + sourceName = soapy.devNameList[0]; + soapy.setDevice(soapy.devList[0]); + if (config::config["sourceSettings"][sourceName]) { + loadSourceConfig(sourceName); } } } - setVFO(fSel.frequency); - config::config["source"] = sourceName; - config::configModified = true; - } - ImGui::PopItemWidth(); - if (ImGui::Combo("##_1_", &srId, soapy.txtSampleRateList.c_str())) { - spdlog::info("Changed sample rate: {0}", srId); - sampleRate = soapy.sampleRates[srId]; - soapy.setSampleRate(sampleRate); - wtf.setBandwidth(sampleRate); - wtf.setViewBandwidth(sampleRate); - sigPath.setSampleRate(sampleRate); - bw.val = sampleRate; + if (playing) { style::endDisabled(); }; - if (!config::config["sourceSettings"].contains(sourceName)) { - saveCurrentSource(); - } - config::config["sourceSettings"][sourceName]["sampleRate"] = sampleRate; - config::configModified = true; - } + float maxTextLength = 0; + float txtLen = 0; + char buf[100]; - ImGui::SameLine(); - bool noDevice = (soapy.devList.size() == 0); - if (ImGui::Button("Refresh", ImVec2(menuColumnWidth - ImGui::GetCursorPosX(), 0.0f))) { - soapy.refresh(); - if (noDevice && soapy.devList.size() > 0) { - sourceName = soapy.devNameList[0]; - soapy.setDevice(soapy.devList[0]); - if (config::config["sourceSettings"][sourceName]) { - loadSourceConfig(sourceName); + // Calculate the spacing + for (int i = 0; i < soapy.gainList.size(); i++) { + sprintf(buf, "%s gain", soapy.gainList[i].c_str()); + txtLen = ImGui::CalcTextSize(buf).x; + if (txtLen > maxTextLength) { + maxTextLength = txtLen; } } - } - if (playing) { style::endDisabled(); }; + for (int i = 0; i < soapy.gainList.size(); i++) { + ImGui::Text("%s gain", soapy.gainList[i].c_str()); + ImGui::SameLine(); + sprintf(buf, "##_gain_slide_%d_", i); - float maxTextLength = 0; - float txtLen = 0; - char buf[100]; - - // Calculate the spacing - for (int i = 0; i < soapy.gainList.size(); i++) { - sprintf(buf, "%s gain", soapy.gainList[i].c_str()); - txtLen = ImGui::CalcTextSize(buf).x; - if (txtLen > maxTextLength) { - maxTextLength = txtLen; + ImGui::SetCursorPosX(maxTextLength + 5); + ImGui::PushItemWidth(menuColumnWidth - (maxTextLength + 5)); + if (ImGui::SliderFloat(buf, &uiGains[i], soapy.gainRanges[i].minimum(), soapy.gainRanges[i].maximum())) { + soapy.setGain(i, uiGains[i]); + config::config["sourceSettings"][sourceName]["gains"][soapy.gainList[i]] = uiGains[i]; + config::configModified = true; + } + ImGui::PopItemWidth(); } - } - for (int i = 0; i < soapy.gainList.size(); i++) { - ImGui::Text("%s gain", soapy.gainList[i].c_str()); - ImGui::SameLine(); - sprintf(buf, "##_gain_slide_%d_", i); - - ImGui::SetCursorPosX(maxTextLength + 5); - ImGui::PushItemWidth(menuColumnWidth - (maxTextLength + 5)); - if (ImGui::SliderFloat(buf, &uiGains[i], soapy.gainRanges[i].minimum(), soapy.gainRanges[i].maximum())) { - soapy.setGain(i, uiGains[i]); - config::config["sourceSettings"][sourceName]["gains"][soapy.gainList[i]] = uiGains[i]; - config::configModified = true; - } - ImGui::PopItemWidth(); - } - - ImGui::Spacing(); - } - - for (int i = 0; i < modCount; i++) { - if (ImGui::CollapsingHeader(mod::moduleNames[i].c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - mod = mod::modules[mod::moduleNames[i]]; - mod._DRAW_MENU_(mod.ctx); ImGui::Spacing(); } - } - - if (ImGui::CollapsingHeader("Audio", ImGuiTreeNodeFlags_DefaultOpen)) { - int count = 0; - int maxCount = audio::streams.size(); - for (auto const& [name, stream] : audio::streams) { - int deviceId; - float vol = 1.0f; - deviceId = stream->audio->getDeviceId(); - - ImGui::SetCursorPosX((menuColumnWidth / 2.0f) - (ImGui::CalcTextSize(name.c_str()).x / 2.0f)); - ImGui::Text(name.c_str()); - - ImGui::PushItemWidth(menuColumnWidth); - bool running = stream->running; - if (ImGui::Combo(("##_audio_dev_0_"+ name).c_str(), &stream->deviceId, stream->audio->devTxtList.c_str())) { - spdlog::warn("Stopping audio stream"); - audio::stopStream(name); - spdlog::warn("Setting device"); - audio::setAudioDevice(name, stream->deviceId, stream->audio->devices[deviceId].sampleRates[0]); - if (running) { - spdlog::warn("Starting stream"); - audio::startStream(name); - } - stream->sampleRateId = 0; - spdlog::warn("Done, saving config"); - - // Create config if it doesn't exist - if (!config::config["audio"].contains(name)) { - config::config["audio"][name]["volume"] = stream->volume; - } - config::config["audio"][name]["device"] = stream->audio->deviceNames[stream->deviceId]; - config::config["audio"][name]["sampleRate"] = stream->audio->devices[stream->deviceId].sampleRates[0]; - config::configModified = true; - } - if (ImGui::Combo(("##_audio_sr_0_" + name).c_str(), &stream->sampleRateId, stream->audio->devices[deviceId].txtSampleRates.c_str())) { - audio::stopStream(name); - audio::setSampleRate(name, stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]); - if (running) { - audio::startStream(name); - } - - // Create config if it doesn't exist - if (!config::config["audio"].contains(name)) { - config::config["audio"][name]["volume"] = stream->volume; - config::config["audio"][name]["device"] = stream->audio->deviceNames[deviceId]; - } - config::config["audio"][name]["sampleRate"] = stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]; - config::configModified = true; - } - if (ImGui::SliderFloat(("##_audio_vol_0_" + name).c_str(), &stream->volume, 0.0f, 1.0f, "")) { - stream->audio->setVolume(stream->volume); - - // Create config if it doesn't exist - if (!config::config["audio"].contains(name)) { - config::config["audio"][name]["device"] = stream->audio->deviceNames[deviceId]; - config::config["audio"][name]["sampleRate"] = stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]; - } - config::config["audio"][name]["volume"] = stream->volume; - config::configModified = true; - } - ImGui::PopItemWidth(); - count++; - if (count < maxCount) { + for (int i = 0; i < modCount; i++) { + if (ImGui::CollapsingHeader(mod::moduleNames[i].c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + mod = mod::modules[mod::moduleNames[i]]; + mod._DRAW_MENU_(mod.ctx); + ImGui::Spacing(); + } + } + + + if (ImGui::CollapsingHeader("Audio", ImGuiTreeNodeFlags_DefaultOpen)) { + int count = 0; + int maxCount = audio::streams.size(); + for (auto const& [name, stream] : audio::streams) { + int deviceId; + float vol = 1.0f; + deviceId = stream->audio->getDeviceId(); + + ImGui::SetCursorPosX((menuColumnWidth / 2.0f) - (ImGui::CalcTextSize(name.c_str()).x / 2.0f)); + ImGui::Text(name.c_str()); + + ImGui::PushItemWidth(menuColumnWidth); + bool running = stream->running; + if (ImGui::Combo(("##_audio_dev_0_"+ name).c_str(), &stream->deviceId, stream->audio->devTxtList.c_str())) { + audio::stopStream(name); + audio::setAudioDevice(name, stream->deviceId, stream->audio->devices[deviceId].sampleRates[0]); + if (running) { + audio::startStream(name); + } + stream->sampleRateId = 0; + + // Create config if it doesn't exist + if (!config::config["audio"].contains(name)) { + config::config["audio"][name]["volume"] = stream->volume; + } + config::config["audio"][name]["device"] = stream->audio->deviceNames[stream->deviceId]; + config::config["audio"][name]["sampleRate"] = stream->audio->devices[stream->deviceId].sampleRates[0]; + config::configModified = true; + } + if (ImGui::Combo(("##_audio_sr_0_" + name).c_str(), &stream->sampleRateId, stream->audio->devices[deviceId].txtSampleRates.c_str())) { + audio::stopStream(name); + audio::setSampleRate(name, stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]); + if (running) { + audio::startStream(name); + } + + // Create config if it doesn't exist + if (!config::config["audio"].contains(name)) { + config::config["audio"][name]["volume"] = stream->volume; + config::config["audio"][name]["device"] = stream->audio->deviceNames[deviceId]; + } + config::config["audio"][name]["sampleRate"] = stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]; + config::configModified = true; + } + if (ImGui::SliderFloat(("##_audio_vol_0_" + name).c_str(), &stream->volume, 0.0f, 1.0f, "")) { + stream->audio->setVolume(stream->volume); + + // Create config if it doesn't exist + if (!config::config["audio"].contains(name)) { + config::config["audio"][name]["device"] = stream->audio->deviceNames[deviceId]; + config::config["audio"][name]["sampleRate"] = stream->audio->devices[deviceId].sampleRates[stream->sampleRateId]; + } + config::config["audio"][name]["volume"] = stream->volume; + config::configModified = true; + } + ImGui::PopItemWidth(); + count++; + if (count < maxCount) { + ImGui::Spacing(); + ImGui::Separator(); + } ImGui::Spacing(); - ImGui::Separator(); } ImGui::Spacing(); } - ImGui::Spacing(); - } - if (ImGui::CollapsingHeader("Band Plan", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::PushItemWidth(menuColumnWidth); - if (ImGui::Combo("##_4_", &bandplanId.val, bandplan::bandplanNameTxt.c_str())) { - config::config["bandPlan"] = bandplan::bandplanNames[bandplanId.val]; - config::configModified = true; + if (ImGui::CollapsingHeader("Band Plan", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::PushItemWidth(menuColumnWidth); + if (ImGui::Combo("##_4_", &bandplanId.val, bandplan::bandplanNameTxt.c_str())) { + config::config["bandPlan"] = bandplan::bandplanNames[bandplanId.val]; + config::configModified = true; + } + ImGui::PopItemWidth(); + if (ImGui::Checkbox("Enabled", &bandPlanEnabled.val)) { + config::config["bandPlanEnabled"] = bandPlanEnabled.val; + config::configModified = true; + } + bandplan::BandPlan_t plan = bandplan::bandplans[bandplan::bandplanNames[bandplanId.val]]; + ImGui::Text("Country: %s (%s)", plan.countryName, plan.countryCode); + ImGui::Text("Author: %s", plan.authorName); + ImGui::Spacing(); + } + + if (ImGui::CollapsingHeader("Display", ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::Checkbox("Show waterfall", &showWaterfall)) { + showWaterfall ? wtf.showWaterfall() : wtf.hideWaterfall(); + } + ImGui::Spacing(); } - ImGui::PopItemWidth(); - if (ImGui::Checkbox("Enabled", &bandPlanEnabled.val)) { - config::config["bandPlanEnabled"] = bandPlanEnabled.val; - config::configModified = true; + + if(ImGui::CollapsingHeader("Debug")) { + ImGui::Text("Frame time: %.3f ms/frame", 1000.0f / ImGui::GetIO().Framerate); + ImGui::Text("Framerate: %.1f FPS", ImGui::GetIO().Framerate); + ImGui::Text("Center Frequency: %.0f Hz", wtf.getCenterFrequency()); + + ImGui::Spacing(); } - bandplan::BandPlan_t plan = bandplan::bandplans[bandplan::bandplanNames[bandplanId.val]]; - ImGui::Text("Country: %s (%s)", plan.countryName, plan.countryCode); - ImGui::Text("Author: %s", plan.authorName); - ImGui::Spacing(); - } - if (ImGui::CollapsingHeader("Display", ImGuiTreeNodeFlags_DefaultOpen)) { - if (ImGui::Checkbox("Show waterfall", &showWaterfall)) { - showWaterfall ? wtf.showWaterfall() : wtf.hideWaterfall(); - } - ImGui::Spacing(); + ImGui::EndChild(); } - - if(ImGui::CollapsingHeader("Debug")) { - ImGui::Text("Frame time: %.3f ms/frame", 1000.0f / ImGui::GetIO().Framerate); - ImGui::Text("Framerate: %.1f FPS", ImGui::GetIO().Framerate); - ImGui::Text("Center Frequency: %.0f Hz", wtf.getCenterFrequency()); - - ImGui::Spacing(); + else { + // When hiding the menu bar + ImGui::Columns(3, "WindowColumns", false); + ImGui::SetColumnWidth(0, 8); + ImGui::SetColumnWidth(1, winSize.x - 8 - 60); + ImGui::SetColumnWidth(2, 60); } - ImGui::EndChild(); - // Right Column ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); ImGui::NextColumn(); diff --git a/src/waterfall.cpp b/src/waterfall.cpp index 3057cf31..d590f780 100644 --- a/src/waterfall.cpp +++ b/src/waterfall.cpp @@ -703,12 +703,12 @@ namespace ImGui { else if (reference == REF_LOWER) { centerOffset = lowerOffset + (bandwidth / 2.0f); upperOffset = lowerOffset + bandwidth; - centerOffsetChanged; + centerOffsetChanged = true; } else if (reference == REF_UPPER) { centerOffset = upperOffset - (bandwidth / 2.0f); lowerOffset = upperOffset - bandwidth; - centerOffsetChanged; + centerOffsetChanged = true; } redrawRequired = true; } @@ -773,6 +773,7 @@ namespace ImGui { void WaterFall::setFFTHeight(int height) { FFTAreaHeight = height; + newFFTAreaHeight = height; onResize(); }