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.

367 lines
8.1KB

  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. /* An Audio_Sequence is a sequence of Audio_Regions. Takes and 'track
  19. * contents' consist of these objects */
  20. #include "debug.h"
  21. #include <sys/time.h>
  22. #include <FL/fl_ask.H>
  23. #include <FL/Fl.H>
  24. #include "Audio_Sequence.H"
  25. #include "Waveform.H"
  26. #include <list>
  27. using namespace std;
  28. #include "Track.H"
  29. #include "Engine/Audio_File.H" // for ::from_file()
  30. #include "Transport.H" // for locate()
  31. #include "Track_Header.H"
  32. #include <errno.h>
  33. #include <unistd.h> // for symlink()
  34. #include "string_util.h"
  35. const char *
  36. Audio_Sequence::name ( void ) const
  37. {
  38. return Sequence::name();
  39. }
  40. void
  41. Audio_Sequence::name ( const char *s )
  42. {
  43. Sequence::name( s );
  44. header()->name_input->value( s );
  45. }
  46. void
  47. Audio_Sequence::cb_button ( Fl_Widget *w, void *v )
  48. {
  49. ((Audio_Sequence*)v)->cb_button( w );
  50. }
  51. void
  52. Audio_Sequence::cb_button ( Fl_Widget *w )
  53. {
  54. Logger log(this);
  55. if ( w == header()->name_input )
  56. {
  57. Sequence::name( header()->name_input->value() );
  58. }
  59. else if ( w == header()->delete_button )
  60. {
  61. track()->remove( this );
  62. }
  63. else if ( w == header()->promote_button )
  64. {
  65. track()->sequence( this );
  66. }
  67. }
  68. void
  69. Audio_Sequence::init ( void )
  70. {
  71. labeltype( FL_NO_LABEL );
  72. {
  73. Audio_Sequence_Header *o = new Audio_Sequence_Header( x(), y(), Track::width(), 52 );
  74. o->name_input->callback( cb_button, this );
  75. o->delete_button->callback( cb_button, this );
  76. o->promote_button->callback( cb_button, this );
  77. Fl_Group::add( o );
  78. }
  79. resizable(0);
  80. }
  81. Audio_Sequence::Audio_Sequence ( Track *track, const char *name ) : Sequence( track )
  82. {
  83. _track = track;
  84. init();
  85. if ( name )
  86. Audio_Sequence::name( name );
  87. else
  88. {
  89. struct timeval tv;
  90. gettimeofday( &tv, NULL );
  91. time_t t = tv.tv_sec;
  92. char s[40];
  93. ctime_r( &t, s );
  94. s[ strlen( s ) - 1 ] = 0;
  95. Audio_Sequence::name( s );
  96. }
  97. if ( track )
  98. track->add( this );
  99. log_create();
  100. }
  101. Audio_Sequence::~Audio_Sequence ( )
  102. {
  103. Loggable::block_start();
  104. clear();
  105. log_destroy();
  106. track()->remove( this );
  107. Loggable::block_end();
  108. }
  109. /** return a pointer to the current capture region for this sequence */
  110. const Audio_Region *
  111. Audio_Sequence::capture_region ( void ) const
  112. {
  113. return track()->capture_region();
  114. }
  115. void
  116. Audio_Sequence::get ( Log_Entry &e ) const
  117. {
  118. e.add( ":track", _track );
  119. e.add( ":name", name() );
  120. }
  121. void
  122. Audio_Sequence::set ( Log_Entry &e )
  123. {
  124. for ( int i = 0; i < e.size(); ++i )
  125. {
  126. const char *s, *v;
  127. e.get( i, &s, &v );
  128. if ( ! strcmp( ":track", s ) )
  129. {
  130. int i;
  131. sscanf( v, "%X", &i );
  132. Track *t = (Track*)Loggable::find( i );
  133. assert( t );
  134. t->sequence( this );
  135. }
  136. else if ( ! strcmp( ":name", s ) )
  137. name( v );
  138. }
  139. }
  140. void
  141. Audio_Sequence::handle_widget_change ( nframes_t start, nframes_t length )
  142. {
  143. Sequence::handle_widget_change( start, length );
  144. /* a region has changed. we may need to rebuffer... */
  145. /* trigger rebuffer */
  146. /* FIXME: we really only need to rebuffer *this* sequence! */
  147. /* FIXME: how does this fit into the selection? */
  148. if ( transport->rolling && ( start > transport->frame || start + length > transport->frame ) )
  149. transport->locate( transport->frame );
  150. }
  151. void
  152. Audio_Sequence::draw ( void )
  153. {
  154. Sequence::draw();
  155. int xfades = 0;
  156. fl_push_clip( drawable_x(), y(), drawable_w(), h() );
  157. /* draw crossfades */
  158. for ( list <Sequence_Widget *>::const_iterator r = _widgets.begin(); r != _widgets.end(); r++ )
  159. {
  160. Sequence_Widget *o = overlaps( *r );
  161. if ( o )
  162. {
  163. if ( *o <= **r )
  164. {
  165. /* if ( o->x() == (*r)->x() && o->w() == (*r)->w() ) */
  166. /* printf( "complete superposition\n" ); */
  167. if ( o->contains( *r ) )
  168. /* completely inside */
  169. continue;
  170. ++xfades;
  171. Rectangle b( (*r)->x(),
  172. o->y(),
  173. (o->x() + o->w()) - (*r)->x(),
  174. o->h() );
  175. if ( b.w > 0 )
  176. {
  177. cairo_t *cc = Fl::cairo_cc();
  178. cairo_set_operator( cc, CAIRO_OPERATOR_HSL_COLOR );
  179. cairo_set_source_rgba( cc, 1, 1, 0, 0.80 );
  180. cairo_rectangle( cc, b.x, b.y, b.w, b.h );
  181. cairo_fill( cc );
  182. cairo_set_operator( cc, CAIRO_OPERATOR_OVER );
  183. }
  184. }
  185. }
  186. }
  187. fl_pop_clip();
  188. }
  189. int
  190. Audio_Sequence::handle_paste ( const char *text )
  191. {
  192. int X = Fl::event_x();
  193. if ( ! strcmp( text, "Audio_Region" ) )
  194. return 1;
  195. char *file;
  196. if ( ! sscanf( text, "file://%m[^\r\n]\n", &file ) )
  197. {
  198. WARNING( "invalid drop \"%s\"\n", text );
  199. return 0;
  200. }
  201. unescape_url( file );
  202. printf( "pasted file \"%s\"\n", file );
  203. fl_cursor( FL_CURSOR_WAIT );
  204. Fl::check();
  205. char *t = strdup( file );
  206. char *filebase = strdup( basename( t ) );
  207. free( t );
  208. char *s = 0;
  209. int i = 0;
  210. for ( ; ; i++ )
  211. {
  212. if ( i )
  213. {
  214. free( s );
  215. asprintf( &s, "sources/%s-%i", filebase, i );
  216. }
  217. else
  218. asprintf( &s, "sources/%s", filebase );
  219. DMESSAGE( "Symlink %s -> %s", file, s );
  220. if ( symlink( file, s ) == 0 )
  221. break;
  222. if ( errno != EEXIST )
  223. {
  224. WARNING( "Failed to create symlink: %s", strerror( errno ) );
  225. break;
  226. }
  227. }
  228. Audio_File *c = Audio_File::from_file( basename( s ) );
  229. free( s );
  230. free( filebase );
  231. fl_cursor( FL_CURSOR_DEFAULT );
  232. Fl::check();
  233. if ( ! c || c->dummy() )
  234. {
  235. fl_alert( "Could not import file \"%s\"", file );
  236. free( file );
  237. if ( c )
  238. {
  239. delete c;
  240. c = NULL;
  241. }
  242. return 0;
  243. }
  244. free( file );
  245. Audio_Region *r =
  246. new Audio_Region( c, this, timeline->xoffset + timeline->x_to_ts( X - drawable_x() ) );
  247. r->log_create();
  248. redraw();
  249. return 1;
  250. }
  251. /** event handler that supports DND of audio clips */
  252. int
  253. Audio_Sequence::handle ( int m )
  254. {
  255. switch ( m )
  256. {
  257. case FL_PASTE:
  258. {
  259. DMESSAGE("Got sequence paste");
  260. if ( ! Fl::event_inside( this ) )
  261. {
  262. DMESSAGE("ignoring");
  263. return 0;
  264. }
  265. return handle_paste(Fl::event_text());
  266. }
  267. default:
  268. return Sequence::handle( m );
  269. }
  270. }