Logo Search packages:      
Sourcecode: qarecord version File versions  Download package

mainwindow.cpp

#include <alsa/asoundlib.h>
#include <QBoxLayout>
#include <QDir>
#include <QGroupBox>
#include <QFileDialog>
#include <QPushButton>
#include <QSocketNotifier>
#include <QMenuBar>   
#include <QMenu>


#include "mainwindow.h"
#include "meter.h"
#include "pixmaps/qarecord_48.xpm"

static const char WAVEEXT[] = ".wav";
static const char FILEPRESET[] = "/New1.wav";


MainWindow::MainWindow(SettingsData* p_settings)
{
    int l1;
    QString meterText;
    fileFilter = tr("WAV files (*.wav)");

    diskwrite = NULL;
    jackCapture = NULL;
    alsaCapture = NULL;
    ringBuffer = NULL;

    settings = p_settings;
    lastDir = QDir::homePath();

    jackMode = settings->getEnableJack();

    open_seq(&seq_handle, in_ports, out_ports, 1, 0);
    initSeqNotifier();

    ringBuffer = new RingBuffer(settings->getRingBufSize(),
        settings->getChannels(), settings->getEnable32bit());

    if (jackMode) {
        jackCapture = new JackCapture(settings);
        jackCapture->setParent(this);
        jackCapture->initJack();
        settings->setRate(jackCapture->getRate());
    }


    // file line
    QHBoxLayout *fileBoxLayout = new QHBoxLayout;
    currentFileLabel = new QLabel(this);
    currentFileLabel->setText(tr("File:"));
    fileBoxLayout->setMargin(3);
    fileBoxLayout->setSpacing(50);
    fileBoxLayout->addWidget(currentFileLabel);
    currentFileLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);


    // time/capture line
    QHBoxLayout *timeBoxLayout = new QHBoxLayout;
    timeBoxLayout->setMargin(3);
    timeBoxLayout->setSpacing(50);

    if (!jackMode) {
        captureToggle = new QCheckBox(this);
        captureToggle->setText(tr("&Capture"));
        QObject::connect(captureToggle, SIGNAL(toggled(bool)),
                this, SLOT(captureToggled(bool)));
        timeBoxLayout->addWidget(captureToggle);
    } else {
        jackCapture->activateJack(ringBuffer);
    }

    timeLabel = new QLabel(this);
    timeLabel->setText(tr("Time: 0:00:00  "));
    timeLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
    timeBoxLayout->addWidget(timeLabel);

    statusLabel = new QLabel(this);
    statusLabel->setText(tr("Stopped"));
    statusLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
    timeBoxLayout->addWidget(statusLabel);


    //meter widgets 
    QHBoxLayout *meterHBoxLayout = new QHBoxLayout;
    meterHBoxLayout->setMargin(3);
    meterHBoxLayout->setSpacing(6);

    QVBoxLayout *meterLabelBoxLayout = new QVBoxLayout;
    meterLabelBoxLayout->setMargin(3);
    meterLabelBoxLayout->setSpacing(3);

    QVBoxLayout *meterVBoxLayout = new QVBoxLayout;
    meterVBoxLayout->setMargin(3);

    for (l1 = 0; l1 < settings->getChannels(); l1++) {
        QLabel *channelMeterLabel = new QLabel(this);
        channelMeterLabel->setSizePolicy(QSizePolicy::Fixed,
                QSizePolicy::Minimum);

        if (settings->getChannels() == 2)
            meterText = l1 ? tr("R") : tr("L");
        else
            meterText = QString::number(l1);

        channelMeterLabel->setText(meterText);
        meterLabelBoxLayout->addWidget(channelMeterLabel);
        meters.append(new Meter((tickType) (l1 & 1), ringBuffer, l1,
            settings->getSampleSize(), -settings->getMeterRange(), this));
        meterVBoxLayout->addWidget(meters[l1]);
    }
    meterHBoxLayout->addLayout(meterLabelBoxLayout);
    meterHBoxLayout->addLayout(meterVBoxLayout);


    //control buttons
    QHBoxLayout *Buttonlayout = new QHBoxLayout;
    Buttonlayout->setMargin(5);
    Buttonlayout->setSpacing(10);

    recButton = new QPushButton(tr("&Record"), this);
    pauseButton = new QPushButton(tr("&Pause"), this);
    stopButton = new QPushButton(tr("&Stop"), this);

    Buttonlayout->addWidget(recButton);
    Buttonlayout->addWidget(pauseButton);
    Buttonlayout->addWidget(stopButton);

    pauseButton->setEnabled(false);
    stopButton->setEnabled(false);

    QObject::connect(recButton, SIGNAL(clicked()), this, SLOT(recordClicked())); 
    QObject::connect(pauseButton, SIGNAL(clicked()), this, SLOT(pauseClicked())); 
    QObject::connect(stopButton, SIGNAL(clicked()), this, SLOT(stopClicked()));


    //buffer status labels
    QGroupBox *bufferBox = new QGroupBox(tr("Buffer fill rate"));
    
    QHBoxLayout *bufLabelLayout = new QHBoxLayout;

    QHBoxLayout *currentLayout = new QHBoxLayout;
    QLabel* currentLabel = new QLabel(tr("Current:"), this);
    bufLabel = new QLabel(tr("%1 %").arg(0), this);
    currentLayout->addWidget(currentLabel);
    currentLayout->addWidget(bufLabel);
    currentLayout->addStretch();

    QHBoxLayout *peakLayout = new QHBoxLayout;
    QLabel* peakLabel = new QLabel(tr("Peak:"), this);
    maxBufLabel = new QLabel(tr("%1 % (%2 bytes)").arg(0).arg(0), this);
    peakLayout->addWidget(peakLabel);
    peakLayout->addWidget(maxBufLabel);
    peakLayout->addStretch();
    
    bufLabelLayout->addLayout(currentLayout);
    bufLabelLayout->addLayout(peakLayout);

    bufferBox->setLayout(bufLabelLayout);
      
    QVBoxLayout *guiBoxLayout = new QVBoxLayout;

    guiBoxLayout->setMargin(4);
    guiBoxLayout->addLayout(fileBoxLayout);
    guiBoxLayout->addLayout(timeBoxLayout);
    guiBoxLayout->addLayout(meterHBoxLayout);
    guiBoxLayout->addLayout(Buttonlayout);
    //guiBoxLayout->addLayout(bufLabelLayout);
    guiBoxLayout->addWidget(bufferBox);
      QWidget *guiBox = new QWidget;
    guiBox->setLayout(guiBoxLayout);
      
    QMenuBar *menuBar = new QMenuBar; 
    QMenu *filePopup = new QMenu(tr("&File"),this); 
    QMenu *aboutMenu = new QMenu(tr("&Help"),this);
    filePopup->addAction(tr("&New..."), this, SLOT(newFile()));
    filePopup->addAction(tr("&Quit"), qApp, SLOT(quit()),
            QKeySequence(tr("Ctrl+Q", "File|Quit")));
    aboutMenu->addAction(tr("&About %1...").arg(APP_NAME), this,
            SLOT(helpAbout())); 
    aboutMenu->addAction(tr("&About Qt..."), this,
            SLOT(helpAboutQt())); 
    menuBar->addMenu(filePopup);
    menuBar->addMenu(aboutMenu);


    setWindowTitle(APP_NAME);
    setWindowIcon(QPixmap(qarecord_48_xpm));
    setMenuBar(menuBar);
    setCentralWidget(guiBox);


    timer = new QTimer(this);
    QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timerProc()));

    if (!jackMode) {
        alsaCapture = new Capture(settings, ringBuffer);
        QObject::connect(alsaCapture, SIGNAL(finished()), this,
                SLOT(captureTerminated()));
    }
    diskwrite = new DiskWrite(settings, ringBuffer);

    show();
}

MainWindow::~MainWindow()
{
    if (jackCapture != NULL) {
        delete jackCapture;
        jackCapture = NULL;
    }

    if (alsaCapture != NULL) {
        delete alsaCapture;
        alsaCapture = NULL;
    }

    if (diskwrite != NULL) {
        delete diskwrite;
        diskwrite = NULL;
    }

    if (ringBuffer != NULL) {
        delete ringBuffer;
        ringBuffer = NULL;
    }
}

void MainWindow::helpAbout()
{
    QMessageBox::about(this, tr("About %1").arg(APP_NAME), ABOUTMSG);
}

void MainWindow::helpAboutQt()
{
    QMessageBox::aboutQt(this, tr("About Qt"));
}

void MainWindow::recordClicked()
{
    if (saveFileName.isEmpty()) {
        newFile();
    }
    if (saveFileName.isEmpty()) {
        return;
    }
    diskwrite->setFileName(saveFileName);
    if (jackMode) {
    } else {
        if (!captureToggle->isChecked()) {
            captureToggle->setChecked(true);
        }
        if (!alsaCapture->isRunning()) {
            alsaCapture->start();
        }
    }
    if (!diskwrite->isRunning()) {
        diskwrite->start();
    }
    diskwrite->setPaused(false);
    if (!jackMode) {
        captureToggle->setEnabled(false);
    }
    timer->start(200);

    statusLabel->setText(tr("Recording"));
    recButton->setEnabled(false);
    pauseButton->setEnabled(true);
    stopButton->setEnabled(true);
}

void MainWindow::stopClicked()
{
    diskwrite->stop();
    if (!jackMode) {
        captureToggle->setEnabled(true);
    }
    statusLabel->setText(tr("Stopped"));
    recButton->setEnabled(true);
    pauseButton->setEnabled(false);
    stopButton->setEnabled(false);
}

void MainWindow::pauseClicked() 
{
    if (!diskwrite->isRunning()) {
        stopClicked();
        return;
    }
    diskwrite->setPaused(true);
    if (!jackMode) {
        captureToggle->setEnabled(true);
    }
    statusLabel->setText(tr("Paused"));
    recButton->setEnabled(true);
    pauseButton->setEnabled(false);
    stopButton->setEnabled(true);
}

void MainWindow::newFile()
{
    QString filename = QFileDialog::getSaveFileName(
        this, tr("Choose file name"), lastDir + FILEPRESET, fileFilter);

    if (filename != "") {
        lastDir = filename.left(filename.lastIndexOf('/'));
        if (!filename.endsWith(WAVEEXT))
            filename.append(WAVEEXT);
        saveFileName = filename;
        currentFileLabel->setText(tr("File: %1").arg(saveFileName));
    }
    ringBuffer->reset();
    timeLabel->setText(tr("Time: 0:00:00"));
}

void MainWindow::timerProc()
{
    QString qs1, qs2, qs3;
    int seconds, minutes, displaySeconds;
    unsigned long current, peak, size;

    bool doRecord = diskwrite->isRunning() && 
        (settings->getEnableJack()
         ? jackCapture->isRunning()
         : alsaCapture->isRunning());

  if (doRecord) {
        timer->start(200);
        seconds = diskwrite->getDataSize() /
            (settings->getFrameSize() * settings->getRate());
        minutes = (seconds % 3600) / 60;
        displaySeconds = seconds % 60;
        qs1.sprintf("%d", seconds / 3600);
        if (minutes < 10) {
            qs2.sprintf("0%d", minutes);
        } else {
            qs2.sprintf("%d", minutes);
        }
        if (displaySeconds < 10) {
            qs3.sprintf("0%d", displaySeconds);
        } else {
            qs3.sprintf("%d", displaySeconds);
        }
        timeLabel->setText(tr("Time: ") + qs1 + ":" + qs2 + ":" +qs3 + "  ");

        // update buffer state labels
        current = ringBuffer->getFillRate();
        peak = ringBuffer->getFillRateMax();
        size = settings->getRingBufSize();

        qs1 = tr("%1 %").arg(100 * current / size);
        bufLabel->setText(qs1);

        if (peak < size) {
            qs1 = tr("%1 % (%2 bytes)").arg(100 * peak / size).arg(peak);
            maxBufLabel->setText(qs1);
        } else {
            maxBufLabel->setText(tr("Buffer overflow"));
        }
    }
}

int MainWindow::initSeqNotifier() {

    int alsaEventFd = 0;  

    struct pollfd pfd[1];
    snd_seq_poll_descriptors(seq_handle, pfd, 1, POLLIN);
    alsaEventFd = pfd[0].fd;
    QSocketNotifier *seqNotifier = new QSocketNotifier(alsaEventFd,
            QSocketNotifier::Read);
    QObject::connect(seqNotifier, SIGNAL(activated(int)),
            this, SLOT(midiAction()));
    return(0);
}

void MainWindow::midiAction() {

    snd_seq_event_t *ev;

    do {
        snd_seq_event_input(seq_handle, &ev);
        if ((ev->type == SND_SEQ_EVENT_NOTEON) && 
            (ev->data.control.channel == settings->getMidiChannel())) {

            switch (ev->data.note.note - settings->getMidiNote()) {
                case 0: 
                    recordClicked();
                    break;
                case 1:
                    pauseClicked();
                    break;
                case 2:
                    stopClicked();
                    break;
            }
        }
        snd_seq_free_event(ev);
    } while (snd_seq_event_input_pending(seq_handle, 0) > 0);
}

int MainWindow::open_seq(snd_seq_t **seq_handle, int in_ports[],
        int out_ports[], int num_in, int num_out)
{
    int l1;
    int err;
    char portname[64];

    err = snd_seq_open(seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0);
    if (err < 0) {
        qWarning("Error opening ALSA sequencer (%s).", snd_strerror(err));
        return(-1);
    }

    err = snd_seq_set_client_name(*seq_handle, PACKAGE);
    if (err < 0) {
        qWarning("Error setting ALSA client name (%s).", snd_strerror(err));
        return(-1);
    }
    
    for (l1 = 0; l1 < num_in; l1++) {
        sprintf(portname, "in_%d", l1);
        if ((in_ports[l1] = snd_seq_create_simple_port(*seq_handle, portname,
                        SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
                        SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
            qWarning("Error creating sequencer port (%s).",
                    snd_strerror(in_ports[l1]));
            return(-1);
        }
    }  
    for (l1 = 0; l1 < num_out; l1++) {
        sprintf(portname, "out_%d", l1);
        if ((out_ports[l1] = snd_seq_create_simple_port(*seq_handle, portname,
                        SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
                        SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
            qWarning("Error creating sequencer port (%s).",
                    snd_strerror(out_ports[l1]));
            return(-1);
        }
    }  
    return(0);
}

void MainWindow::captureToggled(bool on)
{
    int l1;

    if (on) {
        if (!jackMode) {
            if (!alsaCapture->isRunning()) {
                 alsaCapture->start();
            }
        }
    } else {
        if (!jackMode) {
            alsaCapture->stop();
        }
        ringBuffer->reset();
        for (l1 = 0; l1 < meters.size(); l1++) {
            meters[l1]->resetGlobalMax();
        }
    }
}

void MainWindow::captureTerminated()
{
    if (captureToggle->isChecked()) {
        qWarning("ALSA capture failed!");
    }
    pauseClicked();
    captureToggle->setChecked(false);
}

Generated by  Doxygen 1.6.0   Back to index