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.

441 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. #include "sequence.H"
  19. #include "phrase.H"
  20. #include "pattern.H"
  21. #include "smf.H"
  22. #include "non.H"
  23. /* #include <string> */
  24. /* using std::string; */
  25. sequence::sequence ( void )
  26. {
  27. _rd = new data;
  28. _notes = NULL;
  29. }
  30. void
  31. sequence::lock ( void )
  32. {
  33. // create a copy of the lock-free data.
  34. _rw = new data;
  35. data *d = const_cast< data *> (_rd);
  36. _rw->phrases = d->phrases;
  37. _rw->num = d->num;
  38. }
  39. void
  40. sequence::unlock ( void )
  41. {
  42. _history.push_back( const_cast<data *>( _rd ) );
  43. if ( _history.size() > MAX_UNDO + 1 )
  44. {
  45. data *d = _history.front();
  46. if ( d == _rw || d == _rd )
  47. ASSERTION( "something bad has happend." );
  48. delete d;
  49. _history.pop_front();
  50. }
  51. // swap the copy back in (atomically).
  52. _rd = _rw;
  53. _rw = NULL;
  54. }
  55. void
  56. sequence::insert ( unsigned int n, int pn )
  57. {
  58. lock();
  59. /* if ( n > _rw->phrases.size() ) */
  60. /* _rw->phrases.resize( n + 10 ); */
  61. // MESSAGE( "inserting %d at %d", pn, n );
  62. _rw->phrases.insert( _find( n ), pn );
  63. _rw->num++;
  64. unlock();
  65. }
  66. vector <int>::iterator
  67. sequence::_find ( int n )
  68. {
  69. // boy I hate C++/STL.. So lame.
  70. int i = 0;
  71. for ( vector <int>::iterator e = _rw->phrases.begin(); e != _rw->phrases.end(); e++ )
  72. {
  73. if ( i == n )
  74. return e;
  75. i++;
  76. }
  77. return _rw->phrases.end();
  78. }
  79. void
  80. sequence::remove ( int n )
  81. {
  82. lock();
  83. _rw->phrases.erase( _find( n ) );
  84. _rw->num--;
  85. unlock();
  86. }
  87. /** return the number of phrases in this sequence */
  88. int
  89. sequence::phrases ( void ) const
  90. {
  91. return _rd->num;
  92. }
  93. void
  94. sequence::_swap ( int n1, int n2 )
  95. {
  96. int x = _rw->phrases[ n1 ];
  97. _rw->phrases[ n1 ] = _rw->phrases[ n2 ];
  98. _rw->phrases[ n2 ] = x;
  99. }
  100. void
  101. sequence::move ( int n, int dir )
  102. {
  103. lock();
  104. switch ( dir )
  105. {
  106. case UP:
  107. {
  108. if ( n - 1 >= 0 )
  109. _swap( n - 1, n );
  110. break;
  111. }
  112. case DOWN:
  113. {
  114. if ( n + 1 < _rw->num )
  115. _swap( n + 1, n );
  116. break;
  117. }
  118. }
  119. unlock();
  120. }
  121. /* Render sequence to a string.. suitable for display in the UI */
  122. char *
  123. sequence::dump ( void )
  124. {
  125. char *s = (char *)malloc( 256 );
  126. s[0] = '\0';
  127. size_t siz = 256;
  128. int start = 1;
  129. for ( int i = 0; i < _rd->num; i++ )
  130. {
  131. const int len = 256;
  132. char line[len];
  133. int x = _rd->phrases[ i ];
  134. phrase *p = phrase::phrase_by_number( x );
  135. if ( ! p )
  136. return NULL;
  137. snprintf( line, len, "%d\t%d\t%s\n", start, p->number(), p->name() );
  138. start += p->bars();
  139. s = (char *)realloc( s, siz += strlen( line ) + 1 );
  140. strcat( s, line );
  141. }
  142. return s;
  143. }
  144. void
  145. sequence::play ( tick_t start, tick_t end ) const
  146. {
  147. // keep our own copy.
  148. data *d = _rd;
  149. tick_t offset = 0;
  150. for ( int i = 0; i < d->num; i++ )
  151. {
  152. phrase *p = phrase::phrase_by_number( d->phrases[ i ] );
  153. if ( p )
  154. {
  155. tick_t pstart = offset;
  156. tick_t pend = offset + p->length();
  157. // this phrase seems to be current.
  158. if ( pend > start )
  159. {
  160. // FIXME: don't really need to trigger more than once!
  161. _playing = p->number();
  162. _index = start;
  163. p->trigger( pstart, pend );
  164. p->play( start, end );
  165. break;
  166. }
  167. offset = pend;
  168. }
  169. else
  170. WARNING( "programming error: no such phrase." );
  171. }
  172. }
  173. /** return the number of the currently playing phrase, or 0 if none. */
  174. int
  175. sequence::playing ( void ) const
  176. {
  177. return _playing;
  178. }
  179. /** return the location of the playhead for this sequence */
  180. tick_t
  181. sequence::index ( void ) const
  182. {
  183. return _index;
  184. }
  185. /** return the total length of the sequence in ticks */
  186. tick_t
  187. sequence::length ( void ) const
  188. {
  189. tick_t l = 0;
  190. for ( int i = 0; i < _rd->num; i++ )
  191. {
  192. phrase *p = phrase::phrase_by_number( _rd->phrases[ i ] );
  193. if ( ! p )
  194. break;
  195. l += p->length();
  196. }
  197. return l;
  198. }
  199. /** return to a blank slate */
  200. void
  201. sequence::reset ( void )
  202. {
  203. // MESSAGE( "reseting" );
  204. lock();
  205. _rw->num = 0;
  206. phrase::reset();
  207. pattern::reset();
  208. unlock();
  209. }
  210. /** load entire sequence from file, replacing everything */
  211. bool
  212. sequence::load ( const char *name )
  213. {
  214. smf f;
  215. f.open( name, smf::READ );
  216. f.read_header();
  217. if ( f.format() != 2 )
  218. {
  219. WARNING( "not a Non song file" );
  220. return false;
  221. }
  222. f.next_track();
  223. MESSAGE( "reading song info" );
  224. /* read song info */
  225. int mode, phrases, patterns;
  226. char *sname, *notes;
  227. if ( ! f.read_song_info( &mode, &phrases, &patterns, &sname, &notes ) )
  228. {
  229. WARNING( "not a Non song file" );
  230. return false;
  231. }
  232. song.play_mode = (play_mode_e)mode;
  233. if ( sname )
  234. this->name( sname );
  235. if ( notes )
  236. this->notes( notes );
  237. /* tear it down */
  238. reset();
  239. MESSAGE( "reading playlist" );
  240. // f.read_playlist( this );
  241. lock();
  242. char *s;
  243. while ( (s = f.read_cue_point() ) )
  244. {
  245. int n;
  246. sscanf( s, "%d:", &n );
  247. _rw->phrases.insert( _find( _rw->num++ ), n );
  248. }
  249. /* read playlist */
  250. MESSAGE( "reading phrases" );
  251. while ( phrases-- && f.next_track() )
  252. {
  253. phrase *p = new phrase;
  254. p->load( &f );
  255. }
  256. MESSAGE( "reading patterns" );
  257. while ( patterns-- && f.next_track() )
  258. {
  259. pattern *p = new pattern;
  260. p->load( &f );
  261. }
  262. unlock();
  263. signal_new_song();
  264. return true;
  265. }
  266. /** save entire sequence to file */
  267. void
  268. sequence::save ( const char *name ) const
  269. {
  270. smf f;
  271. /* open for writing */
  272. f.open( name, smf::WRITE );
  273. f.write_header( 2 );
  274. MESSAGE( "saving playlist" );
  275. f.open_track( NULL, -1 );
  276. MESSAGE( "saving song info" );
  277. f.write_song_info( song.play_mode, phrase::phrases(), pattern::patterns(), this->name(), notes() );
  278. for ( int i = 0; i < _rd->num; ++i )
  279. {
  280. char pat[256];
  281. phrase *p = phrase::phrase_by_number( _rd->phrases[ i ] );
  282. snprintf( pat, 256, "%d: %s", p->number(), p->name() );
  283. f.write_meta_event( smf::CUEPOINT, pat );
  284. }
  285. f.close_track( 0 );
  286. MESSAGE( "saving phrases" );
  287. for ( int i = 0; i < phrase::phrases(); i++ )
  288. {
  289. phrase *p = phrase::phrase_by_number( i + 1 );
  290. p->dump( &f );
  291. }
  292. MESSAGE( "saving patterns" );
  293. for ( int i = 0; i < pattern::patterns(); i++ )
  294. {
  295. pattern *p = pattern::pattern_by_number( i + 1 );
  296. p->dump( &f );
  297. }
  298. }
  299. /*************/
  300. /* Accessors */
  301. /*************/
  302. char *
  303. sequence::name ( void ) const
  304. {
  305. return _name;
  306. }
  307. void
  308. sequence::name ( const char *s )
  309. {
  310. if ( _name ) free( _name );
  311. _name = strdup( s );
  312. }
  313. char *
  314. sequence::notes ( void ) const
  315. {
  316. return _notes;
  317. }
  318. void
  319. sequence::notes ( const char *s )
  320. {
  321. if ( _notes ) free( _notes );
  322. _notes = strdup( s );
  323. }