changeset 489:111e976f9ed4 3.0-integration

Merge from branch "recording"
author Chris Cannam
date Thu, 17 Sep 2015 13:46:07 +0100
parents 52c0aff69478 (current diff) 66b92c188cbd (diff)
children b3568eca53ba a4d90cf2bb79
files framework/MainWindowBase.cpp
diffstat 4 files changed, 114 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/audio/AudioRecordTarget.cpp	Thu Aug 20 13:15:19 2015 +0100
+++ b/audio/AudioRecordTarget.cpp	Thu Sep 17 13:46:07 2015 +0100
@@ -27,6 +27,7 @@
     m_clientName(clientName.toUtf8().data()),
     m_recording(false),
     m_recordSampleRate(44100),
+    m_frameCount(0),
     m_model(0)
 {
 }
@@ -55,9 +56,30 @@
 void
 AudioRecordTarget::putSamples(int nframes, float **samples)
 {
-    QMutexLocker locker(&m_mutex); //!!! bad here
-    if (!m_recording) return;
-    m_model->addSamples(samples, nframes);
+    bool secChanged = false;
+    sv_frame_t frameToEmit = 0;
+
+    {
+        QMutexLocker locker(&m_mutex); //!!! bad here
+        if (!m_recording) return;
+
+        m_model->addSamples(samples, nframes);
+
+        sv_frame_t priorFrameCount = m_frameCount;
+        m_frameCount += nframes;
+
+        RealTime priorRT = RealTime::frame2RealTime
+            (priorFrameCount, m_recordSampleRate);
+        RealTime postRT = RealTime::frame2RealTime
+            (m_frameCount, m_recordSampleRate);
+
+        secChanged = (postRT.sec > priorRT.sec);
+        if (secChanged) frameToEmit = m_frameCount;
+    }
+
+    if (secChanged) {
+        emit recordDurationChanged(frameToEmit, m_recordSampleRate);
+    }
 }
 
 void
@@ -75,6 +97,19 @@
     }
 }
 
+QString
+AudioRecordTarget::getRecordFolder()
+{
+    QDir parent(TempDirectory::getInstance()->getContainingPath());
+    QString subdirname = "recorded"; //!!! tr?
+    if (!parent.mkpath(subdirname)) {
+        cerr << "ERROR: AudioRecordTarget::getRecordFolder: Failed to create recorded dir in \"" << parent.canonicalPath() << "\"" << endl;
+        return "";
+    } else {
+        return parent.filePath(subdirname);
+    }
+}
+
 WritableWaveFileModel *
 AudioRecordTarget::startRecording()
 {
@@ -86,16 +121,11 @@
     }
 
     m_model = 0;
+    m_frameCount = 0;
 
-    QDir parent(TempDirectory::getInstance()->getContainingPath());
-    QDir recordedDir;
-    QString subdirname = "recorded"; //!!! tr?
-    if (!parent.mkpath(subdirname)) {
-        cerr << "ERROR: AudioRecordTarget::startRecording: Failed to create recorded dir in \"" << parent.canonicalPath() << "\"" << endl;
-        return 0;
-    } else {
-        recordedDir = parent.filePath(subdirname);
-    }
+    QString folder = getRecordFolder();
+    if (folder == "") return 0;
+    QDir recordedDir(folder);
 
     QDateTime now = QDateTime::currentDateTime();
 
--- a/audio/AudioRecordTarget.h	Thu Aug 20 13:15:19 2015 +0100
+++ b/audio/AudioRecordTarget.h	Thu Sep 17 13:46:07 2015 +0100
@@ -51,12 +51,15 @@
 
     virtual void audioProcessingOverload() { }
 
+    QString getRecordFolder();
+    
     bool isRecording() const { return m_recording; }
     WritableWaveFileModel *startRecording(); // caller takes ownership
     void stopRecording();
 
 signals:
     void recordStatusChanged(bool recording);
+    void recordDurationChanged(sv_frame_t, sv_samplerate_t); // emitted occasionally
 
 protected slots:
     void modelAboutToBeDeleted();
@@ -66,6 +69,7 @@
     std::string m_clientName;
     bool m_recording;
     sv_samplerate_t m_recordSampleRate;
+    sv_frame_t m_frameCount;
     QString m_audioFileName;
     WritableWaveFileModel *m_model;
     QMutex m_mutex;
--- a/framework/MainWindowBase.cpp	Thu Aug 20 13:15:19 2015 +0100
+++ b/framework/MainWindowBase.cpp	Thu Sep 17 13:46:07 2015 +0100
@@ -155,6 +155,7 @@
     m_lastPlayStatusSec(0),
     m_initialDarkBackground(false),
     m_defaultFfwdRwdStep(2, 0),
+    m_audioRecordMode(RecordCreateAdditionalModel),
     m_statusLabel(0),
     m_menuShortcutMapper(0)
 {
@@ -230,6 +231,8 @@
     if (m_soundOptions & WithAudioInput) {
         m_recordTarget = new AudioRecordTarget(m_viewManager,
                                                QApplication::applicationName());
+        connect(m_recordTarget, SIGNAL(recordDurationChanged(sv_frame_t, sv_samplerate_t)),
+                this, SLOT(recordDurationChanged(sv_frame_t, sv_samplerate_t)));
     }
 
     connect(m_playSource, SIGNAL(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)),
@@ -611,7 +614,7 @@
     emit canMeasureLayer(haveCurrentLayer);
     emit canSelect(haveMainModel && haveCurrentPane);
     emit canPlay(haveMainModel && havePlayTarget);
-    emit canRecord(m_soundOptions & WithAudioInput); // always possible then
+    emit canRecord(m_recordTarget != 0);
     emit canFfwd(haveMainModel);
     emit canRewind(haveMainModel);
     emit canPaste(haveClipboardContents);
@@ -2195,6 +2198,7 @@
     if (m_soundOptions & WithAudioInput) {
         m_audioIO = breakfastquay::AudioFactory::
             createCallbackIO(m_recordTarget, m_playSource);
+        m_audioIO->suspend(); // start in suspended state
         m_playSource->setSystemPlaybackTarget(m_audioIO);
     } else {
         m_playTarget = breakfastquay::AudioFactory::
@@ -2656,6 +2660,7 @@
         QAction *action = qobject_cast<QAction *>(sender());
         if (action) action->setChecked(false);
     } else {
+        if (m_audioIO) m_audioIO->resume();
         playbackFrameChanged(m_viewManager->getPlaybackFrame());
 	m_playSource->play(m_viewManager->getPlaybackFrame());
     }
@@ -2683,6 +2688,12 @@
         return;
     }
 
+    if (m_audioRecordMode == RecordReplaceSession) {
+        if (!checkSaveModified()) return;
+    }
+
+    if (m_audioIO) m_audioIO->resume();
+
     WritableWaveFileModel *model = m_recordTarget->startRecording();
     if (!model) {
         cerr << "ERROR: MainWindowBase::record: Recording failed" << endl;
@@ -2696,10 +2707,10 @@
         //!!! ???
         return;
     }
-
+    
     PlayParameterRepository::getInstance()->addPlayable(model);
-    
-    if (!getMainModel()) {
+
+    if (m_audioRecordMode == RecordReplaceSession || !getMainModel()) {
 
         //!!! duplication with openAudio here
         
@@ -3014,6 +3025,8 @@
         
     m_playSource->stop();
 
+    if (m_audioIO) m_audioIO->suspend();
+    
     if (m_paneStack && m_paneStack->getCurrentPane()) {
         updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
     } else {
@@ -3352,6 +3365,17 @@
 }
 
 void
+MainWindowBase::recordDurationChanged(sv_frame_t frame, sv_samplerate_t rate)
+{
+    RealTime duration = RealTime::frame2RealTime(frame, rate);
+    QString durStr = duration.toSecText().c_str();
+    
+    m_myStatusMessage = tr("Recording: %1").arg(durStr);
+
+    getStatusLabel()->setText(m_myStatusMessage);
+}
+
+void
 MainWindowBase::globalCentreFrameChanged(sv_frame_t )
 {
     if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
@@ -3613,4 +3637,30 @@
 #endif
 }
 
-    
+void
+MainWindowBase::openLocalFolder(QString path)
+{
+    QDir d(path);
+    if (d.exists()) {
+        QStringList args;
+        QString path = d.canonicalPath();
+#if defined Q_OS_WIN32
+        // Although the Win32 API is quite happy to have
+        // forward slashes as directory separators, Windows
+        // Explorer is not
+        path = path.replace('/', '\\');
+        args << path;
+        QProcess::execute("c:/windows/explorer.exe", args);
+#else
+        args << path;
+        QProcess::execute(
+#if defined Q_OS_MAC
+            "/usr/bin/open",
+#else
+            "/usr/bin/xdg-open",
+#endif
+            args);
+#endif
+    }
+}
+
--- a/framework/MainWindowBase.h	Thu Aug 20 13:15:19 2015 +0100
+++ b/framework/MainWindowBase.h	Thu Sep 17 13:46:07 2015 +0100
@@ -108,6 +108,11 @@
         FileOpenWrongMode // attempted to open layer when no main model present
     };
 
+    enum AudioRecordMode {
+        RecordReplaceSession,
+        RecordCreateAdditionalModel
+    };
+    
     virtual FileOpenStatus open(FileSource source, AudioFileOpenMode = AskUser);
     virtual FileOpenStatus openPath(QString fileOrUrl, AudioFileOpenMode = AskUser);
     virtual FileOpenStatus openAudio(FileSource source, AudioFileOpenMode = AskUser, QString templateName = "");
@@ -130,6 +135,10 @@
         m_defaultFfwdRwdStep = step;
     }
 
+    void setAudioRecordMode(AudioRecordMode mode) {
+        m_audioRecordMode = mode;
+    }
+    
 signals:
     // Used to toggle the availability of menu actions
     void canAddPane(bool);
@@ -238,6 +247,7 @@
     virtual void viewCentreFrameChanged(View *, sv_frame_t);
     virtual void viewZoomLevelChanged(View *, int, bool);
     virtual void outputLevelsChanged(float, float) = 0;
+    virtual void recordDurationChanged(sv_frame_t, sv_samplerate_t);
 
     virtual void currentPaneChanged(Pane *);
     virtual void currentLayerChanged(Pane *, Layer *);
@@ -360,6 +370,8 @@
 
     RealTime                 m_defaultFfwdRwdStep;
 
+    AudioRecordMode          m_audioRecordMode;
+
     mutable QLabel *m_statusLabel;
     QLabel *getStatusLabel() const;
 
@@ -441,6 +453,7 @@
 
     virtual void createAudioIO();
     virtual void openHelpUrl(QString url);
+    virtual void openLocalFolder(QString path);
 
     virtual void setupMenus() = 0;
     virtual void updateVisibleRangeDisplay(Pane *p) const = 0;