]> git.sesse.net Git - casparcg/blobdiff - core/mixer/audio/audio_mixer.cpp
Added support for more than 2 audio channels
[casparcg] / core / mixer / audio / audio_mixer.cpp
index c04f1592a5dc6d5ee8ec1bb2e7fe5b81a79a889d..7ebd70735a09ba29961583f8d133f27cb23b3b62 100644 (file)
@@ -26,6 +26,7 @@
 #include <core/mixer/write_frame.h>\r
 #include <core/producer/frame/frame_transform.h>\r
 #include <common/diagnostics/graph.h>\r
+#include "audio_util.h"\r
 \r
 #include <tbb/cache_aligned_allocator.h>\r
 \r
@@ -60,8 +61,8 @@ typedef std::vector<float, tbb::cache_aligned_allocator<float>> audio_buffer_ps;
        \r
 struct audio_stream\r
 {\r
-       frame_transform         prev_transform;\r
-       audio_buffer_ps         audio_data;\r
+       frame_transform prev_transform;\r
+       audio_buffer_ps audio_data;\r
 };\r
 \r
 struct audio_mixer::implementation\r
@@ -72,6 +73,7 @@ struct audio_mixer::implementation
        std::vector<audio_item>                         items_;\r
        std::vector<size_t>                                     audio_cadence_;\r
        video_format_desc                                       format_desc_;\r
+       channel_layout                                          channel_layout_;\r
        float                                                           master_volume_;\r
        float                                                           previous_master_volume_;\r
        \r
@@ -99,7 +101,34 @@ public:
                audio_item item;\r
                item.tag                = frame.tag();\r
                item.transform  = transform_stack_.top();\r
-               item.audio_data = std::move(frame.audio_data()); // Note: We don't need to care about upper/lower since audio_data is removed/moved from the last field.\r
+\r
+               if (needs_rearranging(frame.get_channel_layout(), channel_layout_))\r
+               {\r
+                       auto src_view = frame.get_multichannel_view();\r
+                       \r
+                       audio_buffer rearranged_buffer;\r
+                       rearranged_buffer.resize(\r
+                                       src_view.num_samples() * channel_layout_.num_channels);\r
+\r
+                       auto dst_view = make_multichannel_view<int32_t>(\r
+                                       rearranged_buffer.begin(),\r
+                                       rearranged_buffer.end(),\r
+                                       channel_layout_);\r
+\r
+                       bool rearrange_success = rearrange_or_rearrange_and_mix(\r
+                                       src_view, dst_view, default_mix_config_repository());\r
+\r
+                       if (!rearrange_success)\r
+                       {\r
+                               failed_rearrange(item.tag, src_view.channel_layout());\r
+                       }\r
+\r
+                       item.audio_data = std::move(rearranged_buffer);\r
+               }\r
+               else\r
+               {\r
+                       item.audio_data = std::move(frame.audio_data()); // Note: We don't need to care about upper/lower since audio_data is removed/moved from the last field.\r
+               }\r
                \r
                items_.push_back(std::move(item));              \r
        }\r
@@ -119,14 +148,15 @@ public:
                master_volume_ = volume;\r
        }\r
        \r
-       audio_buffer mix(const video_format_desc& format_desc)\r
+       audio_buffer mix(const video_format_desc& format_desc, const channel_layout& layout)\r
        {       \r
                if(format_desc_ != format_desc)\r
                {\r
                        audio_streams_.clear();\r
                        audio_cadence_ = format_desc.audio_cadence;\r
                        format_desc_ = format_desc;\r
-               }               \r
+                       channel_layout_ = layout;\r
+               }\r
                \r
                std::map<const void*, audio_stream>     next_audio_streams;\r
 \r
@@ -150,11 +180,11 @@ public:
                        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
+                       auto alpha = (next_volume-prev_volume)/static_cast<float>(item.audio_data.size()/channel_layout_.num_channels);\r
                        \r
                        for(size_t n = 0; n < item.audio_data.size(); ++n)\r
                        {\r
-                               auto sample_multiplier = (prev_volume + (n/format_desc_.audio_channels) * alpha);\r
+                               auto sample_multiplier = (prev_volume + (n/channel_layout_.num_channels) * alpha);\r
                                next_audio.push_back(item.audio_data[n] * sample_multiplier);\r
                        }\r
                                                                                \r
@@ -212,7 +242,20 @@ public:
 \r
        size_t audio_size(size_t num_samples) const\r
        {\r
-               return num_samples * format_desc_.audio_channels;\r
+               return num_samples * channel_layout_.num_channels;\r
+       }\r
+\r
+       void failed_rearrange(const void* tag, const channel_layout& layout)\r
+       {\r
+               if (audio_streams_.find(tag) != audio_streams_.end())\r
+                       return; // We don't want to flood the logs.\r
+\r
+               CASPAR_LOG(warning)\r
+                               << L"[audio_mixer] Could not satisfactory down/upmix from " \r
+                               << layout.name << L" to " << channel_layout_.name \r
+                               << L" because no mix config was found for " \r
+                               << layout.layout_type << L" => " << channel_layout_.layout_type \r
+                               << L". This might cause audio to be lost.";\r
        }\r
 };\r
 \r
@@ -221,6 +264,6 @@ void audio_mixer::begin(core::basic_frame& frame){impl_->begin(frame);}
 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
+audio_buffer audio_mixer::operator()(const video_format_desc& format_desc, const channel_layout& layout){return impl_->mix(format_desc, layout);}\r
 \r
 }}
\ No newline at end of file