comparison audio/AudioCallbackRecordTarget.cpp @ 574:b3c35447ef31 3.0-integration

Wire up record monitoring
author Chris Cannam
date Wed, 04 Jan 2017 16:03:12 +0000
parents audio/AudioRecordTarget.cpp@9fb190c6521b
children c2e27ad7f408
comparison
equal deleted inserted replaced
573:9fb190c6521b 574:b3c35447ef31
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Sonic Visualiser
5 An audio file viewer and annotation editor.
6 Centre for Digital Music, Queen Mary, University of London.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version. See the file
12 COPYING included with this distribution for more information.
13 */
14
15 #include "AudioCallbackRecordTarget.h"
16
17 #include "base/ViewManagerBase.h"
18 #include "base/TempDirectory.h"
19
20 #include "data/model/WritableWaveFileModel.h"
21
22 #include <QDir>
23
24 AudioCallbackRecordTarget::AudioCallbackRecordTarget(ViewManagerBase *manager,
25 QString clientName) :
26 m_viewManager(manager),
27 m_clientName(clientName.toUtf8().data()),
28 m_recording(false),
29 m_recordSampleRate(44100),
30 m_recordChannelCount(2),
31 m_frameCount(0),
32 m_model(0),
33 m_inputLeft(0.f),
34 m_inputRight(0.f)
35 {
36 m_viewManager->setAudioRecordTarget(this);
37
38 connect(this, SIGNAL(recordStatusChanged(bool)),
39 m_viewManager, SLOT(recordStatusChanged(bool)));
40 }
41
42 AudioCallbackRecordTarget::~AudioCallbackRecordTarget()
43 {
44 QMutexLocker locker(&m_mutex);
45 m_viewManager->setAudioRecordTarget(0);
46 }
47
48 int
49 AudioCallbackRecordTarget::getApplicationSampleRate() const
50 {
51 return 0; // don't care
52 }
53
54 int
55 AudioCallbackRecordTarget::getApplicationChannelCount() const
56 {
57 return m_recordChannelCount;
58 }
59
60 void
61 AudioCallbackRecordTarget::setSystemRecordBlockSize(int)
62 {
63 }
64
65 void
66 AudioCallbackRecordTarget::setSystemRecordSampleRate(int n)
67 {
68 m_recordSampleRate = n;
69 }
70
71 void
72 AudioCallbackRecordTarget::setSystemRecordLatency(int)
73 {
74 }
75
76 void
77 AudioCallbackRecordTarget::setSystemRecordChannelCount(int c)
78 {
79 m_recordChannelCount = c;
80 }
81
82 void
83 AudioCallbackRecordTarget::putSamples(const float *const *samples, int, int nframes)
84 {
85 bool secChanged = false;
86 sv_frame_t frameToEmit = 0;
87
88 {
89 QMutexLocker locker(&m_mutex); //!!! bad here
90 if (!m_recording) return;
91
92 m_model->addSamples(samples, nframes);
93
94 sv_frame_t priorFrameCount = m_frameCount;
95 m_frameCount += nframes;
96
97 RealTime priorRT = RealTime::frame2RealTime
98 (priorFrameCount, m_recordSampleRate);
99 RealTime postRT = RealTime::frame2RealTime
100 (m_frameCount, m_recordSampleRate);
101
102 secChanged = (postRT.sec > priorRT.sec);
103 if (secChanged) {
104 m_model->updateModel(); //!!! v bad here
105 frameToEmit = m_frameCount;
106 }
107 }
108
109 if (secChanged) {
110 emit recordDurationChanged(frameToEmit, m_recordSampleRate);
111 }
112 }
113
114 void
115 AudioCallbackRecordTarget::setInputLevels(float left, float right)
116 {
117 if (left > m_inputLeft) m_inputLeft = left;
118 if (right > m_inputRight) m_inputRight = right;
119 }
120
121 bool
122 AudioCallbackRecordTarget::getInputLevels(float &left, float &right)
123 {
124 left = m_inputLeft;
125 right = m_inputRight;
126 m_inputLeft = 0.f;
127 m_inputRight = 0.f;
128 return true;
129 }
130
131 void
132 AudioCallbackRecordTarget::modelAboutToBeDeleted()
133 {
134 QMutexLocker locker(&m_mutex);
135 if (sender() == m_model) {
136 m_model = 0;
137 m_recording = false;
138 }
139 }
140
141 QString
142 AudioCallbackRecordTarget::getRecordContainerFolder()
143 {
144 QDir parent(TempDirectory::getInstance()->getContainingPath());
145 QString subdirname("recorded");
146
147 if (!parent.mkpath(subdirname)) {
148 SVCERR << "ERROR: AudioCallbackRecordTarget::getRecordContainerFolder: Failed to create recorded dir in \"" << parent.canonicalPath() << "\"" << endl;
149 return "";
150 } else {
151 return parent.filePath(subdirname);
152 }
153 }
154
155 QString
156 AudioCallbackRecordTarget::getRecordFolder()
157 {
158 QDir parent(getRecordContainerFolder());
159 QDateTime now = QDateTime::currentDateTime();
160 QString subdirname = QString("%1").arg(now.toString("yyyyMMdd"));
161
162 if (!parent.mkpath(subdirname)) {
163 SVCERR << "ERROR: AudioCallbackRecordTarget::getRecordFolder: Failed to create recorded dir in \"" << parent.canonicalPath() << "\"" << endl;
164 return "";
165 } else {
166 return parent.filePath(subdirname);
167 }
168 }
169
170 WritableWaveFileModel *
171 AudioCallbackRecordTarget::startRecording()
172 {
173 {
174 QMutexLocker locker(&m_mutex);
175
176 if (m_recording) {
177 SVCERR << "WARNING: AudioCallbackRecordTarget::startRecording: We are already recording" << endl;
178 return 0;
179 }
180
181 m_model = 0;
182 m_frameCount = 0;
183
184 QString folder = getRecordFolder();
185 if (folder == "") return 0;
186 QDir recordedDir(folder);
187
188 QDateTime now = QDateTime::currentDateTime();
189
190 // Don't use QDateTime::toString(Qt::ISODate) as the ":" character
191 // isn't permitted in filenames on Windows
192 QString nowString = now.toString("yyyyMMdd-HHmmss-zzz");
193
194 QString filename = tr("recorded-%1.wav").arg(nowString);
195 QString label = tr("Recorded %1").arg(nowString);
196
197 m_audioFileName = recordedDir.filePath(filename);
198
199 m_model = new WritableWaveFileModel(m_recordSampleRate,
200 m_recordChannelCount,
201 m_audioFileName);
202
203 if (!m_model->isOK()) {
204 SVCERR << "ERROR: AudioCallbackRecordTarget::startRecording: Recording failed"
205 << endl;
206 //!!! and throw?
207 delete m_model;
208 m_model = 0;
209 return 0;
210 }
211
212 m_model->setObjectName(label);
213 m_recording = true;
214 }
215
216 emit recordStatusChanged(true);
217 return m_model;
218 }
219
220 void
221 AudioCallbackRecordTarget::stopRecording()
222 {
223 {
224 QMutexLocker locker(&m_mutex);
225 if (!m_recording) {
226 SVCERR << "WARNING: AudioCallbackRecordTarget::startRecording: Not recording" << endl;
227 return;
228 }
229
230 m_model->writeComplete();
231 m_model = 0;
232 m_recording = false;
233 }
234
235 emit recordStatusChanged(false);
236 emit recordCompleted();
237 }
238
239