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.

403 lines
7.7KB

  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. int
  88. sequence::length ( void ) const
  89. {
  90. return _rd->num;
  91. }
  92. void
  93. sequence::_swap ( int n1, int n2 )
  94. {
  95. int x = _rw->phrases[ n1 ];
  96. _rw->phrases[ n1 ] = _rw->phrases[ n2 ];
  97. _rw->phrases[ n2 ] = x;
  98. }
  99. void
  100. sequence::move ( int n, int dir )
  101. {
  102. lock();
  103. switch ( dir )
  104. {
  105. case UP:
  106. {
  107. if ( n - 1 >= 0 )
  108. _swap( n - 1, n );
  109. break;
  110. }
  111. case DOWN:
  112. {
  113. if ( n + 1 < _rw->num )
  114. _swap( n + 1, n );
  115. break;
  116. }
  117. }
  118. unlock();
  119. }
  120. /* Render sequence to a string.. suitable for display in the UI */
  121. char *
  122. sequence::dump ( void )
  123. {
  124. char *s = (char *)malloc( 256 );
  125. s[0] = '\0';
  126. size_t siz = 256;
  127. int start = 1;
  128. for ( int i = 0; i < _rd->num; i++ )
  129. {
  130. const int len = 256;
  131. char line[len];
  132. int x = _rd->phrases[ i ];
  133. phrase *p = phrase::phrase_by_number( x );
  134. if ( ! p )
  135. return NULL;
  136. snprintf( line, len, "%d\t%d\t%s\n", start, p->number(), p->name() );
  137. start += p->bars();
  138. s = (char *)realloc( s, siz += strlen( line ) + 1 );
  139. strcat( s, line );
  140. }
  141. return s;
  142. }
  143. void
  144. sequence::play ( tick_t start, tick_t end ) const
  145. {
  146. // keep our own copy.
  147. data *d = _rd;
  148. tick_t offset = 0;
  149. for ( int i = 0; i < d->num; i++ )
  150. {
  151. phrase *p = phrase::phrase_by_number( d->phrases[ i ] );
  152. if ( p )
  153. {
  154. tick_t pstart = offset;
  155. tick_t pend = offset + p->length();
  156. // this phrase seems to be current.
  157. if ( pend > start )
  158. {
  159. // FIXME: don't really need to trigger more than once!
  160. p->trigger( pstart, pend );
  161. p->play( start, end );
  162. break;
  163. }
  164. offset = pend;
  165. }
  166. else
  167. WARNING( "programming error: no such phrase." );
  168. }
  169. }
  170. /** return to a blank slate */
  171. void
  172. sequence::reset ( void )
  173. {
  174. // MESSAGE( "reseting" );
  175. lock();
  176. _rw->num = 0;
  177. phrase::reset();
  178. pattern::reset();
  179. unlock();
  180. }
  181. /** load entire sequence from file, replacing everything */
  182. bool
  183. sequence::load ( const char *name )
  184. {
  185. smf f;
  186. f.open( name, smf::READ );
  187. f.read_header();
  188. if ( f.format() != 2 )
  189. {
  190. WARNING( "not a Non song file" );
  191. return false;
  192. }
  193. f.next_track();
  194. MESSAGE( "reading song info" );
  195. /* read song info */
  196. int mode, phrases, patterns;
  197. char *sname, *notes;
  198. if ( ! f.read_song_info( &mode, &phrases, &patterns, &sname, &notes ) )
  199. {
  200. WARNING( "not a Non song file" );
  201. return false;
  202. }
  203. song.play_mode = (play_mode_e)mode;
  204. if ( sname )
  205. this->name( sname );
  206. if ( notes )
  207. this->notes( notes );
  208. /* tear it down */
  209. reset();
  210. MESSAGE( "reading playlist" );
  211. // f.read_playlist( this );
  212. lock();
  213. char *s;
  214. while ( (s = f.read_cue_point() ) )
  215. {
  216. int n;
  217. sscanf( s, "%d:", &n );
  218. _rw->phrases.insert( _find( _rw->num++ ), n );
  219. }
  220. /* read playlist */
  221. MESSAGE( "reading phrases" );
  222. while ( phrases-- && f.next_track() )
  223. {
  224. phrase *p = new phrase;
  225. p->load( &f );
  226. }
  227. MESSAGE( "reading patterns" );
  228. while ( patterns-- && f.next_track() )
  229. {
  230. pattern *p = new pattern;
  231. p->load( &f );
  232. }
  233. unlock();
  234. signal_new_song();
  235. return true;
  236. }
  237. /** save entire sequence to file */
  238. void
  239. sequence::save ( const char *name ) const
  240. {
  241. smf f;
  242. /* open for writing */
  243. f.open( name, smf::WRITE );
  244. f.write_header( 2 );
  245. MESSAGE( "saving playlist" );
  246. f.open_track( NULL, -1 );
  247. MESSAGE( "saving song info" );
  248. f.write_song_info( song.play_mode, phrase::phrases(), pattern::patterns(), this->name(), notes() );
  249. for ( int i = 0; i < _rd->num; ++i )
  250. {
  251. char pat[256];
  252. phrase *p = phrase::phrase_by_number( _rd->phrases[ i ] );
  253. snprintf( pat, 256, "%d: %s", p->number(), p->name() );
  254. f.write_meta_event( smf::CUEPOINT, pat );
  255. }
  256. f.close_track( 0 );
  257. MESSAGE( "saving phrases" );
  258. for ( int i = 0; i < phrase::phrases(); i++ )
  259. {
  260. phrase *p = phrase::phrase_by_number( i + 1 );
  261. p->dump( &f );
  262. }
  263. MESSAGE( "saving patterns" );
  264. for ( int i = 0; i < pattern::patterns(); i++ )
  265. {
  266. pattern *p = pattern::pattern_by_number( i + 1 );
  267. p->dump( &f );
  268. }
  269. }
  270. /*************/
  271. /* Accessors */
  272. /*************/
  273. char *
  274. sequence::name ( void ) const
  275. {
  276. return _name;
  277. }
  278. void
  279. sequence::name ( const char *s )
  280. {
  281. if ( _name ) free( _name );
  282. _name = strdup( s );
  283. }
  284. char *
  285. sequence::notes ( void ) const
  286. {
  287. return _notes;
  288. }
  289. void
  290. sequence::notes ( const char *s )
  291. {
  292. if ( _notes ) free( _notes );
  293. _notes = strdup( s );
  294. }