Chris@476: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@476: Chris@476: /* Chris@476: Sonic Visualiser Chris@476: An audio file viewer and annotation editor. Chris@476: Centre for Digital Music, Queen Mary, University of London. Chris@476: Chris@476: This program is free software; you can redistribute it and/or Chris@476: modify it under the terms of the GNU General Public License as Chris@476: published by the Free Software Foundation; either version 2 of the Chris@476: License, or (at your option) any later version. See the file Chris@476: COPYING included with this distribution for more information. Chris@476: */ Chris@476: Chris@476: #include "AudioRecordTarget.h" Chris@476: Chris@476: #include "base/ViewManagerBase.h" Chris@476: #include "base/TempDirectory.h" Chris@476: Chris@477: #include "data/model/WritableWaveFileModel.h" Chris@476: Chris@476: #include Chris@476: Chris@476: AudioRecordTarget::AudioRecordTarget(ViewManagerBase *manager, Chris@476: QString clientName) : Chris@476: m_viewManager(manager), Chris@476: m_clientName(clientName.toUtf8().data()), Chris@476: m_recording(false), Chris@476: m_recordSampleRate(44100), Chris@546: m_recordChannelCount(2), Chris@485: m_frameCount(0), Chris@477: m_model(0) Chris@476: { Chris@476: } Chris@476: Chris@476: AudioRecordTarget::~AudioRecordTarget() Chris@476: { Chris@476: QMutexLocker locker(&m_mutex); Chris@476: } Chris@476: Chris@476: void Chris@491: AudioRecordTarget::setSystemRecordBlockSize(int) Chris@476: { Chris@476: } Chris@476: Chris@476: void Chris@476: AudioRecordTarget::setSystemRecordSampleRate(int n) Chris@476: { Chris@476: m_recordSampleRate = n; Chris@476: } Chris@476: Chris@476: void Chris@491: AudioRecordTarget::setSystemRecordLatency(int) Chris@476: { Chris@476: } Chris@476: Chris@476: void Chris@546: AudioRecordTarget::setSystemRecordChannelCount(int c) Chris@546: { Chris@546: m_recordChannelCount = c; Chris@546: } Chris@546: Chris@546: void Chris@476: AudioRecordTarget::putSamples(int nframes, float **samples) Chris@476: { Chris@485: bool secChanged = false; Chris@485: sv_frame_t frameToEmit = 0; Chris@485: Chris@485: { Chris@485: QMutexLocker locker(&m_mutex); //!!! bad here Chris@485: if (!m_recording) return; Chris@485: Chris@485: m_model->addSamples(samples, nframes); Chris@485: Chris@485: sv_frame_t priorFrameCount = m_frameCount; Chris@485: m_frameCount += nframes; Chris@485: Chris@485: RealTime priorRT = RealTime::frame2RealTime Chris@485: (priorFrameCount, m_recordSampleRate); Chris@485: RealTime postRT = RealTime::frame2RealTime Chris@485: (m_frameCount, m_recordSampleRate); Chris@485: Chris@485: secChanged = (postRT.sec > priorRT.sec); Chris@485: if (secChanged) frameToEmit = m_frameCount; Chris@485: } Chris@485: Chris@485: if (secChanged) { Chris@485: emit recordDurationChanged(frameToEmit, m_recordSampleRate); Chris@485: } Chris@476: } Chris@476: Chris@476: void Chris@491: AudioRecordTarget::setInputLevels(float, float) Chris@476: { Chris@476: } Chris@476: Chris@477: void Chris@477: AudioRecordTarget::modelAboutToBeDeleted() Chris@477: { Chris@477: QMutexLocker locker(&m_mutex); Chris@477: if (sender() == m_model) { Chris@477: m_model = 0; Chris@477: m_recording = false; Chris@477: } Chris@477: } Chris@477: Chris@483: QString Chris@508: AudioRecordTarget::getRecordContainerFolder() Chris@508: { Chris@508: QDir parent(TempDirectory::getInstance()->getContainingPath()); Chris@508: QString subdirname("recorded"); Chris@508: Chris@508: if (!parent.mkpath(subdirname)) { Chris@508: cerr << "ERROR: AudioRecordTarget::getRecordContainerFolder: Failed to create recorded dir in \"" << parent.canonicalPath() << "\"" << endl; Chris@508: return ""; Chris@508: } else { Chris@508: return parent.filePath(subdirname); Chris@508: } Chris@508: } Chris@508: Chris@508: QString Chris@483: AudioRecordTarget::getRecordFolder() Chris@483: { Chris@508: QDir parent(getRecordContainerFolder()); Chris@508: QDateTime now = QDateTime::currentDateTime(); Chris@508: QString subdirname = QString("%1").arg(now.toString("yyyyMMdd")); Chris@508: Chris@483: if (!parent.mkpath(subdirname)) { Chris@483: cerr << "ERROR: AudioRecordTarget::getRecordFolder: Failed to create recorded dir in \"" << parent.canonicalPath() << "\"" << endl; Chris@483: return ""; Chris@483: } else { Chris@483: return parent.filePath(subdirname); Chris@483: } Chris@483: } Chris@483: Chris@477: WritableWaveFileModel * Chris@476: AudioRecordTarget::startRecording() Chris@476: { Chris@477: { Chris@476: QMutexLocker locker(&m_mutex); Chris@498: Chris@476: if (m_recording) { Chris@476: cerr << "WARNING: AudioRecordTarget::startRecording: We are already recording" << endl; Chris@477: return 0; Chris@476: } Chris@476: Chris@477: m_model = 0; Chris@485: m_frameCount = 0; Chris@477: Chris@483: QString folder = getRecordFolder(); Chris@483: if (folder == "") return 0; Chris@483: QDir recordedDir(folder); Chris@476: Chris@480: QDateTime now = QDateTime::currentDateTime(); Chris@476: Chris@480: // Don't use QDateTime::toString(Qt::ISODate) as the ":" character Chris@480: // isn't permitted in filenames on Windows Chris@480: QString filename = QString("recorded-%1.wav") Chris@480: .arg(now.toString("yyyyMMdd-HHmmss-zzz")); Chris@476: Chris@476: m_audioFileName = recordedDir.filePath(filename); Chris@476: Chris@546: m_model = new WritableWaveFileModel(m_recordSampleRate, Chris@546: m_recordChannelCount, Chris@546: m_audioFileName); Chris@477: Chris@477: if (!m_model->isOK()) { Chris@477: cerr << "ERROR: AudioRecordTarget::startRecording: Recording failed" Chris@477: << endl; Chris@476: //!!! and throw? Chris@477: delete m_model; Chris@477: m_model = 0; Chris@477: return 0; Chris@476: } Chris@476: Chris@476: m_recording = true; Chris@477: } Chris@477: Chris@477: emit recordStatusChanged(true); Chris@477: return m_model; Chris@476: } Chris@476: Chris@476: void Chris@476: AudioRecordTarget::stopRecording() Chris@476: { Chris@477: { Chris@476: QMutexLocker locker(&m_mutex); Chris@476: if (!m_recording) { Chris@476: cerr << "WARNING: AudioRecordTarget::startRecording: Not recording" << endl; Chris@476: return; Chris@476: } Chris@476: Chris@497: m_model->writeComplete(); Chris@477: m_model = 0; Chris@476: m_recording = false; Chris@477: } Chris@477: Chris@477: emit recordStatusChanged(false); Chris@497: emit recordCompleted(); Chris@476: } Chris@476: Chris@476: