summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format2
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt33
-rw-r--r--src/abaddon.cpp19
-rw-r--r--src/audio/manager.cpp92
-rw-r--r--src/audio/manager.hpp54
-rw-r--r--src/settings.cpp4
-rw-r--r--src/settings.hpp7
-rw-r--r--src/windows/voicewindow.cpp102
-rw-r--r--src/windows/voicewindow.hpp17
m---------subprojects/rnnoise0
12 files changed, 276 insertions, 59 deletions
diff --git a/.clang-format b/.clang-format
index 074ecf0..6bd8ca0 100644
--- a/.clang-format
+++ b/.clang-format
@@ -35,7 +35,7 @@ DerivePointerAlignment: 'false'
FixNamespaceComments: 'true'
IncludeBlocks: Merge
IndentCaseLabels: 'true'
-IndentPPDirectives: BeforeHash
+IndentPPDirectives: None
IndentWidth: '4'
IndentWrappedFunctionNames: 'false'
JavaScriptQuotes: Double
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6cfb8b7..0f20cb2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -67,7 +67,7 @@ jobs:
with:
cond: ${{ matrix.mindeps == true }}
if_true: |
- cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=${{ matrix.buildtype }} -DUSE_LIBHANDY=OFF -DENABLE_VOICE=OFF -DENABLE_NOTIFICATION_SOUNDS=OFF -DENABLE_QRCODE_LOGIN=OFF
+ cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=${{ matrix.buildtype }} -DUSE_LIBHANDY=OFF -DENABLE_VOICE=OFF -DENABLE_NOTIFICATION_SOUNDS=OFF -DENABLE_QRCODE_LOGIN=OFF -DENABLE_RNNOISE=OFF
cmake --build build
if_false: |
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=${{ matrix.buildtype }} -DCMAKE_CXX_FLAGS="-Wl,--default-image-base-low"
diff --git a/.gitmodules b/.gitmodules
index aae3862..e173bb4 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,6 +13,9 @@
[submodule "subprojects/miniaudio"]
path = subprojects/miniaudio
url = https://github.com/mackron/miniaudio
+[submodule "subprojects/rnnoise"]
+ path = subprojects/rnnoise
+ url = https://github.com/xiph/rnnoise
[submodule "subprojects/qrcodegen"]
path = subprojects/qrcodegen
url = https://github.com/nayuki/QR-Code-generator
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7a55057..37ea1e3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,6 +11,7 @@ option(USE_LIBHANDY "Enable features that require libhandy (default)" ON)
option(ENABLE_VOICE "Enable voice suppport" ON)
option(USE_KEYCHAIN "Store the token in the keychain (default)" ON)
option(ENABLE_NOTIFICATION_SOUNDS "Enable notification sounds (default)" ON)
+option(ENABLE_RNNOISE "Enable RNNoise for voice activity detection (default)" ON)
option(ENABLE_QRCODE_LOGIN "Enable QR code login (default)" ON)
find_package(nlohmann_json REQUIRED)
@@ -161,12 +162,42 @@ if (ENABLE_VOICE)
target_link_libraries(abaddon ${CMAKE_DL_LIBS})
+ if (ENABLE_RNNOISE)
+ target_compile_definitions(abaddon PRIVATE WITH_RNNOISE)
+
+ find_package(rnnoise QUIET)
+ if (NOT rnnoise_FOUND)
+ message("rnnoise was not found and will be included as a submodule")
+ # This is potentially really stupid
+ add_library(rnnoise
+ subprojects/rnnoise/src/arch.h
+ subprojects/rnnoise/src/celt_lpc.c
+ subprojects/rnnoise/src/celt_lpc.h
+ subprojects/rnnoise/src/common.h
+ subprojects/rnnoise/src/denoise.c
+ subprojects/rnnoise/src/kiss_fft.c
+ subprojects/rnnoise/src/kiss_fft.h
+ subprojects/rnnoise/src/opus_types.h
+ subprojects/rnnoise/src/pitch.c
+ subprojects/rnnoise/src/pitch.h
+ subprojects/rnnoise/src/rnn_data.c
+ subprojects/rnnoise/src/rnn_data.h
+ subprojects/rnnoise/src/rnn_reader.c
+ subprojects/rnnoise/src/rnn.c
+ subprojects/rnnoise/src/rnn.h
+ subprojects/rnnoise/src/tansig_table.h
+ subprojects/rnnoise/src/_kiss_fft_guts.h
+ subprojects/rnnoise/include/rnnoise.h)
+ target_include_directories(rnnoise PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/rnnoise/include")
+ target_link_libraries(abaddon rnnoise)
+ endif ()
+ endif ()
+
if (APPLE)
target_link_libraries(abaddon "-framework CoreFoundation")
target_link_libraries(abaddon "-framework CoreAudio")
target_link_libraries(abaddon "-framework AudioToolbox")
endif ()
-
endif ()
if (${ENABLE_NOTIFICATION_SOUNDS})
diff --git a/src/abaddon.cpp b/src/abaddon.cpp
index 2be54ba..a8360c2 100644
--- a/src/abaddon.cpp
+++ b/src/abaddon.cpp
@@ -23,11 +23,11 @@
#include "remoteauth/remoteauthdialog.hpp"
#ifdef WITH_LIBHANDY
- #include <handy.h>
+#include <handy.h>
#endif
#ifdef _WIN32
- #pragma comment(lib, "crypt32.lib")
+#pragma comment(lib, "crypt32.lib")
#endif
Abaddon::Abaddon()
@@ -67,7 +67,7 @@ Abaddon::Abaddon()
if (!accessible)
m_channels_requested.erase(id);
});
- if (GetSettings().Prefetch)
+ if (GetSettings().Prefetch) {
m_discord.signal_message_create().connect([this](const Message &message) {
if (message.Author.HasAvatar())
m_img_mgr.Prefetch(message.Author.GetAvatarURL());
@@ -76,6 +76,11 @@ Abaddon::Abaddon()
m_img_mgr.Prefetch(attachment.ProxyURL);
}
});
+ }
+
+#ifdef WITH_VOICE
+ m_audio.SetVADMethod(GetSettings().VAD);
+#endif
}
Abaddon &Abaddon::Get() {
@@ -475,14 +480,6 @@ void Abaddon::ShowVoiceWindow() {
m_audio.SetPlayback(!is_deaf);
});
- wnd->signal_gate().connect([this](double gate) {
- m_audio.SetCaptureGate(gate);
- });
-
- wnd->signal_gain().connect([this](double gain) {
- m_audio.SetCaptureGain(gain);
- });
-
wnd->signal_mute_user_cs().connect([this](Snowflake id, bool is_mute) {
if (const auto ssrc = m_discord.GetSSRCOfUser(id); ssrc.has_value()) {
m_audio.SetMuteSSRC(*ssrc, is_mute);
diff --git a/src/audio/manager.cpp b/src/audio/manager.cpp
index 67fbcd9..53eff54 100644
--- a/src/audio/manager.cpp
+++ b/src/audio/manager.cpp
@@ -143,6 +143,10 @@ AudioManager::~AudioManager() {
ma_device_uninit(&m_capture_device);
ma_context_uninit(&m_context);
RemoveAllSSRCs();
+
+#ifdef WITH_RNNOISE
+ RNNoiseUninitialize();
+#endif
}
void AudioManager::AddSSRC(uint32_t ssrc) {
@@ -419,7 +423,16 @@ void AudioManager::OnCapturedPCM(const int16_t *pcm, ma_uint32 frames) {
UpdateCaptureVolume(new_pcm.data(), frames);
- if (m_capture_peak_meter / 32768.0 < m_capture_gate) return;
+ switch (m_vad_method) {
+ case VADMethod::Gate:
+ if (!CheckVADVoiceGate()) return;
+ break;
+#ifdef WITH_RNNOISE
+ case VADMethod::RNNoise:
+ if (!CheckVADRNNoise(pcm)) return;
+ break;
+#endif
+ }
m_enc_mutex.lock();
int payload_len = opus_encode(m_encoder, new_pcm.data(), 480, static_cast<unsigned char *>(m_opus_buffer), 1275);
@@ -462,6 +475,41 @@ bool AudioManager::DecayVolumeMeters() {
return true;
}
+bool AudioManager::CheckVADVoiceGate() {
+ return m_capture_peak_meter / 32768.0 > m_capture_gate;
+}
+
+#ifdef WITH_RNNOISE
+bool AudioManager::CheckVADRNNoise(const int16_t *pcm) {
+ static float denoised[480];
+ static float rnnoise_input[480];
+ // take left channel
+ for (size_t i = 0; i < 480; i++) {
+ rnnoise_input[i] = static_cast<float>(pcm[i * 2]);
+ }
+ m_vad_prob = rnnoise_process_frame(m_rnnoise, denoised, rnnoise_input);
+ return m_vad_prob > m_prob_threshold;
+}
+
+void AudioManager::RNNoiseInitialize() {
+ spdlog::get("audio")->debug("Initializing RNNoise");
+ RNNoiseUninitialize();
+ m_rnnoise = rnnoise_create(nullptr);
+ const auto expected = rnnoise_get_frame_size();
+ if (expected != 480) {
+ spdlog::get("audio")->warn("RNNoise expects a frame count other than 480");
+ }
+}
+
+void AudioManager::RNNoiseUninitialize() {
+ if (m_rnnoise != nullptr) {
+ spdlog::get("audio")->debug("Uninitializing RNNoise");
+ rnnoise_destroy(m_rnnoise);
+ m_rnnoise = nullptr;
+ }
+}
+#endif
+
bool AudioManager::OK() const {
return m_ok;
}
@@ -486,6 +534,48 @@ uint32_t AudioManager::GetRTPTimestamp() const noexcept {
return m_rtp_timestamp;
}
+void AudioManager::SetVADMethod(const std::string &method) {
+ spdlog::get("audio")->debug("Setting VAD method to {}", method);
+ if (method == "gate") {
+ SetVADMethod(VADMethod::Gate);
+ } else if (method == "rnnoise") {
+#ifdef WITH_RNNOISE
+ SetVADMethod(VADMethod::RNNoise);
+#else
+ SetVADMethod(VADMethod::Gate);
+ spdlog::get("audio")->error("Tried to set RNNoise VAD method with support disabled");
+#endif
+ } else {
+ SetVADMethod(VADMethod::Gate);
+ spdlog::get("audio")->error("Tried to set unknown VAD method {}", method);
+ }
+}
+
+void AudioManager::SetVADMethod(VADMethod method) {
+ spdlog::get("audio")->debug("Setting VAD method to enum {}", static_cast<int>(method));
+ m_vad_method = method;
+
+#ifdef WITH_RNNOISE
+ if (method == VADMethod::RNNoise) {
+ RNNoiseInitialize();
+ } else {
+ RNNoiseUninitialize();
+ }
+#endif
+}
+
+AudioManager::VADMethod AudioManager::GetVADMethod() const {
+ return m_vad_method;
+}
+
+float AudioManager::GetCurrentVADProbability() const {
+ return m_vad_prob;
+}
+
+double AudioManager::GetRNNProbThreshold() const {
+ return m_prob_threshold;
+}
+
AudioManager::type_signal_opus_packet AudioManager::signal_opus_packet() {
return m_signal_opus_packet;
}
diff --git a/src/audio/manager.hpp b/src/audio/manager.hpp
index ed40f35..dac9738 100644
--- a/src/audio/manager.hpp
+++ b/src/audio/manager.hpp
@@ -14,6 +14,11 @@
#include <miniaudio.h>
#include <opus.h>
#include <sigc++/sigc++.h>
+
+#ifdef WITH_RNNOISE
+#include <rnnoise.h>
+#endif
+
#include "devices.hpp"
// clang-format on
@@ -40,30 +45,42 @@ public:
void SetCaptureGate(double gate);
void SetCaptureGain(double gain);
- [[nodiscard]] double GetCaptureGate() const noexcept;
- [[nodiscard]] double GetCaptureGain() const noexcept;
+ double GetCaptureGate() const noexcept;
+ double GetCaptureGain() const noexcept;
void SetMuteSSRC(uint32_t ssrc, bool mute);
void SetVolumeSSRC(uint32_t ssrc, double volume);
- [[nodiscard]] double GetVolumeSSRC(uint32_t ssrc) const;
+ double GetVolumeSSRC(uint32_t ssrc) const;
void SetEncodingApplication(int application);
- [[nodiscard]] int GetEncodingApplication();
+ int GetEncodingApplication();
void SetSignalHint(int signal);
- [[nodiscard]] int GetSignalHint();
+ int GetSignalHint();
void SetBitrate(int bitrate);
- [[nodiscard]] int GetBitrate();
+ int GetBitrate();
void Enumerate();
- [[nodiscard]] bool OK() const;
+ bool OK() const;
+
+ double GetCaptureVolumeLevel() const noexcept;
+ double GetSSRCVolumeLevel(uint32_t ssrc) const noexcept;
+
+ AudioDevices &GetDevices();
+
+ uint32_t GetRTPTimestamp() const noexcept;
- [[nodiscard]] double GetCaptureVolumeLevel() const noexcept;
- [[nodiscard]] double GetSSRCVolumeLevel(uint32_t ssrc) const noexcept;
+ enum class VADMethod {
+ Gate,
+ RNNoise,
+ };
- [[nodiscard]] AudioDevices &GetDevices();
+ void SetVADMethod(const std::string &method);
+ void SetVADMethod(VADMethod method);
+ VADMethod GetVADMethod() const;
- [[nodiscard]] uint32_t GetRTPTimestamp() const noexcept;
+ float GetCurrentVADProbability() const;
+ double GetRNNProbThreshold() const;
private:
void OnCapturedPCM(const int16_t *pcm, ma_uint32 frames);
@@ -74,6 +91,15 @@ private:
bool DecayVolumeMeters();
+ bool CheckVADVoiceGate();
+
+#ifdef WITH_RNNOISE
+ bool CheckVADRNNoise(const int16_t *pcm);
+
+ void RNNoiseInitialize();
+ void RNNoiseUninitialize();
+#endif
+
friend void data_callback(ma_device *, void *, const void *, ma_uint32);
friend void capture_data_callback(ma_device *, void *, const void *, ma_uint32);
@@ -106,6 +132,8 @@ private:
std::atomic<double> m_capture_gate = 0.0;
std::atomic<double> m_capture_gain = 1.0;
+ std::atomic<double> m_prob_threshold = 0.5;
+ std::atomic<float> m_vad_prob = 0.0;
std::unordered_set<uint32_t> m_muted_ssrcs;
std::unordered_map<uint32_t, double> m_volume_ssrc;
@@ -115,6 +143,10 @@ private:
AudioDevices m_devices;
+ VADMethod m_vad_method;
+#ifdef WITH_RNNOISE
+ DenoiseState *m_rnnoise;
+#endif
std::atomic<uint32_t> m_rtp_timestamp = 0;
public:
diff --git a/src/settings.cpp b/src/settings.cpp
index 0b868da..601205a 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -4,7 +4,7 @@
#include <glibmm/miscutils.h>
#ifdef WITH_KEYCHAIN
- #include <keychain/keychain.h>
+#include <keychain/keychain.h>
#endif
const std::string KeychainPackage = "com.github.uowuo.abaddon";
@@ -70,6 +70,7 @@ void SettingsManager::ReadSettings() {
SMSTR("style", "unreadcolor", UnreadIndicatorColor);
SMBOOL("notifications", "enabled", NotificationsEnabled);
SMBOOL("notifications", "playsound", NotificationsPlaySound);
+ SMSTR("voice", "vad", VAD);
SMBOOL("windows", "hideconsole", HideConsole);
#ifdef WITH_KEYCHAIN
@@ -154,6 +155,7 @@ void SettingsManager::Close() {
SMSTR("style", "unreadcolor", UnreadIndicatorColor);
SMBOOL("notifications", "enabled", NotificationsEnabled);
SMBOOL("notifications", "playsound", NotificationsPlaySound);
+ SMSTR("voice", "vad", VAD);
SMBOOL("windows", "hideconsole", HideConsole);
#ifdef WITH_KEYCHAIN
diff --git a/src/settings.hpp b/src/settings.hpp
index 40cb1d3..0d2e68b 100644
--- a/src/settings.hpp
+++ b/src/settings.hpp
@@ -53,6 +53,13 @@ public:
#endif
bool NotificationsPlaySound { true };
+ // [voice]
+#ifdef WITH_RNNOISE
+ std::string VAD { "rnnoise" };
+#else
+ std::string VAD { "gate" };
+#endif
+
// [windows]
bool HideConsole { false };
};
diff --git a/src/windows/voicewindow.cpp b/src/windows/voicewindow.cpp
index 829a1b8..4ab9864 100644
--- a/src/windows/voicewindow.cpp
+++ b/src/windows/voicewindow.cpp
@@ -115,23 +115,59 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
m_scroll.set_hexpand(true);
m_scroll.set_vexpand(true);
- m_capture_volume.SetShowTick(true);
-
- m_capture_gate.set_range(0.0, 100.0);
- m_capture_gate.set_value_pos(Gtk::POS_LEFT);
- m_capture_gate.set_value(audio.GetCaptureGate() * 100.0);
- m_capture_gate.signal_value_changed().connect([this]() {
- const double val = m_capture_gate.get_value() * 0.01;
- m_signal_gate.emit(val);
- m_capture_volume.SetTick(val);
+ m_vad_value.SetShowTick(true);
+
+ m_vad_param.set_range(0.0, 100.0);
+ m_vad_param.set_value_pos(Gtk::POS_LEFT);
+ m_vad_param.signal_value_changed().connect([this]() {
+ auto &audio = Abaddon::Get().GetAudio();
+ const double val = m_vad_param.get_value() * 0.01;
+ switch (audio.GetVADMethod()) {
+ case AudioManager::VADMethod::Gate:
+ audio.SetCaptureGate(val);
+ m_vad_value.SetTick(val);
+ break;
+#ifdef WITH_RNNOISE
+ case AudioManager::VADMethod::RNNoise:
+ break;
+#endif
+ };
});
+ UpdateVADParamValue();
m_capture_gain.set_range(0.0, 200.0);
m_capture_gain.set_value_pos(Gtk::POS_LEFT);
m_capture_gain.set_value(audio.GetCaptureGain() * 100.0);
m_capture_gain.signal_value_changed().connect([this]() {
- const double val = m_capture_gain.get_value();
- m_signal_gain.emit(val / 100.0);
+ const double val = m_capture_gain.get_value() / 100.0;
+ Abaddon::Get().GetAudio().SetCaptureGain(val);
+ });
+
+ m_vad_combo.set_valign(Gtk::ALIGN_END);
+ m_vad_combo.set_hexpand(true);
+ m_vad_combo.set_halign(Gtk::ALIGN_FILL);
+ m_vad_combo.set_tooltip_text(
+ "Voice Activation Detection method\n"
+ "Gate - Simple volume threshold. Slider changes threshold\n"
+ "RNNoise - Heavier on CPU. Slider changes probability threshold");
+ m_vad_combo.append("gate", "Gate");
+#ifdef WITH_RNNOISE
+ m_vad_combo.append("rnnoise", "RNNoise");
+#endif
+ if (!m_vad_combo.set_active_id(Abaddon::Get().GetSettings().VAD)) {
+#ifdef WITH_RNNOISE
+ m_vad_combo.set_active_id("rnnoise");
+#else
+ m_vad_combo.set_active_id("gate");
+#endif
+ }
+ m_vad_combo.signal_changed().connect([this]() {
+ auto &audio = Abaddon::Get().GetAudio();
+ const auto id = m_vad_combo.get_active_id();
+
+ audio.SetVADMethod(id);
+ Abaddon::Get().GetSettings().VAD = id;
+ UpdateVADParamValue();
});
auto *playback_renderer = Gtk::make_managed<Gtk::CellRendererText>();
@@ -169,7 +205,7 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
auto *window = new VoiceSettingsWindow;
const auto cb = [this](double gain) {
m_capture_gain.set_value(gain * 100.0);
- m_signal_gain.emit(gain);
+ Abaddon::Get().GetAudio().SetCaptureGain(gain);
};
window->signal_gain().connect(sigc::track_obj(cb, *this));
window->show();
@@ -180,10 +216,11 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
m_controls.add(m_deafen);
m_main.add(m_menu_bar);
m_main.add(m_controls);
- m_main.add(m_capture_volume);
- m_main.add(m_capture_gate);
+ m_main.add(m_vad_value);
+ m_main.add(m_vad_param);
m_main.add(m_capture_gain);
m_main.add(m_scroll);
+ m_main.add(m_vad_combo);
m_main.add(m_playback_combo);
m_main.add(m_capture_combo);
add(m_main);
@@ -224,16 +261,41 @@ void VoiceWindow::OnDeafenChanged() {
}
bool VoiceWindow::UpdateVoiceMeters() {
- m_capture_volume.SetVolume(Abaddon::Get().GetAudio().GetCaptureVolumeLevel());
+ auto &audio = Abaddon::Get().GetAudio();
+ switch (audio.GetVADMethod()) {
+ case AudioManager::VADMethod::Gate:
+ m_vad_value.SetVolume(audio.GetCaptureVolumeLevel());
+ break;
+#ifdef WITH_RNNOISE
+ case AudioManager::VADMethod::RNNoise:
+ m_vad_value.SetVolume(audio.GetCurrentVADProbability());
+ break;
+#endif
+ }
+
for (auto [id, row] : m_rows) {
const auto ssrc = Abaddon::Get().GetDiscordClient().GetSSRCOfUser(id);
if (ssrc.has_value()) {
- row->SetVolumeMeter(Abaddon::Get().GetAudio().GetSSRCVolumeLevel(*ssrc));
+ row->SetVolumeMeter(audio.GetSSRCVolumeLevel(*ssrc));
}
}
return true;
}
+void VoiceWindow::UpdateVADParamValue() {
+ auto &audio = Abaddon::Get().GetAudio();
+ switch (audio.GetVADMethod()) {
+ case AudioManager::VADMethod::Gate:
+ m_vad_param.set_value(audio.GetCaptureGate() * 100.0);
+ break;
+#ifdef WITH_RNNOISE
+ case AudioManager::VADMethod::RNNoise:
+ m_vad_param.set_value(audio.GetRNNProbThreshold() * 100.0);
+ break;
+#endif
+ }
+}
+
void VoiceWindow::OnUserConnect(Snowflake user_id, Snowflake to_channel_id) {
if (m_channel_id == to_channel_id) {
if (auto it = m_rows.find(user_id); it == m_rows.end()) {
@@ -259,14 +321,6 @@ VoiceWindow::type_signal_deafen VoiceWindow::signal_deafen() {
return m_signal_deafen;
}
-VoiceWindow::type_signal_gate VoiceWindow::signal_gate() {
- return m_signal_gate;
-}
-
-VoiceWindow::type_signal_gate VoiceWindow::signal_gain() {
- return m_signal_gain;
-}
-
VoiceWindow::type_signal_mute_user_cs VoiceWindow::signal_mute_user_cs() {
return m_signal_mute_user_cs;
}
diff --git a/src/windows/voicewindow.hpp b/src/windows/voicewindow.hpp
index 805d94a..7116f06 100644
--- a/src/windows/voicewindow.hpp
+++ b/src/windows/voicewindow.hpp
@@ -34,6 +34,8 @@ private:
bool UpdateVoiceMeters();
+ void UpdateVADParamValue();
+
Gtk::Box m_main;
Gtk::Box m_controls;
@@ -43,10 +45,15 @@ private:
Gtk::ScrolledWindow m_scroll;
Gtk::ListBox m_user_list;
- VolumeMeter m_capture_volume;
- Gtk::Scale m_capture_gate;
+ // Shows volume for gate VAD method
+ // Shows probability for RNNoise VAD method
+ VolumeMeter m_vad_value;
+ // Volume threshold for gate VAD method
+ // VAD probability threshold for RNNoise VAD method
+ Gtk::Scale m_vad_param;
Gtk::Scale m_capture_gain;
+ Gtk::ComboBoxText m_vad_combo;
Gtk::ComboBox m_playback_combo;
Gtk::ComboBox m_capture_combo;
@@ -62,23 +69,17 @@ private:
public:
using type_signal_mute = sigc::signal<void(bool)>;
using type_signal_deafen = sigc::signal<void(bool)>;
- using type_signal_gate = sigc::signal<void(double)>;
- using type_signal_gain = sigc::signal<void(double)>;
using type_signal_mute_user_cs = sigc::signal<void(Snowflake, bool)>;
using type_signal_user_volume_changed = sigc::signal<void(Snowflake, double)>;
type_signal_mute signal_mute();
type_signal_deafen signal_deafen();
- type_signal_gate signal_gate();
- type_signal_gain signal_gain();
type_signal_mute_user_cs signal_mute_user_cs();
type_signal_user_volume_changed signal_user_volume_changed();
private:
type_signal_mute m_signal_mute;
type_signal_deafen m_signal_deafen;
- type_signal_gate m_signal_gate;
- type_signal_gain m_signal_gain;
type_signal_mute_user_cs m_signal_mute_user_cs;
type_signal_user_volume_changed m_signal_user_volume_changed;
};
diff --git a/subprojects/rnnoise b/subprojects/rnnoise
new file mode 160000
+Subproject 1cbdbcf1283499bbb2230a6b0f126eb9b236def