view editor/edwaveform.cpp @ 2208:90ec1ec89c56

Revamp the palette handling in lib64gfx somewhat, add helper functions to lib64util for handling external palette file options and add support for specifying one of the "internal" palettes or external (.act) palette file to gfxconv and 64vw.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 14 Jun 2019 05:01:12 +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();
}