view audio/AudioRecordTarget.cpp @ 573:9fb190c6521b 3.0-integration

Make writable model updating explicit rather than essentially an arbitrary hidden accident
author Chris Cannam
date Wed, 04 Jan 2017 14:22:39 +0000
parents 6f54789f3127
children
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

/*
    Sonic Visualiser
    An audio file viewer and annotation editor.
    Centre for Digital Music, Queen Mary, University of London.
    
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#include "AudioRecordTarget.h"

#include "base/ViewManagerBase.h"
#include "base/TempDirectory.h"

#include "data/model/WritableWaveFileModel.h"

#include <QDir>

AudioRecordTarget::AudioRecordTarget(ViewManagerBase *manager,
				     QString clientName) :
    m_viewManager(manager),
    m_clientName(clientName.toUtf8().data()),
    m_recording(false),
    m_recordSampleRate(44100),
    m_recordChannelCount(2),
    m_frameCount(0),
    m_model(0)
{
}

AudioRecordTarget::~AudioRecordTarget()
{
    QMutexLocker locker(&m_mutex);
}

int
AudioRecordTarget::getApplicationSampleRate() const
{
    return 0; // don't care
}

int
AudioRecordTarget::getApplicationChannelCount() const
{
    return m_recordChannelCount;
}

void
AudioRecordTarget::setSystemRecordBlockSize(int)
{
}

void
AudioRecordTarget::setSystemRecordSampleRate(int n)
{
    m_recordSampleRate = n;
}

void
AudioRecordTarget::setSystemRecordLatency(int)
{
}

void
AudioRecordTarget::setSystemRecordChannelCount(int c)
{
    m_recordChannelCount = c;
}

void
AudioRecordTarget::putSamples(const float *const *samples, int, int nframes)
{
    bool secChanged = false;
    sv_frame_t frameToEmit = 0;

    {
        QMutexLocker locker(&m_mutex); //!!! bad here
        if (!m_recording) return;

        m_model->addSamples(samples, nframes);

        sv_frame_t priorFrameCount = m_frameCount;
        m_frameCount += nframes;

        RealTime priorRT = RealTime::frame2RealTime
            (priorFrameCount, m_recordSampleRate);
        RealTime postRT = RealTime::frame2RealTime
            (m_frameCount, m_recordSampleRate);

        secChanged = (postRT.sec > priorRT.sec);
        if (secChanged) {
            m_model->updateModel(); //!!! v bad here
            frameToEmit = m_frameCount;
        }
    }

    if (secChanged) {
        emit recordDurationChanged(frameToEmit, m_recordSampleRate);
    }
}

void
AudioRecordTarget::setInputLevels(float left, float right)
{
    cerr << "AudioRecordTarget::setInputLevels(" << left << "," << right << ")"
         << endl;
}

void
AudioRecordTarget::modelAboutToBeDeleted()
{
    QMutexLocker locker(&m_mutex);
    if (sender() == m_model) {
        m_model = 0;
        m_recording = false;
    }
}

QString
AudioRecordTarget::getRecordContainerFolder()
{
    QDir parent(TempDirectory::getInstance()->getContainingPath());
    QString subdirname("recorded");

    if (!parent.mkpath(subdirname)) {
        SVCERR << "ERROR: AudioRecordTarget::getRecordContainerFolder: Failed to create recorded dir in \"" << parent.canonicalPath() << "\"" << endl;
        return "";
    } else {
        return parent.filePath(subdirname);
    }
}

QString
AudioRecordTarget::getRecordFolder()
{
    QDir parent(getRecordContainerFolder());
    QDateTime now = QDateTime::currentDateTime();
    QString subdirname = QString("%1").arg(now.toString("yyyyMMdd"));

    if (!parent.mkpath(subdirname)) {
        SVCERR << "ERROR: AudioRecordTarget::getRecordFolder: Failed to create recorded dir in \"" << parent.canonicalPath() << "\"" << endl;
        return "";
    } else {
        return parent.filePath(subdirname);
    }
}

WritableWaveFileModel *
AudioRecordTarget::startRecording()
{
    {
        QMutexLocker locker(&m_mutex);
    
        if (m_recording) {
            SVCERR << "WARNING: AudioRecordTarget::startRecording: We are already recording" << endl;
            return 0;
        }

        m_model = 0;
        m_frameCount = 0;

        QString folder = getRecordFolder();
        if (folder == "") return 0;
        QDir recordedDir(folder);

        QDateTime now = QDateTime::currentDateTime();

        // Don't use QDateTime::toString(Qt::ISODate) as the ":" character
        // isn't permitted in filenames on Windows
        QString nowString = now.toString("yyyyMMdd-HHmmss-zzz");
    
        QString filename = tr("recorded-%1.wav").arg(nowString);
        QString label = tr("Recorded %1").arg(nowString);

        m_audioFileName = recordedDir.filePath(filename);

        m_model = new WritableWaveFileModel(m_recordSampleRate,
                                            m_recordChannelCount,
                                            m_audioFileName);

        if (!m_model->isOK()) {
            SVCERR << "ERROR: AudioRecordTarget::startRecording: Recording failed"
                   << endl;
            //!!! and throw?
            delete m_model;
            m_model = 0;
            return 0;
        }

        m_model->setObjectName(label);
        m_recording = true;
    }

    emit recordStatusChanged(true);
    return m_model;
}

void
AudioRecordTarget::stopRecording()
{
    {
        QMutexLocker locker(&m_mutex);
        if (!m_recording) {
            SVCERR << "WARNING: AudioRecordTarget::startRecording: Not recording" << endl;
            return;
        }

        m_model->writeComplete();
        m_model = 0;
        m_recording = false;
    }

    emit recordStatusChanged(false);
    emit recordCompleted();
}