From 1b176cf6cd75c8031a140961655cdd3c16589a68 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sun, 9 Jan 2022 12:28:19 -0500 Subject: [PATCH] small changes; sig gen square(), triangle(), pulse() --- {templates => examples}/1_convolve_simple.cpp | 0 .../2_convolve_overlap_save.cpp | 0 {templates => examples}/3_fir.cpp | 0 {templates => examples}/4_fir_pro.cpp | 0 .../5_fir_differentiator.cpp | 0 {templates => examples}/6_iir_test.cpp | 0 {templates => examples}/7_iir_echo.cpp | 0 source/circular.hpp | 11 +++++ source/code.cpp | 26 +++++++++- source/device.cpp | 18 ++++--- source/device_formula.cpp | 44 ++++++++++++++--- source/file.cpp | 12 ++--- source/gui.cpp | 49 ++++++++++++------- source/gui_code.cpp | 4 +- source/gui_device.cpp | 33 ++++++++----- source/imgui/TextEditor.cpp | 2 +- source/logview.cpp | 2 +- source/main.cpp | 48 +++++++++--------- 18 files changed, 175 insertions(+), 74 deletions(-) rename {templates => examples}/1_convolve_simple.cpp (100%) rename {templates => examples}/2_convolve_overlap_save.cpp (100%) rename {templates => examples}/3_fir.cpp (100%) rename {templates => examples}/4_fir_pro.cpp (100%) rename {templates => examples}/5_fir_differentiator.cpp (100%) rename {templates => examples}/6_iir_test.cpp (100%) rename {templates => examples}/7_iir_echo.cpp (100%) diff --git a/templates/1_convolve_simple.cpp b/examples/1_convolve_simple.cpp similarity index 100% rename from templates/1_convolve_simple.cpp rename to examples/1_convolve_simple.cpp diff --git a/templates/2_convolve_overlap_save.cpp b/examples/2_convolve_overlap_save.cpp similarity index 100% rename from templates/2_convolve_overlap_save.cpp rename to examples/2_convolve_overlap_save.cpp diff --git a/templates/3_fir.cpp b/examples/3_fir.cpp similarity index 100% rename from templates/3_fir.cpp rename to examples/3_fir.cpp diff --git a/templates/4_fir_pro.cpp b/examples/4_fir_pro.cpp similarity index 100% rename from templates/4_fir_pro.cpp rename to examples/4_fir_pro.cpp diff --git a/templates/5_fir_differentiator.cpp b/examples/5_fir_differentiator.cpp similarity index 100% rename from templates/5_fir_differentiator.cpp rename to examples/5_fir_differentiator.cpp diff --git a/templates/6_iir_test.cpp b/examples/6_iir_test.cpp similarity index 100% rename from templates/6_iir_test.cpp rename to examples/6_iir_test.cpp diff --git a/templates/7_iir_echo.cpp b/examples/7_iir_echo.cpp similarity index 100% rename from templates/7_iir_echo.cpp rename to examples/7_iir_echo.cpp diff --git a/source/circular.hpp b/source/circular.hpp index 33b8ee0..6b82068 100644 --- a/source/circular.hpp +++ b/source/circular.hpp @@ -1,3 +1,14 @@ +/** + * @file circular.hpp + * @brief Small utility for filling a buffer in a circular manner. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + #ifndef CIRCULAR_HPP #define CIRCULAR_HPP diff --git a/source/code.cpp b/source/code.cpp index 7a9afaa..14f603c 100644 --- a/source/code.cpp +++ b/source/code.cpp @@ -1,3 +1,14 @@ +/** + * @file code.cpp + * @brief Functionality for compiling and disassembling source code. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + #include "stmdsp.hpp" #include "stmdsp_code.hpp" @@ -9,10 +20,13 @@ #include extern std::shared_ptr m_device; -extern void log(const std::string& str); +void log(const std::string& str); -std::string tempFileName; // device.cpp +std::ifstream compileOpenBinaryFile(); +void compileEditorCode(const std::string& code); +void disassembleCode(); +static std::string tempFileName; static std::string newTempFileName(); static bool codeExecuteCommand( const std::string& command, @@ -22,6 +36,14 @@ static void stringReplaceAll( const std::string& what, const std::string& with); +std::ifstream compileOpenBinaryFile() +{ + if (!tempFileName.empty()) + return std::ifstream(tempFileName + ".o"); + else + return std::ifstream(); +} + void compileEditorCode(const std::string& code) { log("Compiling..."); diff --git a/source/device.cpp b/source/device.cpp index abcc88a..11e181e 100644 --- a/source/device.cpp +++ b/source/device.cpp @@ -30,9 +30,9 @@ #include #include -extern std::string tempFileName; extern void log(const std::string& str); extern std::vector deviceGenLoadFormulaEval(const std::string&); +extern std::ifstream compileOpenBinaryFile(); std::shared_ptr m_device; @@ -224,15 +224,21 @@ void deviceLoadLogFile(const std::string& file) bool deviceGenStartToggle() { if (m_device) { - bool running = m_device->is_siggening(); + const bool running = m_device->is_siggening(); + if (!running) { - if (wavOutput.valid()) + if (wavOutput.valid()) { std::thread(feedSigGenTask, m_device).detach(); - else + } else { + std::scoped_lock dlock (mutexDeviceLoad); m_device->siggen_start(); + } log("Generator started."); } else { - m_device->siggen_stop(); + { + std::scoped_lock dlock (mutexDeviceLoad); + m_device->siggen_stop(); + } log("Generator stopped."); } @@ -332,7 +338,7 @@ void deviceAlgorithmUpload() log("No device connected."); } else if (m_device->is_running()) { log("Cannot upload algorithm while running."); - } else if (std::ifstream algo (tempFileName + ".o"); algo.is_open()) { + } else if (auto algo = compileOpenBinaryFile(); algo.is_open()) { std::ostringstream sstr; sstr << algo.rdbuf(); auto str = sstr.str(); diff --git a/source/device_formula.cpp b/source/device_formula.cpp index c94eab7..a70f465 100644 --- a/source/device_formula.cpp +++ b/source/device_formula.cpp @@ -1,31 +1,63 @@ +/** + * @file device_formula.cpp + * @brief Function for filling generator buffer using a mathematical formula. + * This is kept in its own file as exprtk.hpp takes forever to compile. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + #include "stmdsp.hpp" #include "exprtk.hpp" #include +#include #include #include +static std::random_device randomDevice; + std::vector deviceGenLoadFormulaEval(const std::string& formulaString) { double x = 0; exprtk::symbol_table symbol_table; + exprtk::function_compositor compositor (symbol_table); exprtk::expression expression; exprtk::parser parser; - symbol_table.add_variable("x", x); symbol_table.add_constants(); + symbol_table.add_variable("x", x); + symbol_table.add_function("random", + [](double l, double h) -> double { + return std::uniform_real_distribution(l, h)(randomDevice); + }); + compositor.add(exprtk::function_compositor::function() + .name("square") + .var("X") + .expression("ceil(sin(pi*X))")); + compositor.add(exprtk::function_compositor::function() + .name("triangle") + .var("X") + .expression("ceil(sin(pi*X))*(X-floor(X))+ceil(-sin(pi*X))*(-X-floor(-X))")); + compositor.add(exprtk::function_compositor::function() + .name("pulse") + .var("L") + .var("X") + .expression("if(X<=L,1,0)")); expression.register_symbol_table(symbol_table); parser.compile(formulaString, expression); - std::vector samples (stmdsp::SAMPLES_MAX); - - auto genFun = [&x, &expression] { - stmdsp::dacsample_t s = expression.value(); + const auto genFun = [&x, &expression] { + const auto s = std::clamp(expression.value(), -1., 1.) * 2048. + 2048.; ++x; - return s; + return static_cast(std::min(s, 4095.)); }; + std::vector samples (stmdsp::SAMPLES_MAX); std::generate(samples.begin(), samples.end(), genFun); return samples; } diff --git a/source/file.cpp b/source/file.cpp index a5ef1d8..fe5dafb 100644 --- a/source/file.cpp +++ b/source/file.cpp @@ -40,7 +40,7 @@ enum class FileAction { static FileAction fileAction = FileAction::None; static std::string fileCurrentPath; -static std::vector fileTemplateList; +static std::vector fileExampleList; static void saveCurrentFile() { @@ -66,9 +66,9 @@ static void openNewFile() editor.SetText(stmdsp::file_content); } -static std::vector fileScanTemplates() +static std::vector fileScanExamples() { - const auto path = std::filesystem::current_path() / "templates"; + const auto path = std::filesystem::current_path() / "examples"; const std::filesystem::recursive_directory_iterator rdi (path); std::vector list; @@ -83,7 +83,7 @@ static std::vector fileScanTemplates() void fileInit() { - fileTemplateList = fileScanTemplates(); + fileExampleList = fileScanExamples(); openNewFile(); } @@ -102,8 +102,8 @@ void fileRenderMenu() "ChooseFileOpenSave", "Choose File", ".cpp", "."); } - if (ImGui::BeginMenu("Open Template")) { - for (const auto& file : fileTemplateList) { + if (ImGui::BeginMenu("Open Example")) { + for (const auto& file : fileExampleList) { if (ImGui::MenuItem(file.filename().c_str())) { fileCurrentPath = file.string(); openCurrentFile(); diff --git a/source/gui.cpp b/source/gui.cpp index 515d471..80120c4 100644 --- a/source/gui.cpp +++ b/source/gui.cpp @@ -19,15 +19,17 @@ #include #include -ImFont *fontSans = nullptr; -ImFont *fontMono = nullptr; -static ImGuiIO *io = nullptr; +bool guiInitialize(); +void guiRender(); +bool guiHandleEvents(); +void guiShutdown(); + static SDL_Window *window = nullptr; -static decltype(SDL_GL_CreateContext(nullptr)) gl_context; +static SDL_GLContext gl_context; bool guiInitialize() { - if (SDL_Init(/*SDL_INIT_VIDEO*/0) != 0) { + if (SDL_Init(0) != 0) { printf("Error: %s\n", SDL_GetError()); return false; } @@ -42,6 +44,12 @@ bool guiInitialize() SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL /*| SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI*/); + + if (window == nullptr) { + puts("Error: Could not create the window!"); + return false; + } + gl_context = SDL_GL_CreateContext(window); SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync @@ -49,10 +57,7 @@ bool guiInitialize() // Setup Dear ImGui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); - io = &ImGui::GetIO(); //io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - fontSans = io->Fonts->AddFontFromFileTTF("fonts/Roboto-Regular.ttf", 20); - fontMono = io->Fonts->AddFontFromFileTTF("fonts/RobotoMono-Regular.ttf", 20); ImGui_ImplSDL2_InitForOpenGL(window, gl_context); ImGui_ImplOpenGL2_Init(); @@ -99,13 +104,19 @@ bool guiInitialize() return true; } -void guiRender(void (*func)()) +void guiRender() { - glViewport(0, 0, (int)io->DisplaySize.x, (int)io->DisplaySize.y); - glClearColor(1, 1, 1, 1); - glClear(GL_COLOR_BUFFER_BIT); - func(); - SDL_GL_SwapWindow(window); + ImGui::Render(); + + const auto& displaySize = ImGui::GetIO().DisplaySize; + const int sizeX = static_cast(displaySize.x); + const int sizeY = static_cast(displaySize.y); + + glViewport(0, 0, sizeX, sizeY); + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); + SDL_GL_SwapWindow(window); } bool guiHandleEvents() @@ -114,10 +125,14 @@ bool guiHandleEvents() for (SDL_Event event; SDL_PollEvent(&event);) { ImGui_ImplSDL2_ProcessEvent(&event); - if (event.type == SDL_QUIT) - done = true; - if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) + if (event.type == SDL_QUIT) { done = true; + } else if (event.type == SDL_WINDOWEVENT) { + const auto& ew = event.window; + const auto wid = SDL_GetWindowID(window); + if (ew.event == SDL_WINDOWEVENT_CLOSE && ew.windowID == wid) + done = true; + } } return done; diff --git a/source/gui_code.cpp b/source/gui_code.cpp index 6917c72..19fa572 100644 --- a/source/gui_code.cpp +++ b/source/gui_code.cpp @@ -37,9 +37,9 @@ void codeEditorInit() void codeRenderMenu() { if (ImGui::BeginMenu("Code")) { - if (ImGui::MenuItem("Compile code")) + if (ImGui::MenuItem("Compile")) codeCompile(); - if (ImGui::MenuItem("Show disassembly")) + if (ImGui::MenuItem("Disassemble")) codeDisassemble(); ImGui::EndMenu(); diff --git a/source/gui_device.cpp b/source/gui_device.cpp index a1d0555..43c0a58 100644 --- a/source/gui_device.cpp +++ b/source/gui_device.cpp @@ -55,7 +55,7 @@ void deviceRenderMenu() } }; - if (ImGui::BeginMenu("Run")) { + if (ImGui::BeginMenu("Device")) { static std::string connectLabel ("Connect"); addMenuItem(connectLabel, !m_device || !m_device->is_running(), [&] { if (deviceConnect()) { @@ -199,11 +199,6 @@ void deviceRenderWidgets() ImGui::PopStyleColor(); } - if (ImGui::Button("Cancel")) { - siggenInput.clear(); - ImGui::CloseCurrentPopup(); - } - if (ImGui::Button("Save")) { switch (siggenOption) { case 0: @@ -219,6 +214,12 @@ void deviceRenderWidgets() ImGui::CloseCurrentPopup(); } + ImGui::SameLine(); + if (ImGui::Button("Cancel")) { + siggenInput.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); } @@ -387,12 +388,22 @@ void deviceRenderDraw() if (mouse.x > p0.x && mouse.x < p0.x + size.x && mouse.y > p0.y && mouse.y < p0.y + size.y) { - const std::size_t si = (mouse.x - p0.x) / size.x * buffer.size(); - const float s = buffer[si] / 4095.f * 6.6f - 3.3f; - char buf[12]; - snprintf(buf, 16, " %1.3fV", s); + char buf[16]; drawList->AddLine({mouse.x, p0.y}, {mouse.x, p0.y + size.y}, IM_COL32(255, 255, 0, 255)); - drawList->AddText(ImGui::GetMousePos(), IM_COL32(210, 210, 0, 255), buf); + + { + const std::size_t si = (mouse.x - p0.x) / size.x * buffer.size(); + const float s = buffer[si] / 4095.f * 6.6f - 3.3f; + snprintf(buf, sizeof(buf), " %1.3fV", s); + drawList->AddText(mouse, IM_COL32(255, 0, 0, 255), buf); + } + + if (drawSamplesInput) { + const std::size_t si = (mouse.x - p0.x) / size.x * bufferInput.size(); + const float s = bufferInput[si] / 4095.f * 6.6f - 3.3f; + snprintf(buf, sizeof(buf), " %1.3fV", s); + drawList->AddText({mouse.x, mouse.y + 20}, IM_COL32(0, 0, 255, 255), buf); + } } ImGui::End(); diff --git a/source/imgui/TextEditor.cpp b/source/imgui/TextEditor.cpp index b45a21e..85bff74 100644 --- a/source/imgui/TextEditor.cpp +++ b/source/imgui/TextEditor.cpp @@ -46,7 +46,7 @@ TextEditor::TextEditor() , mHandleKeyboardInputs(true) , mHandleMouseInputs(true) , mIgnoreImGuiChild(false) - , mShowWhitespaces(true) + , mShowWhitespaces(false) , mStartTime(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) { SetPalette(GetDarkPalette()); diff --git a/source/logview.cpp b/source/logview.cpp index 267cecb..5a771bf 100644 --- a/source/logview.cpp +++ b/source/logview.cpp @@ -41,7 +41,7 @@ void LogView::Draw(const char* title, bool* p_open, ImGuiWindowFlags flags) } ImGui::Text("Log "); - ImGui::SameLine(); + ImGui::SameLine(ImGui::GetWindowWidth() - 120); if (ImGui::Button("Clear")) Clear(); ImGui::SameLine(); diff --git a/source/main.cpp b/source/main.cpp index 5eac338..e8641bc 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -19,37 +19,31 @@ #include #include +#include #include #include -extern ImFont *fontSans; -extern ImFont *fontMono; - -bool guiInitialize(); -bool guiHandleEvents(); -void guiShutdown(); -void guiRender(void (*func)()); - -void fileRenderMenu(); -void fileRenderDialog(); -void fileInit(); - void codeEditorInit(); void codeRenderMenu(); void codeRenderToolbar(); void codeRenderWidgets(); - void deviceRenderDraw(); void deviceRenderMenu(); void deviceRenderToolbar(); void deviceRenderWidgets(); +void fileRenderMenu(); +void fileRenderDialog(); +void fileInit(); +bool guiInitialize(); +bool guiHandleEvents(); +void guiShutdown(); +void guiRender(); -static LogView logView; +void log(const std::string& str); -void log(const std::string& str) -{ - logView.AddLog(str); -} +static LogView logView; +static ImFont *fontSans = nullptr; +static ImFont *fontMono = nullptr; static void renderWindow(); @@ -58,6 +52,14 @@ int main(int, char **) if (!guiInitialize()) return -1; + auto& io = ImGui::GetIO(); + fontSans = io.Fonts->AddFontFromFileTTF("fonts/Roboto-Regular.ttf", 20); + fontMono = io.Fonts->AddFontFromFileTTF("fonts/RobotoMono-Regular.ttf", 20); + if (fontSans == nullptr || fontMono == nullptr) { + std::cout << "Failed to load fonts!" << std::endl; + return -1; + } + codeEditorInit(); fileInit(); @@ -78,6 +80,11 @@ int main(int, char **) return 0; } +void log(const std::string& str) +{ + logView.AddLog(str); +} + void renderWindow() { // Start the new window frame and render the menu bar. @@ -124,9 +131,6 @@ void renderWindow() deviceRenderDraw(); // Draw everything to the screen. - ImGui::Render(); - guiRender([] { - ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); - }); + guiRender(); }