Update NTK.
[nondaw.git] / sequencer / src / transport.C
blob25d9e0b4c8829d80891f131bde749cba99871a04
2 /*******************************************************************************/
3 /* Copyright (C) 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 <jack/jack.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <math.h>
26 #include "transport.H"
27 #include "common.h"
28 #include "const.h"
30 extern jack_client_t *client;
32 /* FIXME: use JackSyncCallback instead? (sync-callback) */
34 Transport transport;
36 static volatile bool _done;
38 /** callback for when we're Timebase Master, mostly taken from
39  * transport.c in Jack's example clients. */
40 /* FIXME: there is a subtle interaction here between the tempo and
41  * JACK's buffer size. Inflating ticks_per_beat (as jack_transport
42  * does) diminishes the effect of this correlation, but does not
43  * eliminate it... This is caused by the accumulation of a precision
44  * error, and all timebase master routines I've examined appear to
45  * suffer from this same tempo distortion (and all use the magic
46  * number of 1920 ticks_per_beat in an attempt to reduce the magnitude
47  * of the error. Currently, we keep this behaviour. */
48 void
49 Transport::timebase ( jack_transport_state_t, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void * )
52     if ( new_pos || ! _done )
53     {
54         pos->valid = JackPositionBBT;
55         pos->beats_per_bar = transport._master_beats_per_bar;
56         pos->ticks_per_beat = 1920.0;                           /* magic number means what? */
57         pos->beat_type = transport._master_beat_type;
58         pos->beats_per_minute = transport._master_beats_per_minute;
60         double wallclock = (double)pos->frame / (pos->frame_rate * 60);
62         unsigned long abs_tick = wallclock * pos->beats_per_minute * pos->ticks_per_beat;
63         unsigned long abs_beat = abs_tick / pos->ticks_per_beat;
65         pos->bar = abs_beat / pos->beats_per_bar;
66         pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1;
67         pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat);
68         pos->bar_start_tick = pos->bar * pos->beats_per_bar * pos->ticks_per_beat;
69         pos->bar++;
71         _done = true;
72     }
73     else
74     {
75         pos->tick += nframes * pos->ticks_per_beat * pos->beats_per_minute / (pos->frame_rate * 60);
77         while ( pos->tick >= pos->ticks_per_beat )
78         {
79             pos->tick -= pos->ticks_per_beat;
81             if ( ++pos->beat > pos->beats_per_bar )
82             {
83                 pos->beat = 1;
85                 ++pos->bar;
87                 pos->bar_start_tick += pos->beats_per_bar * pos->ticks_per_beat;
88             }
89         }
90     }
94 Transport::Transport ( void )
96     _master_beats_per_bar    = 4;
97     _master_beat_type        = 4;
98     _master_beats_per_minute = 120;
99     _done                    = false;
102 void
103 Transport::poll ( void )
105     jack_transport_state_t ts;
106     jack_position_t pos;
108     ts = jack_transport_query( client, &pos );
110     rolling = ts == JackTransportRolling;
112     valid = pos.valid & JackPositionBBT;
114     bar = pos.bar;
115     beat = pos.beat;
116     tick = pos.tick;
118     /* bars and beats start at 1.. */
119     pos.bar--;
120     pos.beat--;
122     /* FIXME: these probably shouldn't be called from the RT
123        thread... Anyway, it happens infrequently. */
124     if ( pos.beats_per_minute != beats_per_minute )
125         signal_tempo_change( pos.beats_per_minute );
127     if ( pos.beats_per_bar != beats_per_bar )
128         signal_bpb_change( pos.beats_per_bar );
130     if ( pos.beat_type != beat_type )
131         signal_beat_change( pos.beat_type );
133     ticks_per_beat = pos.ticks_per_beat;
134     beats_per_bar = pos.beats_per_bar;
135     beat_type = pos.beat_type;
136     beats_per_minute = pos.beats_per_minute;
138     frame = pos.frame;
139     frame_rate = pos.frame_rate;
141     /* FIXME: this only needs to be calculated if bpm or framerate changes  */
142     {
143         const double frames_per_beat = frame_rate * 60 / beats_per_minute;
145         frames_per_tick = frames_per_beat / (double)PPQN;
146         ticks_per_period = nframes / frames_per_tick;
147     }
149     tick_t abs_tick = (pos.bar * pos.beats_per_bar + pos.beat) * pos.ticks_per_beat + pos.tick;
150 //    tick_t abs_tick = pos.bar_start_tick + (pos.beat * pos.ticks_per_beat) + pos.tick;
152     /* scale Jack's ticks to our ticks */
154     const double pulses_per_tick = PPQN / pos.ticks_per_beat;
156     ticks = abs_tick * pulses_per_tick;
157     tick = tick * pulses_per_tick;
159     ticks_per_beat = PPQN;
162 void
163 Transport::start ( void )
165     MESSAGE( "Starting transport" );
166     jack_transport_start( client );
169 void
170 Transport::stop ( void )
172     MESSAGE( "Stopping transport" );
173     jack_transport_stop( client );
176 void
177 Transport::toggle ( void )
179     if ( rolling )
180         stop();
181     else
182         start();
185 void
186 Transport::locate ( tick_t ticks )
188     jack_nframes_t frame = trunc( ticks * transport.frames_per_tick );
190     MESSAGE( "Relocating transport to %lu, %lu", ticks, frame );
192     jack_transport_locate( client, frame );
195 void
196 Transport::set_beats_per_minute ( double n )
198     _master_beats_per_minute = n;
199     _done = false;
202 void
203 Transport::set_beats_per_bar ( int n )
205     if ( n < 2 )
206         return;
208     _master_beats_per_bar = n;
209     _done = false;
212 void
213 Transport::set_beat_type ( int n )
215     if ( n < 4 )
216         return;
218     _master_beat_type = n;
219     _done = false;