1 /* === S Y N F I G ========================================================= */
2 /*! \file widget_sound.cpp
3 ** \brief Widget Sound Implementation File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
32 #include <gtkmm/adjustment.h>
34 #include <synfig/general.h>
37 #include "widget_sound.h"
38 #include "audiocontainer.h"
44 /* === U S I N G =========================================================== */
48 //using namespace synfig;
50 using studio::AudioProfile;
52 /* === M A C R O S ========================================================= */
54 /* === G L O B A L S ======================================================= */
56 /* === P R O C E D U R E S ================================================= */
58 /* === M E T H O D S ======================================================= */
60 /* === E N T R Y P O I N T ================================================= */
62 studio::Widget_Sound::Widget_Sound()
66 studio::Widget_Sound::~Widget_Sound()
70 void studio::Widget_Sound::set_position(double t)
72 //synfig::info("Setting position to %.2lf s", t);
73 if(adj_timescale && t != adj_timescale->get_value())
75 float upper = adj_timescale->get_upper();
76 float lower = adj_timescale->get_lower();
77 float framesize = upper - lower;
81 lower -= ceil((lower-t)/framesize)*framesize;
82 upper = lower + framesize;
83 adj_timescale->set_lower(lower); adj_timescale->set_upper(upper);
84 adj_timescale->set_value(t);
85 adj_timescale->changed(); adj_timescale->value_changed();
89 lower += ceil((t-upper)/framesize)*framesize;
90 upper = lower + framesize;
91 adj_timescale->set_lower(lower); adj_timescale->set_upper(upper);
92 adj_timescale->set_value(t);
93 adj_timescale->changed(); adj_timescale->value_changed();
96 adj_timescale->set_value(t);
97 adj_timescale->value_changed();
102 double studio::Widget_Sound::get_position() const
106 return adj_timescale->get_value();
111 bool studio::Widget_Sound::set_profile(etl::handle<AudioProfile> p)
127 etl::handle<AudioProfile> studio::Widget_Sound::get_profile() const
132 void studio::Widget_Sound::clear()
137 void studio::Widget_Sound::draw()
142 bool studio::Widget_Sound::on_expose_event(GdkEventExpose */*heh*/)
144 if(!get_window()) return false;
146 //clear the background to dark grey
147 Glib::RefPtr<Gdk::GC> gc = Gdk::GC::create(get_window());
149 if(!gc) return false;
152 Gdk::Rectangle r(0,0,get_width(),get_height());
153 get_window()->begin_paint_rect(r);
155 Gdk::Color c("#3f3f3f");
156 gc->set_rgb_fg_color(c);
157 gc->set_background(c);
160 int baseline = get_height()/2;
161 get_window()->draw_rectangle(gc,true,0,0,w,get_height());
163 //set up the color to be blue
164 c.set_rgb_p(0,0.5,1);
165 gc->set_rgb_fg_color(c);
168 get_window()->draw_line(gc,0,baseline,w,baseline);
170 //redraw all the samples from begin to end, but only if we have samples to draw (or there is no space to draw)
172 //synfig::warning("Ok rendered everything, now must render actual sound wave");
173 if(!audioprof || !adj_timescale || !w)
175 get_window()->end_paint();
180 float framesize = adj_timescale->get_upper() - adj_timescale->get_lower();
185 //position in sample space
187 int cur=0,maxs=0,mins=0;
189 int i=0; //pixel counter
191 //etl::clock check; check.reset();
193 float position = adj_timescale->get_value();
194 float samplerate = audioprof->get_samplerate();
196 //enforce position inside of frame size
198 float offset = audioprof->get_offset();
200 //clamp begin and end to framesize
201 float beginf = adj_timescale->get_lower();
202 float endf = adj_timescale->get_upper();
204 posi = round_to_int((position-beginf)*w/framesize);
205 //posi = (int)((position-beginf)*w/framesize);
207 //calculate in sample space from seconds
208 begin = round_to_int((beginf - offset)*samplerate);
209 end = round_to_int((endf - offset)*samplerate);
210 //begin = (int)((beginf - offset)*samplerate);
211 //end = (int)((endf - offset)*samplerate);
214 delta = (end - begin)/(float)w; //samples per pixel
216 /*synfig::warning("Rendering a framesize of %f secs from [%d,%d) samples to %d samples, took %f sec",
217 framesize, begin, end, w, check());*/
223 //get the maximum of the collected samples
226 for(;cum < delta; ++cum, ++cur)
228 maxs = std::max(maxs,(int)(*audioprof)[cur]);
229 mins = std::min(mins,(int)(*audioprof)[cur]);
233 //draw spike if not needed be
236 int top = maxs * baseline / 64;
237 int bot = mins * baseline / 64;
239 get_window()->draw_line(gc,i,baseline+bot,i,baseline+top);
243 //synfig::warning("Drawing audio line");
245 gc->set_rgb_fg_color(c);
246 get_window()->draw_line(gc,posi,0,posi,get_height());
248 get_window()->end_paint();
253 //--- Handle the single clicking and dragging for scrubbing
255 bool studio::Widget_Sound::on_motion_notify_event(GdkEventMotion* event)
257 Gdk::ModifierType mod = Gdk::ModifierType(event->state);
259 //if we are scrubbing
260 if(mod & Gdk::BUTTON1_MASK)
262 //Can't do this if we don't have a time frame (heheh...)
263 if(!adj_timescale) return false;
265 double beg = adj_timescale->get_lower(), end = adj_timescale->get_upper();
267 //find event position in time
268 double t = beg + event->x * (end-beg) / get_width();
270 //signal that we are scrubbing to this new value...
274 // We should be able to just call
275 // Widget_Timeslider::on_motion_notify_event(),
276 // but that seems to cause the program to halt
277 // for some reason. So for now, let's do the job ourselves
278 //adj_timescale->set_value(t);
279 //adj_timescale->changed();
283 return Widget_Timeslider::on_motion_notify_event(event);
286 bool studio::Widget_Sound::on_button_press_event(GdkEventButton *event)
288 //Assume button PRESS
290 //if we are starting... using left click
291 if(event->button == 1)
293 if(!adj_timescale) return false;
295 double beg = adj_timescale->get_lower(), end = adj_timescale->get_upper();
297 //find event position in time
298 double t = beg + event->x * (end-beg) / get_width();
300 //signal the attached scrubbing devices...
301 signal_start_scrubbing()(t);
306 return Widget_Timeslider::on_button_press_event(event);
309 bool studio::Widget_Sound::on_button_release_event(GdkEventButton *event)
311 //Assume button RELEASE
313 //if we are ending... using left click
314 if(event->button == 1)
316 //signal the scrubbing device... to stop
317 signal_stop_scrubbing()();
322 return Widget_Timeslider::on_button_release_event(event);