Release 0.61.08
[synfig.git] / synfig-studio / tags / 0.61.08 / src / gtkmm / widget_sound.cpp
diff --git a/synfig-studio/tags/0.61.08/src/gtkmm/widget_sound.cpp b/synfig-studio/tags/0.61.08/src/gtkmm/widget_sound.cpp
new file mode 100644 (file)
index 0000000..3d43731
--- /dev/null
@@ -0,0 +1,323 @@
+/* === S Y N F I G ========================================================= */
+/*!    \file widget_sound.cpp
+**     \brief Widget Sound Implementation File
+**
+**     $Id$
+**
+**     \legal
+**     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+**
+**     This package is free software; you can redistribute it and/or
+**     modify it under the terms of the GNU General Public License as
+**     published by the Free Software Foundation; either version 2 of
+**     the License, or (at your option) any later version.
+**
+**     This package is distributed in the hope that it will be useful,
+**     but WITHOUT ANY WARRANTY; without even the implied warranty of
+**     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+**     General Public License for more details.
+**     \endlegal
+*/
+/* ========================================================================= */
+
+/* === H E A D E R S ======================================================= */
+
+#ifdef USING_PCH
+#      include "pch.h"
+#else
+#ifdef HAVE_CONFIG_H
+#      include <config.h>
+#endif
+
+#include <gtkmm/adjustment.h>
+
+#include <synfig/general.h>
+#include <ETL/clock>
+
+#include "widget_sound.h"
+#include "audiocontainer.h"
+
+#include "general.h"
+
+#endif
+
+/* === U S I N G =========================================================== */
+
+using namespace std;
+using namespace etl;
+//using namespace synfig;
+
+using studio::AudioProfile;
+
+/* === M A C R O S ========================================================= */
+
+/* === G L O B A L S ======================================================= */
+
+/* === P R O C E D U R E S ================================================= */
+
+/* === M E T H O D S ======================================================= */
+
+/* === E N T R Y P O I N T ================================================= */
+
+studio::Widget_Sound::Widget_Sound()
+{
+}
+
+studio::Widget_Sound::~Widget_Sound()
+{
+}
+
+void studio::Widget_Sound::set_position(double t)
+{
+       //synfig::info("Setting position to %.2lf s", t);
+       if(adj_timescale && t != adj_timescale->get_value())
+       {
+               float upper = adj_timescale->get_upper();
+               float lower = adj_timescale->get_lower();
+               float framesize =  upper - lower;
+
+               if(t < lower)
+               {
+                       lower -= ceil((lower-t)/framesize)*framesize;
+                       upper = lower + framesize;
+                       adj_timescale->set_lower(lower); adj_timescale->set_upper(upper);
+                       adj_timescale->set_value(t);
+                       adj_timescale->changed(); adj_timescale->value_changed();
+               }else
+               if(t > upper)
+               {
+                       lower += ceil((t-upper)/framesize)*framesize;
+                       upper = lower + framesize;
+                       adj_timescale->set_lower(lower); adj_timescale->set_upper(upper);
+                       adj_timescale->set_value(t);
+                       adj_timescale->changed(); adj_timescale->value_changed();
+               }else
+               {
+                       adj_timescale->set_value(t);
+                       adj_timescale->value_changed();
+               }
+       }
+}
+
+double studio::Widget_Sound::get_position() const
+{
+       if(adj_timescale)
+       {
+               return adj_timescale->get_value();
+       }
+       return 0;
+}
+
+bool studio::Widget_Sound::set_profile(etl::handle<AudioProfile>       p)
+{
+       clear();
+
+       //set the profile
+       audioprof = p;
+
+       if(!audioprof)
+       {
+               clear();
+               return false;
+       }
+
+       return true;
+}
+
+etl::handle<AudioProfile>      studio::Widget_Sound::get_profile() const
+{
+       return audioprof;
+}
+
+void studio::Widget_Sound::clear()
+{
+       audioprof.detach();
+}
+
+void studio::Widget_Sound::draw()
+{
+       on_expose_event();
+}
+
+bool studio::Widget_Sound::on_expose_event(GdkEventExpose */*heh*/)
+{
+       if(!get_window()) return false;
+
+       //clear the background to dark grey
+       Glib::RefPtr<Gdk::GC>   gc = Gdk::GC::create(get_window());
+
+       if(!gc) return false;
+
+       {
+               Gdk::Rectangle r(0,0,get_width(),get_height());
+               get_window()->begin_paint_rect(r);
+       }
+       Gdk::Color      c("#3f3f3f");
+       gc->set_rgb_fg_color(c);
+       gc->set_background(c);
+
+       int w = get_width();
+       int baseline = get_height()/2;
+       get_window()->draw_rectangle(gc,true,0,0,w,get_height());
+
+       //set up the color to be blue
+       c.set_rgb_p(0,0.5,1);
+       gc->set_rgb_fg_color(c);
+
+       //draw the base line
+       get_window()->draw_line(gc,0,baseline,w,baseline);
+
+       //redraw all the samples from begin to end, but only if we have samples to draw (or there is no space to draw)
+
+       //synfig::warning("Ok rendered everything, now must render actual sound wave");
+       if(!audioprof || !adj_timescale || !w)
+       {
+               get_window()->end_paint();
+               return true;
+       }
+
+       //draw you fool!
+       float framesize = adj_timescale->get_upper() - adj_timescale->get_lower();
+       if(framesize)
+       {
+               float delta=0,cum=0;
+
+               //position in sample space
+               int begin=0,end=0;
+               int     cur=0,maxs=0,mins=0;
+
+               int       i=0; //pixel counter
+
+               //etl::clock    check; check.reset();
+
+               float position = adj_timescale->get_value();
+               float samplerate = audioprof->get_samplerate();
+               int             posi = 0;
+               //enforce position inside of frame size
+               {
+                       float offset = audioprof->get_offset();
+
+                       //clamp begin and end to framesize
+                       float beginf = adj_timescale->get_lower();
+                       float endf = adj_timescale->get_upper();
+
+                       posi = round_to_int((position-beginf)*w/framesize);
+                       //posi = (int)((position-beginf)*w/framesize);
+
+                       //calculate in sample space from seconds
+                       begin = round_to_int((beginf - offset)*samplerate);
+                       end = round_to_int((endf - offset)*samplerate);
+                       //begin = (int)((beginf - offset)*samplerate);
+                       //end = (int)((endf - offset)*samplerate);
+               }
+
+               delta = (end - begin)/(float)w; //samples per pixel
+
+               /*synfig::warning("Rendering a framesize of %f secs from [%d,%d) samples to %d samples, took %f sec",
+                                               framesize, begin, end, w, check());*/
+
+               cur = begin;
+               i = 0; cum = 0;
+               for(int i=0;i<w;++i)
+               {
+                       //get the maximum of the collected samples
+                       maxs = 0;
+                       mins = 0;
+                       for(;cum < delta; ++cum, ++cur)
+                       {
+                               maxs = std::max(maxs,(int)(*audioprof)[cur]);
+                               mins = std::min(mins,(int)(*audioprof)[cur]);
+                       }
+                       cum -= delta;
+
+                       //draw spike if not needed be
+                       if(maxs||mins)
+                       {
+                               int top = maxs * baseline / 64;
+                               int bot = mins * baseline / 64;
+
+                               get_window()->draw_line(gc,i,baseline+bot,i,baseline+top);
+                       }
+               }
+
+               //synfig::warning("Drawing audio line");
+               c.set_rgb_p(1,0,0);
+               gc->set_rgb_fg_color(c);
+               get_window()->draw_line(gc,posi,0,posi,get_height());
+       }
+       get_window()->end_paint();
+
+       return true;
+}
+
+//--- Handle the single clicking and dragging for scrubbing
+
+bool studio::Widget_Sound::on_motion_notify_event(GdkEventMotion* event)
+{
+       Gdk::ModifierType       mod = Gdk::ModifierType(event->state);
+
+       //if we are scrubbing
+       if(mod & Gdk::BUTTON1_MASK)
+       {
+               //Can't do this if we don't have a time frame (heheh...)
+               if(!adj_timescale) return false;
+
+               double beg = adj_timescale->get_lower(), end = adj_timescale->get_upper();
+
+               //find event position in time
+               double t = beg + event->x * (end-beg) / get_width();
+
+               //signal that we are scrubbing to this new value...
+               signal_scrub()(t);
+
+
+               // We should be able to just call
+               // Widget_Timeslider::on_motion_notify_event(),
+               // but that seems to cause the program to halt
+               // for some reason. So for now, let's do the job ourselves
+               //adj_timescale->set_value(t);
+               //adj_timescale->changed();
+               //return true;
+       }
+
+       return Widget_Timeslider::on_motion_notify_event(event);
+}
+
+bool studio::Widget_Sound::on_button_press_event(GdkEventButton *event)
+{
+       //Assume button PRESS
+
+       //if we are starting... using left click
+       if(event->button == 1)
+       {
+               if(!adj_timescale) return false;
+
+               double beg = adj_timescale->get_lower(), end = adj_timescale->get_upper();
+
+               //find event position in time
+               double t = beg + event->x * (end-beg) / get_width();
+
+               //signal the attached scrubbing devices...
+               signal_start_scrubbing()(t);
+
+               return true;
+       }
+
+       return Widget_Timeslider::on_button_press_event(event);
+}
+
+bool studio::Widget_Sound::on_button_release_event(GdkEventButton *event)
+{
+       //Assume button RELEASE
+
+       //if we are ending... using left click
+       if(event->button == 1)
+       {
+               //signal the scrubbing device... to stop
+               signal_stop_scrubbing()();
+
+               return true;
+       }
+
+       return Widget_Timeslider::on_button_release_event(event);
+}