small changes; sig gen square(), triangle(), pulse()

pull/1/head
Clyne 3 years ago
parent fde531e7c4
commit 1b176cf6cd

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef CIRCULAR_HPP #ifndef CIRCULAR_HPP
#define CIRCULAR_HPP #define CIRCULAR_HPP

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "stmdsp.hpp" #include "stmdsp.hpp"
#include "stmdsp_code.hpp" #include "stmdsp_code.hpp"
@ -9,10 +20,13 @@
#include <string> #include <string>
extern std::shared_ptr<stmdsp::device> m_device; extern std::shared_ptr<stmdsp::device> 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 std::string newTempFileName();
static bool codeExecuteCommand( static bool codeExecuteCommand(
const std::string& command, const std::string& command,
@ -22,6 +36,14 @@ static void stringReplaceAll(
const std::string& what, const std::string& what,
const std::string& with); 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) void compileEditorCode(const std::string& code)
{ {
log("Compiling..."); log("Compiling...");

@ -30,9 +30,9 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
extern std::string tempFileName;
extern void log(const std::string& str); extern void log(const std::string& str);
extern std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string&); extern std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string&);
extern std::ifstream compileOpenBinaryFile();
std::shared_ptr<stmdsp::device> m_device; std::shared_ptr<stmdsp::device> m_device;
@ -224,15 +224,21 @@ void deviceLoadLogFile(const std::string& file)
bool deviceGenStartToggle() bool deviceGenStartToggle()
{ {
if (m_device) { if (m_device) {
bool running = m_device->is_siggening(); const bool running = m_device->is_siggening();
if (!running) { if (!running) {
if (wavOutput.valid()) if (wavOutput.valid()) {
std::thread(feedSigGenTask, m_device).detach(); std::thread(feedSigGenTask, m_device).detach();
else } else {
std::scoped_lock dlock (mutexDeviceLoad);
m_device->siggen_start(); m_device->siggen_start();
}
log("Generator started."); log("Generator started.");
} else { } else {
{
std::scoped_lock dlock (mutexDeviceLoad);
m_device->siggen_stop(); m_device->siggen_stop();
}
log("Generator stopped."); log("Generator stopped.");
} }
@ -332,7 +338,7 @@ void deviceAlgorithmUpload()
log("No device connected."); log("No device connected.");
} else if (m_device->is_running()) { } else if (m_device->is_running()) {
log("Cannot upload algorithm while 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; std::ostringstream sstr;
sstr << algo.rdbuf(); sstr << algo.rdbuf();
auto str = sstr.str(); auto str = sstr.str();

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "stmdsp.hpp" #include "stmdsp.hpp"
#include "exprtk.hpp" #include "exprtk.hpp"
#include <algorithm> #include <algorithm>
#include <random>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
static std::random_device randomDevice;
std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string& formulaString) std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string& formulaString)
{ {
double x = 0; double x = 0;
exprtk::symbol_table<double> symbol_table; exprtk::symbol_table<double> symbol_table;
exprtk::function_compositor<double> compositor (symbol_table);
exprtk::expression<double> expression; exprtk::expression<double> expression;
exprtk::parser<double> parser; exprtk::parser<double> parser;
symbol_table.add_variable("x", x);
symbol_table.add_constants(); 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<double>(l, h)(randomDevice);
});
compositor.add(exprtk::function_compositor<double>::function()
.name("square")
.var("X")
.expression("ceil(sin(pi*X))"));
compositor.add(exprtk::function_compositor<double>::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<double>::function()
.name("pulse")
.var("L")
.var("X")
.expression("if(X<=L,1,0)"));
expression.register_symbol_table(symbol_table); expression.register_symbol_table(symbol_table);
parser.compile(formulaString, expression); parser.compile(formulaString, expression);
std::vector<stmdsp::dacsample_t> samples (stmdsp::SAMPLES_MAX); const auto genFun = [&x, &expression] {
const auto s = std::clamp(expression.value(), -1., 1.) * 2048. + 2048.;
auto genFun = [&x, &expression] {
stmdsp::dacsample_t s = expression.value();
++x; ++x;
return s; return static_cast<stmdsp::dacsample_t>(std::min(s, 4095.));
}; };
std::vector<stmdsp::dacsample_t> samples (stmdsp::SAMPLES_MAX);
std::generate(samples.begin(), samples.end(), genFun); std::generate(samples.begin(), samples.end(), genFun);
return samples; return samples;
} }

@ -40,7 +40,7 @@ enum class FileAction {
static FileAction fileAction = FileAction::None; static FileAction fileAction = FileAction::None;
static std::string fileCurrentPath; static std::string fileCurrentPath;
static std::vector<std::filesystem::path> fileTemplateList; static std::vector<std::filesystem::path> fileExampleList;
static void saveCurrentFile() static void saveCurrentFile()
{ {
@ -66,9 +66,9 @@ static void openNewFile()
editor.SetText(stmdsp::file_content); editor.SetText(stmdsp::file_content);
} }
static std::vector<std::filesystem::path> fileScanTemplates() static std::vector<std::filesystem::path> 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); const std::filesystem::recursive_directory_iterator rdi (path);
std::vector<std::filesystem::path> list; std::vector<std::filesystem::path> list;
@ -83,7 +83,7 @@ static std::vector<std::filesystem::path> fileScanTemplates()
void fileInit() void fileInit()
{ {
fileTemplateList = fileScanTemplates(); fileExampleList = fileScanExamples();
openNewFile(); openNewFile();
} }
@ -102,8 +102,8 @@ void fileRenderMenu()
"ChooseFileOpenSave", "Choose File", ".cpp", "."); "ChooseFileOpenSave", "Choose File", ".cpp", ".");
} }
if (ImGui::BeginMenu("Open Template")) { if (ImGui::BeginMenu("Open Example")) {
for (const auto& file : fileTemplateList) { for (const auto& file : fileExampleList) {
if (ImGui::MenuItem(file.filename().c_str())) { if (ImGui::MenuItem(file.filename().c_str())) {
fileCurrentPath = file.string(); fileCurrentPath = file.string();
openCurrentFile(); openCurrentFile();

@ -19,15 +19,17 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h> #include <SDL2/SDL_opengl.h>
ImFont *fontSans = nullptr; bool guiInitialize();
ImFont *fontMono = nullptr; void guiRender();
static ImGuiIO *io = nullptr; bool guiHandleEvents();
void guiShutdown();
static SDL_Window *window = nullptr; static SDL_Window *window = nullptr;
static decltype(SDL_GL_CreateContext(nullptr)) gl_context; static SDL_GLContext gl_context;
bool guiInitialize() bool guiInitialize()
{ {
if (SDL_Init(/*SDL_INIT_VIDEO*/0) != 0) { if (SDL_Init(0) != 0) {
printf("Error: %s\n", SDL_GetError()); printf("Error: %s\n", SDL_GetError());
return false; return false;
} }
@ -42,6 +44,12 @@ bool guiInitialize()
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT,
SDL_WINDOW_OPENGL /*| SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI*/); 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); gl_context = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, gl_context); SDL_GL_MakeCurrent(window, gl_context);
SDL_GL_SetSwapInterval(1); // Enable vsync SDL_GL_SetSwapInterval(1); // Enable vsync
@ -49,10 +57,7 @@ bool guiInitialize()
// Setup Dear ImGui context // Setup Dear ImGui context
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
io = &ImGui::GetIO();
//io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; //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_ImplSDL2_InitForOpenGL(window, gl_context);
ImGui_ImplOpenGL2_Init(); ImGui_ImplOpenGL2_Init();
@ -99,12 +104,18 @@ bool guiInitialize()
return true; return true;
} }
void guiRender(void (*func)()) void guiRender()
{ {
glViewport(0, 0, (int)io->DisplaySize.x, (int)io->DisplaySize.y); ImGui::Render();
const auto& displaySize = ImGui::GetIO().DisplaySize;
const int sizeX = static_cast<int>(displaySize.x);
const int sizeY = static_cast<int>(displaySize.y);
glViewport(0, 0, sizeX, sizeY);
glClearColor(1, 1, 1, 1); glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
func(); ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(window); SDL_GL_SwapWindow(window);
} }
@ -114,11 +125,15 @@ bool guiHandleEvents()
for (SDL_Event event; SDL_PollEvent(&event);) { for (SDL_Event event; SDL_PollEvent(&event);) {
ImGui_ImplSDL2_ProcessEvent(&event); ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT) if (event.type == SDL_QUIT) {
done = true; done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) } 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; done = true;
} }
}
return done; return done;
} }

@ -37,9 +37,9 @@ void codeEditorInit()
void codeRenderMenu() void codeRenderMenu()
{ {
if (ImGui::BeginMenu("Code")) { if (ImGui::BeginMenu("Code")) {
if (ImGui::MenuItem("Compile code")) if (ImGui::MenuItem("Compile"))
codeCompile(); codeCompile();
if (ImGui::MenuItem("Show disassembly")) if (ImGui::MenuItem("Disassemble"))
codeDisassemble(); codeDisassemble();
ImGui::EndMenu(); ImGui::EndMenu();

@ -55,7 +55,7 @@ void deviceRenderMenu()
} }
}; };
if (ImGui::BeginMenu("Run")) { if (ImGui::BeginMenu("Device")) {
static std::string connectLabel ("Connect"); static std::string connectLabel ("Connect");
addMenuItem(connectLabel, !m_device || !m_device->is_running(), [&] { addMenuItem(connectLabel, !m_device || !m_device->is_running(), [&] {
if (deviceConnect()) { if (deviceConnect()) {
@ -199,11 +199,6 @@ void deviceRenderWidgets()
ImGui::PopStyleColor(); ImGui::PopStyleColor();
} }
if (ImGui::Button("Cancel")) {
siggenInput.clear();
ImGui::CloseCurrentPopup();
}
if (ImGui::Button("Save")) { if (ImGui::Button("Save")) {
switch (siggenOption) { switch (siggenOption) {
case 0: case 0:
@ -219,6 +214,12 @@ void deviceRenderWidgets()
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
siggenInput.clear();
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup(); ImGui::EndPopup();
} }
@ -386,13 +387,23 @@ void deviceRenderDraw()
const auto mouse = ImGui::GetMousePos(); const auto mouse = ImGui::GetMousePos();
if (mouse.x > p0.x && mouse.x < p0.x + size.x && if (mouse.x > p0.x && mouse.x < p0.x + size.x &&
mouse.y > p0.y && mouse.y < p0.y + size.y) mouse.y > p0.y && mouse.y < p0.y + size.y)
{
char buf[16];
drawList->AddLine({mouse.x, p0.y}, {mouse.x, p0.y + size.y}, IM_COL32(255, 255, 0, 255));
{ {
const std::size_t si = (mouse.x - p0.x) / size.x * buffer.size(); const std::size_t si = (mouse.x - p0.x) / size.x * buffer.size();
const float s = buffer[si] / 4095.f * 6.6f - 3.3f; const float s = buffer[si] / 4095.f * 6.6f - 3.3f;
char buf[12]; snprintf(buf, sizeof(buf), " %1.3fV", s);
snprintf(buf, 16, " %1.3fV", s); drawList->AddText(mouse, IM_COL32(255, 0, 0, 255), buf);
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);
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(); ImGui::End();

@ -46,7 +46,7 @@ TextEditor::TextEditor()
, mHandleKeyboardInputs(true) , mHandleKeyboardInputs(true)
, mHandleMouseInputs(true) , mHandleMouseInputs(true)
, mIgnoreImGuiChild(false) , mIgnoreImGuiChild(false)
, mShowWhitespaces(true) , mShowWhitespaces(false)
, mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) , mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count())
{ {
SetPalette(GetDarkPalette()); SetPalette(GetDarkPalette());

@ -41,7 +41,7 @@ void LogView::Draw(const char* title, bool* p_open, ImGuiWindowFlags flags)
} }
ImGui::Text("Log "); ImGui::Text("Log ");
ImGui::SameLine(); ImGui::SameLine(ImGui::GetWindowWidth() - 120);
if (ImGui::Button("Clear")) if (ImGui::Button("Clear"))
Clear(); Clear();
ImGui::SameLine(); ImGui::SameLine();

@ -19,37 +19,31 @@
#include <chrono> #include <chrono>
#include <cmath> #include <cmath>
#include <iostream>
#include <string> #include <string>
#include <thread> #include <thread>
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 codeEditorInit();
void codeRenderMenu(); void codeRenderMenu();
void codeRenderToolbar(); void codeRenderToolbar();
void codeRenderWidgets(); void codeRenderWidgets();
void deviceRenderDraw(); void deviceRenderDraw();
void deviceRenderMenu(); void deviceRenderMenu();
void deviceRenderToolbar(); void deviceRenderToolbar();
void deviceRenderWidgets(); 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) static LogView logView;
{ static ImFont *fontSans = nullptr;
logView.AddLog(str); static ImFont *fontMono = nullptr;
}
static void renderWindow(); static void renderWindow();
@ -58,6 +52,14 @@ int main(int, char **)
if (!guiInitialize()) if (!guiInitialize())
return -1; 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(); codeEditorInit();
fileInit(); fileInit();
@ -78,6 +80,11 @@ int main(int, char **)
return 0; return 0;
} }
void log(const std::string& str)
{
logView.AddLog(str);
}
void renderWindow() void renderWindow()
{ {
// Start the new window frame and render the menu bar. // Start the new window frame and render the menu bar.
@ -124,9 +131,6 @@ void renderWindow()
deviceRenderDraw(); deviceRenderDraw();
// Draw everything to the screen. // Draw everything to the screen.
ImGui::Render(); guiRender();
guiRender([] {
ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
});
} }

Loading…
Cancel
Save