Mercurial > hg > dmlib
view editor/edwaveform.cpp @ 1707:a0986cfd6f9d
More consistently use DMGrowBuf in the lib64gfx APIs, and implement
"backwards" RLE decoding and encoding (optionally regards input/output).
Not tested very much yet, there may be bugs.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 05 Jun 2018 21:58:10 +0300 |
parents | e2ac08228a0f |
children |
line wrap: on
line source
#include <QtGui> #include <SDL_audio.h> #include "edwaveform.h" QEDWaveTrackDisplay::QEDWaveTrackDisplay(QWidget *parent) : QWidget(parent) { data = NULL; size = 0; format = AUDIO_S16SYS; channels = 1; freq = 1; scale = 1.0f; time = offs = 0; duration = 0; sduration = 0; setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); } void QEDWaveTrackDisplay::setWaveform(void *mdata, int msize, int mformat, int mchannels, int mfreq) { data = mdata; size = msize; format = mformat; channels = mchannels; freq = mfreq; int bps = getBps(); if (bps != 0) { // Duration in milliseconds duration = ((float) (size / bps) / (float) freq) * 1000.0f; // Duration in samples sduration = msize / bps; } else { duration = 0; sduration = 0; } update(); } int QEDWaveTrackDisplay::getBps() { int bps = channels; switch (format) { case AUDIO_S16SYS: case AUDIO_U16SYS: bps *= sizeof(quint16); break; case AUDIO_S8: case AUDIO_U8: bps *= sizeof(quint8); break; } return bps; } float QEDWaveTrackDisplay::getDuration() { return duration; } float QEDWaveTrackDisplay::getTimeScale(float value) { return (value * scale * (float) freq) / 1000.0f; } float QEDWaveTrackDisplay::getTimeFromCoord(float value) { return value * scale; } void QEDWaveTrackDisplay::setTime(const float mtime) { if (time != mtime && mtime >= 0 && mtime < duration) { time = mtime; emit timeChanged(time); } } void QEDWaveTrackDisplay::setOffset(const float moffs) { if (offs != moffs && moffs >= 0 && moffs < getDuration()) { offs = moffs; emit offsetChanged(offs); } } void QEDWaveTrackDisplay::setScale(const float mscale) { if (mscale > 0.05) scale = mscale; emit scaleChanged(scale); } void QEDWaveTrackDisplay::setSelection(const float mstart, const float mend) { if (mstart >= 0 && mend >= 0 && fabs(mend - mstart) > 0) { selectionValid = true; if (mend > mstart) { selectionStart = mstart; selectionDuration = mend - mstart + 1; } else { selectionStart = mend; selectionDuration = mstart - mend + 1; } emit selectionChanged(selectionStart, selectionDuration); } } void QEDWaveTrackDisplay::clearSelection() { selectionValid = false; selectionStart = 0; selectionDuration = 0; emit selectionChanged(selectionStart, selectionDuration); } bool QEDTimelineTrackDisplay::getSelection(float *mstart, float *mduration) { if (selectionValid) { *mstart = selectionStart; *mduration = selectionDuration; } return selectionValid; } float QEDWaveTrackDisplay::getScaledWidth() { return getTimeScale(width()); } float QEDWaveTrackDisplay::getTime() { return time; } float QEDWaveTrackDisplay::getOffset() { return offs; } void QEDWaveTrackDisplay::paintEvent(QPaintEvent *) { QColor waveColor(0, 150, 0); QColor waveCenterLine(100, 100, 100); QColor markerColor(255,255,255); QColor bgColor(0, 0, 0);//255, 255, 255); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.fillRect(QRect(0, 0, width(), height()), bgColor); if (data != NULL) { int voffs = 0; painter.save(); painter.translate(0, height() / 2); painter.setPen(waveCenterLine); painter.drawLine(0, 0, width(), 0); switch (format) { case AUDIO_S16SYS: painter.scale(1.0f, (float) height() / 32768.0f); break; case AUDIO_U16SYS: voffs = -32768; painter.scale(1.0f, height() / 32768.0f); break; case AUDIO_S8: painter.scale(1.0f, height() / 128.0f); break; case AUDIO_U8: voffs = -128; painter.scale(1.0f, height() / 128.0f); break; } painter.scale(1.0f, 0.5f); painter.setPen(waveColor); float mscale = (scale * (float)freq) / 1000.0f; int prevY = 0, prevX = 0; if (format == AUDIO_S16SYS || format == AUDIO_U16SYS) { qint16 *buf = (qint16 *) data; for (int xc = 0; xc < width(); xc++) { int moffs = (int) (((offs + xc) * mscale)); if (moffs >= sduration) break; int value = buf[moffs * channels] + voffs; painter.drawLine(prevX, prevY, xc, value); prevY = value; prevX = xc; } } else if (format == AUDIO_S8 || format == AUDIO_U8) { qint8 *buf = (qint8 *) data; for (int xc = 0; xc < width(); xc++) { int moffs = (int) (((offs + xc) * mscale)); if (moffs >= sduration) break; int value = buf[moffs * channels] + voffs; painter.drawLine(prevX, prevY, xc, value); prevY = value; prevX = xc; } } painter.restore(); } float xc = getTimeScale(time - offs), wd = getTimeScale(width()); if (xc >= 0 && xc <= wd) { xc = time - offs; painter.scale(scale, 1.0f); painter.setPen(markerColor); painter.drawLine(xc, 0, xc, height()); } } void QEDWaveTrackDisplay::mousePressEvent(QMouseEvent *ev) { switch (ev->button()) { case Qt::LeftButton: selectionPoint = ev->pos(); selectionOffs = offs; selecting = false; break; case Qt::RightButton: dragPoint = ev->pos(); dragOffs = offs; dragging = false; break; default: break; } } void QEDWaveTrackDisplay::mouseMoveEvent(QMouseEvent *ev) { if ((ev->buttons() & Qt::LeftButton) && ev->pos().x() != selPoint.x()) { selecting = true; setSelection(selectionOffs + (ev->pos().x() - selectionPoint.x()) / scale); } if ((ev->buttons() & Qt::RightButton) && ev->pos().x() != dragPoint.x()) { dragging = true; setOffset(dragOffs - (ev->pos().x() - dragPoint.x()) / scale); } } void QEDWaveTrackDisplay::mouseReleaseEvent(QMouseEvent *ev) { if (ev->button() == Qt::LeftButton) { if (selecting) { selecting = false; setSelection(selOffs + (ev->pos().x() - selPoint.x()) / scale); } } else if (ev->button() == Qt::RightButton && !dragging) { setTime(offs + getTimeFromCoord(ev->pos().x())); } } QEDWaveTrackView::QEDWaveTrackView(QWidget *parent) : QWidget(parent) { QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setMargin(0); wave = new QEDWaveTrackDisplay(this); QFrame *infoLayoutContainer = new QFrame(this); infoLayoutContainer->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); infoLayoutContainer->setLineWidth(2); infoLayoutContainer->setFixedWidth(200); QVBoxLayout *infoLayout = new QVBoxLayout(infoLayoutContainer); infoLayout->setMargin(0); infoName = new QLabel("Audio"); infoName->setStyleSheet("QLabel { background-color: black; color: white; padding: 2px; }"); infoLayout->addWidget(infoName); infoData = new QLabel(); infoData->setStyleSheet("QLabel { padding: 2px; }"); infoLayout->addWidget(infoData); mainLayout->addWidget(infoLayoutContainer); mainLayout->addWidget(wave); connect(wave, SIGNAL(timeChanged(float)), this, SLOT(slotTimeChanged(float))); connect(wave, SIGNAL(offsetChanged(float)), this, SLOT(slotOffsetChanged(float))); connect(wave, SIGNAL(selectionChanged(float,float)), this, SLOT(slotSelectionChanged(float,float))); } void QEDWaveTrackView::setWaveform(void *mdata, int msize, int mformat, int mchannels, int mfreq) { QString fmt; switch (mformat) { case AUDIO_S16SYS: fmt = "16bit (S)"; break; case AUDIO_U16SYS: fmt = "16bit (U)"; break; case AUDIO_S8: fmt = "8bit (S)"; break; case AUDIO_U8: fmt = "8bit (U)"; break; default: fmt = "?"; break; } infoData->setText(QString("<b>%1</b>, <b>%2</b> ch, <b>%3</b> Hz").arg(fmt).arg(mchannels).arg(mfreq)); wave->setWaveform(mdata, msize, mformat, mchannels, mfreq); update(); } void QEDWaveTrackView::setName(QString name) { infoName->setText(name); update(); } void QEDWaveTrackView::setTime(const float mtime) { wave->setTime(mtime); } void QEDWaveTrackView::setOffset(const float moffs) { wave->setOffset(moffs); } void QEDWaveTrackView::setScale(const float mscale) { wave->setScale(mscale); } float QEDWaveTrackView::getTime() { return wave->getTime(); } float QEDWaveTrackView::getOffset() { return wave->getOffset(); } float QEDWaveTrackView::getScaledWidth() { return wave->getScaledWidth(); } void QEDWaveTrackView::slotTimeChanged(float value) { emit timeChanged(value); } void QEDWaveTrackView::slotOffsetChanged(float value) { emit offsetChanged(value); } float QEDWaveTrackView::getDuration() { return wave->getDuration(); }