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();
}