annotate audio/AudioRecordTarget.cpp @ 562:3c846b06c518 3.0-integration

When returning the frame that we have filled to, avoid accidentally reducing the frame number (making it appear we are less filled than we really are) when we had intended to round it up to the full requested amount. Fixes some unexpected double-playback in non-looping play-selection mode.
author Chris Cannam
date Wed, 14 Dec 2016 11:55:47 +0000
parents e348e0c52115
children 6f54789f3127
rev   line source
Chris@476 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@476 2
Chris@476 3 /*
Chris@476 4 Sonic Visualiser
Chris@476 5 An audio file viewer and annotation editor.
Chris@476 6 Centre for Digital Music, Queen Mary, University of London.
Chris@476 7
Chris@476 8 This program is free software; you can redistribute it and/or
Chris@476 9 modify it under the terms of the GNU General Public License as
Chris@476 10 published by the Free Software Foundation; either version 2 of the
Chris@476 11 License, or (at your option) any later version. See the file
Chris@476 12 COPYING included with this distribution for more information.
Chris@476 13 */
Chris@476 14
Chris@476 15 #include "AudioRecordTarget.h"
Chris@476 16
Chris@476 17 #include "base/ViewManagerBase.h"
Chris@476 18 #include "base/TempDirectory.h"
Chris@476 19
Chris@477 20 #include "data/model/WritableWaveFileModel.h"
Chris@476 21
Chris@476 22 #include <QDir>
Chris@476 23
Chris@476 24 AudioRecordTarget::AudioRecordTarget(ViewManagerBase *manager,
Chris@476 25 QString clientName) :
Chris@476 26 m_viewManager(manager),
Chris@476 27 m_clientName(clientName.toUtf8().data()),
Chris@476 28 m_recording(false),
Chris@476 29 m_recordSampleRate(44100),
Chris@546 30 m_recordChannelCount(2),
Chris@485 31 m_frameCount(0),
Chris@477 32 m_model(0)
Chris@476 33 {
Chris@476 34 }
Chris@476 35
Chris@476 36 AudioRecordTarget::~AudioRecordTarget()
Chris@476 37 {
Chris@476 38 QMutexLocker locker(&m_mutex);
Chris@476 39 }
Chris@476 40
Chris@559 41 int
Chris@559 42 AudioRecordTarget::getApplicationSampleRate() const
Chris@559 43 {
Chris@559 44 return 0; // don't care
Chris@559 45 }
Chris@559 46
Chris@559 47 int
Chris@559 48 AudioRecordTarget::getApplicationChannelCount() const
Chris@559 49 {
Chris@559 50 return m_recordChannelCount;
Chris@559 51 }
Chris@559 52
Chris@476 53 void
Chris@491 54 AudioRecordTarget::setSystemRecordBlockSize(int)
Chris@476 55 {
Chris@476 56 }
Chris@476 57
Chris@476 58 void
Chris@476 59 AudioRecordTarget::setSystemRecordSampleRate(int n)
Chris@476 60 {
Chris@476 61 m_recordSampleRate = n;
Chris@476 62 }
Chris@476 63
Chris@476 64 void
Chris@491 65 AudioRecordTarget::setSystemRecordLatency(int)
Chris@476 66 {
Chris@476 67 }
Chris@476 68
Chris@476 69 void
Chris@546 70 AudioRecordTarget::setSystemRecordChannelCount(int c)
Chris@546 71 {
Chris@546 72 m_recordChannelCount = c;
Chris@546 73 }
Chris@546 74
Chris@546 75 void
Chris@560 76 AudioRecordTarget::putSamples(const float *const *samples, int, int nframes)
Chris@476 77 {
Chris@485 78 bool secChanged = false;
Chris@485 79 sv_frame_t frameToEmit = 0;
Chris@485 80
Chris@485 81 {
Chris@485 82 QMutexLocker locker(&m_mutex); //!!! bad here
Chris@485 83 if (!m_recording) return;
Chris@485 84
Chris@485 85 m_model->addSamples(samples, nframes);
Chris@485 86
Chris@485 87 sv_frame_t priorFrameCount = m_frameCount;
Chris@485 88 m_frameCount += nframes;
Chris@485 89
Chris@485 90 RealTime priorRT = RealTime::frame2RealTime
Chris@485 91 (priorFrameCount, m_recordSampleRate);
Chris@485 92 RealTime postRT = RealTime::frame2RealTime
Chris@485 93 (m_frameCount, m_recordSampleRate);
Chris@485 94
Chris@485 95 secChanged = (postRT.sec > priorRT.sec);
Chris@485 96 if (secChanged) frameToEmit = m_frameCount;
Chris@485 97 }
Chris@485 98
Chris@485 99 if (secChanged) {
Chris@485 100 emit recordDurationChanged(frameToEmit, m_recordSampleRate);
Chris@485 101 }
Chris@476 102 }
Chris@476 103
Chris@476 104 void
Chris@491 105 AudioRecordTarget::setInputLevels(float, float)
Chris@476 106 {
Chris@476 107 }
Chris@476 108
Chris@477 109 void
Chris@477 110 AudioRecordTarget::modelAboutToBeDeleted()
Chris@477 111 {
Chris@477 112 QMutexLocker locker(&m_mutex);
Chris@477 113 if (sender() == m_model) {
Chris@477 114 m_model = 0;
Chris@477 115 m_recording = false;
Chris@477 116 }
Chris@477 117 }
Chris@477 118
Chris@483 119 QString
Chris@508 120 AudioRecordTarget::getRecordContainerFolder()
Chris@508 121 {
Chris@508 122 QDir parent(TempDirectory::getInstance()->getContainingPath());
Chris@508 123 QString subdirname("recorded");
Chris@508 124
Chris@508 125 if (!parent.mkpath(subdirname)) {
Chris@508 126 cerr << "ERROR: AudioRecordTarget::getRecordContainerFolder: Failed to create recorded dir in \"" << parent.canonicalPath() << "\"" << endl;
Chris@508 127 return "";
Chris@508 128 } else {
Chris@508 129 return parent.filePath(subdirname);
Chris@508 130 }
Chris@508 131 }
Chris@508 132
Chris@508 133 QString
Chris@483 134 AudioRecordTarget::getRecordFolder()
Chris@483 135 {
Chris@508 136 QDir parent(getRecordContainerFolder());
Chris@508 137 QDateTime now = QDateTime::currentDateTime();
Chris@508 138 QString subdirname = QString("%1").arg(now.toString("yyyyMMdd"));
Chris@508 139
Chris@483 140 if (!parent.mkpath(subdirname)) {
Chris@483 141 cerr << "ERROR: AudioRecordTarget::getRecordFolder: Failed to create recorded dir in \"" << parent.canonicalPath() << "\"" << endl;
Chris@483 142 return "";
Chris@483 143 } else {
Chris@483 144 return parent.filePath(subdirname);
Chris@483 145 }
Chris@483 146 }
Chris@483 147
Chris@477 148 WritableWaveFileModel *
Chris@476 149 AudioRecordTarget::startRecording()
Chris@476 150 {
Chris@477 151 {
Chris@476 152 QMutexLocker locker(&m_mutex);
Chris@498 153
Chris@476 154 if (m_recording) {
Chris@476 155 cerr << "WARNING: AudioRecordTarget::startRecording: We are already recording" << endl;
Chris@477 156 return 0;
Chris@476 157 }
Chris@476 158
Chris@477 159 m_model = 0;
Chris@485 160 m_frameCount = 0;
Chris@477 161
Chris@483 162 QString folder = getRecordFolder();
Chris@483 163 if (folder == "") return 0;
Chris@483 164 QDir recordedDir(folder);
Chris@476 165
Chris@480 166 QDateTime now = QDateTime::currentDateTime();
Chris@476 167
Chris@480 168 // Don't use QDateTime::toString(Qt::ISODate) as the ":" character
Chris@480 169 // isn't permitted in filenames on Windows
Chris@480 170 QString filename = QString("recorded-%1.wav")
Chris@480 171 .arg(now.toString("yyyyMMdd-HHmmss-zzz"));
Chris@476 172
Chris@476 173 m_audioFileName = recordedDir.filePath(filename);
Chris@476 174
Chris@546 175 m_model = new WritableWaveFileModel(m_recordSampleRate,
Chris@546 176 m_recordChannelCount,
Chris@546 177 m_audioFileName);
Chris@477 178
Chris@477 179 if (!m_model->isOK()) {
Chris@477 180 cerr << "ERROR: AudioRecordTarget::startRecording: Recording failed"
Chris@477 181 << endl;
Chris@476 182 //!!! and throw?
Chris@477 183 delete m_model;
Chris@477 184 m_model = 0;
Chris@477 185 return 0;
Chris@476 186 }
Chris@476 187
Chris@476 188 m_recording = true;
Chris@477 189 }
Chris@477 190
Chris@477 191 emit recordStatusChanged(true);
Chris@477 192 return m_model;
Chris@476 193 }
Chris@476 194
Chris@476 195 void
Chris@476 196 AudioRecordTarget::stopRecording()
Chris@476 197 {
Chris@477 198 {
Chris@476 199 QMutexLocker locker(&m_mutex);
Chris@476 200 if (!m_recording) {
Chris@476 201 cerr << "WARNING: AudioRecordTarget::startRecording: Not recording" << endl;
Chris@476 202 return;
Chris@476 203 }
Chris@476 204
Chris@497 205 m_model->writeComplete();
Chris@477 206 m_model = 0;
Chris@476 207 m_recording = false;
Chris@477 208 }
Chris@477 209
Chris@477 210 emit recordStatusChanged(false);
Chris@497 211 emit recordCompleted();
Chris@476 212 }
Chris@476 213
Chris@476 214