diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d042f12 --- /dev/null +++ b/CMakeLists.txt @@ -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) + diff --git a/source/device.cpp b/source/device.cpp index e5d7839..333fd81 100644 --- a/source/device.cpp +++ b/source/device.cpp @@ -11,9 +11,7 @@ /** * TODO list: - * - Test loading the signal generator with a formula. * - Improve signal generator audio streaming. - * - Log samples (should be good..?) */ #include "stmdsp.hpp" @@ -25,9 +23,9 @@ #include #include #include -#include #include #include +#include #include #include @@ -66,9 +64,9 @@ static bool popupRequestSiggen = false; static bool popupRequestDraw = false; static bool popupRequestLog = false; -static std::mutex mutexDrawSamples; -//static std::vector drawSamplesBuf; -static std::vector drawSamplesBuf2; +static std::timed_mutex mutexDrawSamples; +static std::timed_mutex mutexDeviceLoad; + static std::ofstream logSamplesFile; static wav::clip wavOutput; @@ -97,41 +95,64 @@ static void drawSamplesTask(stmdsp::device *device) const double sampleRate = sampleRateInts[m_device->get_sample_rate()]; unsigned long bufferTime = bufferSize / sampleRate * 0.975 * 1e6; + std::unique_lock lockDraw (mutexDrawSamples, std::defer_lock); + std::unique_lock lockDevice (mutexDeviceLoad, std::defer_lock); + while (m_device && m_device->is_running()) { auto next = std::chrono::high_resolution_clock::now() + std::chrono::microseconds(bufferTime); - auto chunk = m_device->continuous_read(); - while (chunk.empty() && m_device->is_running()) { - std::this_thread::sleep_for(std::chrono::microseconds(20)); + std::vector chunk; + + if (lockDevice.try_lock_until(next)) { chunk = m_device->continuous_read(); - } + int tries = -1; + while (chunk.empty() && m_device->is_running()) { + if (++tries == 100) + break; + std::this_thread::sleep_for(std::chrono::microseconds(20)); + chunk = m_device->continuous_read(); + } + lockDevice.unlock(); + } else { + // Cooldown. + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } if (drawSamplesInput && popupRequestDraw) { - auto chunk2 = m_device->continuous_read_input(); - while (chunk2.empty() && m_device->is_running()) { - std::this_thread::sleep_for(std::chrono::microseconds(20)); + std::vector 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()) { + if (++tries == 100) + break; + std::this_thread::sleep_for(std::chrono::microseconds(20)); + chunk2 = m_device->continuous_read_input(); + } + lockDevice.unlock(); } - { - std::scoped_lock lock (mutexDrawSamples); - auto i = chunk2.cbegin(); - for (const auto& s : chunk) { - drawSamplesQueue.push_back(s); - drawSamplesInputQueue.push_back(*i++); - } + lockDraw.lock(); + auto i = chunk2.cbegin(); + for (const auto& s : chunk) { + drawSamplesQueue.push_back(s); + drawSamplesInputQueue.push_back(*i++); } + lockDraw.unlock(); } else if (!doLogger) { - std::scoped_lock lock (mutexDrawSamples); + lockDraw.lock(); for (const auto& s : chunk) drawSamplesQueue.push_back(s); + lockDraw.unlock(); } else { - std::scoped_lock lock (mutexDrawSamples); + lockDraw.lock(); for (const auto& s : chunk) { drawSamplesQueue.push_back(s); logSamplesFile << s << '\n'; } + lockDraw.unlock(); } std::this_thread::sleep_until(next); @@ -143,33 +164,37 @@ static void feedSigGenTask(stmdsp::device *device) if (device == nullptr) return; - const auto bsize = m_device->get_buffer_size(); - const float srate = sampleRateInts[m_device->get_sample_rate()]; - const unsigned int delay = bsize / srate * 1000.f * 0.4f; + const auto bufferSize = m_device->get_buffer_size(); + const double sampleRate = sampleRateInts[m_device->get_sample_rate()]; + const unsigned long delay = bufferSize / sampleRate * 0.975 * 1e6; + + std::vector wavBuf (bufferSize, 2048); - auto wavBuf = new stmdsp::adcsample_t[bsize]; + std::unique_lock lockDevice (mutexDeviceLoad, std::defer_lock); - { - auto dst = wavBuf; - auto src = reinterpret_cast(wavOutput.next(bsize)); - for (auto i = 0u; i < bsize; ++i) - *dst++ = *src++ / 16 + 2048; - m_device->siggen_upload(wavBuf, bsize); - } + lockDevice.lock(); + // One (or both) of these freezes the device... + m_device->siggen_upload(wavBuf.data(), wavBuf.size()); + //m_device->siggen_start(); + lockDevice.unlock(); - m_device->siggen_start(); + std::this_thread::sleep_for(std::chrono::microseconds(delay)); + return; while (genRunning) { - auto dst = wavBuf; - auto src = reinterpret_cast(wavOutput.next(bsize)); - for (auto i = 0u; i < bsize; ++i) - *dst++ = *src++ / 16 + 2048; - m_device->siggen_upload(wavBuf, bsize); + auto next = std::chrono::high_resolution_clock::now() + + std::chrono::microseconds(delay); - std::this_thread::sleep_for(std::chrono::milliseconds(delay)); - } + auto src = reinterpret_cast(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(); @@ -273,7 +298,10 @@ void deviceRenderWidgets() ImGui::EndPopup(); } - if (ImGuiFileDialog::Instance()->Display("ChooseFileLogGen")) { + if (ImGuiFileDialog::Instance()->Display("ChooseFileLogGen", + ImGuiWindowFlags_NoCollapse, + ImVec2(460, 540))) + { if (ImGuiFileDialog::Instance()->IsOk()) { auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); auto ext = filePathName.substr(filePathName.size() - 4); @@ -291,9 +319,9 @@ void deviceRenderWidgets() if (logSamplesFile.good()) log("Log file ready."); } - - ImGuiFileDialog::Instance()->Close(); } + + ImGuiFileDialog::Instance()->Close(); } } @@ -513,16 +541,23 @@ void deviceConnect() if (m_device == nullptr) { stmdsp::scanner scanner; if (auto devices = scanner.scan(); devices.size() > 0) { - m_device = new stmdsp::device(devices.front()); - if (m_device->connected()) { - auto sri = m_device->get_sample_rate(); - sampleRatePreview = sampleRateList[sri]; - drawSamplesBufferSize = std::round(sampleRateInts[sri] * drawSamplesTimeframe); - log("Connected!"); - } else { - delete m_device; - m_device = nullptr; - log("Failed to connect."); + try { + 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()) { + auto sri = m_device->get_sample_rate(); + sampleRatePreview = sampleRateList[sri]; + drawSamplesBufferSize = std::round(sampleRateInts[sri] * drawSamplesTimeframe); + log("Connected!"); + } else { + delete m_device; + m_device = nullptr; + log("Failed to connect."); + } } } else { log("No devices found."); diff --git a/source/file.cpp b/source/file.cpp index f6222fa..96dac0a 100644 --- a/source/file.cpp +++ b/source/file.cpp @@ -122,7 +122,10 @@ void fileRenderMenu() void fileRenderDialog() { - if (ImGuiFileDialog::Instance()->Display("ChooseFileOpenSave")) { + if (ImGuiFileDialog::Instance()->Display("ChooseFileOpenSave", + ImGuiWindowFlags_NoCollapse, + ImVec2(460, 540))) + { if (ImGuiFileDialog::Instance()->IsOk()) { std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); diff --git a/source/stmdsp/stmdsp.cpp b/source/stmdsp/stmdsp.cpp index 93c52dd..d219d38 100644 --- a/source/stmdsp/stmdsp.cpp +++ b/source/stmdsp/stmdsp.cpp @@ -27,7 +27,7 @@ namespace stmdsp } 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()) { m_serial.flush(); @@ -178,6 +178,9 @@ namespace stmdsp m_serial.write(request, 3); 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)); } }