diff --git a/src/editor/EditorWindow.cpp b/src/editor/EditorWindow.cpp index 1427642a..2bd9d888 100644 --- a/src/editor/EditorWindow.cpp +++ b/src/editor/EditorWindow.cpp @@ -111,7 +111,7 @@ EditorWindow::EditorWindow(QWidget *parent) m_key_splitter = new QSplitter(Qt::Vertical, m_splitter); m_scroll_area = new EditorScrollArea(m_key_splitter, true); - m_keyboard_view = new KeyboardView(m_client, m_moo_clock, m_scroll_area); + m_keyboard_view = new KeyboardView(m_client, m_scroll_area); m_scroll_area->setWidget(m_keyboard_view); // TODO: find a better place for this. @@ -185,14 +185,12 @@ EditorWindow::EditorWindow(QWidget *parent) m_param_scroll_area = new EditorScrollArea(m_key_splitter, false); m_param_scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - m_param_scroll_area->setWidget( - new ParamView(m_client, m_moo_clock, m_param_scroll_area)); + m_param_scroll_area->setWidget(new ParamView(m_client, m_param_scroll_area)); m_measure_scroll_area = new EditorScrollArea(m_splitter, false); m_measure_scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); m_measure_scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - m_measure_view = - new MeasureView(m_client, m_moo_clock, m_measure_scroll_area); + m_measure_view = new MeasureView(m_client, m_measure_scroll_area); m_measure_scroll_area->setWidget(m_measure_view); m_measure_scroll_area->setSizePolicy( QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); diff --git a/src/editor/EditorWindow.h b/src/editor/EditorWindow.h index c75613df..e0e958f5 100644 --- a/src/editor/EditorWindow.h +++ b/src/editor/EditorWindow.h @@ -1,6 +1,7 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#include #include #include #include @@ -27,7 +28,6 @@ #include "sidemenu/UnitListModel.h" #include "views/KeyboardView.h" #include "views/MeasureView.h" -#include QT_BEGIN_NAMESPACE namespace Ui { @@ -55,7 +55,7 @@ class EditorWindow : public QMainWindow { void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; void closeEvent(QCloseEvent* event) override; - bool eventFilter(QObject *watched, QEvent *event) override; + bool eventFilter(QObject* watched, QEvent* event) override; KeyboardView* m_keyboard_view; MeasureView* m_measure_view; pxtnService m_pxtn; diff --git a/src/editor/PxtoneClient.cpp b/src/editor/PxtoneClient.cpp index 51192283..aafa7aa4 100644 --- a/src/editor/PxtoneClient.cpp +++ b/src/editor/PxtoneClient.cpp @@ -115,8 +115,8 @@ void PxtoneClient::loadDescriptor(pxtnDescriptor &desc) { } { bool ok; - double v = Settings::value(BUFFER_LENGTH_KEY, DEFAULT_BUFFER_LENGTH) - .toDouble(&ok); + double v = + Settings::value(BUFFER_LENGTH_KEY, DEFAULT_BUFFER_LENGTH).toDouble(&ok); if (ok) setBufferSize(v); } m_pxtn_device->setPlaying(false); @@ -156,13 +156,13 @@ void PxtoneClient::togglePlayState() { } void PxtoneClient::sendPlayState(bool from_action) { - sendAction(PlayState{pxtn()->moo_get_now_clock(*moo()), - m_pxtn_device->playing(), from_action}); + sendAction( + PlayState{moo()->get_now_clock(), m_pxtn_device->playing(), from_action}); } void PxtoneClient::resetAndSuspendAudio() { m_pxtn_device->setPlaying(false); - if (pxtn()->moo_get_now_clock(*moo()) > m_last_seek) + if (moo()->get_now_clock() > m_last_seek) seekMoo(m_last_seek); else seekMoo(0); diff --git a/src/editor/PxtoneController.cpp b/src/editor/PxtoneController.cpp index 2b581415..f27680aa 100644 --- a/src/editor/PxtoneController.cpp +++ b/src/editor/PxtoneController.cpp @@ -4,13 +4,12 @@ #include #include -#include "audio/RtAudioRenderer.h" - const QTextCodec *shift_jis_codec = QTextCodec::codecForName("Shift-JIS"); PxtoneController::PxtoneController(int uid, pxtnService *pxtn, mooState *moo_state, QObject *parent) : QObject(parent), + m_audio_renderer(std::make_unique(pxtn)), m_uid(uid), m_pxtn(pxtn), m_moo_state(moo_state), @@ -398,9 +397,7 @@ void PxtoneController::seekMoo(int64_t clock) { emit seeked(clock); } -void PxtoneController::refreshMoo() { - seekMoo(m_pxtn->moo_get_now_clock(*m_moo_state)); -} +void PxtoneController::refreshMoo() { seekMoo(m_moo_state->get_now_clock()); } void PxtoneController::setVolume(int volume) { double v = volume / 100.0; @@ -420,6 +417,7 @@ void PxtoneController::setSongComment(const QString &comment) { } bool PxtoneController::loadDescriptor(pxtnDescriptor &desc) { + m_audio_renderer.reset(); emit beginRefresh(); if (desc.get_size_bytes() > 0) { if (m_pxtn->read(&desc) != pxtnOK) { @@ -450,7 +448,7 @@ bool PxtoneController::loadDescriptor(pxtnDescriptor &desc) { emit tempoBeatChanged(); emit newSong(); - new RtAudioRenderer(m_pxtn); + m_audio_renderer = std::make_unique(m_pxtn); return true; } diff --git a/src/editor/PxtoneController.h b/src/editor/PxtoneController.h index 8d18ed56..f19dc097 100644 --- a/src/editor/PxtoneController.h +++ b/src/editor/PxtoneController.h @@ -5,6 +5,7 @@ #include #include "audio/PxtoneIODevice.h" +#include "audio/RtAudioRenderer.h" #include "protocol/PxtoneEditAction.h" #include "protocol/RemoteAction.h" @@ -62,6 +63,8 @@ class PxtoneController : public QObject { return true; }) const; + std::unique_ptr m_audio_renderer; + public slots: // Maybe these types could be grouped. void applyRemoteAction(const EditAction &a, qint64 uid); diff --git a/src/editor/audio/RtAudioRenderer.cpp b/src/editor/audio/RtAudioRenderer.cpp index fb66755f..819797b7 100644 --- a/src/editor/audio/RtAudioRenderer.cpp +++ b/src/editor/audio/RtAudioRenderer.cpp @@ -4,6 +4,13 @@ #include +int MooTiming::now_no_wrap(const pxtnMaster *master) { + return MasterExtended::unwrapClock(master, now_clock, num_loops); +} + +const unsigned int BUFFER_FRAMES = + 256; // At higher buffers, this does stuttter. So you will need a + // MooClock-like thing anyway. int rtAudioMoo(void *outputBuffer, void * /*inputBuffer*/, unsigned int nBufferFrames, double /*streamTime*/, RtAudioStreamStatus status, void *userData) { @@ -17,6 +24,8 @@ int rtAudioMoo(void *outputBuffer, void * /*inputBuffer*/, if (!renderer->m_pxtn->Moo(renderer->m_moo_state, outputBuffer, size, nullptr, nullptr)) return 1; + renderer->m_moo_timing.store( + {renderer->m_moo_state.get_now_clock(), renderer->m_moo_state.num_loop}); return 0; } @@ -26,6 +35,7 @@ RtAudioRenderer::RtAudioRenderer(const pxtnService *pxtn) if (m_dac.getDeviceCount() < 1) throw std::runtime_error("No audio devices found"); + qDebug() << "lock free" << m_moo_timing.is_lock_free(); RtAudio::StreamParameters parameters; parameters.deviceId = m_dac.getDefaultOutputDevice(); parameters.nChannels = 2; @@ -40,13 +50,15 @@ RtAudioRenderer::RtAudioRenderer(const pxtnService *pxtn) } int sampleRate = 44100; - unsigned int bufferFrames = 256; // 256 sample frames + unsigned int bufferFrames = BUFFER_FRAMES; m_dac.openStream(¶meters, NULL, RTAUDIO_SINT16, sampleRate, &bufferFrames, &rtAudioMoo, this); m_dac.startStream(); - qDebug() << "started stream"; + qDebug() << "started stream" << bufferFrames; } +MooTiming RtAudioRenderer::moo_timing() const { return m_moo_timing.load(); } + RtAudioRenderer::~RtAudioRenderer() { try { m_dac.stopStream(); diff --git a/src/editor/audio/RtAudioRenderer.h b/src/editor/audio/RtAudioRenderer.h index 4d413b0b..fea8b491 100644 --- a/src/editor/audio/RtAudioRenderer.h +++ b/src/editor/audio/RtAudioRenderer.h @@ -3,10 +3,20 @@ #include +#include + #include "pxtone/pxtnService.h" +struct MooTiming { + int now_clock; + int num_loops; + + int now_no_wrap(const pxtnMaster *master); +}; + class RtAudioRenderer { const pxtnService *m_pxtn; + std::atomic m_moo_timing; mooState m_moo_state; RtAudio m_dac; friend int rtAudioMoo(void *, void *, unsigned int, double, @@ -14,6 +24,8 @@ class RtAudioRenderer { public: RtAudioRenderer(const pxtnService *pxtn); + MooTiming moo_timing() const; + ~RtAudioRenderer(); }; diff --git a/src/editor/views/KeyboardView.cpp b/src/editor/views/KeyboardView.cpp index b80e1807..84c5bbce 100644 --- a/src/editor/views/KeyboardView.cpp +++ b/src/editor/views/KeyboardView.cpp @@ -38,8 +38,7 @@ void KeyboardView::setHoveredUnitNo(std::optional new_unit_no) { } } -KeyboardView::KeyboardView(PxtoneClient *client, MooClock *moo_clock, - QScrollArea *parent) +KeyboardView::KeyboardView(PxtoneClient *client, QScrollArea *parent) : QWidget(parent), m_scrollarea(parent), m_pxtn(client->pxtn()), @@ -50,7 +49,6 @@ KeyboardView::KeyboardView(PxtoneClient *client, MooClock *moo_clock, m_audio_note_preview(nullptr), m_anim(new Animation(this)), m_client(client), - m_moo_clock(moo_clock), m_select_unit_enabled(false), m_last_left_kb_pitch(0), m_test_activity(false) { @@ -87,7 +85,9 @@ KeyboardView::KeyboardView(PxtoneClient *client, MooClock *moo_clock, void KeyboardView::ensurePlayheadFollowed() { bool follow_exactly = m_client->editState().m_follow_playhead == FollowPlayhead::Follow; - double logicalX = m_moo_clock->now() / m_client->editState().scale.clockPerPx; + double logicalX = + m_client->controller()->m_audio_renderer->moo_timing().now_clock / + m_client->editState().scale.clockPerPx; double x = worldTransform().map(QPointF(logicalX, 0)).x(); emit ensureVisibleX(x, follow_exactly); } @@ -579,7 +579,7 @@ void KeyboardView::paintEvent(QPaintEvent *raw_event) { std::vector drawStates; for (int i = 0; i < m_pxtn->Unit_Num(); ++i) drawStates.emplace_back(); - int clock = m_moo_clock->now(); + int clock = m_client->controller()->m_audio_renderer->moo_timing().now_clock; // Draw the note blocks! Upon hitting an event, see if we are able to draw a // previous block. @@ -659,7 +659,7 @@ void KeyboardView::paintEvent(QPaintEvent *raw_event) { } double on_strength = 0; - if (m_client->isPlaying()) { + if (m_client->isPlaying() || true) { if (clock >= on.start) { if (!m_dark) on_strength = clock < on.end ? 1 : 0; @@ -788,13 +788,15 @@ void KeyboardView::paintEvent(QPaintEvent *raw_event) { m_client->editState().scale.clockPerPx, size().height(), mySelectionAlphaMultiplier); if (!m_select_unit_enabled) - drawOngoingAction(m_client->editState(), m_edit_state, painter, width(), - height(), m_moo_clock->nowNoWrap(), m_pxtn->master, 1, 1, - displayEdo); + drawOngoingAction( + m_client->editState(), m_edit_state, painter, width(), height(), + m_client->controller()->m_audio_renderer->moo_timing().now_no_wrap( + m_pxtn->master), + m_pxtn->master, 1, 1, displayEdo); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); drawLastSeek(painter, m_client, height(), false); - drawRepeatAndEndBars(painter, m_moo_clock, + drawRepeatAndEndBars(painter, m_pxtn->master, m_client->editState().scale.clockPerPx, height()); // Left piano @@ -863,7 +865,7 @@ void KeyboardView::paintEvent(QPaintEvent *raw_event) { painter.setTransform(t); } - drawCurrentPlayerPosition(painter, m_moo_clock, height(), + drawCurrentPlayerPosition(painter, clock, height(), m_client->editState().scale.clockPerPx, false); // Draw cursors diff --git a/src/editor/views/KeyboardView.h b/src/editor/views/KeyboardView.h index f981e7d0..fdca074b 100644 --- a/src/editor/views/KeyboardView.h +++ b/src/editor/views/KeyboardView.h @@ -28,8 +28,7 @@ struct LocalEditState { class KeyboardView : public QWidget { Q_OBJECT public: - explicit KeyboardView(PxtoneClient *client, MooClock *moo_clock, - QScrollArea *parent = nullptr); + explicit KeyboardView(PxtoneClient *client, QScrollArea *parent = nullptr); void cycleCurrentUnit(int offset, bool selectedOnly); void setCurrentUnitNo(int unit_no, bool preserve_follow); @@ -78,7 +77,6 @@ class KeyboardView : public QWidget { std::unique_ptr m_audio_note_preview; Animation *m_anim; PxtoneClient *m_client; - MooClock *m_moo_clock; std::optional m_focused_unit_no; std::optional m_hovered_unit_no; std::map m_midi_notes; diff --git a/src/editor/views/MeasureView.cpp b/src/editor/views/MeasureView.cpp index b4ee3307..21ece72e 100644 --- a/src/editor/views/MeasureView.cpp +++ b/src/editor/views/MeasureView.cpp @@ -26,12 +26,10 @@ constexpr int UNIT_EDIT_MARGIN = 1; constexpr int UNIT_EDIT_INCREMENT = UNIT_EDIT_MARGIN + UNIT_EDIT_HEIGHT; inline int unit_edit_y(int i) { return UNIT_EDIT_Y + UNIT_EDIT_INCREMENT * i; } -MeasureView::MeasureView(PxtoneClient *client, MooClock *moo_clock, - QWidget *parent) +MeasureView::MeasureView(PxtoneClient *client, QWidget *parent) : QWidget(parent), m_client(client), m_anim(new Animation(this)), - m_moo_clock(moo_clock), m_label_font(QFont()), m_label_font_metrics(m_label_font), m_audio_note_preview(nullptr), @@ -356,16 +354,15 @@ void MeasureView::paintEvent(QPaintEvent *raw_event) { StyleEditor::config.color.MeasureBeat); } drawFlag(&painter, FlagType::Top, false, 0, FLAG_Y); - if (m_moo_clock->repeat_clock() > 0) { - drawFlag( - &painter, FlagType::Repeat, false, - m_moo_clock->repeat_clock() / m_client->editState().scale.clockPerPx, - FLAG_Y); + int repeat_clock = MasterExtended::repeat_clock(m_client->pxtn()->master); + if (repeat_clock > 0) { + drawFlag(&painter, FlagType::Repeat, false, + repeat_clock / m_client->editState().scale.clockPerPx, FLAG_Y); } - if (m_moo_clock->has_last()) { + int last_clock = MasterExtended::last_clock(m_client->pxtn()->master); + if (last_clock > 0) { drawFlag(&painter, FlagType::Last, false, - m_moo_clock->last_clock() / m_client->editState().scale.clockPerPx, - FLAG_Y); + last_clock / m_client->editState().scale.clockPerPx, FLAG_Y); } double scaleX = m_client->editState().scale.clockPerPx; @@ -414,7 +411,7 @@ void MeasureView::paintEvent(QPaintEvent *raw_event) { double seconds_per_clock = 60 / m_client->pxtn()->master->get_beat_tempo() / m_client->pxtn()->master->get_beat_clock(); - int now = m_moo_clock->now(); + int now = m_client->controller()->m_audio_renderer->moo_timing().now_clock; auto drawLastOn = [&](int no, bool erase) { if (last_on_by_no.count(no) > 0) { const Interval &i = last_on_by_no[no]; @@ -466,7 +463,7 @@ void MeasureView::paintEvent(QPaintEvent *raw_event) { drawLastOn(it->first, false); drawLastSeek(painter, m_client, height, true); - drawCurrentPlayerPosition(painter, m_moo_clock, height, + drawCurrentPlayerPosition(painter, now, height, m_client->editState().scale.clockPerPx, true); // Draw text labels if (Settings::PinnedUnitLabels::get()) { @@ -566,11 +563,15 @@ void MeasureView::paintEvent(QPaintEvent *raw_event) { } drawExistingSelection(painter, m_client->editState().mouse_edit_state, m_client->editState().scale.clockPerPx, height, 1); - if (!m_jump_to_unit_enabled) + if (!m_jump_to_unit_enabled) { + int now_no_wrap = + m_client->controller()->m_audio_renderer->moo_timing().now_no_wrap( + master); drawOngoingAction(m_client->editState(), unit_draw_params_map, m_client->unitIdMap(), painter, height, - m_client->quantizeClock(), clockPerMeas, - m_moo_clock->nowNoWrap(), m_client->pxtn()->master, 1, 1); + m_client->quantizeClock(), clockPerMeas, now_no_wrap, + m_client->pxtn()->master, 1, 1); + } // Draw cursors for (const auto &[uid, remote_state] : m_client->remoteEditStates()) { diff --git a/src/editor/views/MeasureView.h b/src/editor/views/MeasureView.h index 5875cc41..71d1c197 100644 --- a/src/editor/views/MeasureView.h +++ b/src/editor/views/MeasureView.h @@ -15,7 +15,6 @@ class MeasureView : public QWidget { PxtoneClient *m_client; Animation *m_anim; Scale m_last_scale; - MooClock *m_moo_clock; QFont m_label_font; QFontMetrics m_label_font_metrics; std::unique_ptr m_audio_note_preview; @@ -42,8 +41,7 @@ class MeasureView : public QWidget { void setHoveredUnitNo(std::optional); public: - explicit MeasureView(PxtoneClient *client, MooClock *moo_clock, - QWidget *parent = nullptr); + explicit MeasureView(PxtoneClient *client, QWidget *parent = nullptr); void setFocusedUnit(std::optional unit_no); void setSelectUnitEnabled(bool); diff --git a/src/editor/views/MooClock.cpp b/src/editor/views/MooClock.cpp index fd40796a..adc36fce 100644 --- a/src/editor/views/MooClock.cpp +++ b/src/editor/views/MooClock.cpp @@ -20,7 +20,7 @@ MooClock::MooClock(PxtoneClient *client) } void MooClock::tick() { - int clock = m_client->pxtn()->moo_get_now_clock(*m_client->moo()); + int clock = m_client->moo()->get_now_clock(); // Some really hacky magic to get the playhead smoother given that // there's a ton of buffering that makes it hard to actually tell where the diff --git a/src/editor/views/ParamView.cpp b/src/editor/views/ParamView.cpp index b78166f7..5f7ad866 100644 --- a/src/editor/views/ParamView.cpp +++ b/src/editor/views/ParamView.cpp @@ -9,11 +9,10 @@ #include "editor/Settings.h" #include "editor/StyleEditor.h" -ParamView::ParamView(PxtoneClient *client, MooClock *moo_clock, QWidget *parent) +ParamView::ParamView(PxtoneClient *client, QWidget *parent) : QWidget(parent), m_client(client), m_anim(new Animation(this)), - m_moo_clock(moo_clock), m_audio_note_preview(nullptr), m_woice_menu(new QMenu(this)), m_last_woice_menu_preview_id(-1) { @@ -495,8 +494,9 @@ void ParamView::paintEvent(QPaintEvent *raw_event) { 1, 0); drawLastSeek(painter, m_client, height, false); - drawCurrentPlayerPosition(painter, m_moo_clock, height, clockPerPx, false); - drawRepeatAndEndBars(painter, m_moo_clock, clockPerPx, height); + int clock = m_client->controller()->m_audio_renderer->moo_timing().now_clock; + drawCurrentPlayerPosition(painter, clock, height, clockPerPx, false); + drawRepeatAndEndBars(painter, m_client->pxtn()->master, clockPerPx, height); // Draw cursors for (const auto &[uid, remote_state] : m_client->remoteEditStates()) { diff --git a/src/editor/views/ParamView.h b/src/editor/views/ParamView.h index 08899496..578def7c 100644 --- a/src/editor/views/ParamView.h +++ b/src/editor/views/ParamView.h @@ -5,7 +5,6 @@ #include #include "Animation.h" -#include "MooClock.h" #include "editor/PxtoneClient.h" #include "editor/audio/NotePreview.h" @@ -15,7 +14,6 @@ class ParamView : public QWidget { PxtoneClient *m_client; Animation *m_anim; Scale m_last_scale; - MooClock *m_moo_clock; std::unique_ptr m_audio_note_preview; QMenu *m_woice_menu; int m_last_woice_menu_preview_id; @@ -29,8 +27,7 @@ class ParamView : public QWidget { QSize sizeHint() const override; public: - explicit ParamView(PxtoneClient *client, MooClock *moo_clock, - QWidget *parent = nullptr); + explicit ParamView(PxtoneClient *client, QWidget *parent = nullptr); signals: }; diff --git a/src/editor/views/ViewHelper.cpp b/src/editor/views/ViewHelper.cpp index f732b278..1e83b328 100644 --- a/src/editor/views/ViewHelper.cpp +++ b/src/editor/views/ViewHelper.cpp @@ -61,14 +61,12 @@ void drawPlayhead(QPainter &painter, qint32 x, qint32 height, QColor color, painter.fillRect(x, s, 1, height, color); } -void drawCurrentPlayerPosition(QPainter &painter, MooClock *moo_clock, - int height, qreal clockPerPx, bool drawHead) { +void drawCurrentPlayerPosition(QPainter &painter, int now, int height, + qreal clockPerPx, bool drawHead) { QColor color = Settings::RecordMidi::get() ? StyleEditor::config.color.PlayheadRecording : StyleEditor::config.color.Playhead; - if (!moo_clock->this_seek_caught_up() || moo_clock->now() <= 0) - color = makeTranslucent(color, 2); - const int x = moo_clock->now() / clockPerPx; + const int x = now / clockPerPx; drawPlayhead(painter, x, height, color, drawHead); } @@ -83,13 +81,15 @@ void drawLastSeek(QPainter &painter, const PxtoneClient *client, qint32 height, } } -void drawRepeatAndEndBars(QPainter &painter, const MooClock *moo_clock, +void drawRepeatAndEndBars(QPainter &painter, const pxtnMaster *master, qreal clockPerPx, int height) { - if (moo_clock->has_last()) - painter.fillRect(moo_clock->last_clock() / clockPerPx, 0, 1, height, + if (master->get_last_meas() > 0) + painter.fillRect(MasterExtended::last_clock(master) / clockPerPx, 0, 1, + height, makeTranslucent(StyleEditor::config.color.Playhead, 2)); - painter.fillRect(moo_clock->repeat_clock() / clockPerPx, 0, 1, height, + painter.fillRect(MasterExtended::repeat_clock(master) / clockPerPx, 0, 1, + height, makeTranslucent(StyleEditor::config.color.Playhead, 2)); } diff --git a/src/editor/views/ViewHelper.h b/src/editor/views/ViewHelper.h index c4e1bbef..e5920d4c 100644 --- a/src/editor/views/ViewHelper.h +++ b/src/editor/views/ViewHelper.h @@ -5,20 +5,19 @@ #include #include -#include "MooClock.h" +#include "editor/PxtoneClient.h" extern int impliedVelocity(MouseEditState state, qreal pitchPerPx); extern void drawCursor(const QPoint &position, QPainter &painter, const QColor &color, const QString &username, qint64 uid); -extern void drawCurrentPlayerPosition(QPainter &painter, MooClock *moo_clock, - int height, qreal clockPerPx, - bool drawHead); +extern void drawCurrentPlayerPosition(QPainter &painter, int now, int height, + qreal clockPerPx, bool drawHead); extern void drawPlayhead(QPainter &painter, qint32 x, qint32 height, QColor color, bool drawHead); extern void drawLastSeek(QPainter &painter, const PxtoneClient *client, qint32 height, bool drawHead); -extern void drawRepeatAndEndBars(QPainter &painter, const MooClock *moo_clock, +extern void drawRepeatAndEndBars(QPainter &painter, const pxtnMaster *master, qreal clockPerPx, int height); extern void handleWheelEventWithModifier(QWheelEvent *event, PxtoneClient *client); diff --git a/src/pxtone/pxtnMaster.cpp b/src/pxtone/pxtnMaster.cpp index 4f5cab95..41d07868 100644 --- a/src/pxtone/pxtnMaster.cpp +++ b/src/pxtone/pxtnMaster.cpp @@ -271,4 +271,7 @@ int wrapClock(const pxtnMaster *master, int clock) { repeat_clock(master); return clock; } +int unwrapClock(const pxtnMaster *master, int clock, int num_loops) { + return clock + num_loops * (last_clock(master) - repeat_clock(master)); +} } // namespace MasterExtended diff --git a/src/pxtone/pxtnMaster.h b/src/pxtone/pxtnMaster.h index bd19ab49..873b6ee4 100644 --- a/src/pxtone/pxtnMaster.h +++ b/src/pxtone/pxtnMaster.h @@ -58,6 +58,7 @@ class pxtnMaster { namespace MasterExtended { int wrapClock(const pxtnMaster *master, int clock); +int unwrapClock(const pxtnMaster *master, int clock, int num_loops); int last_clock(const pxtnMaster *master); int repeat_clock(const pxtnMaster *master); } // namespace MasterExtended diff --git a/src/pxtone/pxtnService.h b/src/pxtone/pxtnService.h index f108d52e..5e10754e 100644 --- a/src/pxtone/pxtnService.h +++ b/src/pxtone/pxtnService.h @@ -110,6 +110,7 @@ struct mooState { void resetGroups(int32_t group_num); bool resetUnits(size_t unit_num, std::shared_ptr woice); bool addUnit(std::shared_ptr woice); + int32_t get_now_clock(int smp_offset = 0) const; void tones_clear(); }; @@ -300,7 +301,6 @@ class pxtnService { int32_t moo_get_total_sample() const; - int32_t moo_get_now_clock(const mooState &moo_state) const; int32_t moo_get_end_clock() const; int32_t moo_get_sampling_offset() const; int32_t moo_get_sampling_end() const; diff --git a/src/pxtone/pxtnService_moo.cpp b/src/pxtone/pxtnService_moo.cpp index 8a9c2b99..61518326 100644 --- a/src/pxtone/pxtnService_moo.cpp +++ b/src/pxtone/pxtnService_moo.cpp @@ -41,6 +41,12 @@ bool mooState::addUnit(std::shared_ptr woice) { return true; } +int32_t mooState::get_now_clock(int smp_offset) const { + if (params.clock_rate) + return (int32_t)((smp_count - smp_offset) / params.clock_rate); + return 0; +} + //////////////////////////////////////////////// // Units //////////////////////////////////// //////////////////////////////////////////////// @@ -354,13 +360,6 @@ int32_t pxtnService::moo_tone_sample_multi(std::map p_us, bool pxtnService::moo_is_valid_data() const { return _moo_b_valid_data; } -/* This place might be a chance to allow variable tempo songs */ -int32_t pxtnService::moo_get_now_clock(const mooState& moo_state) const { - if (moo_state.params.clock_rate) - return (int32_t)(moo_state.smp_count / moo_state.params.clock_rate); - return 0; -} - int32_t pxtnService::moo_get_end_clock() const { return master->get_this_clock(master->get_play_meas(), 0, 0); } diff --git a/todo b/todo index 58f73b9d..fcf900d2 100644 --- a/todo +++ b/todo @@ -538,16 +538,22 @@ unit view: 2. left piano midi highlight 3. option to make pinned unit click also switch to the unit +11/19 + Todo by priority ---------------- +- rtaudio + - have playback be able to communicate position + - modify moostate + - have it stop / startable + - have it seekable + - modify pxtn + - some sorta buffering system? + - update gh-pages - - update beat-fit meaning - - page w all keybindings - - update how to copy / paste - - update legend on unit tab - move voices - - drag voices / units + - drag voices / units - test to see if the midi noodling is causing the lag. delete voice previews if so - way to elongate notes (ctrl click in unit row)