#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
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
, 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
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
{\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