comparison framework/MainWindowBase.cpp @ 714:fe268c16ae28

Make it possible to open an audio device for playback and upgrade it to I/O later on - avoiding the Mac microphone-permission dialog until we are actually wanting to record
author Chris Cannam
date Wed, 16 Oct 2019 15:26:59 +0100
parents 8e9702c0b9c7
children ec8f21a20fa7
comparison
equal deleted inserted replaced
713:ce698f8d0831 714:fe268c16ae28
135 return 0; 135 return 0;
136 } 136 }
137 #undef Window 137 #undef Window
138 #endif 138 #endif
139 139
140 MainWindowBase::MainWindowBase(SoundOptions soundOptions, 140 MainWindowBase::MainWindowBase(AudioMode audioMode,
141 MIDIMode midiMode,
141 PaneStack::Options paneStackOptions) : 142 PaneStack::Options paneStackOptions) :
142 m_document(nullptr), 143 m_document(nullptr),
143 m_paneStack(nullptr), 144 m_paneStack(nullptr),
144 m_viewManager(nullptr), 145 m_viewManager(nullptr),
145 m_timeRulerLayer(nullptr), 146 m_timeRulerLayer(nullptr),
146 m_soundOptions(soundOptions), 147 m_audioMode(audioMode),
148 m_midiMode(midiMode),
147 m_playSource(nullptr), 149 m_playSource(nullptr),
148 m_recordTarget(nullptr), 150 m_recordTarget(nullptr),
149 m_resamplerWrapper(nullptr), 151 m_resamplerWrapper(nullptr),
150 m_playTarget(nullptr), 152 m_playTarget(nullptr),
151 m_audioIO(nullptr), 153 m_audioIO(nullptr),
169 { 171 {
170 Profiler profiler("MainWindowBase::MainWindowBase"); 172 Profiler profiler("MainWindowBase::MainWindowBase");
171 173
172 SVDEBUG << "MainWindowBase::MainWindowBase" << endl; 174 SVDEBUG << "MainWindowBase::MainWindowBase" << endl;
173 175
174 if (m_soundOptions & WithAudioInput) {
175 if (!(m_soundOptions & WithAudioOutput)) {
176 SVCERR << "WARNING: MainWindowBase: WithAudioInput requires WithAudioOutput -- recording will not work" << endl;
177 }
178 }
179
180 qRegisterMetaType<sv_frame_t>("sv_frame_t"); 176 qRegisterMetaType<sv_frame_t>("sv_frame_t");
181 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t"); 177 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t");
182 qRegisterMetaType<ModelId>("ModelId"); 178 qRegisterMetaType<ModelId>("ModelId");
183 179
184 #ifdef Q_WS_X11 180 #ifdef Q_WS_X11
248 SVDEBUG << "MainWindowBase: Creating play source" << endl; 244 SVDEBUG << "MainWindowBase: Creating play source" << endl;
249 245
250 m_playSource = new AudioCallbackPlaySource 246 m_playSource = new AudioCallbackPlaySource
251 (m_viewManager, QApplication::applicationName()); 247 (m_viewManager, QApplication::applicationName());
252 248
253 if (m_soundOptions & WithAudioInput) { 249 if (m_audioMode == AUDIO_PLAYBACK_NOW_RECORD_LATER ||
250 m_audioMode == AUDIO_PLAYBACK_AND_RECORD) {
254 SVDEBUG << "MainWindowBase: Creating record target" << endl; 251 SVDEBUG << "MainWindowBase: Creating record target" << endl;
255 m_recordTarget = new AudioCallbackRecordTarget 252 m_recordTarget = new AudioCallbackRecordTarget
256 (m_viewManager, QApplication::applicationName()); 253 (m_viewManager, QApplication::applicationName());
257 connect(m_recordTarget, 254 connect(m_recordTarget,
258 SIGNAL(recordDurationChanged(sv_frame_t, sv_samplerate_t)), 255 SIGNAL(recordDurationChanged(sv_frame_t, sv_samplerate_t)),
301 settings.endGroup(); 298 settings.endGroup();
302 299
303 m_labeller = new Labeller(labellerType); 300 m_labeller = new Labeller(labellerType);
304 m_labeller->setCounterCycleSize(cycle); 301 m_labeller->setCounterCycleSize(cycle);
305 302
306 if (m_soundOptions & WithMIDIInput) { 303 if (m_midiMode == MIDI_LISTEN) {
307 SVDEBUG << "MainWindowBase: Creating MIDI input" << endl; 304 SVDEBUG << "MainWindowBase: Creating MIDI input" << endl;
308 m_midiInput = new MIDIInput(QApplication::applicationName(), this); 305 m_midiInput = new MIDIInput(QApplication::applicationName(), this);
309 } 306 }
310 307
311 QTimer::singleShot(1500, this, SIGNAL(hideSplash())); 308 QTimer::singleShot(1500, this, SIGNAL(hideSplash()));
737 734
738 // This is quite subtle -- whereas we can play back only if a 735 // This is quite subtle -- whereas we can play back only if a
739 // system play target or I/O exists, we can record even if no 736 // system play target or I/O exists, we can record even if no
740 // record source (i.e. audioIO) exists because we can record into 737 // record source (i.e. audioIO) exists because we can record into
741 // an empty session before the audio device has been 738 // an empty session before the audio device has been
742 // opened. However, if there is no record *target* then recording 739 // opened.
743 // was actively disabled (flag not set in m_soundOptions). And if 740 //
744 // we have a play target instead of an audioIO, then we must have 741 // However, if there is no record *target* then recording was
745 // tried to open the device but failed to find any capture source. 742 // actively disabled via the audio mode setting.
743 //
744 // If we have a play target instead of an audioIO, then if the
745 // audio mode is AUDIO_PLAYBACK_NOW_RECORD_LATER, we are still
746 // expecting to open the IO on demand, but if it is
747 // AUDIO_PLAYBACK_AND_RECORD then we must have tried to open the
748 // device and failed to find any capture source.
749 //
746 bool recordDisabled = (m_recordTarget == nullptr); 750 bool recordDisabled = (m_recordTarget == nullptr);
747 bool recordDeviceFailed = (m_playTarget != nullptr && m_audioIO == nullptr); 751 bool recordDeviceFailed =
752 (m_audioMode == AUDIO_PLAYBACK_AND_RECORD &&
753 (m_playTarget != nullptr && m_audioIO == nullptr));
748 emit canRecord(!recordDisabled && !recordDeviceFailed); 754 emit canRecord(!recordDisabled && !recordDeviceFailed);
749 } 755 }
750 756
751 void 757 void
752 MainWindowBase::updateWindowTitle() 758 MainWindowBase::updateWindowTitle()
2501 { 2507 {
2502 if (m_playTarget || m_audioIO) return; 2508 if (m_playTarget || m_audioIO) return;
2503 2509
2504 static AudioLogCallback audioLogCallback; 2510 static AudioLogCallback audioLogCallback;
2505 breakfastquay::AudioFactory::setLogCallback(&audioLogCallback); 2511 breakfastquay::AudioFactory::setLogCallback(&audioLogCallback);
2506 2512
2507 if (!(m_soundOptions & WithAudioOutput)) return; 2513 if (m_audioMode == AUDIO_NONE) return;
2508 2514
2509 QSettings settings; 2515 QSettings settings;
2510 settings.beginGroup("Preferences"); 2516 settings.beginGroup("Preferences");
2511 QString implementation = settings.value 2517 QString implementation = settings.value
2512 ("audio-target", "").toString(); 2518 ("audio-target", "").toString();
2539 m_playSource->setResamplerWrapper(m_resamplerWrapper); 2545 m_playSource->setResamplerWrapper(m_resamplerWrapper);
2540 } 2546 }
2541 2547
2542 std::string errorString; 2548 std::string errorString;
2543 2549
2544 if (m_soundOptions & WithAudioInput) { 2550 if (m_audioMode == AUDIO_PLAYBACK_AND_RECORD) {
2545 m_audioIO = breakfastquay::AudioFactory:: 2551 m_audioIO = breakfastquay::AudioFactory::
2546 createCallbackIO(m_recordTarget, m_resamplerWrapper, 2552 createCallbackIO(m_recordTarget, m_resamplerWrapper,
2547 preference, errorString); 2553 preference, errorString);
2548 if (m_audioIO) { 2554 if (m_audioIO) {
2549 SVCERR << "MainWindowBase::createAudioIO: Suspending on creation" << endl; 2555 SVCERR << "MainWindowBase::createAudioIO: Suspending on creation" << endl;
2577 if (error == "") { 2583 if (error == "") {
2578 firstBit = tr("<b>No audio available</b><p>Could not open an audio device.</p>"); 2584 firstBit = tr("<b>No audio available</b><p>Could not open an audio device.</p>");
2579 } else { 2585 } else {
2580 firstBit = tr("<b>No audio available</b><p>Could not open audio device: %1</p>").arg(error); 2586 firstBit = tr("<b>No audio available</b><p>Could not open audio device: %1</p>").arg(error);
2581 } 2587 }
2582 if (m_soundOptions & WithAudioInput) { 2588 if (m_audioMode == AUDIO_PLAYBACK_NOW_RECORD_LATER ||
2589 m_audioMode == AUDIO_PLAYBACK_AND_RECORD) {
2583 secondBit = tr("<p>Automatic audio device detection failed. Audio playback and recording will not be available during this session.</p>"); 2590 secondBit = tr("<p>Automatic audio device detection failed. Audio playback and recording will not be available during this session.</p>");
2584 } else { 2591 } else {
2585 secondBit = tr("<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>"); 2592 secondBit = tr("<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>");
2586 } 2593 }
2587 } else { 2594 } else {
2591 if (error == "") { 2598 if (error == "") {
2592 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\").</p>").arg(driverName); 2599 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\").</p>").arg(driverName);
2593 } else { 2600 } else {
2594 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\"): %2.</p>").arg(driverName).arg(error); 2601 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\"): %2.</p>").arg(driverName).arg(error);
2595 } 2602 }
2596 if (m_soundOptions & WithAudioInput) { 2603 if (m_audioMode == AUDIO_PLAYBACK_NOW_RECORD_LATER ||
2604 m_audioMode == AUDIO_PLAYBACK_AND_RECORD) {
2597 secondBit = tr("<p>Audio playback and recording will not be available during this session.</p>"); 2605 secondBit = tr("<p>Audio playback and recording will not be available during this session.</p>");
2598 } else { 2606 } else {
2599 secondBit = tr("<p>Audio playback will not be available during this session.</p>"); 2607 secondBit = tr("<p>Audio playback will not be available during this session.</p>");
2600 } 2608 }
2601 } 2609 }
3189 void 3197 void
3190 MainWindowBase::record() 3198 MainWindowBase::record()
3191 { 3199 {
3192 QAction *action = qobject_cast<QAction *>(sender()); 3200 QAction *action = qobject_cast<QAction *>(sender());
3193 3201
3194 if (!(m_soundOptions & WithAudioInput)) { 3202 if (m_audioMode == AUDIO_NONE || m_audioMode == AUDIO_PLAYBACK_ONLY) {
3195 if (action) action->setChecked(false); 3203 if (action) action->setChecked(false);
3196 return; 3204 return;
3197 } 3205 }
3198 3206
3199 if (!m_recordTarget) { 3207 if (!m_recordTarget) {
3200 if (action) action->setChecked(false); 3208 if (action) action->setChecked(false);
3201 return; 3209 return;
3210 }
3211
3212 if (m_audioMode == AUDIO_PLAYBACK_NOW_RECORD_LATER) {
3213 SVDEBUG << "MainWindowBase::record: upgrading from "
3214 << "AUDIO_PLAYBACK_NOW_RECORD_LATER to "
3215 << "AUDIO_PLAYBACK_AND_RECORD" << endl;
3216 m_audioMode = AUDIO_PLAYBACK_AND_RECORD;
3217 deleteAudioIO();
3202 } 3218 }
3203 3219
3204 if (!m_audioIO) { 3220 if (!m_audioIO) {
3205 SVDEBUG << "MainWindowBase::record: about to create audio IO" << endl; 3221 SVDEBUG << "MainWindowBase::record: about to create audio IO" << endl;
3206 createAudioIO(); 3222 createAudioIO();
4088 { 4104 {
4089 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl; 4105 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl;
4090 updateDescriptionLabel(); 4106 updateDescriptionLabel();
4091 auto model = ModelById::getAs<WaveFileModel>(modelId); 4107 auto model = ModelById::getAs<WaveFileModel>(modelId);
4092 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); 4108 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
4093 if (model && !(m_playTarget || m_audioIO) && 4109 if (model && !(m_playTarget || m_audioIO) && (m_audioMode != AUDIO_NONE)) {
4094 (m_soundOptions & WithAudioOutput)) {
4095 createAudioIO(); 4110 createAudioIO();
4096 } 4111 }
4097 } 4112 }
4098 4113
4099 void 4114 void