|
|
@ -25,6 +25,7 @@
|
|
|
|
#include "ImGuiFileDialog.h"
|
|
|
|
#include "ImGuiFileDialog.h"
|
|
|
|
#include "wav.hpp"
|
|
|
|
#include "wav.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
#include <charconv>
|
|
|
|
#include <charconv>
|
|
|
|
#include <cmath>
|
|
|
|
#include <cmath>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdio>
|
|
|
@ -39,23 +40,23 @@ extern void log(const std::string& str);
|
|
|
|
|
|
|
|
|
|
|
|
extern std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string_view);
|
|
|
|
extern std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string_view);
|
|
|
|
|
|
|
|
|
|
|
|
static const char *sampleRateList[6] = {
|
|
|
|
static const std::array<const char *, 6> sampleRateList {{
|
|
|
|
"8 kHz",
|
|
|
|
"8 kHz",
|
|
|
|
"16 kHz",
|
|
|
|
"16 kHz",
|
|
|
|
"20 kHz",
|
|
|
|
"20 kHz",
|
|
|
|
"32 kHz",
|
|
|
|
"32 kHz",
|
|
|
|
"48 kHz",
|
|
|
|
"48 kHz",
|
|
|
|
"96 kHz"
|
|
|
|
"96 kHz"
|
|
|
|
};
|
|
|
|
}};
|
|
|
|
static const char *sampleRatePreview = sampleRateList[0];
|
|
|
|
static const char *sampleRatePreview = sampleRateList[0];
|
|
|
|
static const unsigned int sampleRateInts[6] = {
|
|
|
|
static const std::array<unsigned int, 6> sampleRateInts {{
|
|
|
|
8'000,
|
|
|
|
8'000,
|
|
|
|
16'000,
|
|
|
|
16'000,
|
|
|
|
20'000,
|
|
|
|
20'000,
|
|
|
|
32'000,
|
|
|
|
32'000,
|
|
|
|
48'000,
|
|
|
|
48'000,
|
|
|
|
96'000
|
|
|
|
96'000
|
|
|
|
};
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
|
|
static bool measureCodeTime = false;
|
|
|
|
static bool measureCodeTime = false;
|
|
|
|
static bool drawSamples = false;
|
|
|
|
static bool drawSamples = false;
|
|
|
@ -104,7 +105,7 @@ static void drawSamplesTask(stmdsp::device *device)
|
|
|
|
|
|
|
|
|
|
|
|
auto bufferTime = std::chrono::high_resolution_clock::now();
|
|
|
|
auto bufferTime = std::chrono::high_resolution_clock::now();
|
|
|
|
while (m_device && m_device->is_running()) {
|
|
|
|
while (m_device && m_device->is_running()) {
|
|
|
|
if (samplesToPush < bufferSize) {
|
|
|
|
if (samplesToPush < bufferSize || drawSamplesTimeframe < 0.25) {
|
|
|
|
if (lastReadIndexD >= bufferSize - 1)
|
|
|
|
if (lastReadIndexD >= bufferSize - 1)
|
|
|
|
lastReadIndexD -= bufferSize - 1;
|
|
|
|
lastReadIndexD -= bufferSize - 1;
|
|
|
|
|
|
|
|
|
|
|
@ -115,7 +116,7 @@ static void drawSamplesTask(stmdsp::device *device)
|
|
|
|
std::scoped_lock lock (mutexDrawSamples);
|
|
|
|
std::scoped_lock lock (mutexDrawSamples);
|
|
|
|
for (; lastReadIndexD < end; lastReadIndexD += 1) {
|
|
|
|
for (; lastReadIndexD < end; lastReadIndexD += 1) {
|
|
|
|
if (lastReadIndex >= lastReadBuffer.size()) {
|
|
|
|
if (lastReadIndex >= lastReadBuffer.size()) {
|
|
|
|
auto old = samplesToPush;
|
|
|
|
//auto old = samplesToPush;
|
|
|
|
|
|
|
|
|
|
|
|
auto now = std::chrono::high_resolution_clock::now();
|
|
|
|
auto now = std::chrono::high_resolution_clock::now();
|
|
|
|
std::chrono::duration<double> diff = now - bufferTime;
|
|
|
|
std::chrono::duration<double> diff = now - bufferTime;
|
|
|
@ -125,7 +126,7 @@ static void drawSamplesTask(stmdsp::device *device)
|
|
|
|
drawSamplesBuf2 = m_device->continuous_read_input();
|
|
|
|
drawSamplesBuf2 = m_device->continuous_read_input();
|
|
|
|
if (lastReadBuffer.empty()) {
|
|
|
|
if (lastReadBuffer.empty()) {
|
|
|
|
do {
|
|
|
|
do {
|
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(2));
|
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(20));
|
|
|
|
lastReadBuffer = m_device->continuous_read();
|
|
|
|
lastReadBuffer = m_device->continuous_read();
|
|
|
|
} while (lastReadBuffer.empty() && m_device->is_running());
|
|
|
|
} while (lastReadBuffer.empty() && m_device->is_running());
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -142,6 +143,11 @@ static void drawSamplesTask(stmdsp::device *device)
|
|
|
|
samplesToPush = (samplesToPush * c / desiredTime) * 0.98;
|
|
|
|
samplesToPush = (samplesToPush * c / desiredTime) * 0.98;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//if (std::abs(old - samplesToPush) > 4) {
|
|
|
|
|
|
|
|
// printf("\r%0.2lf", samplesToPush);
|
|
|
|
|
|
|
|
// fflush(stdout);
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
lastReadIndex = 0;
|
|
|
|
lastReadIndex = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -169,12 +175,16 @@ static void drawSamplesTask(stmdsp::device *device)
|
|
|
|
std::chrono::duration<double> diff = now - bufferTime;
|
|
|
|
std::chrono::duration<double> diff = now - bufferTime;
|
|
|
|
bufferTime = now;
|
|
|
|
bufferTime = now;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (drawSamplesTimeframe >= 0.25) {
|
|
|
|
double c = diff.count();
|
|
|
|
double c = diff.count();
|
|
|
|
if (c < desiredTime) {
|
|
|
|
if (c < desiredTime) {
|
|
|
|
samplesToPush = (samplesToPush * c / desiredTime) * 0.98;
|
|
|
|
samplesToPush = (samplesToPush * c / desiredTime) * 0.98;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//if (doLogger) {
|
|
|
|
//if (doLogger) {
|
|
|
@ -346,29 +356,42 @@ void deviceRenderWidgets()
|
|
|
|
void deviceRenderDraw()
|
|
|
|
void deviceRenderDraw()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (popupRequestDraw) {
|
|
|
|
if (popupRequestDraw) {
|
|
|
|
|
|
|
|
static std::vector<stmdsp::dacsample_t> buffer;
|
|
|
|
|
|
|
|
static decltype(buffer.begin()) bufferCursor;
|
|
|
|
|
|
|
|
static unsigned int yMinMax = 4095;
|
|
|
|
|
|
|
|
//static long unsigned int drawChunkSize = 0;
|
|
|
|
|
|
|
|
//static std::chrono::time_point<std::chrono::high_resolution_clock> timee;
|
|
|
|
|
|
|
|
|
|
|
|
ImGui::Begin("draw", &popupRequestDraw);
|
|
|
|
ImGui::Begin("draw", &popupRequestDraw);
|
|
|
|
ImGui::Checkbox("Draw input", &drawSamplesInput);
|
|
|
|
ImGui::Text("Draw input ");
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
ImGui::Checkbox("", &drawSamplesInput);
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::Text("| time: %0.3f sec", drawSamplesTimeframe);
|
|
|
|
ImGui::Text("Time: %0.3f sec", drawSamplesTimeframe);
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::SameLine();
|
|
|
|
if (ImGui::Button("-", {30, 0})) {
|
|
|
|
if (ImGui::Button("-", {30, 0})) {
|
|
|
|
drawSamplesTimeframe = std::max(drawSamplesTimeframe - 0.25, 0.5);
|
|
|
|
drawSamplesTimeframe = std::max(drawSamplesTimeframe / 2., 0.0078125);
|
|
|
|
auto sr = sampleRateInts[m_device->get_sample_rate()];
|
|
|
|
auto sr = sampleRateInts[m_device->get_sample_rate()];
|
|
|
|
auto tf = drawSamplesTimeframe;
|
|
|
|
auto tf = drawSamplesTimeframe;
|
|
|
|
drawSamplesBufferSize = std::round(sr * tf);
|
|
|
|
drawSamplesBufferSize = std::round(sr * tf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::SameLine();
|
|
|
|
if (ImGui::Button("+", {30, 0})) {
|
|
|
|
if (ImGui::Button("+", {30, 0})) {
|
|
|
|
drawSamplesTimeframe = std::min(drawSamplesTimeframe + 0.25, 30.);
|
|
|
|
drawSamplesTimeframe = std::min(drawSamplesTimeframe * 2, 32.);
|
|
|
|
auto sr = sampleRateInts[m_device->get_sample_rate()];
|
|
|
|
auto sr = sampleRateInts[m_device->get_sample_rate()];
|
|
|
|
auto tf = drawSamplesTimeframe;
|
|
|
|
auto tf = drawSamplesTimeframe;
|
|
|
|
drawSamplesBufferSize = std::round(sr * tf);
|
|
|
|
drawSamplesBufferSize = std::round(sr * tf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
static std::vector<stmdsp::dacsample_t> buffer;
|
|
|
|
ImGui::Text("Y-minmax: %u", yMinMax);
|
|
|
|
static decltype(buffer.begin()) bufferCursor;
|
|
|
|
ImGui::SameLine();
|
|
|
|
static long unsigned int drawChunkSize = 0;
|
|
|
|
if (ImGui::Button("--", {30, 0})) {
|
|
|
|
static std::chrono::time_point<std::chrono::high_resolution_clock> timee;
|
|
|
|
yMinMax = std::max(63u, yMinMax >> 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
if (ImGui::Button("++", {30, 0})) {
|
|
|
|
|
|
|
|
yMinMax = std::min(4095u, (yMinMax << 1) | 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (buffer.size() != drawSamplesBufferSize) {
|
|
|
|
if (buffer.size() != drawSamplesBufferSize) {
|
|
|
|
buffer.resize(drawSamplesBufferSize);
|
|
|
|
buffer.resize(drawSamplesBufferSize);
|
|
|
@ -403,22 +426,41 @@ void deviceRenderDraw()
|
|
|
|
size.y -= 70;
|
|
|
|
size.y -= 70;
|
|
|
|
drawList->AddRectFilled(p0, {p0.x + size.x, p0.y + size.y}, IM_COL32(0, 0, 0, 255));
|
|
|
|
drawList->AddRectFilled(p0, {p0.x + size.x, p0.y + size.y}, IM_COL32(0, 0, 0, 255));
|
|
|
|
|
|
|
|
|
|
|
|
const unsigned int didx = 1.f / (size.x / static_cast<float>(buffer.size()));
|
|
|
|
const float di = static_cast<float>(buffer.size()) / size.x;
|
|
|
|
|
|
|
|
const float dx = std::ceil(size.x / static_cast<float>(buffer.size()));
|
|
|
|
ImVec2 pp = p0;
|
|
|
|
ImVec2 pp = p0;
|
|
|
|
for (auto i = 0u; i < buffer.size(); i += didx) {
|
|
|
|
float i = 0;
|
|
|
|
ImVec2 next (pp.x + 1, p0.y + size.y - (float)buffer[i] / 4095.f * size.y);
|
|
|
|
while (pp.x < p0.x + size.x) {
|
|
|
|
|
|
|
|
unsigned int idx = i;
|
|
|
|
|
|
|
|
float n = std::clamp((buffer[idx] - 2048.) / yMinMax, -0.5, 0.5);
|
|
|
|
|
|
|
|
i += di;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ImVec2 next (pp.x + dx, p0.y + size.y * (0.5 - n));
|
|
|
|
drawList->AddLine(pp, next, ImGui::GetColorU32(IM_COL32(255, 0, 0, 255)));
|
|
|
|
drawList->AddLine(pp, next, ImGui::GetColorU32(IM_COL32(255, 0, 0, 255)));
|
|
|
|
pp = next;
|
|
|
|
pp = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (drawSamplesInput) {
|
|
|
|
//const unsigned int didx = std::ceil(1.f / (size.x / static_cast<float>(buffer.size())));
|
|
|
|
pp = p0;
|
|
|
|
//const auto dx = size.x / buffer.size();
|
|
|
|
for (auto i = 0u; i < drawSamplesBuf2.size(); i += didx) {
|
|
|
|
//ImVec2 pp = p0;
|
|
|
|
ImVec2 next (pp.x + 1, p0.y + size.y - (float)buffer[i] / 4095.f * size.y);
|
|
|
|
//for (auto i = 0u; i < buffer.size(); i += didx) {
|
|
|
|
drawList->AddLine(pp, next, ImGui::GetColorU32(IM_COL32(0, 0, 255, 255)));
|
|
|
|
// float n = std::clamp((buffer[i] - 2048.) / yMinMax, -0.5, 0.5);
|
|
|
|
pp = next;
|
|
|
|
|
|
|
|
}
|
|
|
|
// ImVec2 next (pp.x + 1, p0.y + size.y * (0.5 - n));
|
|
|
|
}
|
|
|
|
// drawList->AddLine(pp, next, ImGui::GetColorU32(IM_COL32(255, 0, 0, 255)));
|
|
|
|
|
|
|
|
// pp = next;
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//if (drawSamplesInput) {
|
|
|
|
|
|
|
|
// pp = p0;
|
|
|
|
|
|
|
|
// for (auto i = 0u; i < drawSamplesBuf2.size(); i += didx) {
|
|
|
|
|
|
|
|
// ImVec2 next (pp.x + 1,
|
|
|
|
|
|
|
|
// p0.y + size.y -
|
|
|
|
|
|
|
|
// (static_cast<float>(buffer[i]) / yMinMax) * size.y);
|
|
|
|
|
|
|
|
// drawList->AddLine(pp, next, ImGui::GetColorU32(IM_COL32(0, 0, 255, 255)));
|
|
|
|
|
|
|
|
// pp = next;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
//}
|
|
|
|
ImGui::End();
|
|
|
|
ImGui::End();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -431,8 +473,8 @@ void deviceRenderMenu()
|
|
|
|
|
|
|
|
|
|
|
|
static const char *connectLabel = "Connect";
|
|
|
|
static const char *connectLabel = "Connect";
|
|
|
|
if (ImGui::MenuItem(connectLabel)) {
|
|
|
|
if (ImGui::MenuItem(connectLabel)) {
|
|
|
|
connectLabel = isConnected ? "Connect" : "Disconnect";
|
|
|
|
|
|
|
|
deviceConnect();
|
|
|
|
deviceConnect();
|
|
|
|
|
|
|
|
connectLabel = m_device == nullptr ? "Connect" : "Disconnect";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
ImGui::Separator();
|
|
|
@ -508,7 +550,7 @@ void deviceRenderToolbar()
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::SetNextItemWidth(100);
|
|
|
|
ImGui::SetNextItemWidth(100);
|
|
|
|
if (ImGui::BeginCombo("", sampleRatePreview)) {
|
|
|
|
if (ImGui::BeginCombo("", sampleRatePreview)) {
|
|
|
|
for (int i = 0; i < 6; ++i) {
|
|
|
|
for (int i = 0; i < sampleRateList.size() - 1; ++i) {
|
|
|
|
if (ImGui::Selectable(sampleRateList[i])) {
|
|
|
|
if (ImGui::Selectable(sampleRateList[i])) {
|
|
|
|
sampleRatePreview = sampleRateList[i];
|
|
|
|
sampleRatePreview = sampleRateList[i];
|
|
|
|
if (m_device != nullptr && !m_device->is_running()) {
|
|
|
|
if (m_device != nullptr && !m_device->is_running()) {
|
|
|
|