Update NTK.
[nondaw.git] / sequencer / src / phrase.C
blob0db6ae261f25a126d54458be3fe4658ac9632c59
2 /*******************************************************************************/
3 /* Copyright (C) 2007,2008 Jonathan Moore Liles                                */
4 /*                                                                             */
5 /* This program is free software; you can redistribute it and/or modify it     */
6 /* under the terms of the GNU General Public License as published by the       */
7 /* Free Software Foundation; either version 2 of the License, or (at your      */
8 /* option) any later version.                                                  */
9 /*                                                                             */
10 /* This program is distributed in the hope that it will be useful, but WITHOUT */
11 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       */
12 /* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   */
13 /* more details.                                                               */
14 /*                                                                             */
15 /* You should have received a copy of the GNU General Public License along     */
16 /* with This program; see the file COPYING.  If not,write to the Free Software */
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18 /*******************************************************************************/
20 #include "phrase.H"
21 #include "gui/draw.H"
22 #include "pattern.H"
23 #include "smf.H"
24 #include "common.h"
25 #include <math.h>
27 vector <phrase*> phrase::_phrases;
28 signal <void> phrase::signal_create_destroy;
30 phrase::phrase ( void )
32     viewport.h = 32;
33     viewport.w = 32;
35     _add();
37     char *s;
38     asprintf( &s, "Phrase %d", number() );
40     name( s );
45 phrase::~phrase ( void )
47     DMESSAGE( "deleting phrase %d", number() );
48     signal_create_destroy();
51 void
52 phrase::_add ( void )
54    // keep track of all the phrases
55     phrase::_phrases.push_back( this );
56     _number = phrases();
58     signal_create_destroy();
61 /* copy constructor */
62 phrase::phrase ( const phrase &rhs ) : Grid( rhs )
64     _add();
67 phrase *
68 phrase::clone ( void )
70     return new phrase( *this );
73 /******************/
74 /* Static methods */
75 /******************/
77 int
78 phrase::phrases ( void )
80     return phrase::_phrases.size();
83 phrase *
84 phrase::phrase_by_number ( int n )
86     if ( n <= phrases() && n > 0 )
87     {
88         return phrase::_phrases[ n - 1 ];
89     }
90     return NULL;
93 void
94 phrase::reset ( void )
96     for ( int n = phrase::phrases(); n-- ; )
97     {
98         delete phrase::_phrases.back();
99         phrase::_phrases.pop_back();
100     }
106 /*******************/
107 /* Virtual Methods */
108 /*******************/
110 phrase *
111 phrase::create ( void )
113     if ( phrase::phrases() < 128 )
114     {
115         return new phrase;
116     }
117     else
118         return NULL;
121 phrase *
122 phrase::by_number ( int n ) const
124     return phrase::phrase_by_number( n );
127 void
128 phrase::put ( int x, int y, tick_t l )
130     // FIXME: fix insertion length to the length of the pattern
131     // referred to by this row.
133     l = 4;
135     // FIXME: use translation here.
136     pattern *p = pattern::pattern_by_number( y + 1 );
138     if ( ! p )
139         return;
141     l = p->length();
143     Grid::put( x, y, l );
146 const char *
147 phrase::row_name ( int r ) const
149     pattern *p = pattern::pattern_by_number( r + 1 );
151     return p ? p->name() : NULL;
154 void
155 phrase::draw_row_names ( Canvas *c ) const
157     for ( int y = viewport.h; y--; )
158     {
159         pattern *p = pattern::pattern_by_number( y + 1 );
161         if ( p && p->name() )
162             c->draw_row_name( y, p->name(), 0 );
163     }
167 void
168 phrase::trigger ( tick_t start, tick_t end )
170     _start = start;
171     _end = end;
174 // FIXME: so much of this is copied from pattern.C, there has
175 // to be a way to share more of this code.
176 void
177 phrase::play ( tick_t start, tick_t end )
179     /* get our own copy of this pointer so UI thread can change it. */
180     const data *d = const_cast< const data * >(_rd);
182     if ( start > _end )
183     {
184         _playing = false;
185         return;
186     }
187     
188     if ( start < _start )
189         start = _start;
191     if ( end > _end )
192         end = _end;
194     _playing = true;
196     // where we are in the absolute time
197     tick_t tick = start - _start;
198     int num_played = tick / d->length;
199     tick_t offset = _start + (d->length * num_played);
201     _index = fmod( tick, d->length );
203     if ( _index < end - start )
204         DMESSAGE( "Triggered phrase %d at tick %lu (ls: %lu, le: %lu, o: %lu)", number(), start, _start, _end, offset  );
206 try_again:
208     // pattern is empty
209     if ( d->events.empty() )
210         goto done;
212     for ( const event *e = d->events.first(); e; e = e->next() )
213     {
214         //    MESSAGE( "s[%ld] -> t[%ld] : %ld, len %ld", start, end, e->timestamp(), _length ); // (*e).print();
216         const tick_t ts = e->timestamp() + offset;
218         if ( ts >= end )
219             goto done;
221         if ( e->is_note_on() )
222         {
223             const tick_t tse = offset + e->link()->timestamp();
225             if ( tse > start )
226             {
227                 pattern *p = pattern::pattern_by_number( 1 + note_to_y( e->note() ) );
228             
229                 p->trigger( ts, tse );
230                 
231                 p->play( start, end );
232             }
233         }
234     }
236     // ran out of events, but there's still some loop left to play.
237     offset += d->length;
238     goto try_again;
240     MESSAGE( "out of events, resetting to satisfy loop" );
242 done: ;
246 void
247 phrase::load ( smf *f )
249     lock();
251     f->read_phrase_info( this );
253     tick_t len;
255     list <midievent> *me = f->read_track_events( &len );
257     _rw->events = *me;
258     delete me;
260     if ( len )
261         _rw->length = len;
263     unlock();
266 void
267 phrase::dump ( smf *f )
269     f->open_track( _name, -1 );
271     f->write_phrase_info( this );
273     f->cue( true );
275     Grid::dump( f, 0 );
277     f->close_track( length() );