feat: voice playback delay compensation + waveform click-to-seek

This commit is contained in:
Evgeny committed 2026-07-27 14:53:53 +03:00
1 parent da953c6c7a
commit 6b765de5cc
3 files changed
+60 -9

No files matched your search

+51 -9
View File
@@ -71,15 +71,58 @@ bool MessageDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
QMouseEvent* me = static_cast<QMouseEvent*>(event);
QPoint localPos = me->pos() - option.rect.topLeft();
if (!L.voicePlayBtnRect.contains(localPos)) return false;
bool onPlayBtn = L.voicePlayBtnRect.contains(localPos);
bool onWaveform = L.voiceWaveformRect.contains(localPos);
if (!onPlayBtn && !onWaveform) return false;
QString filePath = index.data(MsgVoiceFileRole).toString();
GUI_DEBUG("editorEvent voice click: filePath=%s exists=%d",
qPrintable(filePath), QFile::exists(filePath));
GUI_DEBUG("editorEvent voice click: filePath=%s exists=%d wave=%d",
qPrintable(filePath), QFile::exists(filePath), (int)onWaveform);
if (filePath.isEmpty()) return false;
ensureVoiceTimer();
VoicePlayState& st = s_voiceStates[filePath];
QString durStr = index.data(MsgVoiceDurationRole).toString();
durStr.remove('s');
float dur = durStr.toFloat();
if (dur <= 0) dur = 1.0f;
if (onWaveform) {
float clickFrac = (float)(localPos.x() - L.voiceWaveformRect.x()) / L.voiceWaveformRect.width();
if (clickFrac < 0) clickFrac = 0; if (clickFrac > 1) clickFrac = 1;
float targetSec = clickFrac * dur;
qint64 now = QDateTime::currentMSecsSinceEpoch();
if (!st.playing && !st.paused) {
/* Start playback then seek */
st.playing = true;
st.paused = false;
st.durationSec = dur;
st.startMs = now - (qint64)(targetSec * 1000.0);
st.pausedPosSec = targetSec;
VoicePlayer::playOpusFile(filePath);
int sr = SoundManager::instance()->currentPcmSampleRate();
if (sr > 0)
SoundManager::instance()->seekCurrentPcm((unsigned long long)(targetSec * sr));
s_voiceTimer->start();
model->setData(index, 1, MsgVoicePlayStateRole);
} else {
/* Currently playing or paused — seek */
st.startMs = now - (qint64)(targetSec * 1000.0);
if (st.paused)
st.pausedPosSec = targetSec;
else if (!st.playing)
{ st.playing = true; s_voiceTimer->start(); }
int sr = SoundManager::instance()->currentPcmSampleRate();
if (sr > 0)
SoundManager::instance()->seekCurrentPcm((unsigned long long)(targetSec * sr));
}
return true;
}
/* --- Play button click (original logic) --- */
bool isOtherPlaying = false;
for (auto it = s_voiceStates.begin(); it != s_voiceStates.end(); ++it) {
if (it.key() != filePath && (it->playing || it->paused))
@@ -117,11 +160,6 @@ bool MessageDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
SoundManager::instance()->stopCurrentPcm();
}
QString durStr = index.data(MsgVoiceDurationRole).toString();
durStr.remove('s');
float dur = durStr.toFloat();
if (dur <= 0) dur = 1.0f;
st.playing = true;
st.paused = false;
st.pausedPosSec = 0;
@@ -633,7 +671,11 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
elapsed = (now - st.startMs) / 1000.0f;
if (elapsed > durSec) elapsed = durSec;
}
if (durSec > 0) frac = elapsed / durSec;
if (durSec > 0) {
float dispElapsed = elapsed - 0.2f; /* 200ms audio output delay */
if (dispElapsed < 0) dispElapsed = 0;
frac = dispElapsed / durSec;
}
if (frac < 0) frac = 0; if (frac > 1) frac = 1;
QRectF playR = L.voicePlayBtnRect;