diff framework/MainWindowBase.cpp @ 482:01669adb0956 tony-2.0-integration

Merge through to branch for Tony 2.0
author Chris Cannam
date Thu, 20 Aug 2015 14:54:21 +0100
parents 52c0aff69478
children 01aeda073720 111e976f9ed4
line wrap: on
line diff
--- a/framework/MainWindowBase.cpp	Mon Apr 13 13:52:05 2015 +0100
+++ b/framework/MainWindowBase.cpp	Thu Aug 20 14:54:21 2015 +0100
@@ -16,10 +16,10 @@
 #include "MainWindowBase.h"
 #include "Document.h"
 
-
 #include "view/Pane.h"
 #include "view/PaneStack.h"
-#include "data/model/WaveFileModel.h"
+#include "data/model/ReadOnlyWaveFileModel.h"
+#include "data/model/WritableWaveFileModel.h"
 #include "data/model/SparseOneDimensionalModel.h"
 #include "data/model/NoteModel.h"
 #include "data/model/FlexiNoteModel.h"
@@ -47,10 +47,10 @@
 #include "widgets/ModelDataTableDialog.h"
 #include "widgets/InteractiveFileFinder.h"
 
-#include "audioio/AudioCallbackPlaySource.h"
-#include "audioio/AudioCallbackPlayTarget.h"
-#include "audioio/AudioTargetFactory.h"
-#include "audioio/PlaySpeedRangeMapper.h"
+#include "audio/AudioCallbackPlaySource.h"
+#include "audio/AudioRecordTarget.h"
+#include "audio/PlaySpeedRangeMapper.h"
+
 #include "data/fileio/DataFileReaderFactory.h"
 #include "data/fileio/PlaylistFileReader.h"
 #include "data/fileio/WavFileWriter.h"
@@ -60,8 +60,6 @@
 #include "data/fileio/AudioFileReaderFactory.h"
 #include "rdf/RDFImporter.h"
 
-#include "data/fft/FFTDataServer.h"
-
 #include "base/RecentFiles.h"
 
 #include "base/PlayParameterRepository.h"
@@ -75,6 +73,10 @@
 #include "data/osc/OSCQueue.h"
 #include "data/midi/MIDIInput.h"
 
+#include <bqaudioio/SystemPlaybackTarget.h>
+#include <bqaudioio/SystemAudioIO.h>
+#include <bqaudioio/AudioFactory.h>
+
 #include <QApplication>
 #include <QMessageBox>
 #include <QGridLayout>
@@ -131,15 +133,16 @@
 #undef Window
 #endif
 
-MainWindowBase::MainWindowBase(bool withAudioOutput,
-                               bool withMIDIInput) :
+MainWindowBase::MainWindowBase(SoundOptions options) :
     m_document(0),
     m_paneStack(0),
     m_viewManager(0),
     m_timeRulerLayer(0),
-    m_audioOutput(withAudioOutput),
+    m_soundOptions(options),
     m_playSource(0),
+    m_recordTarget(0),
     m_playTarget(0),
+    m_audioIO(0),
     m_oscQueue(0),
     m_oscQueueStarter(0),
     m_midiInput(0),
@@ -157,6 +160,12 @@
 {
     Profiler profiler("MainWindowBase::MainWindowBase");
 
+    if (options & WithAudioInput) {
+        if (!(options & WithAudioOutput)) {
+            cerr << "WARNING: MainWindowBase: WithAudioInput requires WithAudioOutput -- recording will not work" << endl;
+        }
+    }
+    
     qRegisterMetaType<sv_frame_t>("sv_frame_t");
     qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t");
 
@@ -164,6 +173,8 @@
     XSetErrorHandler(handle_x11_error);
 #endif
 
+    connect(this, SIGNAL(hideSplash()), this, SLOT(emitHideSplash()));
+    
     connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()),
 	    this, SLOT(documentModified()));
     connect(CommandHistory::getInstance(), SIGNAL(documentRestored()),
@@ -216,6 +227,10 @@
 
     m_playSource = new AudioCallbackPlaySource(m_viewManager,
                                                QApplication::applicationName());
+    if (m_soundOptions & WithAudioInput) {
+        m_recordTarget = new AudioRecordTarget(m_viewManager,
+                                               QApplication::applicationName());
+    }
 
     connect(m_playSource, SIGNAL(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)),
 	    this,           SLOT(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)));
@@ -256,17 +271,20 @@
     m_labeller = new Labeller(labellerType);
     m_labeller->setCounterCycleSize(cycle);
 
-    if (withMIDIInput) {
+    if (m_soundOptions & WithMIDIInput) {
         m_midiInput = new MIDIInput(QApplication::applicationName(), this);
     }
+
+    QTimer::singleShot(1500, this, SIGNAL(hideSplash()));
 }
 
 MainWindowBase::~MainWindowBase()
 {
     SVDEBUG << "MainWindowBase::~MainWindowBase" << endl;
-    if (m_playTarget) m_playTarget->shutdown();
-//    delete m_playTarget;
+    delete m_playTarget;
     delete m_playSource;
+    delete m_audioIO;
+    delete m_recordTarget;
     delete m_viewManager;
     delete m_oscQueue;
     delete m_oscQueueStarter;
@@ -275,6 +293,12 @@
 }
 
 void
+MainWindowBase::emitHideSplash()
+{
+    emit hideSplash(this);
+}
+
+void
 MainWindowBase::finaliseMenus()
 {
     delete m_menuShortcutMapper;
@@ -542,7 +566,7 @@
     bool haveMainModel =
 	(getMainModel() != 0);
     bool havePlayTarget =
-	(m_playTarget != 0);
+	(m_playTarget != 0 || m_audioIO != 0);
     bool haveSelection = 
 	(m_viewManager &&
 	 !m_viewManager->getSelections().empty());
@@ -587,8 +611,9 @@
     emit canMeasureLayer(haveCurrentLayer);
     emit canSelect(haveMainModel && haveCurrentPane);
     emit canPlay(haveMainModel && havePlayTarget);
-    emit canFfwd(true);
-    emit canRewind(true);
+    emit canRecord(m_soundOptions & WithAudioInput); // always possible then
+    emit canFfwd(haveMainModel);
+    emit canRewind(haveMainModel);
     emit canPaste(haveClipboardContents);
     emit canInsertInstant(haveCurrentPane);
     emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection);
@@ -1303,7 +1328,7 @@
         rate = m_playSource->getSourceSampleRate();
     }
 
-    WaveFileModel *newModel = new WaveFileModel(source, rate);
+    ReadOnlyWaveFileModel *newModel = new ReadOnlyWaveFileModel(source, rate);
 
     if (!newModel->isOK()) {
 	delete newModel;
@@ -2150,28 +2175,42 @@
 }
 
 void
-MainWindowBase::createPlayTarget()
+MainWindowBase::createAudioIO()
 {
-    if (m_playTarget) return;
-
+    if (m_playTarget || m_audioIO) return;
+
+    if (!(m_soundOptions & WithAudioOutput)) return;
+
+    //!!! how to handle preferences
+/*    
     QSettings settings;
     settings.beginGroup("Preferences");
     QString targetName = settings.value("audio-target", "").toString();
     settings.endGroup();
-
     AudioTargetFactory *factory = AudioTargetFactory::getInstance();
 
     factory->setDefaultCallbackTarget(targetName);
-    m_playTarget = factory->createCallbackTarget(m_playSource);
-
-    if (!m_playTarget) {
+*/
+
+    if (m_soundOptions & WithAudioInput) {
+        m_audioIO = breakfastquay::AudioFactory::
+            createCallbackIO(m_recordTarget, m_playSource);
+        m_playSource->setSystemPlaybackTarget(m_audioIO);
+    } else {
+        m_playTarget = breakfastquay::AudioFactory::
+            createCallbackPlayTarget(m_playSource);
+        m_playSource->setSystemPlaybackTarget(m_playTarget);
+    }
+
+    if (!m_playTarget && !m_audioIO) {
         emit hideSplash();
 
-        if (factory->isAutoCallbackTarget(targetName)) {
+//        if (factory->isAutoCallbackTarget(targetName)) {
             QMessageBox::warning
 	    (this, tr("Couldn't open audio device"),
 	     tr("<b>No audio available</b><p>Could not open an audio device for playback.<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>"),
 	     QMessageBox::Ok);
+/*
         } else {
             QMessageBox::warning
                 (this, tr("Couldn't open audio device"),
@@ -2179,6 +2218,8 @@
                  .arg(factory->getCallbackTargetDescription(targetName)),
                  QMessageBox::Ok);
         }
+*/
+            return;
     }
 }
 
@@ -2610,8 +2651,10 @@
 void
 MainWindowBase::play()
 {
-    if (m_playSource->isPlaying()) {
+    if (m_recordTarget->isRecording() || m_playSource->isPlaying()) {
         stop();
+        QAction *action = qobject_cast<QAction *>(sender());
+        if (action) action->setChecked(false);
     } else {
         playbackFrameChanged(m_viewManager->getPlaybackFrame());
 	m_playSource->play(m_viewManager->getPlaybackFrame());
@@ -2619,6 +2662,124 @@
 }
 
 void
+MainWindowBase::record()
+{
+    if (!(m_soundOptions & WithAudioInput)) {
+        return;
+    }
+
+    if (!m_recordTarget) {
+        //!!! report
+        return;
+    }
+
+    if (!m_audioIO) {
+        createAudioIO();
+    }
+    
+    if (m_recordTarget->isRecording()) {
+        m_recordTarget->stopRecording();
+        emit audioFileLoaded();
+        return;
+    }
+
+    WritableWaveFileModel *model = m_recordTarget->startRecording();
+    if (!model) {
+        cerr << "ERROR: MainWindowBase::record: Recording failed" << endl;
+        //!!! report
+        return;
+    }
+
+    if (!model->isOK()) {
+        m_recordTarget->stopRecording();
+        delete model;
+        //!!! ???
+        return;
+    }
+
+    PlayParameterRepository::getInstance()->addPlayable(model);
+    
+    if (!getMainModel()) {
+
+        //!!! duplication with openAudio here
+        
+        QString templateName = getDefaultSessionTemplate();
+        bool loadedTemplate = false;
+        
+        if (templateName != "") {
+            FileOpenStatus tplStatus = openSessionTemplate(templateName);
+            if (tplStatus == FileOpenCancelled) {
+                return;
+            }
+            if (tplStatus != FileOpenFailed) {
+                loadedTemplate = true;
+            }
+        }
+
+        if (!loadedTemplate) {
+            closeSession();
+            createDocument();
+        }
+        
+        Model *prevMain = getMainModel();
+        if (prevMain) {
+            m_playSource->removeModel(prevMain);
+            PlayParameterRepository::getInstance()->removePlayable(prevMain);
+        }
+        
+        m_document->setMainModel(model);
+        setupMenus();
+
+	if (loadedTemplate || (m_sessionFile == "")) {
+            //!!! shouldn't be dealing directly with title from here -- call a method
+	    setWindowTitle(tr("%1: %2")
+                           .arg(QApplication::applicationName())
+                           .arg(model->getLocation()));
+	    CommandHistory::getInstance()->clear();
+	    CommandHistory::getInstance()->documentSaved();
+	    m_documentModified = false;
+	} else {
+	    setWindowTitle(tr("%1: %2 [%3]")
+                           .arg(QApplication::applicationName())
+			   .arg(QFileInfo(m_sessionFile).fileName())
+			   .arg(model->getLocation()));
+	    if (m_documentModified) {
+		m_documentModified = false;
+		documentModified(); // so as to restore "(modified)" window title
+	    }
+	}
+
+    } else {
+
+        CommandHistory::getInstance()->startCompoundOperation
+            (tr("Import Recorded Audio"), true);
+
+        m_document->addImportedModel(model);
+
+        AddPaneCommand *command = new AddPaneCommand(this);
+        CommandHistory::getInstance()->addCommand(command);
+
+        Pane *pane = command->getPane();
+
+        if (m_timeRulerLayer) {
+            m_document->addLayerToView(pane, m_timeRulerLayer);
+        }
+
+        Layer *newLayer = m_document->createImportedLayer(model);
+
+        if (newLayer) {
+            m_document->addLayerToView(pane, newLayer);
+        }
+	
+        CommandHistory::getInstance()->endCompoundOperation();
+    }
+
+    updateMenuStates();
+    m_recentFiles.addFile(model->getLocation());
+    currentPaneChanged(m_paneStack->getCurrentPane());
+}
+
+void
 MainWindowBase::ffwd()
 {
     if (!getMainModel()) return;
@@ -2846,6 +3007,11 @@
 void
 MainWindowBase::stop()
 {
+    if (m_recordTarget->isRecording()) {
+        m_recordTarget->stopRecording();
+        emit audioFileLoaded();
+    }
+        
     m_playSource->stop();
 
     if (m_paneStack && m_paneStack->getCurrentPane()) {
@@ -3316,8 +3482,9 @@
 //    SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl;
     updateDescriptionLabel();
     if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
-    if (model && !m_playTarget && m_audioOutput) {
-        createPlayTarget();
+    if (model && !(m_playTarget || m_audioIO) &&
+        (m_soundOptions & WithAudioOutput)) {
+        createAudioIO();
     }
 }
 
@@ -3329,7 +3496,6 @@
         m_viewManager->setPlaybackModel(0);
     }
     m_playSource->removeModel(model);
-    FFTDataServer::modelAboutToBeDeleted(model);
 }
 
 void