From 7b5bc6d236b9d7d91ea418416cfa5a2ec9868637 Mon Sep 17 00:00:00 2001 From: Bruno Herbelin Date: Sun, 21 Apr 2024 23:20:44 +0200 Subject: [PATCH] BugFix Implementation of Audio in Source Generalized audio support into Source class, instead of MediaPlayer. --- src/ImGuiVisitor.cpp | 48 ---------------------- src/MediaPlayer.cpp | 66 +++++------------------------ src/MediaPlayer.h | 25 +++-------- src/MediaSource.cpp | 45 ++++++++++++++++---- src/MediaSource.h | 1 + src/Session.cpp | 3 ++ src/SessionCreator.cpp | 21 +++++----- src/SessionSource.cpp | 5 +++ src/SessionVisitor.cpp | 12 +++--- src/Source.cpp | 56 ++++++++++++++++++++++++- src/Source.h | 38 ++++++++++++++++- src/SourceControlWindow.cpp | 4 +- src/UserInterfaceManager.cpp | 80 +++++++++++++++++++++++++++++++++++- 13 files changed, 248 insertions(+), 156 deletions(-) diff --git a/src/ImGuiVisitor.cpp b/src/ImGuiVisitor.cpp index 57781677..aeaa3343 100644 --- a/src/ImGuiVisitor.cpp +++ b/src/ImGuiVisitor.cpp @@ -740,54 +740,6 @@ void ImGuiVisitor::visit (MediaSource& s) ImGui::TextDisabled("Hardware decoding disabled"); } - // enable / disable audio if available - if (mp->audioAvailable()) { - - ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - if (ImGui::BeginCombo("Audio", mp->audioEnabled() ? ICON_FA_VOLUME_UP " Enabled" : ICON_FA_VOLUME_MUTE " Disabled" ) ) - { - if (ImGui::Selectable( ICON_FA_VOLUME_UP " Enable", mp->audioEnabled() )) - mp->setAudioEnabled(true); - if (ImGui::IsItemHovered() && !mp->audioEnabled()) - ImGuiToolkit::ToolTip( "Changing audio will\nre-open the media" ); - - if (ImGui::Selectable( ICON_FA_VOLUME_MUTE " Disable", !mp->audioEnabled() )) - mp->setAudioEnabled(false); - if (ImGui::IsItemHovered() && mp->audioEnabled()) - ImGuiToolkit::ToolTip( "Changing audio will\nre-open the media" ); - ImGui::EndCombo(); - } - - if (mp->audioEnabled()) { - - ImGuiIO& io = ImGui::GetIO(); - /// - /// AUDIO VOLUME - /// - int vol = mp->audioVolume(); - ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - if ( ImGui::SliderInt("##Volume", &vol, 0, 100, "%d%%") ) - mp->setAudioVolume(vol); - if (ImGui::IsItemHovered() && io.MouseWheel != 0.f ){ - vol = CLAMP(vol + int(10.f * io.MouseWheel), 0, 100); - mp->setAudioVolume(vol); - } - ImGui::SameLine(0, IMGUI_SAME_LINE); - if (ImGuiToolkit::TextButton("Volume")) { - mp->setAudioVolume(100); - } - - ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - int m = mp->audioVolumeMix(); - if ( ImGui::Combo("##Multiplier", &m, "None\0Alpha\0Opacity\0Alpha * Opacity\0") ) { - mp->setAudioVolumeMix( (MediaPlayer::VolumeFactorsMix) m ); - } - ImGui::SameLine(0, IMGUI_SAME_LINE); - if (ImGuiToolkit::TextButton("Multiplier")) { - mp->setAudioVolumeMix( MediaPlayer::VOLUME_ONLY ); - } - } - } } else ImGui::SetCursorPos(botom); diff --git a/src/MediaPlayer.cpp b/src/MediaPlayer.cpp index 2d643172..7b2b49d0 100644 --- a/src/MediaPlayer.cpp +++ b/src/MediaPlayer.cpp @@ -60,6 +60,7 @@ MediaPlayer::MediaPlayer() opened_ = false; enabled_ = true; desired_state_ = GST_STATE_PAUSED; + audio_enabled_ = false; failed_ = false; pending_ = false; @@ -77,13 +78,6 @@ MediaPlayer::MediaPlayer() loop_ = LoopMode::LOOP_REWIND; fading_mode_ = FadingMode::FADING_COLOR; - // default audio disabled - audio_enabled_ = false; - audio_volume_[0] = 1.f; - audio_volume_[1] = 1.f; - audio_volume_[2] = 1.f; - audio_volume_mix_ = VOLUME_ONLY; - // start index in frame_ stack write_index_ = 0; last_index_ = 0; @@ -517,8 +511,6 @@ void MediaPlayer::execute_open() if (media_.hasaudio) { Log::Info("MediaPlayer %s Audio track %s", std::to_string(id_).c_str(), audio_enabled_ ? "enabled" : "disabled"); - if (audio_enabled_) - setAudioVolume(); } opened_ = true; @@ -1727,14 +1719,12 @@ void MediaPlayer::TimeCounter::tic () } } - void MediaPlayer::setAudioEnabled(bool on) { // in case of change if (audio_enabled_ != on) { // toggle audio_enabled_ = on; - // if openned if (media_.hasaudio ) { // apply @@ -1743,55 +1733,19 @@ void MediaPlayer::setAudioEnabled(bool on) } } -void MediaPlayer::setAudioVolume(int vol) -{ - // set value - if ( !(vol < 0) ) - audio_volume_[0] = CLAMP( (float)(vol) * 0.01f, 0.f, 1.f); - - // apply value - if (pipeline_ && media_.hasaudio) { - - // base volume - gdouble new_vol = (gdouble) (audio_volume_[0]); - - // apply factors - if ( audio_volume_mix_ == MediaPlayer::VOLUME_MULT_BOTH ) - new_vol *= (gdouble) (audio_volume_[1] * audio_volume_[2]); - else if ( audio_volume_mix_ == MediaPlayer::VOLUME_MULT_2 ) - new_vol *= (gdouble) (audio_volume_[2]); - else if ( audio_volume_mix_ == MediaPlayer::VOLUME_MULT_1 ) - new_vol *= (gdouble) (audio_volume_[1]); - - - g_object_set ( G_OBJECT (pipeline_), "volume", new_vol, NULL); -// gst_stream_volume_set_volume (GST_STREAM_VOLUME (pipeline_), GST_STREAM_VOLUME_FORMAT_LINEAR, new_vol); - } -} - -void MediaPlayer::setAudioVolumeMix(VolumeFactorsMix m) +void MediaPlayer::setAudioVolume(float vol) { - audio_volume_mix_ = m; - setAudioVolume(); + if (pipeline_ && media_.hasaudio) + g_object_set(G_OBJECT(pipeline_), "volume", vol, NULL); + // gst_stream_volume_set_volume (GST_STREAM_VOLUME (pipeline_), GST_STREAM_VOLUME_FORMAT_LINEAR, vol); } -void MediaPlayer::setAudioVolumeFactor(uint index, float value) +float MediaPlayer::audioVolume() const { - if (index > 2) - return; - - if ( ABS_DIFF( audio_volume_[index], value ) > EPSILON ) { - - // set value - audio_volume_[index] = CLAMP(value, 0.f, 1.f); - - // apply value - if ( audio_volume_mix_ == MediaPlayer::VOLUME_MULT_BOTH || - (index == 1 && audio_volume_mix_ == MediaPlayer::VOLUME_MULT_1) || - (index == 2 && audio_volume_mix_ == MediaPlayer::VOLUME_MULT_2) ) { - setAudioVolume(); - } - } + float vol = 0.f; + if (pipeline_ && media_.hasaudio) + g_object_get(G_OBJECT(pipeline_), "volume", &vol, NULL); + return vol; } //static void audio_changed_callback (GstElement *pipeline, MediaPlayer *mp) diff --git a/src/MediaPlayer.h b/src/MediaPlayer.h index 83005347..189d838f 100644 --- a/src/MediaPlayer.h +++ b/src/MediaPlayer.h @@ -277,23 +277,12 @@ class MediaPlayer { inline std::string videoEffect() { return video_filter_; } inline bool videoEffectAvailable() { return video_filter_available_; } /** - * Enables or disables audio - * NB: setAudioEnabled reopens the video + * audio implementation * */ - void setAudioEnabled(bool on); - void setAudioVolume(int vol = -1); - void setAudioVolumeFactor(uint index, float value); - typedef enum { - VOLUME_ONLY = 0, - VOLUME_MULT_1 = 1, - VOLUME_MULT_2 = 2, - VOLUME_MULT_BOTH = 3 - } VolumeFactorsMix; - void setAudioVolumeMix(VolumeFactorsMix m); - inline VolumeFactorsMix audioVolumeMix() const { return audio_volume_mix_; } - inline bool audioEnabled() const { return audio_enabled_; } - inline int audioVolume() const { return (int) (audio_volume_[0] * 100.f); } inline bool audioAvailable() const { return media_.hasaudio; } + void setAudioEnabled(bool on); + void setAudioVolume(float v); + float audioVolume() const; /** * Accept visitors @@ -326,6 +315,7 @@ class MediaPlayer { Timeline timeline_; FadingMode fading_mode_; std::future discoverer_; + bool audio_enabled_; // GST & Play status GstClockTime position_; @@ -345,11 +335,6 @@ class MediaPlayer { bool video_filter_available_; std::string video_filter_; - // audio - bool audio_enabled_; - float audio_volume_[3]; - VolumeFactorsMix audio_volume_mix_; - // Play speed gdouble rate_; typedef enum { diff --git a/src/MediaSource.cpp b/src/MediaSource.cpp index 54deb827..4ecded32 100644 --- a/src/MediaSource.cpp +++ b/src/MediaSource.cpp @@ -20,6 +20,7 @@ #include +#include "defines.h" #include "Resource.h" #include "Decorations.h" #include "MediaPlayer.h" @@ -121,6 +122,10 @@ void MediaSource::init() // deep update to reorder (two frames to give time to insert) View::need_deep_update_ += 2; + // test audio is available + if (mediaplayer_->audioAvailable()) + audio_flags_ |= Source::Audio_available; + // done init Log::Info("Source '%s' linked to MediaPlayer %s.", name().c_str(), std::to_string(mediaplayer_->id()).c_str()); } @@ -178,13 +183,31 @@ void MediaSource::update(float dt) // update video mediaplayer_->update(); +} + +void MediaSource::updateAudio() +{ + // update enable/ disable status of audio of media player (do nothing if no change) + mediaplayer_->setAudioEnabled( audio_flags_ & Source::Audio_enabled ); + + // update audio volume if enabled + if (audio_flags_ & Source::Audio_enabled) { - // update audio - if (mediaplayer_->audioEnabled() ) { - // apply alpha as volume factor 1 - mediaplayer_->setAudioVolumeFactor(1, alpha()); - // apply opacity as volume factor 2 - mediaplayer_->setAudioVolumeFactor(2, mediaplayer_->currentTimelineFading()); + // base volume + gdouble new_vol = (gdouble) (audio_volume_[VOLUME_BASE]); + + // apply factors + if (audio_volume_mix_ & Source::Volume_mult_alpha) + new_vol *= (gdouble) (alpha()); + if (audio_volume_mix_ & Source::Volume_mult_opacity) + new_vol *= (gdouble) (mediaplayer_->currentTimelineFading()); + if (audio_volume_mix_ & Source::Volume_mult_parent) + new_vol *= (gdouble) (audio_volume_[VOLUME_PARENT]); + if (audio_volume_mix_ & Source::Volume_mult_session) + new_vol *= (gdouble) (audio_volume_[VOLUME_SESSION]); + + // implementation for media player gstreamer pipeline + mediaplayer_->setAudioVolume(new_vol); } } @@ -197,10 +220,16 @@ void MediaSource::render() // NB: this also applies the color correction shader renderbuffer_->begin(); // apply fading - if (mediaplayer_->timelineFadingMode() != MediaPlayer::FADING_ALPHA) + float __f = mediaplayer_->currentTimelineFading(); + setAudioVolumeFactor(Source::VOLUME_OPACITY, __f); + if (mediaplayer_->timelineFadingMode() != MediaPlayer::FADING_ALPHA) { + // color fading texturesurface_->shader()->color = glm::vec4( glm::vec3(mediaplayer_->currentTimelineFading()), 1.f); - else + } + else { + // alpha fading texturesurface_->shader()->color = glm::vec4( glm::vec3(1.f), mediaplayer_->currentTimelineFading()); + } texturesurface_->draw(glm::identity(), renderbuffer_->projection()); renderbuffer_->end(); ready_ = true; diff --git a/src/MediaSource.h b/src/MediaSource.h index 341472d8..70b4a906 100644 --- a/src/MediaSource.h +++ b/src/MediaSource.h @@ -24,6 +24,7 @@ class MediaSource : public Source Failure failed() const override; uint texture() const override; void accept (Visitor& v) override; + void updateAudio() override; // Media specific interface void setPath(const std::string &p); diff --git a/src/Session.cpp b/src/Session.cpp index b7932ec2..c792e137 100644 --- a/src/Session.cpp +++ b/src/Session.cpp @@ -294,6 +294,9 @@ void Session::update(float dt) // render the source (*it)->render(); } + + // apply session fading to audio + (*it)->setAudioVolumeFactor(Source::VOLUME_SESSION, 1.f - render_.fading()); } // update session's mixing groups diff --git a/src/SessionCreator.cpp b/src/SessionCreator.cpp index 6fdf6f6a..b14613bf 100644 --- a/src/SessionCreator.cpp +++ b/src/SessionCreator.cpp @@ -919,17 +919,6 @@ void SessionLoader::visit(MediaPlayer &n) n.setTimeline(tl); } - // audio - int audiovolume = 100; - mediaplayerNode->QueryIntAttribute("audio_volume", &audiovolume); - n.setAudioVolume(audiovolume); - int audiomix = 0; - mediaplayerNode->QueryIntAttribute("audio_mix", &audiomix); - n.setAudioVolumeMix( (MediaPlayer::VolumeFactorsMix) audiomix); - bool audioenabled = false; - mediaplayerNode->QueryBoolAttribute("audio", &audioenabled); - n.setAudioEnabled(audioenabled); - // change play rate: will be activated in SessionLoader::visit (MediaSource& s) double speed = 1.0; mediaplayerNode->QueryDoubleAttribute("speed", &speed); @@ -1113,6 +1102,16 @@ void SessionLoader::visit (Source& s) groups_sources_id_.push_back(idlist); } + xmlCurrent_ = sourceNode->FirstChildElement("Audio"); + if (xmlCurrent_) { + bool on = xmlCurrent_->BoolAttribute("enabled", false); + s.setAudioEnabled(on); + float volume = xmlCurrent_->FloatAttribute("volume", 1.f); + s.setAudioVolumeFactor(Source::VOLUME_BASE, volume); + int mix = xmlCurrent_->IntAttribute("volume_mix", 0); + s.setAudioVolumeMix( Source::Volume_mult_parent | mix); + } + // restore current xmlCurrent_ = sourceNode; diff --git a/src/SessionSource.cpp b/src/SessionSource.cpp index c563ffe8..805258d7 100644 --- a/src/SessionSource.cpp +++ b/src/SessionSource.cpp @@ -150,6 +150,11 @@ void SessionSource::update(float dt) timer_ += guint64(dt * 1000.f) * GST_USECOND; } + // update audio + for (auto it = session_->begin(); it != session_->end(); ++it) { + (*it)->setAudioVolumeFactor(Source::VOLUME_PARENT, blendingshader_->color.a); + } + // manage sources which failed if ( !session_->failedSources().empty() ) { diff --git a/src/SessionVisitor.cpp b/src/SessionVisitor.cpp index a7707597..816be067 100644 --- a/src/SessionVisitor.cpp +++ b/src/SessionVisitor.cpp @@ -428,12 +428,6 @@ void SessionVisitor::visit(MediaPlayer &n) XMLElement *newelement = xmlDoc_->NewElement("MediaPlayer"); newelement->SetAttribute("id", n.id()); - if (n.audioAvailable()) { - newelement->SetAttribute("audio", n.audioEnabled()); - newelement->SetAttribute("audio_volume", n.audioVolume()); - newelement->SetAttribute("audio_mix", (int) n.audioVolumeMix()); - } - if (!n.singleFrame()) { newelement->SetAttribute("loop", (int) n.loop()); newelement->SetAttribute("speed", n.playSpeed()); @@ -661,6 +655,12 @@ void SessionVisitor::visit (Source& s) s.mixingGroup()->accept(*this); } + xmlCurrent_ = xmlDoc_->NewElement( "Audio" ); + xmlCurrent_->SetAttribute("enabled", (bool) (s.audioFlags() & Source::Audio_enabled) ); + xmlCurrent_->SetAttribute("volume", s.audioVolumeFactor(Source::VOLUME_BASE) ); + xmlCurrent_->SetAttribute("volume_mix", (int) s.audioVolumeMix() ); + sourceNode->InsertEndChild(xmlCurrent_); + xmlCurrent_ = sourceNode; // parent for next visits (other subtypes of Source) } diff --git a/src/Source.cpp b/src/Source.cpp index 9514878c..29495cef 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -380,6 +380,14 @@ Source::Source(uint64_t id) : SourceCore(), id_(id), ready_(false), symbol_(null maskbuffer_ = nullptr; maskimage_ = nullptr; masksource_ = new SourceLink; + + // default audio + audio_flags_ = Audio_none; + audio_volume_mix_ = Volume_mult_parent | Volume_mult_session; + audio_volume_[0] = 0.f; + audio_volume_[1] = 1.f; + audio_volume_[2] = 1.f; + audio_volume_[3] = 1.f; } @@ -817,8 +825,12 @@ void Source::update(float dt) // ADJUST alpha based on MIXING node // read position of the mixing node and interpret this as transparency of render output glm::vec2 dist = glm::vec2(groups_[View::MIXING]->translation_); - // use the sinusoidal transfer function - blendingshader_->color = glm::vec4(1.f, 1.f, 1.f, SourceCore::alphaFromCordinates( dist.x, dist.y )); + // use the sinusoidal transfer function to compute alpha + float __a = SourceCore::alphaFromCordinates(dist.x, dist.y); + // audio update in case if depends on alpha + setAudioVolumeFactor(Source::VOLUME_ALPHA, __a); + // apply alpha + blendingshader_->color = glm::vec4(1.f, 1.f, 1.f, __a); mixingshader_->color = blendingshader_->color; // adjust scale of mixing icon : smaller if not active @@ -956,6 +968,14 @@ void Source::update(float dt) } } + // update audio if requested: + if (need_update_ & SourceUpdate_Audio) { + // do not update Audio next frame + need_update_ &= ~SourceUpdate_Audio; + // implementation depends on subclasses + updateAudio(); + } + if (processingshader_link_.connected() && imageProcessingEnabled()) { Source *ref_source = processingshader_link_.source(); if (ref_source!=nullptr) { @@ -1062,6 +1082,38 @@ void Source::clearMixingGroup() overlay_mixinggroup_->visible_ = false; } +// set audio factors and mixing mode +void Source::setAudioEnabled(bool on) +{ + if (on) + audio_flags_ |= Source::Audio_enabled; + else + audio_flags_ &= ~Source::Audio_enabled; + + need_update_ |= Source::SourceUpdate_Audio; +} + +void Source::setAudioVolumeFactor(AudioVolumeFactor index, float value) +{ + if (ABS_DIFF(audio_volume_[index], value) > EPSILON + && (index == VOLUME_BASE + || (index == VOLUME_ALPHA && audio_volume_mix_ & Volume_mult_alpha ) + || (index == VOLUME_OPACITY && audio_volume_mix_ & Volume_mult_opacity) + || (index == VOLUME_PARENT && audio_volume_mix_ & Volume_mult_parent ) + || (index == VOLUME_SESSION && audio_volume_mix_ & Volume_mult_session) )) { + need_update_ |= Source::SourceUpdate_Audio; + } + + audio_volume_[index] = CLAMP(value, 0.f, 1.f); +} + +void Source::setAudioVolumeMix(AudioVolumeMixing f) +{ + if ( audio_volume_mix_ != f ) + need_update_ |= Source::SourceUpdate_Audio; + + audio_volume_mix_ = f; +} glm::vec2 Source::attractor(size_t i) const { diff --git a/src/Source.h b/src/Source.h index b8ae86ef..84f9c411 100644 --- a/src/Source.h +++ b/src/Source.h @@ -147,7 +147,8 @@ class Source : public SourceCore SourceUpdate_None = 0, SourceUpdate_Render = 1 << 1, SourceUpdate_Mask = 1 << 2, - SourceUpdate_Mask_fill = 1 << 3 + SourceUpdate_Mask_fill = 1 << 3, + SourceUpdate_Audio = 1 << 4 }; typedef int UpdateFlags; inline void touch (UpdateFlags f = SourceUpdate_Render) { need_update_ |= f; } @@ -228,6 +229,34 @@ class Source : public SourceCore MixingGroup *mixingGroup() const { return mixinggroup_; } void clearMixingGroup(); + // audio + enum AudioFlags_ { Audio_none = 0, Audio_available = 1 << 1, Audio_enabled = 1 << 2 }; + typedef int AudioFlags; + inline AudioFlags audioFlags() const { return audio_flags_; } + void setAudioEnabled(bool on); + typedef enum { + VOLUME_BASE = 0, + VOLUME_ALPHA = 1, + VOLUME_OPACITY = 2, + VOLUME_PARENT = 3, + VOLUME_SESSION = 4 + } AudioVolumeFactor; + void setAudioVolumeFactor(AudioVolumeFactor index, float value); + inline float audioVolumeFactor(AudioVolumeFactor index) const { return audio_volume_[index]; } + enum AudioVolumeMixingFlags_ { + Volume_mult_none = 0, + Volume_mult_alpha = 1 << 1, + Volume_mult_opacity = 1 << 2, + Volume_mult_parent = 1 << 3, + Volume_mult_session = 1 << 4 + }; + typedef int AudioVolumeMixing; + void setAudioVolumeMix(AudioVolumeMixing f); + inline AudioVolumeMixing audioVolumeMix() const { return audio_volume_mix_; } + // default implementation of audio support is empty + virtual void updateAudio() {} + + // Source propertis querry struct hasNode { bool operator()(const Source* elem) const; @@ -284,8 +313,8 @@ class Source : public SourceCore // class-dependent notification virtual std::string info () const { return "Undefined"; } + // DRAFT & NOT USED SourceLink processingshader_link_; - glm::vec2 attractor(size_t i) const; void setAttractor(size_t i, glm::vec2 a); @@ -361,6 +390,11 @@ class Source : public SourceCore MixingGroup *mixinggroup_; Switch *overlay_mixinggroup_; Symbol *rotation_mixingroup_; + + // audio + AudioFlags audio_flags_; + float audio_volume_[5]; + AudioVolumeMixing audio_volume_mix_; }; diff --git a/src/SourceControlWindow.cpp b/src/SourceControlWindow.cpp index 33e3cd90..03e0e0a8 100644 --- a/src/SourceControlWindow.cpp +++ b/src/SourceControlWindow.cpp @@ -1586,7 +1586,7 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms) ImGui::PopStyleColor(1); ImGui::SetCursorScreenPos(imgarea.GetTL() + ImVec2(h_space_, v_space_)); - if ( mediaplayer_active_->audioEnabled()) + if ( ms->audioFlags() & Source::Audio_enabled ) // Icon to inform audio decoding ImGui::Text("%s " ICON_FA_VOLUME_UP, ms->initials()); else @@ -1612,7 +1612,7 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms) ImGui::Text("%s", info_.str().c_str()); // Icon to inform audio decoding - if ( mediaplayer_active_->audioEnabled()) { + if ( ms->audioFlags() & Source::Audio_enabled ) { ImGui::SetCursorScreenPos(imgarea.GetTL() + ImVec2( imgarea.GetWidth() - 2.f * ImGui::GetTextLineHeightWithSpacing(), 0.35f * tooltip_height)); ImGui::Text(ICON_FA_VOLUME_UP); } diff --git a/src/UserInterfaceManager.cpp b/src/UserInterfaceManager.cpp index 1c22a62e..a13c22c8 100644 --- a/src/UserInterfaceManager.cpp +++ b/src/UserInterfaceManager.cpp @@ -3414,9 +3414,87 @@ void Navigator::RenderSourcePannel(Source *s, const ImVec2 &iconsize) // Source pannel static ImGuiVisitor v; s->accept(v); - ImGui::Text(" "); + + /// + /// AUDIO PANEL if audio available on source + /// + if (Settings::application.accept_audio && s->audioFlags() & Source::Audio_available) { + ImGuiIO &io = ImGui::GetIO(); + + // test audio and read volume + bool audio_is_on = s->audioFlags() & Source::Audio_enabled; + int vol = audio_is_on ? (int) (s->audioVolumeFactor(Source::VOLUME_BASE) * 100.f) : -1; + std::string label = audio_is_on ? (vol > 50 ? ICON_FA_VOLUME_UP " %d%%" + : ICON_FA_VOLUME_DOWN " %d%%") + : ICON_FA_VOLUME_MUTE " Disabled"; + // VOLUME & on/off slider + ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); + bool volume_change = ImGui::SliderInt("##VolumeAudio", &vol, -1, 100, label.c_str()); + if (ImGui::IsItemHovered()) { + if (io.MouseWheel != 0.f) { + vol = CLAMP(vol + int(10.f * io.MouseWheel), 0, 100); + volume_change = true; + } else if (!audio_is_on) + ImGuiToolkit::ToolTip("Enabling audio will reload source."); + } + if (volume_change) { + if (vol < 0) + s->setAudioEnabled(false); + else { + s->setAudioEnabled(true); + s->setAudioVolumeFactor(Source::VOLUME_BASE, + CLAMP((float) (vol) *0.01f, 0.f, 1.f)); + } + } + ImGui::SameLine(0, IMGUI_SAME_LINE); + if (ImGuiToolkit::TextButton("Audio")) { + s->setAudioEnabled(false); + } + + // AUDIO MIXING menu + if (audio_is_on) { + ImGui::SameLine(0, 2 * IMGUI_SAME_LINE); + static uint counter_menu_timeout_2 = 0; + if (ImGuiToolkit::IconButton(6, 2) + || ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) { + counter_menu_timeout_2 = 0; + ImGui::OpenPopup("MenuMixAudio"); + } + if (ImGui::BeginPopup("MenuMixAudio")) { + ImGui::TextDisabled("Multiply volume with:"); + Source::AudioVolumeMixing flags = s->audioVolumeMix(); + bool mix = flags & Source::Volume_mult_alpha; + if (ImGui::MenuItem("Source alpha", NULL, &mix)) { + if (mix) + s->setAudioVolumeMix(flags | Source::Volume_mult_alpha); + else + s->setAudioVolumeMix(flags & ~Source::Volume_mult_alpha); + } + mix = flags & Source::Volume_mult_opacity; + if (ImGui::MenuItem("Source fading", NULL, &mix)) { + if (mix) + s->setAudioVolumeMix(flags | Source::Volume_mult_opacity); + else + s->setAudioVolumeMix(flags & ~Source::Volume_mult_opacity); + } + mix = flags & Source::Volume_mult_session; + if (ImGui::MenuItem("Output fading", NULL, &mix)) { + if (mix) + s->setAudioVolumeMix(flags | Source::Volume_mult_session); + else + s->setAudioVolumeMix(flags & ~Source::Volume_mult_session); + } + if (ImGui::IsWindowHovered()) + counter_menu_timeout_2 = 0; + else if (++counter_menu_timeout_2 > 10) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + } + } // clone button + ImGui::Text(" "); if ( s->failed() ) { ImGuiToolkit::ButtonDisabled( ICON_FA_SHARE_SQUARE " Clone & Filter", ImVec2(ImGui::GetContentRegionAvail().x, 0)); }