std::vector<audio_item> items_;\r
std::vector<size_t> audio_cadence_;\r
video_format_desc format_desc_;\r
+ float master_volume_;\r
+ float previous_master_volume_;\r
\r
public:\r
implementation(const safe_ptr<diagnostics::graph>& graph)\r
: graph_(graph)\r
, format_desc_(video_format_desc::get(video_format::invalid))\r
+ , master_volume_(1.0f)\r
+ , previous_master_volume_(master_volume_)\r
{\r
graph_->set_color("volume", diagnostics::color(1.0f, 0.8f, 0.1f));\r
transform_stack_.push(core::frame_transform());\r
{\r
transform_stack_.pop();\r
}\r
+\r
+ void set_master_volume(float volume)\r
+ {\r
+ master_volume_ = volume;\r
+ }\r
\r
audio_buffer mix(const video_format_desc& format_desc)\r
{ \r
if(prev_transform.volume < 0.001 && next_transform.volume < 0.001)\r
continue;\r
\r
- const float prev_volume = static_cast<float>(prev_transform.volume);\r
- const float next_volume = static_cast<float>(next_transform.volume);\r
+ const float prev_volume = static_cast<float>(prev_transform.volume) * previous_master_volume_;\r
+ const float next_volume = static_cast<float>(next_transform.volume) * master_volume_;\r
\r
auto alpha = (next_volume-prev_volume)/static_cast<float>(item.audio_data.size()/format_desc.audio_channels);\r
\r
for(size_t n = 0; n < item.audio_data.size(); ++n)\r
- next_audio.push_back(item.audio_data[n] * (prev_volume + (n/format_desc_.audio_channels) * alpha));\r
+ {\r
+ auto sample_multiplier = (prev_volume + (n/format_desc_.audio_channels) * alpha);\r
+ next_audio.push_back(item.audio_data[n] * sample_multiplier);\r
+ }\r
\r
next_audio_streams[item.tag].prev_transform = std::move(next_transform); // Store all active tags, inactive tags will be removed at the end.\r
next_audio_streams[item.tag].audio_data = std::move(next_audio); \r
- } \r
+ }\r
\r
+ previous_master_volume_ = master_volume_;\r
items_.clear();\r
\r
audio_streams_ = std::move(next_audio_streams);\r
}\r
\r
std::vector<float> result_ps(audio_cadence_.front(), 0.0f);\r
+\r
BOOST_FOREACH(auto& stream, audio_streams_ | boost::adaptors::map_values)\r
{\r
//CASPAR_LOG(debug) << stream.audio_data.size() << L" : " << result_ps.size();\r
\r
auto out = boost::range::transform(result_ps, stream.audio_data, std::begin(result_ps), std::plus<float>());\r
stream.audio_data.erase(std::begin(stream.audio_data), std::begin(stream.audio_data) + std::distance(std::begin(result_ps), out));\r
- } \r
+ }\r
\r
boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
\r
void audio_mixer::begin(core::basic_frame& frame){impl_->begin(frame);}\r
void audio_mixer::visit(core::write_frame& frame){impl_->visit(frame);}\r
void audio_mixer::end(){impl_->end();}\r
+void audio_mixer::set_master_volume(float volume) { impl_->set_master_volume(volume); }\r
audio_buffer audio_mixer::operator()(const video_format_desc& format_desc){return impl_->mix(format_desc);}\r
\r
}}
\ No newline at end of file
blend_modes_.clear();\r
}, high_priority);\r
}\r
+\r
+ void set_master_volume(float volume)\r
+ {\r
+ executor_.begin_invoke([=]\r
+ {\r
+ audio_mixer_.set_master_volume(volume);\r
+ }, high_priority);\r
+ }\r
\r
void set_video_format_desc(const video_format_desc& format_desc)\r
{\r
void mixer::set_blend_mode(int index, blend_mode::type value){impl_->set_blend_mode(index, value);}\r
void mixer::clear_blend_mode(int index) { impl_->clear_blend_mode(index); }\r
void mixer::clear_blend_modes() { impl_->clear_blend_modes(); }\r
+void mixer::set_master_volume(float volume) { impl_->set_master_volume(volume); }\r
void mixer::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
boost::unique_future<boost::property_tree::wptree> mixer::info() const{return impl_->info();}\r
}}
\ No newline at end of file