From b1449ebcf67da3064ade32998edccb4f0e680051 Mon Sep 17 00:00:00 2001 From: zetaPRIME Date: Mon, 22 Jul 2019 03:26:39 -0400 Subject: [PATCH] attempt to speed up pattern switching --- notes | 8 ++-- xybrid/ui/patterneditormodel.cpp | 72 ++++++++++++++++---------------- xybrid/ui/patterneditorview.cpp | 12 ++++-- 3 files changed, 48 insertions(+), 44 deletions(-) diff --git a/notes b/notes index 9570c92..121c1bd 100644 --- a/notes +++ b/notes @@ -32,17 +32,13 @@ parameters { TODO { immediate frontburner { - - reimplement sample import to IPC from standalone ffmpeg since QAudioDecoder is partially broken on arch and completely broken on macOS - # ffprobe -v quiet -show_streams -select_streams a -of json testOut.mp3 - # ffmpeg -i input.flv -f f32le -acodec pcm_f32le - distortion effect single-selection sampler global (default) pan (PXX) for InstrumentCore - - node function to release unneeded old data when stopping playback - ... + add ,XX support to global tempo } - actual config file loading/saving @@ -55,6 +51,8 @@ TODO { bugs to fix { playback after stopping immediately after a note in the first pattern played sometimes skips that note things can apparently be hooked up cyclically, which completely breaks the queue + + pattern switching is slow when changing (especially increasing) number of rows; set fixed page size to avoid reallocation? } misc features needed before proper release { diff --git a/xybrid/ui/patterneditormodel.cpp b/xybrid/ui/patterneditormodel.cpp index a17f56e..be458df 100644 --- a/xybrid/ui/patterneditormodel.cpp +++ b/xybrid/ui/patterneditormodel.cpp @@ -5,6 +5,8 @@ using Xybrid::Data::Pattern; #include "ui/patterneditorview.h" using Xybrid::UI::PatternEditorView; +#include "util/strings.h" + #include #include #include @@ -16,6 +18,7 @@ namespace { // helper functions int cellWidthParam; int cellWidthParamTab; int headerHeight; + QSize hsz, hhsz; constexpr char hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' @@ -23,21 +26,21 @@ namespace { // helper functions constexpr char notemap[] = "C-C#D-D#E-F-F#G-G#A-A#B-"; - std::string hexStr(unsigned char *data, uint len) { - std::string s(len * 2, ' '); - for (uint i = 0; i < len; ++i) { + QString hexStr(unsigned char *data, int len) { + QString s(len * 2, ' '); + for (int i = 0; i < len; ++i) { s[2 * i] = hexmap[(data[i] & 0xF0) >> 4]; s[2 * i + 1] = hexmap[data[i] & 0x0F]; } return s; } - std::string byteStr(int t) { + QString byteStr(int t) { unsigned char c = static_cast(t & 255); return hexStr(&c, 1); } - std::string noteStr(int n) { - std::string s(3, ' '); + QString noteStr(int n) { + QString s(3, ' '); int nn = n % 12; int oc = (n - nn) / 12; s[2] = '0' + static_cast(oc); @@ -95,29 +98,27 @@ QVariant PatternEditorModel::data(const QModelIndex &index, int role) const { int ch = (index.column() - cc) / colsPerChannel; auto& row = pattern->rowAt(ch, index.row()-1); if (cc == 0) { // port - if (row.port >= 0 && row.port < 256) return QString::fromStdString(byteStr(row.port)); - if (row.port == -2) return QString("(G)"); - if (row.port == -3) return QString("L"); - return QString(" - "); + if (row.port >= 0 && row.port < 256) return byteStr(row.port); + if (row.port == -2) return qs("(G)"); + if (row.port == -3) return qs("L"); + return qs(" - "); } else if (cc == 1) { // note - if (row.note >= 0) return QString::fromStdString(noteStr(row.note)); - if (row.note == -2) return QString(" ^ "); // note off - if (row.note == -3) return QString(" x "); // hard cut - return QString(" - "); + if (row.note >= 0) return noteStr(row.note); + if (row.note == -2) return qs(" ^ "); // note off + if (row.note == -3) return qs(" x "); // hard cut + return qs(" - "); } else { size_t cp = static_cast(((cc - 2) - (cc % 2)) / 2); - //return QString::number((cp)); if (cc % 2 == 0) { - if (row.numParams() > cp) return QString::fromStdString(std::string(1,static_cast(row.params->at(cp)[0]))); - if (row.numParams() == cp) return QString("» "); - return QString(""); + if (row.numParams() > cp) return QString(1,static_cast(row.params->at(cp)[0])); + if (row.numParams() == cp) return qs("» "); + return qs(""); } if (row.numParams() > cp) { - if (row.params->at(cp)[0] == ' ') return QString("- "); - return QString::fromStdString(byteStr(row.params->at(cp)[1])); + if (row.params->at(cp)[0] == ' ') return qs("- "); + return byteStr(row.params->at(cp)[1]); } - return QString(""); - //return QString("--"); + return qs(""); } } else if (role == Qt::SizeHintRole) { if (index.row() >= pattern->rows) return QSize(-1, -1); @@ -131,12 +132,15 @@ QVariant PatternEditorModel::headerData(int section, Qt::Orientation orientation if (section == 0 || section > pattern->rows) return QVariant(); // blank end section return QString::number(section-1); } else if (role == Qt::SizeHintRole) { - auto fm = QFontMetrics(QFont(/*"Iosevka Term Light", 9*/)); - if (orientation == Qt::Orientation::Vertical) { - if (section == 0 || section > pattern->rows) return QSize(-1, endHeight); // fill ends to center - return fm.boundingRect("255").size() + QSize(8, 4); // this should fit 0-999 + if (orientation == Qt::Orientation::Vertical) if (section == 0 || section > pattern->rows) return QSize(-1, endHeight); // fill ends to center + if (hsz.isEmpty()) { + auto fm = QFontMetrics(QFont(/*"Iosevka Term Light", 9*/)); + hsz = fm.boundingRect("255").size() + QSize(8, 4); // this should fit 0-999 + hhsz = QSize(0, hsz.height()); } - return QSize(0, fm.height() + 4); + return orientation == Qt::Vertical ? hsz : hhsz; + + //return QSize(0, fm.height() + 4); } else if (role == Qt::TextAlignmentRole) return Qt::AlignCenter; return QVariant(); } @@ -179,12 +183,10 @@ void PatternEditorModel::setPattern(const std::shared_ptr& pattern) { } void PatternEditorModel::updateColumnDisplay() { - /*static int qi = 0; - qDebug() << QString("column display request #%1").arg(qi++);//*/ if (pattern == nullptr) return; auto view = static_cast(parent()); - view->setUpdatesEnabled(false); - auto fm = QFontMetrics(QFont("Iosevka Term Light", 9)); + //view->setUpdatesEnabled(false); + //auto fm = QFontMetrics(QFont("Iosevka Term Light", 9)); for (size_t ch = 0; ch < pattern->channels.size(); ch++) { auto& c = pattern->channels.at(ch); size_t maxParams = 0; @@ -217,13 +219,13 @@ void PatternEditorModel::updateColumnDisplay() { int lsw = view->columnWidth(lastShown); view->setColumnWidth(lastShown, std::max(lsw + 3, minWidth - (chWidth - lsw))); } - view->setUpdatesEnabled(true); + //view->setUpdatesEnabled(true); view->updateHeader(true); } void PatternEditorModel::updateFold() { auto view = static_cast(parent()); - view->setUpdatesEnabled(false); + //view->setUpdatesEnabled(false); int ifold = 1; if (folded && pattern->fold > 1) ifold = pattern->fold; int rows = this->rowCount()-2; @@ -231,9 +233,9 @@ void PatternEditorModel::updateFold() { view->setRowHidden(rows+1, false); for (int i = 0; i < rows; i++) { view->setRowHidden(i+1, false); // dispel any "phantoms" we might end up having - view->setRowHidden(i+1, (i < pattern->rows && i % ifold != 0)); + if (i < pattern->rows && i % ifold != 0) view->setRowHidden(i+1, true); } - view->setUpdatesEnabled(true); + //view->setUpdatesEnabled(true); } void PatternEditorModel::toggleFold() { diff --git a/xybrid/ui/patterneditorview.cpp b/xybrid/ui/patterneditorview.cpp index 1314f5c..4f28dfb 100644 --- a/xybrid/ui/patterneditorview.cpp +++ b/xybrid/ui/patterneditorview.cpp @@ -158,6 +158,7 @@ PatternEditorView::PatternEditorView(QWidget *parent) : QTableView(parent) { // fold connect(new QShortcut(QKeySequence("Ctrl+Space"), this), &QShortcut::activated, this, [this] { + setUpdatesEnabled(false); mdl->toggleFold(); auto p = mdl->getPattern(); auto ind = currentIndex(); @@ -167,7 +168,9 @@ PatternEditorView::PatternEditorView(QWidget *parent) : QTableView(parent) { setCurrentIndex(ind); if (selectedIndexes().count() <= 1) selectionModel()->select(ind, QItemSelectionModel::SelectionFlag::ClearAndSelect); } - QTimer::singleShot(1, [this, ind]{ scrollTo(ind, ScrollHint::PositionAtCenter); }); + scrollTo(ind, ScrollHint::PositionAtCenter); + setUpdatesEnabled(true); + //QTimer::singleShot(1, [this, ind]{ scrollTo(ind, ScrollHint::PositionAtCenter); }); }); // cut/copy/paste @@ -321,10 +324,10 @@ void PatternEditorView::stopPreview(int key) { } void PatternEditorView::setPattern(const std::shared_ptr& pattern) { + setUpdatesEnabled(false); mdl->setPattern(pattern); - //horizontalHeader()->isSectionHidden() - //columnCountChanged(0, mdl->columnCount()); - rowCountChanged(0, mdl->rowCount()); + + //rowCountChanged(0, mdl->rowCount()); auto cur = currentIndex(); auto ind = model()->index(std::clamp(cur.row(), 1, pattern->rows), std::clamp(cur.column(), 0, std::max(0, mdl->columnCount() - 2))); @@ -333,6 +336,7 @@ void PatternEditorView::setPattern(const std::shared_ptr& pattern) { setCurrentIndex(ind); selectionModel()->select(ind, QItemSelectionModel::ClearAndSelect); scrollTo(ind, ScrollHint::PositionAtCenter); + setUpdatesEnabled(true); } void PatternEditorView::updateGeometries() {