1 /* === S I N F G =========================================================== */
2 /*! \file widget_sound.cpp
3 ** \brief Widget Sound Implementation File
5 ** $Id: widget_sound.cpp,v 1.1.1.1 2005/01/07 03:34:37 darco Exp $
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
10 ** This software and associated documentation
11 ** are CONFIDENTIAL and PROPRIETARY property of
12 ** the above-mentioned copyright holder.
14 ** You may not copy, print, publish, or in any
15 ** other way distribute this software without
16 ** a prior written agreement with
17 ** the copyright holder.
20 /* ========================================================================= */
22 /* === H E A D E R S ======================================================= */
31 #include <gtkmm/adjustment.h>
33 #include <sinfg/general.h>
36 #include "widget_sound.h"
37 #include "audiocontainer.h"
41 /* === U S I N G =========================================================== */
45 //using namespace sinfg;
47 using studio::AudioProfile;
49 /* === M A C R O S ========================================================= */
51 /* === G L O B A L S ======================================================= */
53 /* === P R O C E D U R E S ================================================= */
55 /* === M E T H O D S ======================================================= */
57 /* === E N T R Y P O I N T ================================================= */
59 studio::Widget_Sound::Widget_Sound()
63 studio::Widget_Sound::~Widget_Sound()
67 void studio::Widget_Sound::set_position(double t)
69 //sinfg::info("Setting position to %.2lf s", t);
70 if(adj_timescale && t != adj_timescale->get_value())
72 float upper = adj_timescale->get_upper();
73 float lower = adj_timescale->get_lower();
74 float framesize = upper - lower;
78 lower -= ceil((lower-t)/framesize)*framesize;
79 upper = lower + framesize;
80 adj_timescale->set_lower(lower); adj_timescale->set_upper(upper);
81 adj_timescale->set_value(t);
82 adj_timescale->changed(); adj_timescale->value_changed();
86 lower += ceil((t-upper)/framesize)*framesize;
87 upper = lower + framesize;
88 adj_timescale->set_lower(lower); adj_timescale->set_upper(upper);
89 adj_timescale->set_value(t);
90 adj_timescale->changed(); adj_timescale->value_changed();
93 adj_timescale->set_value(t);
94 adj_timescale->value_changed();
99 double studio::Widget_Sound::get_position() const
103 return adj_timescale->get_value();
108 bool studio::Widget_Sound::set_profile(etl::handle<AudioProfile> p)
124 etl::handle<AudioProfile> studio::Widget_Sound::get_profile() const
129 void studio::Widget_Sound::clear()
134 void studio::Widget_Sound::draw()
139 bool studio::Widget_Sound::on_expose_event(GdkEventExpose *heh)
141 if(!get_window()) return false;
143 //clear the background to dark grey
144 Glib::RefPtr<Gdk::GC> gc = Gdk::GC::create(get_window());
146 if(!gc) return false;
149 Gdk::Rectangle r(0,0,get_width(),get_height());
150 get_window()->begin_paint_rect(r);
152 Gdk::Color c("#3f3f3f");
153 gc->set_rgb_fg_color(c);
154 gc->set_background(c);
157 int baseline = get_height()/2;
158 get_window()->draw_rectangle(gc,true,0,0,w,get_height());
160 //set up the color to be blue
161 c.set_rgb_p(0,0.5,1);
162 gc->set_rgb_fg_color(c);
165 get_window()->draw_line(gc,0,baseline,w,baseline);
167 //redraw all the samples from begin to end, but only if we have samples to draw (or there is no space to draw)
169 //sinfg::warning("Ok rendered everything, now must render actual sound wave");
170 if(!audioprof || !adj_timescale || !w)
172 get_window()->end_paint();
177 float framesize = adj_timescale->get_upper() - adj_timescale->get_lower();
182 //position in sample space
184 int cur=0,maxs=0,mins=0;
186 int i=0; //pixel counter
188 //etl::clock check; check.reset();
190 float position = adj_timescale->get_value();
191 float samplerate = audioprof->get_samplerate();
193 //enforce position inside of frame size
195 float offset = audioprof->get_offset();
197 //clamp begin and end to framesize
198 float beginf = adj_timescale->get_lower();
199 float endf = adj_timescale->get_upper();
201 posi = round_to_int((position-beginf)*w/framesize);
202 //posi = (int)((position-beginf)*w/framesize);
204 //calculate in sample space from seconds
205 begin = round_to_int((beginf - offset)*samplerate);
206 end = round_to_int((endf - offset)*samplerate);
207 //begin = (int)((beginf - offset)*samplerate);
208 //end = (int)((endf - offset)*samplerate);
211 delta = (end - begin)/(float)w; //samples per pixel
213 /*sinfg::warning("Rendering a framesize of %f secs from [%d,%d) samples to %d samples, took %f sec",
214 framesize, begin, end, w, check());*/
220 //get the maximum of the collected samples
223 for(;cum < delta; ++cum, ++cur)
225 maxs = std::max(maxs,(int)(*audioprof)[cur]);
226 mins = std::min(mins,(int)(*audioprof)[cur]);
230 //draw spike if not needed be
233 int top = maxs * baseline / 64;
234 int bot = mins * baseline / 64;
236 get_window()->draw_line(gc,i,baseline+bot,i,baseline+top);
240 //sinfg::warning("Drawing audio line");
242 gc->set_rgb_fg_color(c);
243 get_window()->draw_line(gc,posi,0,posi,get_height());
245 get_window()->end_paint();
250 //--- Handle the single clicking and dragging for scrubbing
252 bool studio::Widget_Sound::on_motion_notify_event(GdkEventMotion* event)
254 Gdk::ModifierType mod = Gdk::ModifierType(event->state);
256 //if we are scrubbing
257 if(mod & Gdk::BUTTON1_MASK)
259 //Can't do this if we don't have a time frame (heheh...)
260 if(!adj_timescale) return false;
262 double beg = adj_timescale->get_lower(), end = adj_timescale->get_upper();
264 //find event position in time
265 double t = beg + event->x * (end-beg) / get_width();
267 //signal that we are scrubbing to this new value...
271 // We should be able to just call
272 // Widget_Timeslider::on_motion_notify_event(),
273 // but that seems to cause the program to halt
274 // for some reason. So for now, let's do the job ourselves
275 //adj_timescale->set_value(t);
276 //adj_timescale->changed();
280 return Widget_Timeslider::on_motion_notify_event(event);
283 bool studio::Widget_Sound::on_button_press_event(GdkEventButton *event)
285 //Assume button PRESS
287 //if we are starting... using left click
288 if(event->button == 1)
290 if(!adj_timescale) return false;
292 double beg = adj_timescale->get_lower(), end = adj_timescale->get_upper();
294 //find event position in time
295 double t = beg + event->x * (end-beg) / get_width();
297 //signal the attached scrubbing devices...
298 signal_start_scrubbing()(t);
303 return Widget_Timeslider::on_button_press_event(event);
306 bool studio::Widget_Sound::on_button_release_event(GdkEventButton *event)
308 //Assume button RELEASE
310 //if we are ending... using left click
311 if(event->button == 1)
313 //signal the scrubbing device... to stop
314 signal_stop_scrubbing()();
319 return Widget_Timeslider::on_button_release_event(event);