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.

354 lines
8.4KB

  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. /** event handler that supports DND of audio clips */
  190. int
  191. Audio_Sequence::handle ( int m )
  192. {
  193. switch ( m )
  194. {
  195. case FL_PASTE:
  196. {
  197. if ( ! Fl::event_inside( this ) )
  198. return 0;
  199. const char *text = Fl::event_text();
  200. if ( ! strcmp( text, "Audio_Region" ) )
  201. return 1;
  202. char *file;
  203. if ( ! sscanf( text, "file://%a[^\r\n]\n", &file ) )
  204. {
  205. WARNING( "invalid drop \"%s\"\n", text );
  206. return 0;
  207. }
  208. unescape_url( file );
  209. printf( "pasted file \"%s\"\n", file );
  210. fl_cursor( FL_CURSOR_WAIT );
  211. Fl::check();
  212. char *t = strdup( file );
  213. char *filebase = strdup( basename( t ) );
  214. free( t );
  215. char *s = 0;
  216. int i = 0;
  217. for ( ; ; i++ )
  218. {
  219. if ( i )
  220. {
  221. free( s );
  222. asprintf( &s, "sources/%s-%i", filebase, i );
  223. }
  224. else
  225. asprintf( &s, "sources/%s", filebase );
  226. DMESSAGE( "Symlink %s -> %s", file, s );
  227. if ( symlink( file, s ) == 0 )
  228. break;
  229. if ( errno != EEXIST )
  230. {
  231. WARNING( "Failed to create symlink: %s", strerror( errno ) );
  232. break;
  233. }
  234. }
  235. Audio_File *c = Audio_File::from_file( basename( s ) );
  236. free( s );
  237. free( filebase );
  238. fl_cursor( FL_CURSOR_DEFAULT );
  239. Fl::check();
  240. if ( ! c || c->dummy() )
  241. {
  242. fl_alert( "Could not import file \"%s\"", file );
  243. free( file );
  244. if ( c )
  245. {
  246. delete c;
  247. c = NULL;
  248. }
  249. return 0;
  250. }
  251. free( file );
  252. Audio_Region *r =
  253. new Audio_Region( c, this, timeline->xoffset + timeline->x_to_ts( Fl::event_x() - drawable_x() ) );
  254. r->log_create();
  255. redraw();
  256. return 1;
  257. }
  258. default:
  259. return Sequence::handle( m );
  260. }
  261. }