diff --git a/src/AppConfig.cpp b/src/AppConfig.cpp index 4fbff52..dc68da5 100644 --- a/src/AppConfig.cpp +++ b/src/AppConfig.cpp @@ -4,6 +4,8 @@ #include "AppConfig.h" #include "CubicSDR.h" +#include + DeviceConfig::DeviceConfig() : deviceId("") { ppm.store(0); offset.store(0); @@ -513,6 +515,25 @@ std::string AppConfig::getRecordingPath() { return recordingPath; } +bool AppConfig::verifyRecordingPath() { + string recPathStr = wxGetApp().getConfig()->getRecordingPath(); + + if (recPathStr.empty()) { + wxMessageBox( wxT("Recording path is not set. Please use 'Set Recording Path' from the 'File' Menu."), wxT("Recording Path Error"), wxICON_INFORMATION); + + return false; + } + + wxFileName recPath(recPathStr); + + if (!recPath.Exists() || !recPath.IsDirWritable()) { + wxMessageBox( wxT("Recording path does not exist or is not writable. Please use 'Set Recording Path' from the 'File' Menu."), wxT("Recording Path Error"), wxICON_INFORMATION); + + return false; + } + + return true; +} void AppConfig::setConfigName(std::string configName) { this->configName = configName; diff --git a/src/AppConfig.h b/src/AppConfig.h index d620ee9..5121272 100644 --- a/src/AppConfig.h +++ b/src/AppConfig.h @@ -141,6 +141,8 @@ public: void setRecordingPath(std::string recPath); std::string getRecordingPath(); + bool verifyRecordingPath(); + #if USE_HAMLIB int getRigModel(); void setRigModel(int rigModel); diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 5e24b27..c0c0177 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -2643,9 +2643,7 @@ int AppFrame::OnGlobalKeyUp(wxKeyEvent &event) { return 1; break; case 'R': - if (activeDemod) { - activeDemod->setRecording(!activeDemod->isRecording()); - } + toggleActiveDemodRecording(); break; case 'P': wxGetApp().getSpectrumProcessor()->setPeakHold(!wxGetApp().getSpectrumProcessor()->getPeakHold()); @@ -2691,6 +2689,19 @@ int AppFrame::OnGlobalKeyUp(wxKeyEvent &event) { return 1; } +void AppFrame::toggleActiveDemodRecording() { + if (!wxGetApp().getConfig()->verifyRecordingPath()) { + return; + } + + DemodulatorInstancePtr activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator(); + + if (activeDemod) { + activeDemod->setRecording(!activeDemod->isRecording()); + wxGetApp().getBookmarkMgr().updateActiveList(); + } +} + void AppFrame::setWaterfallLinesPerSecond(int lps) { waterfallSpeedMeter->setUserInputValue(sqrt(lps)); diff --git a/src/AppFrame.h b/src/AppFrame.h index fcee6e5..8d64fcd 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -115,6 +115,8 @@ public: int OnGlobalKeyDown(wxKeyEvent &event); int OnGlobalKeyUp(wxKeyEvent &event); + void toggleActiveDemodRecording(); + void setWaterfallLinesPerSecond(int lps); void setSpectrumAvgSpeed(double avg); diff --git a/src/audio/AudioSinkThread.cpp b/src/audio/AudioSinkThread.cpp index 11e9009..edf3152 100644 --- a/src/audio/AudioSinkThread.cpp +++ b/src/audio/AudioSinkThread.cpp @@ -7,6 +7,7 @@ AudioSinkThread::AudioSinkThread() { inputQueuePtr = std::make_shared(); + inputQueuePtr->set_max_num_items(1000); setInputQueue("input", inputQueuePtr); } diff --git a/src/audio/AudioThread.h b/src/audio/AudioThread.h index d648895..d37593b 100644 --- a/src/audio/AudioThread.h +++ b/src/audio/AudioThread.h @@ -24,7 +24,7 @@ public: std::vector data; AudioThreadInput() : - frequency(0), sampleRate(0), inputRate(0), channels(0), peak(0), type(0) { + frequency(0), inputRate(0), sampleRate(0), channels(0), peak(0), type(0) { } diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index 8e243c0..0afb863 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -331,12 +331,11 @@ void DemodulatorThread::run() { std::cout << "DemodulatorThread::run() cannot push ati into audioOutputQueue, is full !" << std::endl; std::this_thread::yield(); } - - if (localAudioSinkOutputQueue != nullptr) { - if (!audioSinkOutputQueue->try_push(ati)) { - std::cout << "DemodulatorThread::run() cannot push ati into audioSinkOutputQueue, is full !" << std::endl; - std::this_thread::yield(); - } + } + + if (localAudioSinkOutputQueue != nullptr) { + if (!audioSinkOutputQueue->try_push(ati)) { + std::cout << "DemodulatorThread::run() cannot push ati into audioSinkOutputQueue, is full !" << std::endl; } } } @@ -418,4 +417,4 @@ void DemodulatorThread::releaseSquelchLock(DemodulatorInstance* inst) { if (inst == nullptr || squelchLock == inst) { squelchLock = nullptr; } -} \ No newline at end of file +} diff --git a/src/forms/Bookmark/BookmarkView.cpp b/src/forms/Bookmark/BookmarkView.cpp index 4cb9888..7fabbb4 100644 --- a/src/forms/Bookmark/BookmarkView.cpp +++ b/src/forms/Bookmark/BookmarkView.cpp @@ -816,8 +816,16 @@ void BookmarkView::activeSelection(DemodulatorInstancePtr dsel) { clearButtons(); addBookmarkChoice(m_buttonPanel); - addButton(m_buttonPanel, "Remove Active", wxCommandEventHandler( BookmarkView::onRemoveActive )); + + if (dsel->isActive() && !(dsel->isRecording())) { + addButton(m_buttonPanel, "Start Recording", wxCommandEventHandler( BookmarkView::onStartRecording )); + } else { + addButton(m_buttonPanel, "Stop Recording", wxCommandEventHandler( BookmarkView::onStopRecording )); + } + addButton(m_buttonPanel, "Remove Active", wxCommandEventHandler( BookmarkView::onRemoveActive )); + + showProps(); showButtons(); refreshLayout(); @@ -1149,6 +1157,30 @@ void BookmarkView::onRemoveActive( wxCommandEvent& /* event */ ) { } } +void BookmarkView::onStartRecording( wxCommandEvent& /* event */ ) { + TreeViewItem *curSel = itemToTVI(m_treeView->GetSelection()); + + if (curSel && curSel->type == TreeViewItem::TREEVIEW_ITEM_TYPE_ACTIVE) { + if (!curSel->demod->isRecording() && wxGetApp().getConfig()->verifyRecordingPath()) { + curSel->demod->setRecording(true); + wxGetApp().getBookmarkMgr().updateActiveList(); + } + } +} + + +void BookmarkView::onStopRecording( wxCommandEvent& /* event */ ) { + TreeViewItem *curSel = itemToTVI(m_treeView->GetSelection()); + + if (curSel && curSel->type == TreeViewItem::TREEVIEW_ITEM_TYPE_ACTIVE) { + if (curSel->demod->isRecording()) { + curSel->demod->setRecording(false); + wxGetApp().getBookmarkMgr().updateActiveList(); + } + } +} + + void BookmarkView::onRemoveBookmark( wxCommandEvent& /* event */ ) { if (editingLabel) { diff --git a/src/forms/Bookmark/BookmarkView.h b/src/forms/Bookmark/BookmarkView.h index 8ed1bff..820ece1 100644 --- a/src/forms/Bookmark/BookmarkView.h +++ b/src/forms/Bookmark/BookmarkView.h @@ -145,6 +145,8 @@ protected: void onBookmarkChoice( wxCommandEvent &event ); void onRemoveActive( wxCommandEvent& event ); + void onStartRecording( wxCommandEvent& event ); + void onStopRecording( wxCommandEvent& event ); void onRemoveBookmark( wxCommandEvent& event ); void onActivateBookmark( wxCommandEvent& event ); diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index a951a1f..03760ab 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -565,14 +565,14 @@ void WaterfallCanvas::updateHoverState() { mouseTracker.setVertDragLock(true); mouseTracker.setHorizDragLock(false); - setStatusText("Click and drag to change demodulator bandwidth. SPACE or numeric key for direct frequency input. [, ] to nudge, M for mute, D to delete, C to center, E to edit label."); + setStatusText("Click and drag to change demodulator bandwidth. SPACE or numeric key for direct frequency input. [, ] to nudge, M for mute, D to delete, C to center, E to edit label, R to record."); } else { SetCursor(wxCURSOR_SIZING); nextDragState = WF_DRAG_FREQUENCY; mouseTracker.setVertDragLock(true); mouseTracker.setHorizDragLock(false); - setStatusText("Click and drag to change demodulator frequency; SPACE or numeric key for direct input. [, ] to nudge, M for mute, D to delete, C to center, E to edit label."); + setStatusText("Click and drag to change demodulator frequency; SPACE or numeric key for direct input. [, ] to nudge, M for mute, D to delete, C to center, E to edit label, R to record."); } } else {