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