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
#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_code.hpp"
@ -9,10 +20,13 @@
#include <string>
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 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...");

@ -30,9 +30,9 @@
#include <thread>
#include <vector>
extern std::string tempFileName;
extern void log(const std::string& str);
extern std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string&);
extern std::ifstream compileOpenBinaryFile();
std::shared_ptr<stmdsp::device> 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();

@ -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 "exprtk.hpp"
#include <algorithm>
#include <random>
#include <string_view>
#include <vector>
static std::random_device randomDevice;
std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string& formulaString)
{
double x = 0;
exprtk::symbol_table<double> symbol_table;
exprtk::function_compositor<double> compositor (symbol_table);
exprtk::expression<double> expression;
exprtk::parser<double> 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<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);
parser.compile(formulaString, expression);
std::vector<stmdsp::dacsample_t> 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<stmdsp::dacsample_t>(std::min(s, 4095.));
};
std::vector<stmdsp::dacsample_t> samples (stmdsp::SAMPLES_MAX);
std::generate(samples.begin(), samples.end(), genFun);
return samples;
}

@ -40,7 +40,7 @@ enum class FileAction {
static FileAction fileAction = FileAction::None;
static std::string fileCurrentPath;
static std::vector<std::filesystem::path> fileTemplateList;
static std::vector<std::filesystem::path> fileExampleList;
static void saveCurrentFile()
{
@ -66,9 +66,9 @@ static void openNewFile()
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);
std::vector<std::filesystem::path> list;
@ -83,7 +83,7 @@ static std::vector<std::filesystem::path> 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();

@ -19,15 +19,17 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
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<int>(displaySize.x);
const int sizeY = static_cast<int>(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;

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

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

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

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

@ -19,37 +19,31 @@
#include <chrono>
#include <cmath>
#include <iostream>
#include <string>
#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 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();
}

Loading…
Cancel
Save