#include <core/frame/frame.h>
#include <core/frame/frame_transform.h>
+#include <core/monitor/monitor.h>
+
#include <common/diagnostics/graph.h>
#include <common/linq.h>
#include <boost/range/adaptors.hpp>
#include <boost/range/distance.hpp>
+#include <boost/lexical_cast.hpp>
#include <map>
#include <stack>
struct audio_mixer::impl : boost::noncopyable
{
+ monitor::subject monitor_subject_ { "/audio" };
std::stack<core::audio_transform> transform_stack_;
std::map<const void*, audio_stream> audio_streams_;
std::vector<audio_item> items_;
video_format_desc format_desc_;
float master_volume_ = 1.0f;
float previous_master_volume_ = master_volume_;
+ spl::shared_ptr<diagnostics::graph> graph_;
public:
- impl()
+ impl(spl::shared_ptr<diagnostics::graph> graph)
+ : graph_(std::move(graph))
{
+ graph_->set_color("volume", diagnostics::color(1.0f, 0.8f, 0.1f));
transform_stack_.push(core::audio_transform());
}
result.reserve(result_ps.size());
boost::range::transform(result_ps, std::back_inserter(result), [](float sample){return static_cast<int32_t>(sample);});
+ const int num_channels = format_desc_.audio_channels;
+ monitor_subject_ << monitor::message("/nb_channels") % num_channels;
+
+ auto max = std::vector<int32_t>(num_channels, std::numeric_limits<int32_t>::min());
+
+ for (size_t n = 0; n < result.size(); n += num_channels)
+ for (int ch = 0; ch < num_channels; ++ch)
+ max[ch] = std::max(max[ch], std::abs(result[n + ch]));
+
+ // Makes the dBFS of silence => -dynamic range of 32bit LPCM => about -192 dBFS
+ // Otherwise it would be -infinity
+ static const auto MIN_PFS = 0.5f / static_cast<float>(std::numeric_limits<int32_t>::max());
+
+ for (int i = 0; i < num_channels; ++i)
+ {
+ const auto pFS = max[i] / static_cast<float>(std::numeric_limits<int32_t>::max());
+ const auto dBFS = 20.0f * std::log10(std::max(MIN_PFS, pFS));
+
+ auto chan_str = boost::lexical_cast<std::string>(i + 1);
+
+ monitor_subject_ << monitor::message("/" + chan_str + "/pFS") % pFS;
+ monitor_subject_ << monitor::message("/" + chan_str + "/dBFS") % dBFS;
+ }
+
+ graph_->set_value("volume", static_cast<double>(*boost::max_element(max)) / std::numeric_limits<int32_t>::max());
+
return result;
}
}
};
-audio_mixer::audio_mixer() : impl_(new impl()){}
+audio_mixer::audio_mixer(spl::shared_ptr<diagnostics::graph> graph) : impl_(new impl(std::move(graph))){}
void audio_mixer::push(const frame_transform& transform){impl_->push(transform);}
void audio_mixer::visit(const const_frame& frame){impl_->visit(frame);}
void audio_mixer::pop(){impl_->pop();}
void audio_mixer::set_master_volume(float volume) { impl_->set_master_volume(volume); }
float audio_mixer::get_master_volume() { return impl_->get_master_volume(); }
audio_buffer audio_mixer::operator()(const video_format_desc& format_desc){ return impl_->mix(format_desc); }
+monitor::subject& audio_mixer::monitor_output(){ return impl_->monitor_subject_; }
}}
struct mixer::impl : boost::noncopyable
{
int channel_index_;
- spl::shared_ptr<diagnostics::graph> graph_;
+ spl::shared_ptr<diagnostics::graph> graph_;
tbb::atomic<int64_t> current_mix_time_;
- audio_mixer audio_mixer_;
+ spl::shared_ptr<monitor::subject> monitor_subject_ = spl::make_shared<monitor::subject>("/mixer");
+ audio_mixer audio_mixer_ { graph_ };
spl::shared_ptr<image_mixer> image_mixer_;
- executor executor_ { L"mixer " + boost::lexical_cast<std::wstring>(channel_index_) };
+ executor executor_ { L"mixer " + boost::lexical_cast<std::wstring>(channel_index_) };
public:
impl(int channel_index, spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer)
{
graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8f));
current_mix_time_ = 0;
+ audio_mixer_.monitor_output().attach_parent(monitor_subject_);
}
const_frame operator()(std::map<int, draw_frame> frames, const video_format_desc& format_desc)
std::future<boost::property_tree::wptree> mixer::delay_info() const{ return impl_->delay_info(); }
const_frame mixer::operator()(std::map<int, draw_frame> frames, const video_format_desc& format_desc){ return (*impl_)(std::move(frames), format_desc); }
mutable_frame mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->image_mixer_->create_frame(tag, desc);}
+monitor::subject& mixer::monitor_output() { return *impl_->monitor_subject_; }
}}