libvisual  0.5.0
lv_morph.cpp
1 /* Libvisual - The audio visualisation framework.
2  *
3  * Copyright (C) 2012 ibvisual team
4  * 2004-2006 Dennis Smit
5  *
6  * Authors: Dennis Smit <ds@nerds-incorporated.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as
10  * published by the Free Software Foundation; either version 2.1
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  */
22 
23 #include "config.h"
24 #include "lv_morph.h"
25 #include "lv_common.h"
26 #include "lv_plugin_registry.h"
27 #include <algorithm>
28 #include <stdexcept>
29 
30 namespace LV {
31 
32  class Morph::Impl
33  {
34  public:
35 
36  VisPluginData* plugin;
37  VideoPtr dest;
38  float progress;
39  Palette* morphpal;
40  Time morphtime;
41  Timer timer;
42 
43  Impl ();
44 
45  ~Impl ();
46 
47  VisMorphPlugin* get_morph_plugin () const;
48  };
49 
50  Morph::Impl::Impl ()
51  : plugin {nullptr}
52  , progress {0}
53  , morphpal {nullptr}
54  {
55  // nothing
56  }
57 
58  Morph::Impl::~Impl ()
59  {
60  if (plugin) {
61  visual_plugin_unload (plugin);
62  }
63 
64  delete morphpal;
65  }
66 
67  VisMorphPlugin* Morph::Impl::get_morph_plugin () const
68  {
69  return static_cast<VisMorphPlugin*> (visual_plugin_get_info (plugin)->plugin);
70  }
71 
72  VisPluginData* Morph::get_plugin ()
73  {
74  return m_impl->plugin;
75  }
76 
77  MorphPtr Morph::load (std::string const& name)
78  {
79  try {
80  return {new Morph {name}, false};
81  }
82  catch (std::exception& error)
83  {
84  visual_log (VISUAL_LOG_ERROR, "%s", error.what ());
85  return nullptr;
86  }
87  }
88 
89  Morph::Morph (std::string const& name)
90  : m_impl (new Impl)
91  , m_ref_count (1)
92  {
93  if (!PluginRegistry::instance()->has_plugin (VISUAL_PLUGIN_TYPE_MORPH, name)) {
94  throw std::runtime_error {"Morph plugin not found"};
95  }
96 
97  m_impl->plugin = visual_plugin_load (VISUAL_PLUGIN_TYPE_MORPH, name.c_str ());
98  if (!m_impl->plugin) {
99  throw std::runtime_error {"Failed to load morph plugin"};
100  }
101 
102  m_impl->morphpal = new LV::Palette {256};
103  }
104 
105  Morph::~Morph ()
106  {
107  // nothing
108  }
109 
111  {
112  return visual_plugin_realize (m_impl->plugin);
113  }
114 
116  {
117  return m_impl->get_morph_plugin ()->vidoptions.depth;
118  }
119 
120  VisVideoAttrOptions const* Morph::get_video_attribute_options ()
121  {
122  return &m_impl->get_morph_plugin ()->vidoptions;
123  }
124 
125  void Morph::set_video (VideoPtr const& video)
126  {
127  m_impl->dest = video;
128  }
129 
130  void Morph::set_time (Time const& time)
131  {
132  m_impl->morphtime = time;
133  }
134 
135  void Morph::set_progress (float progress)
136  {
137  m_impl->progress = std::min (std::max (progress, 0.0f), 1.0f);
138  }
139 
141  {
142  // FIXME: This should return nullptr if there is no palette
143  return m_impl->morphpal;
144  }
145 
147  {
148  if (m_impl->progress >= 1.0) {
149  m_impl->timer.stop ();
150  return true;
151  }
152 
153  return false;
154  }
155 
156  bool Morph::run (Audio const& audio, VideoPtr const& src1, VideoPtr const& src2)
157  {
158  visual_return_val_if_fail (src1, FALSE);
159  visual_return_val_if_fail (src2, FALSE);
160 
161  auto morph_plugin = m_impl->get_morph_plugin ();
162 
163  // If we're morphing using the timer, start the timer
164  if (!m_impl->timer.is_active ()) {
165  m_impl->timer.start ();
166  }
167 
168  if (morph_plugin->palette) {
169  morph_plugin->palette (m_impl->plugin, m_impl->progress, const_cast<Audio*> (&audio), m_impl->morphpal, src1.get (), src2.get ());
170  }
171  else {
172  auto const& src1_pal = src1->get_palette ();
173  auto const& src2_pal = src2->get_palette ();
174 
175  //if (src1_pal && src2_pal) {
176  m_impl->morphpal->blend (src1_pal, src2_pal, m_impl->progress);
177  //}
178  }
179 
180  morph_plugin->apply (m_impl->plugin, m_impl->progress, const_cast<Audio*> (&audio), m_impl->dest.get (), src1.get (), src2.get ());
181 
182  m_impl->dest->set_palette (*get_palette ());
183 
184  // Update morph progression
185 
186  double usec_elapsed = m_impl->timer.elapsed ().to_usecs ();
187  double usec_morph = m_impl->morphtime.to_usecs ();
188 
189  m_impl->progress = std::min (std::max (usec_elapsed / usec_morph, 0.0), 1.0);
190 
191  return true;
192  }
193 
194 } // LV namespace