view edwaveform.cpp @ 510:43ea59887c69

Start work on making C64 formats encoding possible by changing DMDecodeOps to DMEncDecOps and adding fields and op enums for custom encode functions, renaming, etc. Split generic op sanity checking into a separate function in preparation for its use in generic encoding function.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 19 Nov 2012 15:06:01 +0200
parents d34922e6a244
children a4666c9e1336
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;
        update();
        emit timeChanged(time);
    }
}


void QEDWaveTrackDisplay::setOffset(const float moffs)
{
    if (offs != moffs && moffs >= 0 && moffs < getDuration())
    {
        offs = moffs;
        update();
        emit offsetChanged(offs);
    }
}


void QEDWaveTrackDisplay::setScale(const float mscale)
{
    if (mscale > 0.05)
        scale = mscale;
    update();
}


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)
{
    if (ev->button() == Qt::LeftButton)
    {
        dragPoint = ev->pos();
        dragOffs = offs;
        dragging = false;
    }
}


void QEDWaveTrackDisplay::mouseMoveEvent(QMouseEvent *ev)
{
    if ((ev->buttons() & Qt::LeftButton) && 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)
    {
        dragging = false;
    }
    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);
//    QVBoxLayout *infoLayout = new QVBoxLayout();
    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->addLayout(infoLayout);
    mainLayout->addWidget(wave);

    connect(wave, SIGNAL(timeChanged(float)), this, SLOT(slotTimeChanged(float)));
    connect(wave, SIGNAL(offsetChanged(float)), this, SLOT(slotOffsetChanged(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();
}