Assists music production by grouping standalone programs into sessions. Community version of "Non Session Manager".
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2223 lines
52KB

  1. /*******************************************************************************/
  2. /* Copyright (C) 2008 Jonathan Moore Liles */
  3. /* */
  4. /* This program is free software; you can redistribute it and/or modify it */
  5. /* under the terms of the GNU General Public License as published by the */
  6. /* Free Software Foundation; either version 2 of the License, or (at your */
  7. /* option) any later version. */
  8. /* */
  9. /* This program is distributed in the hope that it will be useful, but WITHOUT */
  10. /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
  11. /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
  12. /* more details. */
  13. /* */
  14. /* You should have received a copy of the GNU General Public License along */
  15. /* with This program; see the file COPYING. If not,write to the Free Software */
  16. /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  17. /*******************************************************************************/
  18. /* This is the Timeline widget, which contains all the tracks and
  19. * provides cursor overlays, scrolling, zooming, measure lines, tempo
  20. * map and just about everything else. */
  21. #include <FL/Fl.H>
  22. #include <FL/Fl_Scroll.H>
  23. #include <FL/Fl_Pack.H>
  24. #include <FL/Fl_Scrollbar.H>
  25. #include <FL/Fl_Widget.H>
  26. #include <FL/fl_draw.H>
  27. #include <FL/Fl_Menu_Button.H>
  28. #include <FL/Fl_Panzoomer.H>
  29. #include <FL/Fl_Tile.H>
  30. #include "Timeline.H"
  31. #include "Tempo_Sequence.H"
  32. #include "Time_Sequence.H"
  33. #include "Cursor_Sequence.H"
  34. #include "Audio_Sequence.H"
  35. #include "Control_Sequence.H"
  36. #include "Sequence.H"
  37. #include "Annotation_Sequence.H"
  38. #include "Track.H"
  39. #include "Transport.H"
  40. #include "FL/menu_popup.H"
  41. #include "const.h"
  42. #include "debug.h"
  43. /* these headers are just for the NSM support */
  44. #include "Project.H"
  45. #include "TLE.H"
  46. /* */
  47. #include "OSC_Thread.H"
  48. #include "OSC/Endpoint.H"
  49. #include <unistd.h>
  50. #include <nsm.h>
  51. extern nsm_client_t *nsm;
  52. #define BASE Fl_Group
  53. #define BX this->x()
  54. #define BY this->y()
  55. bool Timeline::draw_with_measure_lines = true;
  56. bool Timeline::draw_with_cursor_overlay = true;
  57. Timeline::snap_e Timeline::snap_to = Bars;
  58. bool Timeline::snapping_on_hold = false;
  59. bool Timeline::snap_magnetic = true;
  60. bool Timeline::follow_playhead = true;
  61. bool Timeline::center_playhead = true;
  62. bool Timeline::playback_latency_compensation = false;
  63. const float UPDATE_FREQ = 1.0f / 18.0f;
  64. extern const char *instance_name;
  65. extern TLE *tle;
  66. /** return the combined height of all visible children of (veritcal)
  67. pack, /p/. This is necessary because pack sizes are adjusted only
  68. when the relevant areas are exposes. */
  69. static int
  70. pack_visible_height ( const Fl_Pack *p )
  71. {
  72. int th = 0;
  73. const Fl_Widget* const *w = p->array();
  74. for ( int i = p->children(); i--; ++w )
  75. if ( (*w)->visible() )
  76. th += (*w)->h() + p->spacing();
  77. return th;
  78. }
  79. #define BP fl_begin_polygon()
  80. #define EP fl_end_polygon()
  81. #define vv(x,y) fl_vertex( x, y )
  82. #define BL fl_begin_line()
  83. #define EL fl_end_line()
  84. void
  85. draw_full_arrow_symbol ( Fl_Color color )
  86. {
  87. /* draw cap */
  88. fl_color( color );
  89. BP;
  90. vv( -1, -1 );
  91. vv( 0, 1 );
  92. vv( 1, -1 );
  93. EP;
  94. /* draw cap outline */
  95. fl_color( FL_BLACK );
  96. BL;
  97. vv( -1, -1 );
  98. vv( 0, 1 );
  99. vv( 1, -1 );
  100. EL;
  101. }
  102. class Timeline::Timeline_Panzoomer : public Fl_Panzoomer
  103. {
  104. public:
  105. Timeline_Panzoomer ( int X,int Y,int W,int H, const char *L=0)
  106. : Fl_Panzoomer(X,Y,W,H)
  107. {
  108. }
  109. protected:
  110. void
  111. draw_background ( int X, int Y,int W, int H )
  112. {
  113. nframes_t ef = timeline->x_to_ts( _xmax );
  114. double ty = Y;
  115. for ( int i = 0; i < timeline->tracks->children(); i++ )
  116. {
  117. Track *t = (Track*)timeline->tracks->child( i );
  118. Sequence *s = t->sequence();
  119. if ( !s )
  120. continue;
  121. fl_color( FL_DARK1 );
  122. const double scale = (double)H / ( pack_visible_height( timeline->tracks ) );
  123. // double th = (double)H / timeline->tracks->children();
  124. const double th = t->h() * scale;
  125. fl_line( X, ty,
  126. X + W, ty );
  127. for ( list <Sequence_Widget *>::const_iterator r = s->_widgets.begin();
  128. r != s->_widgets.end(); ++r )
  129. {
  130. fl_rectf(
  131. X + ( W * ( (double)(*r)->start() / ef ) ),
  132. ty,
  133. W * ( (double)(*r)->length() / ef ),
  134. th,
  135. (*r)->actual_box_color());
  136. }
  137. fl_font( FL_HELVETICA, th );
  138. fl_color( FL_FOREGROUND_COLOR );
  139. fl_draw( t->name(), X, ty, W, th, (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_INSIDE ));
  140. ty += th;
  141. }
  142. }
  143. };
  144. void
  145. Timeline::redraw_overlay ( void )
  146. {
  147. ((Fl_Overlay_Window*)window())->redraw_overlay();
  148. }
  149. nframes_t
  150. Timeline::range_start ( void ) const
  151. {
  152. if ( edit_cursor_track->active_cursor() )
  153. return edit_cursor_track->active_cursor()->start();
  154. else
  155. return 0;
  156. }
  157. nframes_t
  158. Timeline::range_end ( void ) const
  159. {
  160. if ( edit_cursor_track->active_cursor() )
  161. return edit_cursor_track->active_cursor()->start() + edit_cursor_track->active_cursor()->length();
  162. else
  163. return 0;
  164. }
  165. void
  166. Timeline::range_start ( nframes_t n )
  167. {
  168. if ( ! edit_cursor_track->active_cursor() )
  169. new Cursor_Region( 0, 0, "Edit", NULL );
  170. Logger log( edit_cursor_track->active_cursor() );
  171. edit_cursor_track->active_cursor()->set_left( n );
  172. }
  173. void
  174. Timeline::range_end ( nframes_t n )
  175. {
  176. if ( ! edit_cursor_track->active_cursor() )
  177. new Cursor_Region( 0, 0, "Edit", NULL );
  178. Logger log( edit_cursor_track->active_cursor() );
  179. edit_cursor_track->active_cursor()->set_right( n );
  180. }
  181. /** return first frame of playback (might not be 0) */
  182. nframes_t
  183. Timeline::playback_home ( void ) const
  184. {
  185. if ( play_cursor_track->active_cursor() )
  186. return play_cursor_track->active_cursor()->start();
  187. else
  188. return 0;
  189. }
  190. /** return last frame of playback */
  191. nframes_t
  192. Timeline::playback_end ( void ) const
  193. {
  194. if ( play_cursor_track->active_cursor() )
  195. return play_cursor_track->active_cursor()->start() + play_cursor_track->active_cursor()->length();
  196. else
  197. return length();
  198. }
  199. void
  200. Timeline::reset_range ( void )
  201. {
  202. delete edit_cursor_track->active_cursor();
  203. }
  204. /** callback used by Loggable class to create a snapshot of system
  205. * state. */
  206. void
  207. Timeline::snapshot ( void )
  208. {
  209. tempo_track->log_children();
  210. time_track->log_children();
  211. edit_cursor_track->log_children();
  212. punch_cursor_track->log_children();
  213. play_cursor_track->log_children();
  214. update_track_order();
  215. for ( int i = 0; i < tracks->children(); ++i )
  216. {
  217. ((Track*)tracks->child( i ))->log_children();
  218. }
  219. }
  220. /** recalculate the size of horizontal scrolling area and inform scrollbar */
  221. void
  222. Timeline::adjust_panzoomer ( void )
  223. {
  224. panzoomer->y_value( panzoomer->y_value(), h() - rulers->h() - panzoomer->h(), 0, pack_visible_height( tracks ));
  225. panzoomer->x_value( ts_to_x( xoffset ), /* pos */
  226. tracks->w() - Track::width(), /* window size */
  227. 0, /* min */
  228. max( ts_to_x( length() ), tracks->w() - Track::width() )/* max */
  229. );
  230. }
  231. void
  232. Timeline::cb_scroll ( Fl_Widget *w, void *v )
  233. {
  234. ((Timeline*)v)->cb_scroll( w );
  235. }
  236. void
  237. Timeline::cb_scroll ( Fl_Widget *w )
  238. {
  239. //adjust_panzoomer();
  240. if ( panzoomer->zoom_changed() )
  241. {
  242. nframes_t under_mouse = x_to_offset( Fl::event_x() );
  243. _fpp = panzoomer->zoom();
  244. panzoomer->x_value( ts_to_x( under_mouse ) );
  245. redraw();
  246. }
  247. if ( _old_yposition != panzoomer->y_value() )
  248. {
  249. tracks->position( tracks->x(), track_window->y() - (int)panzoomer->y_value() );
  250. damage( FL_DAMAGE_SCROLL );
  251. }
  252. if ( _old_xposition != x_to_ts( panzoomer->x_value() ))
  253. {
  254. damage( FL_DAMAGE_SCROLL );
  255. xposition( panzoomer->x_value() );
  256. }
  257. }
  258. void
  259. Timeline::menu_cb ( Fl_Widget *w, void *v )
  260. {
  261. ((Timeline*)v)->menu_cb( (Fl_Menu_*)w );
  262. }
  263. /** ensure that p1 is less than range_end() */
  264. void
  265. Timeline::fix_range ( void )
  266. {
  267. if ( range_start() > range_end() )
  268. {
  269. nframes_t t = range_end();
  270. range_end( range_start() );
  271. range_start( t );
  272. }
  273. }
  274. /** set the range to /start/ + /length/ */
  275. void
  276. Timeline::range ( nframes_t start, nframes_t length )
  277. {
  278. range_start( start );
  279. range_end( start + length );
  280. redraw();
  281. }
  282. /** create a new take for every armed track */
  283. void
  284. Timeline::add_take_for_armed_tracks ( void )
  285. {
  286. THREAD_ASSERT( UI );
  287. track_lock.wrlock();
  288. for ( int i = tracks->children(); i-- ; )
  289. {
  290. Track *t = (Track*)tracks->child( i );
  291. if ( t->armed() && t->sequence()->_widgets.size() )
  292. t->sequence( new Audio_Sequence( t ) );
  293. }
  294. track_lock.unlock();
  295. }
  296. void
  297. Timeline::menu_cb ( Fl_Menu_ *m )
  298. {
  299. if ( ! active_r() )
  300. return;
  301. const char *picked = m->mvalue()->label();
  302. /* m->item_pathname( picked, sizeof( picked ) ); */
  303. DMESSAGE( "%s", picked );
  304. if ( ! strcmp( picked, "Add audio track" ) )
  305. {
  306. /* FIXME: prompt for I/O config? */
  307. Loggable::block_start();
  308. /* add audio track */
  309. char *name = get_unique_track_name( "Audio" );
  310. Track *t = new Track( name );
  311. free( name );
  312. Audio_Sequence *o = new Audio_Sequence( t );
  313. add_track( t );
  314. t->sequence( o );
  315. t->take_focus();
  316. Loggable::block_end();
  317. }
  318. else if ( ! strcmp( picked, "Tempo from edit (beat)" ) )
  319. {
  320. if ( range_start() != range_end() )
  321. {
  322. fix_range();
  323. beats_per_minute( range_start(), sample_rate() * 60 / (float)( range_end() - range_start() ) );
  324. range_end( range_start() );
  325. }
  326. }
  327. else if ( ! strcmp( picked, "Tempo from edit (bar)" ) )
  328. {
  329. if ( range_start() != range_end() )
  330. {
  331. fix_range();
  332. position_info pi = solve_tempomap( range_start() );
  333. beats_per_minute( range_start(), sample_rate() * 60 / (float)( ( range_end() - range_start() ) / pi.beats_per_bar ) );
  334. range_end( range_start() );
  335. }
  336. }
  337. else if ( ! strcmp( picked, "Playhead to mouse" ) )
  338. {
  339. int X = Fl::event_x() - Track::width();
  340. if ( X > 0 )
  341. {
  342. transport->locate( xoffset + x_to_ts( X ) );
  343. }
  344. }
  345. else if ( ! strcmp( picked, "Edit start to mouse" ) )
  346. {
  347. int X = Fl::event_x() - Track::width();
  348. if ( X > 0 )
  349. {
  350. range_start( xoffset + x_to_ts( X ) );
  351. }
  352. fix_range();
  353. /* FIXME: only needs to damage the location of the old cursor! */
  354. redraw();
  355. }
  356. else if ( ! strcmp( picked, "Edit end to mouse" ) )
  357. {
  358. int X = Fl::event_x() - Track::width();
  359. if ( X > 0 )
  360. {
  361. range_end( xoffset + x_to_ts( X ) );
  362. }
  363. fix_range();
  364. /* FIXME: only needs to damage the location of the old cursor! */
  365. redraw();
  366. }
  367. else if ( ! strcmp( picked, "Playhead left beat" ) )
  368. {
  369. nframes_t f = transport->frame;
  370. if ( prev_line( &f ) )
  371. transport->locate( f );
  372. }
  373. else if ( ! strcmp( picked, "Playhead right beat" ) )
  374. {
  375. nframes_t f = transport->frame;
  376. if ( next_line( &f ) )
  377. transport->locate( f );
  378. }
  379. else if ( ! strcmp( picked, "Playhead left bar" ) )
  380. {
  381. nframes_t f = transport->frame;
  382. if ( prev_line( &f, true ) )
  383. transport->locate( f );
  384. }
  385. else if ( ! strcmp( picked, "Playhead right bar" ) )
  386. {
  387. nframes_t f = transport->frame;
  388. if ( next_line( &f, true ) )
  389. transport->locate( f );
  390. }
  391. else if ( ! strcmp( picked, "Swap edit start and playhead" ) )
  392. {
  393. nframes_t t = transport->frame;
  394. transport->locate( range_start() );
  395. range_start( t );
  396. redraw();
  397. }
  398. else if ( ! strcmp( picked, "Swap edit end and playhead" ) )
  399. {
  400. nframes_t t = transport->frame;
  401. transport->locate( range_end() );
  402. range_end( t );
  403. redraw();
  404. }
  405. else if ( ! strcmp( picked, "Edit start to playhead" ) )
  406. {
  407. range_start( transport->frame );
  408. redraw();
  409. }
  410. else if ( ! strcmp( picked, "Edit end to playhead" ) )
  411. {
  412. range_end( transport->frame );
  413. redraw();
  414. }
  415. else if ( ! strcmp( picked, "Punch from edit" ) )
  416. {
  417. if ( range_start() != range_end() )
  418. {
  419. Loggable::block_start();
  420. new Cursor_Region( range_start(), range_end() - range_start(), "Punch", NULL );
  421. reset_range();
  422. Loggable::block_end();
  423. }
  424. redraw();
  425. }
  426. else if ( ! strcmp( picked, "Playback from edit" ) )
  427. {
  428. if ( range_start() != range_end() )
  429. {
  430. Loggable::block_start();
  431. if ( play_cursor_track->active_cursor() )
  432. {
  433. play_cursor_track->active_cursor()->start( range_start() );
  434. play_cursor_track->active_cursor()->set_right( range_end() );
  435. }
  436. else
  437. {
  438. new Cursor_Region( range_start(), range_end() - range_start(), "Playback", NULL );
  439. }
  440. reset_range();
  441. Loggable::block_end();
  442. }
  443. redraw();
  444. }
  445. else if ( ! strcmp( picked, "Redraw" ) )
  446. {
  447. redraw();
  448. }
  449. else
  450. WARNING( "programming error: Unknown menu item" );
  451. }
  452. int
  453. Timeline::ntracks ( void ) const
  454. {
  455. return tracks->children();
  456. }
  457. Timeline::~Timeline ( )
  458. {
  459. delete osc_thread;
  460. osc_thread = 0;
  461. delete osc;
  462. osc = 0;
  463. }
  464. Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : BASE( X, Y, W, H, L )
  465. {
  466. Loggable::snapshot_callback( &Timeline::snapshot, this );
  467. edit_cursor_track = NULL;
  468. punch_cursor_track = NULL;
  469. play_cursor_track = NULL;
  470. _created_new_takes = 0;
  471. osc_thread = 0;
  472. _sample_rate = 44100;
  473. box( FL_FLAT_BOX );
  474. xoffset = 0;
  475. _old_yposition = 0;
  476. _old_xposition = 0;
  477. // range_start( range_end( 0 ) );
  478. menu = new Fl_Menu_Button( 0, 0, 0, 0, "Timeline" );
  479. /* menu->add( "Add Track", 0, 0, 0 ); */
  480. int ruler_height = 0;
  481. menu->add( "Add audio track", 'a', 0, 0 );
  482. menu->add( "Tempo from edit (beat)", 't', 0, 0 );
  483. menu->add( "Tempo from edit (bar)", FL_CTRL + 't', 0, 0 );
  484. menu->add( "Playhead to mouse", 'p', 0, 0 );
  485. menu->add( "Edit start to mouse", '[', 0, 0 );
  486. menu->add( "Edit end to mouse", ']', 0, 0 );
  487. menu->add( "Playhead left beat", FL_SHIFT + FL_Left, 0, 0 );
  488. menu->add( "Playhead right beat", FL_SHIFT + FL_Right, 0, 0 );
  489. menu->add( "Playhead left bar", FL_CTRL + FL_SHIFT + FL_Left, 0, 0 );
  490. menu->add( "Playhead right bar", FL_CTRL + FL_SHIFT + FL_Right, 0, 0 );
  491. menu->add( "Swap edit start and playhead", FL_CTRL + FL_SHIFT + '[', 0, 0 );
  492. menu->add( "Swap edit end and playhead", FL_CTRL + FL_SHIFT + ']', 0, 0 );
  493. menu->add( "Edit start to playhead", FL_CTRL + '[', 0, 0 );
  494. menu->add( "Edit end to playhead", FL_CTRL + ']', 0, 0 );
  495. menu->add( "Punch from edit", FL_CTRL + FL_SHIFT + 'p', 0, 0 );
  496. menu->add( "Playback from edit", FL_CTRL + FL_SHIFT + 'l', 0, 0 );
  497. menu->add( "Redraw", FL_CTRL + 'l', 0, 0 );
  498. menu_set_callback( const_cast<Fl_Menu_Item*>(menu->menu()), &Timeline::menu_cb, (void*)this );
  499. {
  500. Fl_Pack *o = new Fl_Pack( X, Y, W, 1, "rulers" );
  501. o->type( Fl_Pack::VERTICAL );
  502. {
  503. Tempo_Sequence *o = new Tempo_Sequence( 0, 0, 800, 18 );
  504. o->color( FL_DARK1 );
  505. /* o->label( "Tempo" ); */
  506. tempo_track = o;
  507. }
  508. {
  509. Time_Sequence *o = new Time_Sequence( 0, 24, 800, 18 );
  510. o->color( FL_DARK2 );
  511. /* o->name( "Time" ); */
  512. time_track = o;
  513. }
  514. {
  515. Cursor_Sequence *o = new Cursor_Sequence( 0, 24, 800, 18 );
  516. o->color( FL_DARK1 );
  517. o->label( "Edit" );
  518. o->cursor_color( FL_YELLOW );
  519. edit_cursor_track = o;
  520. }
  521. {
  522. Cursor_Sequence *o = new Cursor_Sequence( 0, 24, 800, 18 );
  523. o->color( FL_DARK2 );
  524. o->label( "Punch" );
  525. o->cursor_color( FL_RED );
  526. punch_cursor_track = o;
  527. }
  528. {
  529. Cursor_Sequence *o = new Cursor_Sequence( 0, 24, 800, 18 );
  530. o->color( FL_DARK1 );
  531. o->label( "Playback" );
  532. o->cursor_color( FL_GREEN );
  533. play_cursor_track = o;
  534. }
  535. /* { */
  536. /* Annotation_Sequence *o = new Annotation_Sequence( 0, 24, 800, 24 ); */
  537. /* o->color( fl_gray_ramp( 'F' ) ); */
  538. /* o->label( "Ruler" ); */
  539. /* o->align( FL_ALIGN_LEFT ); */
  540. /* ruler_track = o; */
  541. /* } */
  542. rulers = o;
  543. o->end();
  544. ruler_height = o->child( 0 )->h() * o->children();
  545. DMESSAGE( "Ruler height: %i", ruler_height );
  546. o->size( o->w(), ruler_height );
  547. }
  548. {
  549. Fl_Tile *o = new Fl_Tile( X, rulers->y() + ruler_height, W, H - rulers->h() );
  550. o->box(FL_FLAT_BOX);
  551. o->when( FL_WHEN_RELEASE );
  552. {
  553. Fl_Group *o = new Fl_Group( X, rulers->y() + rulers->h(), W, ( H - rulers->h() ) - 50 );
  554. o->box(FL_FLAT_BOX);
  555. o->clip_children(true);
  556. o->resizable(NULL);
  557. {
  558. _fpp = 8;
  559. Fl_Pack *o = new Fl_Pack( X, rulers->y() + rulers->h(), W, 1 );
  560. o->type( Fl_Pack::VERTICAL );
  561. o->spacing( 1 );
  562. tracks = o;
  563. o->end();
  564. /* Fl_Group::current()->resizable( o ); */
  565. }
  566. o->end();
  567. track_window = o;
  568. }
  569. {
  570. Fl_Panzoomer *o = new Timeline_Panzoomer( X,
  571. track_window->y() + track_window->h(),
  572. W,
  573. 50 );
  574. o->zoom_range( 1, 20 );
  575. o->zoom( 8 );
  576. o->box( FL_FLAT_BOX );
  577. o->color( FL_DARK1 );
  578. o->type( FL_HORIZONTAL );
  579. o->callback( cb_scroll, this );
  580. panzoomer = o;
  581. }
  582. /* this is used to define the sizing limits of the enclosing Fl_Tile */
  583. Fl_Box *spacebox = new Fl_Box( 0,0,1,1 );
  584. /* doesn't need to be visible */
  585. spacebox->hide();
  586. o->end();
  587. o->resizable( spacebox );
  588. spacebox->resize( X, rulers->y() + ( ( H - rulers->h() ) - 50 ),
  589. W, 125 );
  590. o->position( panzoomer->x(), panzoomer->y(),
  591. panzoomer->x(), track_window->y() + track_window->h() );
  592. tile = o;
  593. resizable(o);
  594. }
  595. /* rulers go above tracks... */
  596. add( rulers );
  597. /* redraw(); */
  598. end();
  599. Fl::add_timeout( UPDATE_FREQ, update_cb, this );
  600. }
  601. void
  602. Timeline::beats_per_minute ( nframes_t when, float bpm )
  603. {
  604. tempo_track->add( new Tempo_Point( when, bpm ) );
  605. }
  606. void
  607. Timeline::time ( nframes_t when, int bpb, int note_type )
  608. {
  609. time_track->add( new Time_Point( when, bpb, note_type ) );
  610. }
  611. /************/
  612. /* Snapping */
  613. /************/
  614. struct nearest_line_arg
  615. {
  616. nframes_t original;
  617. nframes_t closest;
  618. bool bar;
  619. };
  620. const int snap_pixel = 10;
  621. static nframes_t
  622. abs_diff ( nframes_t n1, nframes_t n2 )
  623. {
  624. return n1 > n2 ? n1 - n2 : n2 - n1;
  625. }
  626. static void
  627. nearest_line_snap_cb ( nframes_t frame, const BBT &bbt, void *arg )
  628. {
  629. nearest_line_arg *n = (nearest_line_arg *)arg;
  630. if ( n->bar && bbt.beat )
  631. return;
  632. if ( Timeline::snap_magnetic &&
  633. abs_diff( frame, n->original ) > timeline->x_to_ts( snap_pixel ) )
  634. return;
  635. if ( abs_diff( frame, n->original ) < abs_diff( n->original, n->closest ) )
  636. n->closest = frame;
  637. }
  638. static void
  639. nearest_line_cb ( nframes_t frame, const BBT &bbt, void *arg )
  640. {
  641. nearest_line_arg *n = (nearest_line_arg *)arg;
  642. if ( n->bar && bbt.beat )
  643. return;
  644. if ( abs_diff( frame, n->original ) < abs_diff( n->original, n->closest ) )
  645. n->closest = frame;
  646. }
  647. static void
  648. prev_next_line_cb ( nframes_t frame, const BBT &bbt, void *arg )
  649. {
  650. nearest_line_arg *n = (nearest_line_arg *)arg;
  651. if ( n->bar && bbt.beat )
  652. return;
  653. if ( abs_diff( frame, n->original ) < abs_diff( n->original, n->closest ) )
  654. n->closest = frame;
  655. }
  656. /** Set the value pointed to by /frame/ to the frame number of the of
  657. the nearest measure line to /when/. Returns true if the new value of
  658. *frame is valid, false otherwise. */
  659. bool
  660. Timeline::nearest_line ( nframes_t *frame, bool snap ) const
  661. {
  662. if ( snap && ( snapping_on_hold || None == Timeline::snap_to ) )
  663. return false;
  664. nframes_t when = *frame;
  665. nearest_line_arg n = { when, JACK_MAX_FRAMES, snap && Timeline::Bars == Timeline::snap_to };
  666. render_tempomap( when > x_to_ts( w() >> 1 ) ? when - x_to_ts( w() >> 1 ) : 0,
  667. when + x_to_ts( w() >> 1 ), snap ? nearest_line_snap_cb : nearest_line_cb, &n );
  668. if ( n.closest == JACK_MAX_FRAMES )
  669. return false;
  670. else
  671. {
  672. *frame = n.closest;
  673. return true;
  674. }
  675. }
  676. /** Set the value pointed to by /frame/ to the frame number of the of
  677. the nearest measure line to *greater than* /when/. Returns true if
  678. the new value of *frame is valid, false otherwise. */
  679. bool
  680. Timeline::next_line ( nframes_t *frame, bool bar ) const
  681. {
  682. const nframes_t when = *frame + 1;
  683. nearest_line_arg n = { when, JACK_MAX_FRAMES, bar };
  684. const nframes_t window = sample_rate() * 60;
  685. nframes_t length = window;
  686. if ( when > JACK_MAX_FRAMES - length )
  687. length = JACK_MAX_FRAMES - when;
  688. render_tempomap( when, length, prev_next_line_cb, &n );
  689. *frame = n.closest;
  690. return true;
  691. }
  692. /** Set the value pointed to by /frame/ to the frame number of the of
  693. the nearest measure line to *less than* /when/. Returns true if
  694. the new value of *frame is valid, false otherwise. */
  695. bool
  696. Timeline::prev_line ( nframes_t *frame, bool bar ) const
  697. {
  698. if ( ! *frame )
  699. return false;
  700. const nframes_t when = *frame - 1;
  701. nearest_line_arg n = { when, 0, bar };
  702. const nframes_t window = sample_rate() * 60;
  703. nframes_t start = 0;
  704. nframes_t length = when;
  705. if ( when > window )
  706. {
  707. start = when - window;
  708. length = window;
  709. }
  710. render_tempomap( start, length, prev_next_line_cb, &n );
  711. *frame = n.closest;
  712. return true;
  713. }
  714. /** given screen pixel coordinate /x/ return frame offset into
  715. * timeline, taking into account the current scroll position, widget
  716. * layout, etc. */
  717. nframes_t
  718. Timeline::x_to_offset ( int x ) const
  719. {
  720. int d = x - Track::width();
  721. int64_t r;
  722. if ( d < 0 )
  723. r = (int64_t)xoffset - x_to_ts( 0 - d );
  724. else
  725. r = (int64_t)xoffset + x_to_ts( d );
  726. if ( r > JACK_MAX_FRAMES )
  727. return JACK_MAX_FRAMES;
  728. else if ( r < 0 )
  729. return 0;
  730. else
  731. return r;
  732. }
  733. int
  734. Timeline::offset_to_x ( nframes_t frame ) const
  735. {
  736. return ts_to_x( frame - xoffset ) + Track::width();
  737. }
  738. /** draws a single measure line */
  739. void
  740. Timeline::draw_measure_cb ( nframes_t frame, const BBT &bbt, void *v )
  741. {
  742. Timeline *o = (Timeline*)v;
  743. Fl_Color c = FL_LIGHT3;
  744. if ( o->panzoomer->zoom() >= 15 )
  745. return;
  746. if ( bbt.beat )
  747. {
  748. if ( o->panzoomer->zoom() > 12 )
  749. return;
  750. else
  751. c = FL_DARK1;
  752. }
  753. fl_color( fl_color_add_alpha( c, 64 ) );
  754. const int x = timeline->ts_to_x( frame - timeline->xoffset ) + Track::width();
  755. fl_line( x, 0, x, 2000 );
  756. }
  757. /* FIXME: wrong place for this */
  758. const float ticks_per_beat = 1920.0;
  759. /** re-render the unified tempomap based on the current contents of the Time and Tempo sequences */
  760. void
  761. Timeline::update_tempomap ( void )
  762. {
  763. /* FIXME: we need some type of locking! */
  764. _tempomap.clear();
  765. for ( list <Sequence_Widget *>::const_iterator i = time_track->_widgets.begin();
  766. i != time_track->_widgets.end(); ++i )
  767. _tempomap.push_back( *i );
  768. for ( list <Sequence_Widget *>::const_iterator i = tempo_track->_widgets.begin();
  769. i != tempo_track->_widgets.end(); ++i )
  770. _tempomap.push_back( *i );
  771. _tempomap.sort( Sequence_Widget::sort_func );
  772. }
  773. /** return a stucture containing the BBT info which applies at /frame/ */
  774. position_info
  775. Timeline::solve_tempomap ( nframes_t frame ) const
  776. {
  777. return render_tempomap( frame, 0, 0, 0 );
  778. }
  779. /* THREAD: UI and RT */
  780. /** draw appropriate measure lines inside the given bounding box */
  781. position_info
  782. Timeline::render_tempomap( nframes_t start, nframes_t length, measure_line_callback * cb, void *arg ) const
  783. {
  784. const nframes_t end = start + length;
  785. position_info pos;
  786. memset( &pos, 0, sizeof( pos ) );
  787. BBT &bbt = pos.bbt;
  788. /* default values */
  789. pos.beat_type = 4;
  790. pos.beats_per_bar = 4;
  791. pos.tempo = 120.0;
  792. const nframes_t samples_per_minute = sample_rate() * 60;
  793. float bpm = 120.0f;
  794. time_sig sig;
  795. sig.beats_per_bar = 4;
  796. sig.beat_type = 4;
  797. nframes_t f = 0;
  798. nframes_t next = 0;
  799. nframes_t frames_per_beat = samples_per_minute / bpm;
  800. if ( ! _tempomap.size() )
  801. return pos;
  802. for ( list <const Sequence_Widget *>::const_iterator i = _tempomap.begin();
  803. i != _tempomap.end(); ++i )
  804. {
  805. if ( ! strcmp( (*i)->class_name(), "Tempo_Point" ) )
  806. {
  807. const Tempo_Point *p = (Tempo_Point*)(*i);
  808. bpm = p->tempo();
  809. frames_per_beat = samples_per_minute / bpm;
  810. }
  811. else
  812. {
  813. const Time_Point *p = (Time_Point*)(*i);
  814. sig = p->time();
  815. /* Time point resets beat */
  816. bbt.beat = 0;
  817. }
  818. {
  819. list <const Sequence_Widget *>::const_iterator n = i;
  820. ++n;
  821. if ( n == _tempomap.end() )
  822. next = end;
  823. else
  824. // next = min( (*n)->start(), end );
  825. /* points may not always be aligned with beat boundaries, so we must align here */
  826. next = (*n)->start() - ( ( (*n)->start() - (*i)->start() ) % frames_per_beat );
  827. }
  828. for ( ; f < next; ++bbt.beat, f += frames_per_beat )
  829. {
  830. if ( bbt.beat == sig.beats_per_bar )
  831. {
  832. bbt.beat = 0;
  833. ++bbt.bar;
  834. }
  835. if ( f >= start )
  836. {
  837. /* in the zone */
  838. if ( cb )
  839. cb( f, bbt, arg );
  840. }
  841. /* ugliness to avoid failing out at -1 */
  842. if ( end >= frames_per_beat )
  843. {
  844. if ( f >= end - frames_per_beat )
  845. goto done;
  846. }
  847. else if ( f + frames_per_beat >= end )
  848. goto done;
  849. }
  850. }
  851. done:
  852. pos.frame = f;
  853. pos.tempo = bpm;
  854. pos.beats_per_bar = sig.beats_per_bar;
  855. pos.beat_type = sig.beat_type;
  856. assert( f <= end );
  857. assert( end - f <= frames_per_beat );
  858. /* FIXME: this this right? */
  859. const double frames_per_tick = frames_per_beat / ticks_per_beat;
  860. bbt.tick = ( end - f ) / frames_per_tick;
  861. return pos;
  862. }
  863. /** maybe draw appropriate measure lines in rectangle defined by X, Y, W, and H, using color /color/ as a base */
  864. void
  865. Timeline::draw_measure_lines ( int X, int Y, int W, int H )
  866. {
  867. if ( ! draw_with_measure_lines )
  868. return;
  869. fl_line_style( FL_SOLID, 0 );
  870. const nframes_t start = x_to_offset( X );
  871. const nframes_t length = x_to_ts( W );
  872. fl_push_clip( X, Y, W, H );
  873. render_tempomap( start, length, draw_measure_cb, this );
  874. fl_pop_clip();
  875. }
  876. void
  877. Timeline::draw_clip_rulers ( void * v, int X, int Y, int W, int H )
  878. {
  879. Timeline *tl = (Timeline *)v;
  880. fl_push_clip( X, Y, W, H );
  881. tl->draw_box();
  882. tl->draw_child( *tl->rulers );
  883. fl_pop_clip();
  884. }
  885. void
  886. Timeline::draw_clip_tracks ( void * v, int X, int Y, int W, int H )
  887. {
  888. Timeline *tl = (Timeline *)v;
  889. fl_push_clip( X, Y, W, H );
  890. tl->draw_box();
  891. fl_damage_t pzd = tl->panzoomer->damage();
  892. tl->draw_child( *tl->tile );
  893. tl->panzoomer->damage( pzd );
  894. fl_pop_clip();
  895. }
  896. /** handle resize event */
  897. void
  898. Timeline::resize ( int X, int Y, int W, int H )
  899. {
  900. int old_panzoomer_h = panzoomer->h();
  901. BASE::resize( X, Y, W, H );
  902. tile->resizable()->resize( X,
  903. tile->y() + tile->h() - 150,
  904. W, 125 );
  905. panzoomer->resize( X,
  906. tile->y() + tile->h() - old_panzoomer_h,
  907. W,
  908. old_panzoomer_h );
  909. track_window->resize( X,
  910. tile->y(),
  911. W,
  912. tile->h() - panzoomer->h());
  913. tracks->resize( tracks->x(), tracks->y(), W, tracks->h() );
  914. /* /\* rulers->resize( X, *\/ */
  915. /* /\* rulers->y(), *\/ */
  916. /* /\* W, *\/ */
  917. /* /\* rulers->h() ); *\/ */
  918. /* tile->redraw(); */
  919. }
  920. void
  921. Timeline::add_cursor ( Cursor_Region *o )
  922. {
  923. if ( !strcmp( o->type(), "Edit" ) )
  924. {
  925. DMESSAGE( "Adding cursor to edit track" );
  926. edit_cursor_track->add( o );
  927. }
  928. else if ( !strcmp( o->type(), "Punch" ) )
  929. {
  930. DMESSAGE( "Adding cursor to punch track" );
  931. punch_cursor_track->add( o );
  932. }
  933. else if ( !strcmp( o->type(), "Playback" ) )
  934. {
  935. DMESSAGE( "Adding cursor to punch track" );
  936. play_cursor_track->add( o );
  937. }
  938. }
  939. void
  940. Timeline::add_cursor ( Cursor_Point *o )
  941. {
  942. if ( !strcmp( o->type(), "Edit" ) )
  943. edit_cursor_track->add( o );
  944. else if ( !strcmp( o->type(), "Punch" ) )
  945. punch_cursor_track->add( o );
  946. }
  947. void
  948. Timeline::draw_cursors ( Cursor_Sequence *o ) const
  949. {
  950. fl_push_clip( tracks->x() + Track::width(), rulers->y() + rulers->h(), tracks->w() - Track::width(), h() - rulers->h() - panzoomer->h() );
  951. if ( o && o->_widgets.size() > 0 )
  952. {
  953. for ( std::list<Sequence_Widget*>::const_iterator i = o->_widgets.begin();
  954. i != o->_widgets.end();
  955. i++ )
  956. {
  957. if ( Timeline::draw_with_cursor_overlay )
  958. {
  959. fl_color( fl_color_add_alpha( (*i)->box_color(), 25 ) );
  960. fl_rectf( (*i)->line_x(), tracks->y(), (*i)->abs_w(), tracks->h() );
  961. }
  962. else
  963. {
  964. fl_color( fl_color_add_alpha( (*i)->box_color(), 127 ));
  965. fl_line( (*i)->line_x(), tracks->y(), (*i)->line_x(), tracks->y() + tracks->h() );
  966. fl_line( (*i)->line_x() + (*i)->abs_w(), tracks->y(), (*i)->line_x() + (*i)->abs_w(), tracks->y() + tracks->h() );
  967. }
  968. }
  969. }
  970. fl_pop_clip();
  971. }
  972. /** draw ancillary cursors (not necessarily in the overlay plane) */
  973. void
  974. Timeline::draw_cursors ( void ) const
  975. {
  976. draw_cursors( edit_cursor_track );
  977. if ( transport->punch_enabled() )
  978. draw_cursors( punch_cursor_track );
  979. }
  980. void
  981. Timeline::draw ( void )
  982. {
  983. /* Any code that might affect the structures used for drawing from
  984. * another thread must use Fl::lock()/unlock()! */
  985. THREAD_ASSERT( UI );
  986. // rdlock();
  987. int X, Y, W, H;
  988. int bdx = 0;
  989. int bdw = 0;
  990. X = tracks->x() + bdx + 1;
  991. Y = tracks->y();
  992. W = tracks->w() - bdw - 1;
  993. H = tracks->h();
  994. adjust_panzoomer();
  995. int dx = ts_to_x( _old_xposition ) - ts_to_x( xoffset );
  996. int dy = _old_yposition - (int)panzoomer->y_value();
  997. int c = damage();
  998. // c = FL_DAMAGE_ALL;
  999. if ( c & FL_DAMAGE_SCROLL )
  1000. {
  1001. {
  1002. /* draw_child( *rulers ); */
  1003. Y = track_window->y();
  1004. H = track_window->h();
  1005. if ( dx )
  1006. /* when scrolling horizontally, scroll rulers */
  1007. fl_scroll( rulers->x() + Track::width(),
  1008. rulers->y(),
  1009. rulers->w(),
  1010. rulers->h(), dx, 0, draw_clip_rulers, this );
  1011. if ( dy )
  1012. /* when scrolling vertically, also scroll track headers */
  1013. fl_scroll(
  1014. X,
  1015. Y,
  1016. Track::width(),
  1017. H, 0, dy, draw_clip_tracks, this );
  1018. /* scroll sequences */
  1019. fl_scroll( X + Track::width(),
  1020. Y,
  1021. W - Track::width(),
  1022. H, dx, dy, draw_clip_tracks, this );
  1023. }
  1024. }
  1025. // panzoomer->redraw();
  1026. if ( c & FL_DAMAGE_ALL )
  1027. {
  1028. DMESSAGE( "complete redraw" );
  1029. draw_box( box(), BX, BY, w(), h(), color() );
  1030. draw_child( *rulers );
  1031. fl_push_clip( tile->x(),
  1032. tile->y(),
  1033. tile->w(),
  1034. tile->h() );
  1035. draw_child(*tile);
  1036. fl_pop_clip();
  1037. redraw_overlay();
  1038. goto done;
  1039. }
  1040. if ( c & FL_DAMAGE_CHILD )
  1041. {
  1042. update_child(*rulers);
  1043. fl_push_clip( tile->x(),
  1044. tile->y(),
  1045. tile->w(),
  1046. tile->h() );
  1047. /* redraw the panzoomer preview whenever tracks change */
  1048. /* if ( tracks->damage() ) */
  1049. /* panzoomer->redraw(); */
  1050. update_child(*tile);
  1051. fl_pop_clip();
  1052. redraw_overlay();
  1053. }
  1054. done:
  1055. // unlock();
  1056. /* panzoomer->redraw(); */
  1057. // update_child( *panzoomer );
  1058. _old_xposition = xoffset;
  1059. _old_yposition = panzoomer->y_value();
  1060. }
  1061. void
  1062. Timeline::damage_sequence ( void )
  1063. {
  1064. panzoomer->redraw();
  1065. }
  1066. /** draw a single cursor line at /frame/ with color /color/ using symbol routine /symbol/ for the cap */
  1067. void
  1068. Timeline::draw_cursor ( nframes_t frame, Fl_Color color, void (*symbol)(Fl_Color) ) const
  1069. {
  1070. // int x = ( ts_to_x( frame ) - ts_to_x( xoffset ) ) + tracks->x() + Track::width();
  1071. if ( frame < xoffset )
  1072. return;
  1073. const int x = ts_to_x( frame - xoffset ) + tracks->x() + Track::width();
  1074. if ( x > tracks->x() + tracks->w() )
  1075. return;
  1076. const int y = rulers->y() + rulers->h();
  1077. const int h = this->h() - rulers->h() - panzoomer->h();
  1078. fl_push_clip( tracks->x() + Track::width(), y, tracks->w(), h );
  1079. fl_line_style( FL_SOLID, 0 );
  1080. fl_color( color );
  1081. fl_line( x, y, x, y + h );
  1082. fl_push_matrix();
  1083. fl_translate( x, y );
  1084. fl_scale( 8, 4 );
  1085. symbol( color );
  1086. fl_pop_matrix();
  1087. fl_pop_clip();
  1088. }
  1089. /** set /in/ and /out/ to start and end of next punch region from /frame/ */
  1090. bool
  1091. Timeline::next_punch ( nframes_t frame, nframes_t *in, nframes_t *out ) const
  1092. {
  1093. if ( !transport->punch_enabled() )
  1094. return false;
  1095. const Sequence_Widget *w = punch_cursor_track->next( frame );
  1096. if ( w && w->start() >= frame )
  1097. {
  1098. *in = w->start();
  1099. *out = w->start() + w->length();
  1100. return true;
  1101. }
  1102. return false;
  1103. }
  1104. void
  1105. Timeline::draw_playhead ( void )
  1106. {
  1107. draw_cursor( transport->frame, FL_RED, draw_full_arrow_symbol );
  1108. // draw_cursor( length(), FL_BLACK, draw_full_arrow_symbol );
  1109. }
  1110. void
  1111. Timeline::redraw_playhead ( void )
  1112. {
  1113. // static nframes_t last_playhead = -1;
  1114. static int last_playhead_x = -1;
  1115. if ( transport->rolling )
  1116. {
  1117. if ( play_cursor_track->active_cursor() )
  1118. {
  1119. if ( transport->loop_enabled() )
  1120. {
  1121. if ( transport->frame > playback_end() )
  1122. {
  1123. if ( ! seek_pending() )
  1124. {
  1125. if ( transport->recording )
  1126. {
  1127. stop();
  1128. transport->locate( playback_home() );
  1129. record();
  1130. }
  1131. else
  1132. {
  1133. transport->locate( playback_home() );
  1134. }
  1135. }
  1136. }
  1137. }
  1138. else
  1139. if ( transport->frame > playback_end() )
  1140. transport->stop();
  1141. }
  1142. }
  1143. int playhead_x = ts_to_x( transport->frame );
  1144. if ( last_playhead_x != playhead_x )
  1145. {
  1146. redraw_overlay();
  1147. // last_playhead = transport->frame;
  1148. last_playhead_x = playhead_x;
  1149. if ( follow_playhead )
  1150. {
  1151. if ( center_playhead && active() )
  1152. xposition( max( 0, playhead_x - ( ( tracks->w() - Track::width() ) >> 1 ) ) );
  1153. else if ( playhead_x > ts_to_x( xoffset ) + ( tracks->w() - Track::width() ) )
  1154. xposition( playhead_x );
  1155. adjust_panzoomer();
  1156. }
  1157. }
  1158. }
  1159. /** called so many times a second to redraw the playhead etc. */
  1160. void
  1161. Timeline::update_cb ( void *arg )
  1162. {
  1163. Fl::repeat_timeout( UPDATE_FREQ, update_cb, arg );
  1164. Timeline *tl = (Timeline *)arg;
  1165. tl->redraw_playhead();
  1166. }
  1167. /** draw cursors in overlay plane */
  1168. void
  1169. Timeline::draw_overlay ( void )
  1170. {
  1171. draw_playhead();
  1172. draw_cursors();
  1173. if ( ! ( _selection.w && _selection.h ) )
  1174. return;
  1175. fl_push_clip( tracks->x() + Track::width(), rulers->y() + rulers->h(), tracks->w() - Track::width(), h() - rulers->h() - panzoomer->h() );
  1176. const Rectangle &r = _selection;
  1177. fl_color( FL_MAGENTA );
  1178. fl_line_style( FL_SOLID, 0 );
  1179. fl_rect( r.x, r.y, r.w, r.h );
  1180. fl_pop_clip();
  1181. }
  1182. /** select sequence widgets within rectangle /r/ */
  1183. void
  1184. Timeline::select ( const Rectangle &r )
  1185. {
  1186. const int Y = r.y;
  1187. for ( int i = tracks->children(); i-- ; )
  1188. {
  1189. Track *t = (Track*)tracks->child( i );
  1190. if ( ! ( t->y() > Y + r.h || t->y() + t->h() < Y ) )
  1191. t->select( r.x, r.y, r.w, r.h, true, true );
  1192. }
  1193. }
  1194. /** delete all selected sequence widgets */
  1195. void
  1196. Timeline::delete_selected ( void )
  1197. {
  1198. Sequence_Widget::delete_selected();
  1199. }
  1200. /** clear the selection of seqeunce widgets */
  1201. void
  1202. Timeline::select_none ( void )
  1203. {
  1204. Sequence_Widget::select_none();
  1205. }
  1206. int
  1207. Timeline::nselected ( void ) const
  1208. {
  1209. return Sequence_Widget::nselected();
  1210. }
  1211. /** An unfortunate necessity for implementing our own DND aside from
  1212. * the (bogus) native FLTK system */
  1213. Track *
  1214. Timeline::track_under ( int Y )
  1215. {
  1216. for ( int i = tracks->children(); i-- ; )
  1217. {
  1218. Track *t = (Track*)tracks->child( i );
  1219. if ( ! ( t->y() > Y || t->y() + t->h() < Y ) )
  1220. return t;
  1221. }
  1222. return NULL;
  1223. }
  1224. #include "FL/event_name.H"
  1225. #include "FL/test_press.H"
  1226. /** a bit of a hack to keep FLTK's focus navigation stuff from
  1227. * stealing the arrow keys from us */
  1228. int
  1229. Timeline::handle_scroll ( int m )
  1230. {
  1231. if ( m == FL_KEYBOARD &&
  1232. Fl::event_key() != FL_Home &&
  1233. Fl::event_key() != FL_End )
  1234. return menu->test_shortcut() || panzoomer->handle( m );
  1235. else
  1236. return 0;
  1237. }
  1238. Track *
  1239. Timeline::event_inside ( void )
  1240. {
  1241. for ( int i = tracks->children(); i--; )
  1242. if ( Fl::event_inside( tracks->child(i) ) )
  1243. return (Track*)tracks->child(i);
  1244. return NULL;
  1245. }
  1246. int
  1247. Timeline::handle ( int m )
  1248. {
  1249. static Drag *drag = NULL;
  1250. static bool range = false;
  1251. /* if ( m != FL_NO_EVENT ) */
  1252. /* DMESSAGE( "%s", event_name( m ) ); */
  1253. /* int r = BASE::handle( m ); */
  1254. switch ( m )
  1255. {
  1256. case FL_ENTER:
  1257. return 1;
  1258. case FL_LEAVE:
  1259. return 1;
  1260. case FL_KEYDOWN:
  1261. if ( Fl::event_state() & ( FL_ALT | FL_CTRL | FL_SHIFT ) )
  1262. /* we don't want any keys with modifiers... */
  1263. return 0;
  1264. if ( Fl::event_key() == 'r' )
  1265. {
  1266. range = true;
  1267. return 1;
  1268. }
  1269. else if ( Fl::event_key() == 's' )
  1270. {
  1271. snapping_on_hold = true;
  1272. return 1;
  1273. }
  1274. return 0;
  1275. case FL_KEYUP:
  1276. if ( Fl::event_state() & ( FL_ALT | FL_CTRL | FL_SHIFT ) )
  1277. /* we don't want any keys with modifiers... */
  1278. return 0;
  1279. if ( Fl::event_key() == 'r' )
  1280. {
  1281. range = false;
  1282. return 1;
  1283. }
  1284. else if ( Fl::event_key() == 's' )
  1285. {
  1286. snapping_on_hold = false;
  1287. return 1;
  1288. }
  1289. return 0;
  1290. // case FL_KEYBOARD:
  1291. case FL_SHORTCUT:
  1292. {
  1293. if ( Fl::event_state() & ( FL_ALT | FL_CTRL | FL_SHIFT ) )
  1294. /* we don't want any keys with modifiers... */
  1295. return 0;
  1296. switch ( Fl::event_key() )
  1297. {
  1298. case FL_Delete:
  1299. case FL_Home:
  1300. case FL_End:
  1301. /* keep scrollbar from eating these. */
  1302. return 0;
  1303. default:
  1304. return BASE::handle( m );
  1305. }
  1306. return 0;
  1307. }
  1308. default:
  1309. {
  1310. int r = BASE::handle( m );
  1311. if ( m != FL_RELEASE && r )
  1312. return r;
  1313. const int X = Fl::event_x();
  1314. const int Y = Fl::event_y();
  1315. switch ( m )
  1316. {
  1317. case FL_PUSH:
  1318. {
  1319. if (
  1320. Fl::event_x() >= Track::width() &&
  1321. ( test_press( FL_BUTTON1 ) || test_press( FL_BUTTON1 + FL_CTRL ) ))
  1322. {
  1323. assert( ! drag );
  1324. drag = new Drag( X, Y );
  1325. _selection.x = X;
  1326. _selection.y = Y;
  1327. if ( ! Fl::event_ctrl() )
  1328. select_none();
  1329. return 1;
  1330. }
  1331. else if ( test_press( FL_BUTTON3 ) )
  1332. {
  1333. menu_popup( menu );
  1334. return 1;
  1335. }
  1336. }
  1337. return 0;
  1338. case FL_DRAG:
  1339. {
  1340. int ox = X - drag->x;
  1341. int oy = Y - drag->y;
  1342. if ( ox < 0 )
  1343. _selection.x = X;
  1344. if ( oy < 0 )
  1345. _selection.y = Y;
  1346. _selection.w = abs( ox );
  1347. _selection.h = abs( oy );
  1348. if ( range )
  1349. {
  1350. range_start( x_to_offset( _selection.x ) );
  1351. range_end( x_to_offset( _selection.x + _selection.w ) );
  1352. redraw();
  1353. }
  1354. redraw_overlay();
  1355. return 1;
  1356. break;
  1357. }
  1358. case FL_RELEASE:
  1359. {
  1360. delete drag;
  1361. drag = NULL;
  1362. if ( range )
  1363. {
  1364. range_start( x_to_offset( _selection.x ) );
  1365. range_end( x_to_offset( _selection.x + _selection.w ) );
  1366. redraw();
  1367. }
  1368. else
  1369. select( _selection );
  1370. _selection.x = _selection.y =_selection.w = _selection.h = 0;
  1371. redraw_overlay();
  1372. return 1;
  1373. }
  1374. default:
  1375. return 0;
  1376. break;
  1377. }
  1378. return 0;
  1379. }
  1380. }
  1381. }
  1382. /** retrun a pointer to the track named /name/, or NULL if no track is named /name/ */
  1383. Track *
  1384. Timeline::track_by_name ( const char *name )
  1385. {
  1386. for ( int i = tracks->children(); i-- ; )
  1387. {
  1388. Track *t = (Track*)tracks->child( i );
  1389. if ( name && t->name() && ! strcmp( name, t->name() ) )
  1390. return t;
  1391. }
  1392. return NULL;
  1393. }
  1394. /** return a malloc'd string representing a unique name for a new track */
  1395. char *
  1396. Timeline::get_unique_track_name ( const char *name )
  1397. {
  1398. char pat[256];
  1399. strcpy( pat, name );
  1400. for ( int i = 1; track_by_name( pat ); ++i )
  1401. snprintf( pat, sizeof( pat ), "%s.%d", name, i );
  1402. return strdup( pat );
  1403. }
  1404. /**********/
  1405. /* Public */
  1406. /**********/
  1407. /** return the current length of the timeline, which is arrived at by
  1408. * calculating the end frame of the rightmost audio region on an
  1409. * active audio sequence. Control_Points, etc. do not factor into this
  1410. * calcaulation. */
  1411. nframes_t
  1412. Timeline::length ( void ) const
  1413. {
  1414. nframes_t l = 0;
  1415. for ( int i = tracks->children(); i--; )
  1416. {
  1417. Sequence *t = ((Track*)tracks->child( i ))->sequence();
  1418. if ( t )
  1419. l = max( l, ((Track*)tracks->child( i ))->sequence()->length() );
  1420. }
  1421. return l;
  1422. }
  1423. /** set horizontal scroll postion to absolute pixel coordinate /X/ */
  1424. void
  1425. Timeline::xposition ( int X )
  1426. {
  1427. xoffset = x_to_ts( X );
  1428. long dx = ts_to_x( _old_xposition ) - ts_to_x( xoffset );
  1429. if ( dx )
  1430. damage( FL_DAMAGE_SCROLL );
  1431. }
  1432. /** zoom in by one zoom step */
  1433. void
  1434. Timeline::zoom_in ( void )
  1435. {
  1436. panzoomer->zoom_in();
  1437. }
  1438. /** zoom out by one zoom step */
  1439. void
  1440. Timeline::zoom_out ( void )
  1441. {
  1442. panzoomer->zoom_out();
  1443. }
  1444. /** zoom the display to show /secs/ seconds per screen */
  1445. void
  1446. Timeline::zoom ( float secs )
  1447. {
  1448. const int sw = tracks->w() - Track::width();
  1449. int fpp = (int)((secs * sample_rate()) / sw);
  1450. int p = 0;
  1451. while ( 1 << p < fpp ) p++;
  1452. panzoomer->zoom( p );
  1453. redraw();
  1454. }
  1455. /** fit the zoom to the current length of the timeline (subject to nearest power of two) */
  1456. void
  1457. Timeline::zoom_fit ( void )
  1458. {
  1459. xposition( 0 );
  1460. if ( length() )
  1461. zoom( length() / (float)sample_rate() );
  1462. else
  1463. zoom( 60 );
  1464. }
  1465. /** add /track/ to the timeline */
  1466. void
  1467. Timeline::add_track ( Track *track )
  1468. {
  1469. DMESSAGE( "added new track to the timeline" );
  1470. tracks->add( track );
  1471. /* FIXME: why is this necessary? doesn't the above add do DAMAGE_CHILD? */
  1472. redraw();
  1473. }
  1474. void
  1475. Timeline::insert_track ( Track *track, Track *before )
  1476. {
  1477. tracks->insert( *track, before );
  1478. tracks->redraw();
  1479. }
  1480. void
  1481. Timeline::insert_track ( Track *track, int n )
  1482. {
  1483. if ( n > tracks->children() || n < 0 )
  1484. return;
  1485. tracks->insert( *track, n );
  1486. tracks->redraw();
  1487. /* FIXME: why is this necessary? doesn't the above add do DAMAGE_CHILD? */
  1488. // redraw();
  1489. }
  1490. static
  1491. bool
  1492. compare_tracks ( Track *a, Track *b )
  1493. {
  1494. return *a < *b;
  1495. }
  1496. void
  1497. Timeline::apply_track_order ( void )
  1498. {
  1499. /* wrlock(); */
  1500. std::list<Track*> tl;
  1501. for ( int i = 0; i < tracks->children(); i++ )
  1502. tl.push_back( (Track*)tracks->child( i ) );
  1503. tl.sort(compare_tracks);
  1504. Fl_Widget **a = const_cast<Fl_Widget**>(tracks->array());
  1505. int j = 0;
  1506. for ( std::list<Track*>::const_iterator i = tl.begin();
  1507. i != tl.end();
  1508. i++, j++ )
  1509. a[j] = *i;
  1510. update_track_order();
  1511. /* unlock(); */
  1512. }
  1513. void
  1514. Timeline::update_track_order ( void )
  1515. {
  1516. for ( int i = 0; i < tracks->children(); i++ )
  1517. ((Track*)tracks->child( i ))->row( i );
  1518. }
  1519. int
  1520. Timeline::find_track ( const Track *track ) const
  1521. {
  1522. return tracks->find( *track );
  1523. }
  1524. /** remove /track/ from the timeline */
  1525. void
  1526. Timeline::remove_track ( Track *track )
  1527. {
  1528. DMESSAGE( "removed track from the timeline" );
  1529. /* FIXME: what to do about track contents? */
  1530. tracks->remove( track );
  1531. /* FIXME: why is this necessary? doesn't the above add do DAMAGE_CHILD? */
  1532. redraw();
  1533. }
  1534. /************/
  1535. /* Commands */
  1536. /************/
  1537. void
  1538. Timeline::command_move_track_up ( Track *track )
  1539. {
  1540. track_lock.wrlock();
  1541. insert_track( track, find_track( track ) - 1 );
  1542. track_lock.unlock();
  1543. }
  1544. void
  1545. Timeline::command_move_track_down ( Track *track )
  1546. {
  1547. track_lock.wrlock();
  1548. insert_track( track, find_track( track ) + 2 );
  1549. track_lock.unlock();
  1550. }
  1551. void
  1552. Timeline::command_remove_track ( Track *track )
  1553. {
  1554. track_lock.wrlock();
  1555. remove_track(track);
  1556. track_lock.unlock();
  1557. }
  1558. void
  1559. Timeline::command_quit ( void )
  1560. {
  1561. track_lock.wrlock();
  1562. Project::close();
  1563. track_lock.unlock();
  1564. command_save();
  1565. while ( Fl::first_window() ) Fl::first_window()->hide();
  1566. }
  1567. void
  1568. Timeline::command_undo ( void )
  1569. {
  1570. /* FIXME: sequence lock too? */
  1571. track_lock.wrlock();
  1572. Project::undo();
  1573. track_lock.unlock();
  1574. }
  1575. bool
  1576. Timeline::command_load ( const char *name, const char *display_name )
  1577. {
  1578. if ( ! name )
  1579. return false;
  1580. track_lock.wrlock();
  1581. int r = Project::open( name );
  1582. track_lock.unlock();
  1583. if ( r < 0 )
  1584. {
  1585. const char *s = Project::errstr( r );
  1586. fl_alert( "Could not open project \"%s\":\n\n\t%s", name, s );
  1587. return false;
  1588. }
  1589. if ( display_name )
  1590. Project::set_name ( display_name );
  1591. apply_track_order();
  1592. return true;
  1593. }
  1594. bool
  1595. Timeline::command_save ( )
  1596. {
  1597. tle->save_options();
  1598. return true;
  1599. }
  1600. bool
  1601. Timeline::command_new ( const char *name, const char *display_name )
  1602. {
  1603. bool b = Project::create( name, NULL );
  1604. Project::set_name ( display_name );
  1605. /* FIXME: there's other stuff that needs to be done here! */
  1606. /* tle->update_menu(); */
  1607. /* tle->main_window->redraw(); */
  1608. return b;
  1609. }
  1610. const char *
  1611. Timeline::session_manager_name ( void )
  1612. {
  1613. return nsm_get_session_manager_name( nsm );
  1614. }
  1615. /*******/
  1616. /* OSC */
  1617. /*******/
  1618. int
  1619. Timeline::init_osc ( const char *osc_port )
  1620. {
  1621. osc = new OSC::Endpoint();
  1622. if ( int r = osc->init( LO_UDP, osc_port ) )
  1623. return r;
  1624. osc->owner = this;
  1625. char *url = osc->url();
  1626. printf( "OSC=%s\n", url );
  1627. free(url);
  1628. osc->add_method( "/non/hello", "ssss", &Timeline::osc_non_hello, osc, "" );
  1629. // osc->start();
  1630. if ( ! osc_thread )
  1631. {
  1632. osc_thread = new OSC_Thread();
  1633. osc_thread->start();
  1634. }
  1635. return 0;
  1636. }
  1637. int
  1638. Timeline::osc_non_hello ( const char *, const char *, lo_arg **, int , lo_message msg, void * )
  1639. {
  1640. THREAD_ASSERT( OSC );
  1641. timeline->handle_hello(msg);
  1642. return 0;
  1643. }
  1644. void
  1645. Timeline::handle_hello ( lo_message msg )
  1646. {
  1647. int argc = lo_message_get_argc( msg );
  1648. lo_arg **argv = lo_message_get_argv( msg );
  1649. if ( argc >= 4 )
  1650. {
  1651. const char *url = &argv[0]->s;
  1652. const char *name = &argv[1]->s;
  1653. const char *version = &argv[2]->s;
  1654. const char *id = &argv[3]->s;
  1655. MESSAGE( "Got hello from NON peer %s (%s) @ %s with ID \"%s\"", name, version, url, id );
  1656. osc->handle_hello( &argv[3]->s, &argv[0]->s );
  1657. }
  1658. }
  1659. void
  1660. Timeline::say_hello ( void )
  1661. {
  1662. if ( nsm_is_active( nsm ) )
  1663. {
  1664. lo_message m = lo_message_new();
  1665. lo_message_add( m, "sssss",
  1666. "/non/hello",
  1667. osc->url(),
  1668. APP_NAME,
  1669. VERSION,
  1670. instance_name );
  1671. nsm_send_broadcast( nsm, m );
  1672. }
  1673. }
  1674. void
  1675. Timeline::connect_osc ( void )
  1676. {
  1677. /* reconnect OSC signals */
  1678. for ( int i = tracks->children(); i-- ; )
  1679. {
  1680. Track *t = (Track*)tracks->child( i );
  1681. t->connect_osc();
  1682. }
  1683. }
  1684. void
  1685. Timeline::update_osc_connection_state ( void )
  1686. {
  1687. /* reconnect OSC signals */
  1688. for ( int i = tracks->children(); i-- ; )
  1689. {
  1690. Track *t = (Track*)tracks->child( i );
  1691. t->update_osc_connection_state();
  1692. }
  1693. }
  1694. /* runs in the OSC thread... */
  1695. void
  1696. Timeline::process_osc ( void )
  1697. {
  1698. THREAD_ASSERT( OSC );
  1699. sequence_lock.rdlock();
  1700. for ( int i = tracks->children(); i-- ; )
  1701. {
  1702. Track *t = (Track*)tracks->child( i );
  1703. t->process_osc();
  1704. }
  1705. sequence_lock.unlock();
  1706. }