buffered draw samples; increased read rate

pull/1/head
Clyne 3 years ago
parent 1cf4908a23
commit 9f48039620

@ -16,6 +16,9 @@
#include "wav.hpp"
#include <charconv>
#include <cmath>
#include <cstdio>
#include <deque>
#include <fstream>
#include <mutex>
#include <thread>
@ -43,6 +46,14 @@ static const unsigned int sampleRateInts[6] = {
48'000,
96'000
};
static const unsigned int sampleRateBSizes[6] = {
8000,
16000,
20000,
32000,
48000,
96000,
};
static bool measureCodeTime = false;
static bool drawSamples = false;
@ -56,11 +67,14 @@ static bool popupRequestDraw = false;
static bool popupRequestLog = false;
static std::mutex mutexDrawSamples;
static std::vector<stmdsp::dacsample_t> drawSamplesBuf;
static std::vector<stmdsp::dacsample_t> drawSamplesBuf2;
//static std::vector<stmdsp::dacsample_t> drawSamplesBuf;
//static std::vector<stmdsp::dacsample_t> drawSamplesBuf2;
static std::ofstream logSamplesFile;
static wav::clip wavOutput;
static std::deque<stmdsp::dacsample_t> drawSamplesQueue;
static unsigned int drawSamplesBufferSize = 4096;
static void measureCodeTask(stmdsp::device *device)
{
if (device == nullptr)
@ -77,28 +91,94 @@ static void drawSamplesTask(stmdsp::device *device)
const bool doLogger = logResults && logSamplesFile.good();
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.5f;
const double bufferSize = m_device->get_buffer_size();
const double sampleRate = sampleRateInts[m_device->get_sample_rate()];
double samplesToPush = sampleRate * 0.0007 * 2;
while (m_device->is_running()) {
{
std::scoped_lock lock (mutexDrawSamples);
drawSamplesBuf = m_device->continuous_read();
if (drawSamplesInput && popupRequestDraw)
drawSamplesBuf2 = m_device->continuous_read_input();
std::vector<stmdsp::dacsample_t> lastReadBuffer (bufferSize, 2048);
double lastReadIndexD = 0;
double desiredTime = bufferSize / sampleRate * 1.01;
auto bufferTime = std::chrono::high_resolution_clock::now();
while (m_device && m_device->is_running()) {
if (samplesToPush < bufferSize) {
if (lastReadIndexD >= bufferSize - 1)
lastReadIndexD -= bufferSize - 1;
unsigned int lastReadIndex = std::floor(lastReadIndexD);
unsigned int end = lastReadIndexD + samplesToPush;
{
std::scoped_lock lock (mutexDrawSamples);
for (; lastReadIndexD < end; lastReadIndexD += 1) {
if (lastReadIndex >= lastReadBuffer.size()) {
auto old = samplesToPush;
auto now = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = now - bufferTime;
lastReadBuffer = m_device->continuous_read();
if (drawSamplesInput && popupRequestDraw)
drawSamplesBuf2 = m_device->continuous_read_input();
if (lastReadBuffer.empty()) {
do {
std::this_thread::sleep_for(std::chrono::microseconds(2));
lastReadBuffer = m_device->continuous_read();
} while (lastReadBuffer.empty() && m_device->is_running());
}
bufferTime = now;
if (double c = diff.count(); c > desiredTime + 0.001) {
// Too slow
samplesToPush = (samplesToPush * c / desiredTime) * 0.98;
if (samplesToPush > bufferSize)
samplesToPush = bufferSize;
} else if (c < desiredTime - 0.001) {
// Too fast
samplesToPush = (samplesToPush * c / desiredTime) * 0.98;
}
lastReadIndex = 0;
}
drawSamplesQueue.push_back(lastReadBuffer[lastReadIndex++]);
}
}
std::this_thread::sleep_for(std::chrono::microseconds(700));
}
// Full blast
else {
lastReadBuffer = m_device->continuous_read();
while (lastReadBuffer.empty() && m_device->is_running()) {
std::this_thread::sleep_for(std::chrono::microseconds(1));
lastReadBuffer = m_device->continuous_read();
}
{
std::scoped_lock lock (mutexDrawSamples);
for (const auto& s : lastReadBuffer)
drawSamplesQueue.push_back(s);
}
auto now = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = now - bufferTime;
bufferTime = now;
double c = diff.count();
if (c < desiredTime) {
samplesToPush = (samplesToPush * c / desiredTime) * 0.98;
}
if (doLogger) {
for (const auto& s : drawSamplesBuf)
logSamplesFile << s << '\n';
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
//if (doLogger) {
// for (const auto& s : drawSamplesBuf)
// logSamplesFile << s << '\n';
//}
}
std::fill(drawSamplesBuf.begin(), drawSamplesBuf.end(), 2048);
std::fill(drawSamplesBuf2.begin(), drawSamplesBuf2.end(), 2048);
}
static void feedSigGenTask(stmdsp::device *device)
@ -264,34 +344,62 @@ void deviceRenderDraw()
{
if (popupRequestDraw) {
ImGui::Begin("draw", &popupRequestDraw);
ImGui::Checkbox("Draw input", &drawSamplesInput);
{
std::scoped_lock lock (mutexDrawSamples);
auto drawList = ImGui::GetWindowDrawList();
const ImVec2 p0 = ImGui::GetWindowPos();
const auto size = ImGui::GetWindowSize();
//ImVec2 p1 (p0.x + size.x, p0.y + size.y);
//ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
//ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
//drawList->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
const unsigned int didx = 1.f / (size.x / static_cast<float>(drawSamplesBuf.size()));
ImVec2 pp = p0;
for (auto i = 0u; i < drawSamplesBuf.size(); i += didx) {
ImVec2 next (pp.x + 1, p0.y + (float)drawSamplesBuf[i] / 4095.f * size.y);
drawList->AddLine(pp, next, ImGui::GetColorU32(IM_COL32(128, 0, 0, 255)));
pp = next;
}
ImGui::Checkbox("Draw input", &drawSamplesInput);
if (drawSamplesInput) {
pp = p0;
for (auto i = 0u; i < drawSamplesBuf2.size(); i += didx) {
ImVec2 next (pp.x + 1, p0.y + (float)drawSamplesBuf2[i] / 4095.f * size.y);
drawList->AddLine(pp, next, ImGui::GetColorU32(IM_COL32(0, 0, 128, 255)));
pp = next;
}
static std::vector<stmdsp::dacsample_t> buffer;
static decltype(buffer.begin()) bufferCursor;
static long unsigned int drawChunkSize = 0;
static std::chrono::time_point<std::chrono::high_resolution_clock> timee;
if (buffer.size() != drawSamplesBufferSize) {
buffer.resize(drawSamplesBufferSize);
bufferCursor = buffer.begin();
}
{
std::scoped_lock lock (mutexDrawSamples);
auto qsize = drawSamplesQueue.size();
auto count = qsize;//std::min(qsize, drawChunkSize);
//if (count > 0)
// printf("draw: %9llu/%9lu\n", qsize, count);
for (auto i = count; i; --i) {
*bufferCursor = drawSamplesQueue.front();
drawSamplesQueue.pop_front();
if (++bufferCursor == buffer.end()) {
bufferCursor = buffer.begin();
//auto now = std::chrono::high_resolution_clock::now();
//std::chrono::duration<double> diff = now - timee;
//timee = now;
//printf("\rtime: %.9lf", diff);
//fflush(stdout);
}
}
}
auto drawList = ImGui::GetWindowDrawList();
ImVec2 p0 = ImGui::GetWindowPos();
auto size = ImGui::GetWindowSize();
p0.y += 65;
size.y -= 70;
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()));
ImVec2 pp = p0;
for (auto i = 0u; i < buffer.size(); i += didx) {
ImVec2 next (pp.x + 1, p0.y + size.y - (float)buffer[i] / 4095.f * size.y);
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 - (float)buffer[i] / 4095.f * size.y);
drawList->AddLine(pp, next, ImGui::GetColorU32(IM_COL32(0, 0, 255, 255)));
pp = next;
}
}
ImGui::End();
}
}
@ -304,21 +412,21 @@ void deviceRenderMenu()
static const char *connectLabel = "Connect";
if (ImGui::MenuItem(connectLabel)) {
connectLabel = isConnected ? "Connect" : "Disconnect";
deviceConnect();
connectLabel = isConnected ? "Disconnect" : "Connect";
}
ImGui::Separator();
static const char *startLabel = "Start";
if (ImGui::MenuItem(startLabel, nullptr, false, isConnected)) {
startLabel = isRunning ? "Start" : "Stop";
deviceStart();
startLabel = isRunning ? "Stop" : "Start";
}
/**
TODO test siggen formula
TODO improve siggen audio streaming
TODO draw: smoothly chain captures
TODO draw: smoothly chain captures for 96kHz
*/
if (ImGui::MenuItem("Upload algorithm", nullptr, false, isConnected))
deviceAlgorithmUpload();
@ -389,8 +497,14 @@ void deviceRenderToolbar()
for (int i = 0; i < 6; ++i) {
if (ImGui::Selectable(sampleRateList[i])) {
sampleRatePreview = sampleRateList[i];
if (m_device != nullptr && !m_device->is_running())
m_device->set_sample_rate(i);
if (m_device != nullptr && !m_device->is_running()) {
do {
m_device->set_sample_rate(i);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
} while (m_device->get_sample_rate() != i);
drawSamplesBufferSize = sampleRateBSizes[i];
}
}
}
ImGui::EndCombo();
@ -404,7 +518,9 @@ void deviceConnect()
if (auto devices = scanner.scan(); devices.size() > 0) {
m_device = new stmdsp::device(devices.front());
if (m_device->connected()) {
sampleRatePreview = sampleRateList[m_device->get_sample_rate()];
auto sri = m_device->get_sample_rate();
sampleRatePreview = sampleRateList[sri];
drawSamplesBufferSize = sampleRateBSizes[sri];
log("Connected!");
} else {
delete m_device;
@ -429,7 +545,11 @@ void deviceStart()
}
if (m_device->is_running()) {
m_device->continuous_stop();
{
std::scoped_lock lock (mutexDrawSamples);
std::this_thread::sleep_for(std::chrono::microseconds(150));
m_device->continuous_stop();
}
if (logResults) {
logSamplesFile.close();
logResults = false;

@ -19,7 +19,6 @@
#include <string>
// Externs
extern ImFont *fontSans;
extern ImFont *fontMono;

@ -27,7 +27,7 @@ namespace stmdsp
}
device::device(const std::string& file) :
m_serial(file, 1000000/*230400*/, serial::Timeout::simpleTimeout(50))
m_serial(file, 8'000'000/*230400*/, serial::Timeout::simpleTimeout(50))
{
if (m_serial.isOpen()) {
m_serial.flush();

Loading…
Cancel
Save