added cmake support

pull/1/head
Clyne 3 years ago
parent a1700f3ca6
commit 41ae9b3b1b

@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 3.10)
project(stmdspgui VERSION 0.5)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_compile_options(-O0 -ggdb -g3 -Wall -Wextra -pedantic)
file(GLOB SRC_IMGUI_BACKENDS "${CMAKE_SOURCE_DIR}/source/imgui/backends/*.cpp")
file(GLOB SRC_IMGUI "${CMAKE_SOURCE_DIR}/source/imgui/*.cpp")
file(GLOB SRC_STMDSP "${CMAKE_SOURCE_DIR}/source/stmdsp/*.cpp")
file(GLOB SRC_STMDSPGUI "${CMAKE_SOURCE_DIR}/source/*.cpp")
add_executable(stmdspgui
source/serial/src/serial.cc
source/serial/src/impl/unix.cc
source/serial/src/impl/list_ports/list_ports_linux.cc
${SRC_IMGUI_BACKENDS}
${SRC_IMGUI}
${SRC_STMDSP}
${SRC_STMDSPGUI})
target_include_directories(stmdspgui PUBLIC
${CMAKE_SOURCE_DIR}/source
${CMAKE_SOURCE_DIR}/source/imgui
${CMAKE_SOURCE_DIR}/source/stmdsp
${CMAKE_SOURCE_DIR}/source/serial/include)
target_link_libraries(stmdspgui PRIVATE SDL2 GL pthread)

@ -11,9 +11,7 @@
/** /**
* TODO list: * TODO list:
* - Test loading the signal generator with a formula.
* - Improve signal generator audio streaming. * - Improve signal generator audio streaming.
* - Log samples (should be good..?)
*/ */
#include "stmdsp.hpp" #include "stmdsp.hpp"
@ -25,9 +23,9 @@
#include <array> #include <array>
#include <charconv> #include <charconv>
#include <cmath> #include <cmath>
#include <cstdio>
#include <deque> #include <deque>
#include <fstream> #include <fstream>
#include <iostream>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
@ -66,9 +64,9 @@ static bool popupRequestSiggen = false;
static bool popupRequestDraw = false; static bool popupRequestDraw = false;
static bool popupRequestLog = false; static bool popupRequestLog = false;
static std::mutex mutexDrawSamples; static std::timed_mutex mutexDrawSamples;
//static std::vector<stmdsp::dacsample_t> drawSamplesBuf; static std::timed_mutex mutexDeviceLoad;
static std::vector<stmdsp::dacsample_t> drawSamplesBuf2;
static std::ofstream logSamplesFile; static std::ofstream logSamplesFile;
static wav::clip wavOutput; static wav::clip wavOutput;
@ -97,41 +95,64 @@ static void drawSamplesTask(stmdsp::device *device)
const double sampleRate = sampleRateInts[m_device->get_sample_rate()]; const double sampleRate = sampleRateInts[m_device->get_sample_rate()];
unsigned long bufferTime = bufferSize / sampleRate * 0.975 * 1e6; unsigned long bufferTime = bufferSize / sampleRate * 0.975 * 1e6;
std::unique_lock<std::timed_mutex> lockDraw (mutexDrawSamples, std::defer_lock);
std::unique_lock<std::timed_mutex> lockDevice (mutexDeviceLoad, std::defer_lock);
while (m_device && m_device->is_running()) { while (m_device && m_device->is_running()) {
auto next = std::chrono::high_resolution_clock::now() + auto next = std::chrono::high_resolution_clock::now() +
std::chrono::microseconds(bufferTime); std::chrono::microseconds(bufferTime);
auto chunk = m_device->continuous_read(); std::vector<stmdsp::dacsample_t> chunk;
if (lockDevice.try_lock_until(next)) {
chunk = m_device->continuous_read();
int tries = -1;
while (chunk.empty() && m_device->is_running()) { while (chunk.empty() && m_device->is_running()) {
if (++tries == 100)
break;
std::this_thread::sleep_for(std::chrono::microseconds(20)); std::this_thread::sleep_for(std::chrono::microseconds(20));
chunk = m_device->continuous_read(); chunk = m_device->continuous_read();
} }
lockDevice.unlock();
} else {
// Cooldown.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
if (drawSamplesInput && popupRequestDraw) { if (drawSamplesInput && popupRequestDraw) {
auto chunk2 = m_device->continuous_read_input(); std::vector<stmdsp::dacsample_t> chunk2;
if (lockDevice.try_lock_for(std::chrono::milliseconds(1))) {
chunk2 = m_device->continuous_read_input();
int tries = -1;
while (chunk2.empty() && m_device->is_running()) { while (chunk2.empty() && m_device->is_running()) {
if (++tries == 100)
break;
std::this_thread::sleep_for(std::chrono::microseconds(20)); std::this_thread::sleep_for(std::chrono::microseconds(20));
chunk2 = m_device->continuous_read_input(); chunk2 = m_device->continuous_read_input();
} }
lockDevice.unlock();
}
{ lockDraw.lock();
std::scoped_lock lock (mutexDrawSamples);
auto i = chunk2.cbegin(); auto i = chunk2.cbegin();
for (const auto& s : chunk) { for (const auto& s : chunk) {
drawSamplesQueue.push_back(s); drawSamplesQueue.push_back(s);
drawSamplesInputQueue.push_back(*i++); drawSamplesInputQueue.push_back(*i++);
} }
} lockDraw.unlock();
} else if (!doLogger) { } else if (!doLogger) {
std::scoped_lock lock (mutexDrawSamples); lockDraw.lock();
for (const auto& s : chunk) for (const auto& s : chunk)
drawSamplesQueue.push_back(s); drawSamplesQueue.push_back(s);
lockDraw.unlock();
} else { } else {
std::scoped_lock lock (mutexDrawSamples); lockDraw.lock();
for (const auto& s : chunk) { for (const auto& s : chunk) {
drawSamplesQueue.push_back(s); drawSamplesQueue.push_back(s);
logSamplesFile << s << '\n'; logSamplesFile << s << '\n';
} }
lockDraw.unlock();
} }
std::this_thread::sleep_until(next); std::this_thread::sleep_until(next);
@ -143,33 +164,37 @@ static void feedSigGenTask(stmdsp::device *device)
if (device == nullptr) if (device == nullptr)
return; return;
const auto bsize = m_device->get_buffer_size(); const auto bufferSize = m_device->get_buffer_size();
const float srate = sampleRateInts[m_device->get_sample_rate()]; const double sampleRate = sampleRateInts[m_device->get_sample_rate()];
const unsigned int delay = bsize / srate * 1000.f * 0.4f; const unsigned long delay = bufferSize / sampleRate * 0.975 * 1e6;
std::vector<stmdsp::adcsample_t> wavBuf (bufferSize, 2048);
auto wavBuf = new stmdsp::adcsample_t[bsize]; std::unique_lock<std::timed_mutex> lockDevice (mutexDeviceLoad, std::defer_lock);
{ lockDevice.lock();
auto dst = wavBuf; // One (or both) of these freezes the device...
auto src = reinterpret_cast<uint16_t *>(wavOutput.next(bsize)); m_device->siggen_upload(wavBuf.data(), wavBuf.size());
for (auto i = 0u; i < bsize; ++i) //m_device->siggen_start();
*dst++ = *src++ / 16 + 2048; lockDevice.unlock();
m_device->siggen_upload(wavBuf, bsize);
}
m_device->siggen_start(); std::this_thread::sleep_for(std::chrono::microseconds(delay));
return;
while (genRunning) { while (genRunning) {
auto dst = wavBuf; auto next = std::chrono::high_resolution_clock::now() +
auto src = reinterpret_cast<uint16_t *>(wavOutput.next(bsize)); std::chrono::microseconds(delay);
for (auto i = 0u; i < bsize; ++i)
*dst++ = *src++ / 16 + 2048;
m_device->siggen_upload(wavBuf, bsize);
std::this_thread::sleep_for(std::chrono::milliseconds(delay)); auto src = reinterpret_cast<uint16_t *>(wavOutput.next(bufferSize));
} for (auto& w : wavBuf)
w = *src++ / 16 + 2048;
delete[] wavBuf; if (lockDevice.try_lock_until(next)) {
m_device->siggen_upload(wavBuf.data(), wavBuf.size());
lockDevice.unlock();
std::this_thread::sleep_until(next);
}
}
} }
static void deviceConnect(); static void deviceConnect();
@ -273,7 +298,10 @@ void deviceRenderWidgets()
ImGui::EndPopup(); ImGui::EndPopup();
} }
if (ImGuiFileDialog::Instance()->Display("ChooseFileLogGen")) { if (ImGuiFileDialog::Instance()->Display("ChooseFileLogGen",
ImGuiWindowFlags_NoCollapse,
ImVec2(460, 540)))
{
if (ImGuiFileDialog::Instance()->IsOk()) { if (ImGuiFileDialog::Instance()->IsOk()) {
auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
auto ext = filePathName.substr(filePathName.size() - 4); auto ext = filePathName.substr(filePathName.size() - 4);
@ -291,11 +319,11 @@ void deviceRenderWidgets()
if (logSamplesFile.good()) if (logSamplesFile.good())
log("Log file ready."); log("Log file ready.");
} }
}
ImGuiFileDialog::Instance()->Close(); ImGuiFileDialog::Instance()->Close();
} }
} }
}
void deviceRenderDraw() void deviceRenderDraw()
{ {
@ -513,7 +541,13 @@ void deviceConnect()
if (m_device == nullptr) { if (m_device == nullptr) {
stmdsp::scanner scanner; stmdsp::scanner scanner;
if (auto devices = scanner.scan(); devices.size() > 0) { if (auto devices = scanner.scan(); devices.size() > 0) {
try {
m_device = new stmdsp::device(devices.front()); m_device = new stmdsp::device(devices.front());
} catch (...) {
log("Failed to connect (check permissions?).");
m_device = nullptr;
}
if (m_device != nullptr) {
if (m_device->connected()) { if (m_device->connected()) {
auto sri = m_device->get_sample_rate(); auto sri = m_device->get_sample_rate();
sampleRatePreview = sampleRateList[sri]; sampleRatePreview = sampleRateList[sri];
@ -524,6 +558,7 @@ void deviceConnect()
m_device = nullptr; m_device = nullptr;
log("Failed to connect."); log("Failed to connect.");
} }
}
} else { } else {
log("No devices found."); log("No devices found.");
} }

@ -122,7 +122,10 @@ void fileRenderMenu()
void fileRenderDialog() void fileRenderDialog()
{ {
if (ImGuiFileDialog::Instance()->Display("ChooseFileOpenSave")) { if (ImGuiFileDialog::Instance()->Display("ChooseFileOpenSave",
ImGuiWindowFlags_NoCollapse,
ImVec2(460, 540)))
{
if (ImGuiFileDialog::Instance()->IsOk()) { if (ImGuiFileDialog::Instance()->IsOk()) {
std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName();

@ -27,7 +27,7 @@ namespace stmdsp
} }
device::device(const std::string& file) : device::device(const std::string& file) :
m_serial(file, 8'000'000/*230400*/, serial::Timeout::simpleTimeout(50)) m_serial(file, 8'000'000, serial::Timeout::simpleTimeout(50))
{ {
if (m_serial.isOpen()) { if (m_serial.isOpen()) {
m_serial.flush(); m_serial.flush();
@ -178,6 +178,9 @@ namespace stmdsp
m_serial.write(request, 3); m_serial.write(request, 3);
m_serial.write((uint8_t *)buffer, size * sizeof(dacsample_t)); m_serial.write((uint8_t *)buffer, size * sizeof(dacsample_t));
// TODO
if (!m_is_running)
m_serial.write((uint8_t *)buffer, size * sizeof(dacsample_t));
} }
} }

Loading…
Cancel
Save