Mercurial > hg > svapp
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 |