]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2: Mixer audio transform interpolation.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 3 Mar 2011 08:23:10 +0000 (08:23 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 3 Mar 2011 08:23:10 +0000 (08:23 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@513 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

mixer/audio/audio_transform.cpp
mixer/audio/audio_transform.h
mixer/frame_mixer_device.cpp
protocol/amcp/AMCPCommandsImpl.cpp

index 456f6a7bab12066e0f87f8a87dc465608d51a30a..4f55d61401f7aba0720ae0463d861f15f0db72c6 100644 (file)
@@ -28,4 +28,17 @@ const audio_transform audio_transform::operator*(const audio_transform &other) c
        return audio_transform(*this) *= other;\r
 }\r
 \r
+template<typename T>\r
+T mix(const T& lhs, const T& rhs, float alpha)\r
+{\r
+       return (1.0f - alpha) * lhs + alpha * rhs;\r
+}\r
+\r
+audio_transform lerp(const audio_transform& lhs, const audio_transform& rhs, float alpha)\r
+{\r
+       audio_transform result;\r
+       result.set_gain(mix(lhs.get_gain(), rhs.get_gain(), alpha));\r
+       return result;\r
+}\r
+\r
 }}
\ No newline at end of file
index 772167f10795c2be01eb8ac954a8b10d4a9128e5..6f671188bbad24c5a0ba030184ab318ce7de6895 100644 (file)
@@ -16,4 +16,6 @@ private:
        double gain_;\r
 };\r
 \r
+audio_transform lerp(const audio_transform& lhs, const audio_transform& rhs, float alpha);\r
+\r
 }}
\ No newline at end of file
index 39129b3edac15c5774b1862f54af0a0451ee03d1..070ead69bf811533af2e85f886eec3cc3de5e044 100644 (file)
 #include <unordered_map>\r
 \r
 namespace caspar { namespace core {\r
+\r
+template<typename T>\r
+struct animated_value\r
+{\r
+       virtual T fetch() = 0;\r
+       virtual T fetch_and_tick(bool& done) = 0;\r
+       T fetch_and_tick()\r
+       {\r
+               bool dummy;\r
+               return fetch_and_tick(dummy);\r
+       }\r
+\r
+       virtual safe_ptr<animated_value<T>> source() = 0;\r
+       virtual safe_ptr<animated_value<T>> dest() = 0;\r
+};\r
+\r
+template<typename T>\r
+class basic_animated_value : public animated_value<T>\r
+{\r
+       T current_;\r
+public:\r
+       basic_animated_value(){}\r
+       basic_animated_value(const T& current) : current_(current){}\r
+       \r
+       virtual T fetch(){return current_;}\r
+       virtual T fetch_and_tick(bool& done)\r
+       {\r
+               done = false;\r
+               return current_;\r
+       }\r
+\r
+       virtual safe_ptr<animated_value<T>> source() {return make_safe<basic_animated_value<T>>(current_);}\r
+       virtual safe_ptr<animated_value<T>> dest() {return make_safe<basic_animated_value<T>>(current_);}\r
+};\r
+       \r
+template<typename T>\r
+class nested_animated_value : public animated_value<T>\r
+{\r
+       safe_ptr<animated_value<T>> source_;\r
+       safe_ptr<animated_value<T>> dest_;\r
+       const int duration_;\r
+       int time_;\r
+public:\r
+       nested_animated_value()\r
+               : source_(basic_animated_value<T>())\r
+               , dest_(basic_animated_value<T>())\r
+               , duration_(duration)\r
+               , time_(0){}\r
+       nested_animated_value(const safe_ptr<animated_value<T>>& source, const safe_ptr<animated_value<T>>& dest, int duration)\r
+               : source_(source)\r
+               , dest_(dest)\r
+               , duration_(duration)\r
+               , time_(0){}\r
        \r
+       virtual T fetch()\r
+       {\r
+               return lerp(source_->fetch(), dest_->fetch(), duration_ < 1 ? 1.0f : static_cast<float>(time_)/static_cast<float>(duration_));\r
+       }\r
+       virtual T fetch_and_tick(bool& done)\r
+       {\r
+               done = time_ >= duration_;\r
+\r
+               bool src_done = false;\r
+               auto src = source_->fetch_and_tick(src_done);\r
+               if(src_done)\r
+                       source_ = source_->dest();\r
+               \r
+               bool dst_done = false;\r
+               auto dst = dest_->fetch_and_tick(dst_done);\r
+               if(dst_done)\r
+                       dest_ = dest_->dest();\r
+                                               \r
+               time_ = std::min(time_+1, duration_);\r
+               return lerp(src, dst, duration_ < 1 ? 1.0f : (static_cast<float>(time_)/static_cast<float>(duration_)));\r
+       }\r
+\r
+       virtual safe_ptr<animated_value<T>> source() {return source_;}\r
+       virtual safe_ptr<animated_value<T>> dest() {return dest_;}\r
+};\r
+\r
 struct frame_mixer_device::implementation : boost::noncopyable\r
 {              \r
        const printer                   parent_printer_;\r
@@ -45,7 +124,7 @@ struct frame_mixer_device::implementation : boost::noncopyable
        std::unordered_map<int, audio_transform> audio_transforms_;\r
 \r
        image_transform root_image_transform_;\r
-       audio_transform root_audio_transform_;\r
+       safe_ptr<animated_value<audio_transform>> root_audio_transform_;\r
 \r
        executor executor_;\r
 public:\r
@@ -56,6 +135,7 @@ public:
                , image_mixer_(format_desc)\r
                , output_(output)\r
                , executor_(print())\r
+               , root_audio_transform_(basic_animated_value<audio_transform>())\r
        {\r
                graph_->guide("frame-time", 0.5f);      \r
                graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
@@ -83,7 +163,7 @@ public:
                        auto audio = audio_mixer_.begin_pass();\r
                        BOOST_FOREACH(auto& frame, frames)\r
                        {\r
-                               audio_mixer_.begin(root_audio_transform_*audio_transforms_[frame->get_layer_index()]);\r
+                               audio_mixer_.begin(root_audio_transform_->fetch_and_tick()*audio_transforms_[frame->get_layer_index()]);\r
                                frame->process_audio(audio_mixer_);\r
                                audio_mixer_.end();\r
                        }\r
@@ -127,7 +207,7 @@ public:
        {\r
                return executor_.invoke([&]\r
                {\r
-                       root_audio_transform_ = root_audio_transform_;\r
+                       root_audio_transform_ = make_safe<nested_animated_value<audio_transform>>(root_audio_transform_, make_safe<basic_animated_value<audio_transform>>(transform), mix_duration);\r
                });\r
        }\r
 \r
index 111637559f04ecbdcb55502a1207e6f49c4f5819..febc4ffb6f04443855f180ee465073ba58e325c4 100644 (file)
@@ -268,7 +268,7 @@ bool MixerCommand::DoExecute()
                {\r
                        if(_parameters[1] == L"GAIN")\r
                        {\r
-                               int duration = _parameters.size() > 2 ? lexical_cast_or_default(_parameters[2], 0) : 0;\r
+                               int duration = _parameters.size() > 3 ? lexical_cast_or_default(_parameters[3], 0) : 0;\r
                                double value = boost::lexical_cast<double>(_parameters[2]);\r
                                auto transform = GetChannel()->mixer().get_audio_transform(GetLayerIndex());\r
                                transform.set_gain(value);\r