2008-08-04 20:14:03 -04:00
/*
2019-08-02 22:01:25 -04:00
* Copyright ( C ) 2008 - 2013 Hans Baier < hansfbaier @ googlemail . com >
* Copyright ( C ) 2009 - 2010 Carl Hetherington < carl @ carlh . net >
* Copyright ( C ) 2009 - 2012 David Robillard < d @ drobilla . net >
* Copyright ( C ) 2009 - 2019 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2012 - 2013 Robin Gareus < robin @ gareus . org >
* Copyright ( C ) 2013 - 2018 John Emmas < john @ creativepost . co . uk >
* Copyright ( C ) 2015 - 2016 Nick Mainsbridge < mainsbridge @ gmail . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2008-08-04 20:14:03 -04:00
2010-01-31 22:36:29 -05:00
# include <cmath>
2008-08-04 20:14:03 -04:00
# include <errno.h>
# include <sys/types.h>
# include <unistd.h>
2009-02-25 13:26:51 -05:00
# include "pbd/error.h"
# include "pbd/failed_constructor.h"
# include "pbd/pthread_utils.h"
2012-04-12 07:45:40 -04:00
# include "pbd/convert.h"
2008-08-04 20:14:03 -04:00
2009-02-25 13:26:51 -05:00
# include "midi++/port.h"
2010-01-31 22:36:29 -05:00
2018-09-18 18:51:59 -04:00
# include "ardour/audioengine.h"
2010-01-31 22:36:29 -05:00
# include "ardour/debug.h"
2013-08-07 22:22:11 -04:00
# include "ardour/midi_buffer.h"
# include "ardour/midi_port.h"
2018-09-18 18:51:59 -04:00
# include "ardour/session.h"
2009-02-25 13:26:51 -05:00
# include "ardour/tempo.h"
2018-09-18 18:51:59 -04:00
# include "ardour/transport_master.h"
2018-10-08 12:59:51 -04:00
# include "ardour/transport_master_manager.h"
2008-08-04 20:14:03 -04:00
2016-07-14 14:44:52 -04:00
# include "pbd/i18n.h"
2008-08-04 20:14:03 -04:00
2009-05-12 13:03:42 -04:00
using namespace std ;
2008-08-04 20:14:03 -04:00
using namespace ARDOUR ;
using namespace MIDI ;
using namespace PBD ;
2018-09-18 18:51:59 -04:00
# define ENGINE AudioEngine::instance()
MIDIClock_TransportMaster : : MIDIClock_TransportMaster ( std : : string const & name , int ppqn )
: TransportMaster ( MIDIClock , name )
, ppqn ( ppqn )
, midi_clock_count ( 0 )
, _running ( false )
, _bpm ( 0 )
2008-08-04 20:14:03 -04:00
{
}
2018-09-18 18:51:59 -04:00
MIDIClock_TransportMaster : : ~ MIDIClock_TransportMaster ( )
2009-06-20 09:39:49 -04:00
{
2018-09-18 18:51:59 -04:00
port_connections . drop_connections ( ) ;
2009-06-20 09:39:49 -04:00
}
2018-09-18 18:51:59 -04:00
void
MIDIClock_TransportMaster : : init ( )
2008-08-04 20:14:03 -04:00
{
2023-02-19 09:16:43 -05:00
reset ( false ) ;
2020-05-27 17:39:28 -04:00
resync_latency ( false ) ;
}
void
2023-02-16 18:33:28 -05:00
MIDIClock_TransportMaster : : connection_handler ( std : : weak_ptr < ARDOUR : : Port > w0 , std : : string n0 , std : : weak_ptr < ARDOUR : : Port > w1 , std : : string n1 , bool con )
2020-05-27 17:39:28 -04:00
{
TransportMaster : : connection_handler ( w0 , n0 , w1 , n1 , con ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Port > p = w1 . lock ( ) ;
2020-05-27 17:39:28 -04:00
if ( p = = _port ) {
resync_latency ( false ) ;
}
2008-08-04 20:14:03 -04:00
}
2019-09-17 20:26:03 -04:00
void
MIDIClock_TransportMaster : : create_port ( )
{
if ( ( _port = create_midi_port ( string_compose ( " %1 in " , _name ) ) ) = = 0 ) {
throw failed_constructor ( ) ;
}
}
2013-08-13 12:53:28 -04:00
void
2020-05-27 17:39:28 -04:00
MIDIClock_TransportMaster : : set_session ( Session * s )
2008-08-04 20:14:03 -04:00
{
2020-05-27 17:39:28 -04:00
TransportMaster : : set_session ( s ) ;
TransportMasterViaMIDI : : set_session ( s ) ;
2018-09-18 18:51:59 -04:00
port_connections . drop_connections ( ) ;
2013-08-07 22:22:11 -04:00
2018-09-18 18:51:59 -04:00
/* only connect to signals if we have a proxy, because otherwise we
* cannot interpet incoming data ( no tempo map etc . )
*/
2013-08-07 22:22:11 -04:00
2018-09-18 18:51:59 -04:00
if ( _session ) {
parser . timing . connect_same_thread ( port_connections , boost : : bind ( & MIDIClock_TransportMaster : : update_midi_clock , this , _1 , _2 ) ) ;
parser . start . connect_same_thread ( port_connections , boost : : bind ( & MIDIClock_TransportMaster : : start , this , _1 , _2 ) ) ;
parser . contineu . connect_same_thread ( port_connections , boost : : bind ( & MIDIClock_TransportMaster : : contineu , this , _1 , _2 ) ) ;
parser . stop . connect_same_thread ( port_connections , boost : : bind ( & MIDIClock_TransportMaster : : stop , this , _1 , _2 ) ) ;
2018-09-25 17:46:59 -04:00
parser . position . connect_same_thread ( port_connections , boost : : bind ( & MIDIClock_TransportMaster : : position , this , _1 , _2 , _3 , _4 ) ) ;
2008-08-04 20:14:03 -04:00
2019-01-25 00:05:20 -05:00
reset ( true ) ;
2018-09-18 18:51:59 -04:00
}
}
2009-10-14 12:10:01 -04:00
void
2018-09-22 03:48:41 -04:00
MIDIClock_TransportMaster : : pre_process ( MIDI : : pframes_t nframes , samplepos_t now , boost : : optional < samplepos_t > session_pos )
2009-01-01 01:52:18 -05:00
{
2018-09-18 18:51:59 -04:00
/* Read and parse incoming MIDI */
2021-06-27 10:36:59 -04:00
if ( ! _midi_port ) {
_bpm = 0.0 ;
_running = false ;
_current_delta = 0 ;
midi_clock_count = 0 ;
DEBUG_TRACE ( DEBUG : : MidiClock , " No MIDI Clock port registered " ) ;
return ;
}
2018-09-18 18:51:59 -04:00
2018-09-25 17:46:59 -04:00
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " preprocess with lt = %1 @ %2, running ? %3 \n " , current . timestamp , now , _running ) ) ;
2018-09-18 18:51:59 -04:00
/* no clock messages ever, or no clock messages for 1/4 second ? conclude that its stopped */
2020-05-27 17:13:19 -04:00
if ( ! current . timestamp | | one_ppqn_in_samples = = 0 | | ( now > current . timestamp & & ( ( now - current . timestamp ) > ( ENGINE - > sample_rate ( ) / 4 ) ) ) ) {
2018-09-18 18:51:59 -04:00
_bpm = 0.0 ;
_running = false ;
_current_delta = 0 ;
midi_clock_count = 0 ;
2020-05-27 17:13:19 -04:00
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " No MIDI Clock messages received for some time, stopping! ts = %1 @ %2 ppqn = %3 \n " , current . timestamp , now , one_ppqn_in_samples ) ) ;
2018-09-18 18:51:59 -04:00
}
2023-02-22 12:37:39 -05:00
_midi_port - > read_and_parse_entire_midi_buffer_with_no_speed_adjustment ( nframes , parser , now ) ;
2018-09-18 18:51:59 -04:00
if ( session_pos ) {
2018-09-25 17:46:59 -04:00
const samplepos_t current_pos = current . position + ( ( now - current . timestamp ) * current . speed ) ;
2018-09-18 18:51:59 -04:00
_current_delta = current_pos - * session_pos ;
} else {
_current_delta = 0 ;
}
2018-09-25 17:46:59 -04:00
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " speed_and_position: speed %1 should-be %2 transport %3 \n " , current . speed , current . position , _session - > transport_sample ( ) ) ) ;
2018-09-18 18:51:59 -04:00
}
void
MIDIClock_TransportMaster : : calculate_one_ppqn_in_samples_at ( samplepos_t time )
{
2023-06-12 14:36:16 -04:00
const Temporal : : TempoMetric & metric = Temporal : : TempoMap : : use ( ) - > metric_at ( timepos_t ( time ) ) ;
2020-11-11 11:31:52 -05:00
const double samples_per_quarter_note = metric . tempo ( ) . samples_per_quarter_note ( ENGINE - > sample_rate ( ) ) ;
2008-08-04 20:14:03 -04:00
2017-09-18 12:39:17 -04:00
one_ppqn_in_samples = samples_per_quarter_note / double ( ppqn ) ;
2020-05-27 17:13:19 -04:00
// DEBUG_TRACE (DEBUG::MidiClock, string_compose ("at %1, one ppqn = %2 [spl] spqn = %3, ppqn = %4\n", time, one_ppqn_in_samples, samples_per_quarter_note, ppqn));
2009-01-01 01:52:18 -05:00
}
2017-09-18 12:39:17 -04:00
ARDOUR : : samplepos_t
2018-09-18 18:51:59 -04:00
MIDIClock_TransportMaster : : calculate_song_position ( uint16_t song_position_in_sixteenth_notes )
2009-02-12 05:14:22 -05:00
{
2017-09-18 12:39:17 -04:00
samplepos_t song_position_samples = 0 ;
2009-02-12 05:14:22 -05:00
for ( uint16_t i = 1 ; i < = song_position_in_sixteenth_notes ; + + i ) {
// one quarter note contains ppqn pulses, so a sixteenth note is ppqn / 4 pulses
2017-09-18 12:39:17 -04:00
calculate_one_ppqn_in_samples_at ( song_position_samples ) ;
song_position_samples + = one_ppqn_in_samples * ( samplepos_t ) ( ppqn / 4 ) ;
2009-02-12 05:14:22 -05:00
}
2009-10-14 12:10:01 -04:00
2017-09-18 12:39:17 -04:00
return song_position_samples ;
2009-02-12 05:14:22 -05:00
}
2009-10-14 12:10:01 -04:00
void
2018-09-18 18:51:59 -04:00
MIDIClock_TransportMaster : : calculate_filter_coefficients ( double qpm )
2009-01-05 04:15:08 -05:00
{
2023-02-23 11:26:05 -05:00
const double omega = 2.0 * M_PI * ( 60 / qpm ) / 24 ;
2018-09-18 18:51:59 -04:00
b = 1.4142135623730950488 * omega ; // sqrt (2.0) * omega
2009-10-14 12:10:01 -04:00
c = omega * omega ;
2018-09-18 18:51:59 -04:00
2023-02-23 11:26:05 -05:00
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " DLL coefficients: omega:%1 b:%2 c:%3 \n " , omega , b , c ) ) ;
2009-01-05 04:15:08 -05:00
}
2009-01-01 01:52:18 -05:00
void
2018-09-18 18:51:59 -04:00
MIDIClock_TransportMaster : : update_midi_clock ( Parser & /*parser*/ , samplepos_t timestamp )
2009-10-14 12:10:01 -04:00
{
2022-06-21 20:36:12 -04:00
# ifndef NDEBUG
2022-06-21 23:46:54 -04:00
samplepos_t elapsed_since_start = timestamp - first_timestamp ;
2022-06-21 20:36:12 -04:00
# endif
2013-12-17 21:55:15 -05:00
2018-09-25 17:46:59 -04:00
calculate_one_ppqn_in_samples_at ( current . position ) ;
2009-10-14 12:10:01 -04:00
2018-09-25 17:46:59 -04:00
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " clock count %1, sbp %2 \n " , midi_clock_count , current . position ) ) ;
2009-10-14 12:10:01 -04:00
2018-09-18 18:51:59 -04:00
if ( midi_clock_count = = 0 ) {
/* second 0xf8 message after start/reset has arrived */
2009-10-14 12:10:01 -04:00
2009-01-05 04:15:08 -05:00
first_timestamp = timestamp ;
2023-02-19 09:16:43 -05:00
current . update ( current . position , timestamp , 0 ) ;
2009-10-14 12:10:01 -04:00
2013-12-17 20:26:43 -05:00
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " first clock message after start received @ %1 \n " , timestamp ) ) ;
2018-09-18 18:51:59 -04:00
midi_clock_count + + ;
2009-10-14 12:10:01 -04:00
2018-09-18 18:51:59 -04:00
} else if ( midi_clock_count = = 1 ) {
/* second 0xf8 message has arrived. we can now estimate QPM
* ( quarters per minute , and fully initialize the DLL
*/
2020-05-27 17:13:19 -04:00
e2 = timestamp - current . timestamp ;
2018-09-18 18:51:59 -04:00
2023-02-22 12:37:39 -05:00
const samplecnt_t samples_per_quarter = e2 * ppqn ;
2020-05-27 17:13:19 -04:00
double bpm = ( ENGINE - > sample_rate ( ) * 60.0 ) / samples_per_quarter ;
2018-09-18 18:51:59 -04:00
2020-05-27 17:13:19 -04:00
if ( bpm < 1 | | bpm > 999 ) {
2023-02-19 09:16:43 -05:00
current . update ( current . position , timestamp , 0 ) ;
2020-05-27 17:13:19 -04:00
midi_clock_count = 1 ; /* start over */
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " BPM is out of bounds (%1) \n " , timestamp , current . timestamp ) ) ;
} else {
_bpm = bpm ;
2018-09-18 18:51:59 -04:00
2020-05-27 17:13:19 -04:00
/* finish DLL initialization */
2023-02-23 11:26:05 -05:00
calculate_filter_coefficients ( 500.0 ) ; // do not rely on initial bpm, but assume a realistic BW
2009-10-14 12:10:01 -04:00
2020-05-27 17:13:19 -04:00
t0 = timestamp ;
t1 = t0 + e2 ; /* timestamp we predict for the next 0xf8 clock message */
midi_clock_count + + ;
2023-02-19 09:16:43 -05:00
current . update ( current . position + one_ppqn_in_samples + midi_port_latency . max , timestamp , 0 ) ;
2020-05-27 17:13:19 -04:00
}
2018-09-18 18:51:59 -04:00
} else {
/* 3rd or later MIDI clock message. We can now compute actual
* speed ( and tempo ) with the DLL
*/
2020-05-27 17:13:19 -04:00
double e = timestamp - t1 ; // error between actual time of arrival of clock message and our predicted time
2009-01-05 04:15:08 -05:00
t0 = t1 ;
t1 + = b * e + e2 ;
2009-10-14 12:10:01 -04:00
e2 + = c * e ;
2018-09-18 18:51:59 -04:00
2023-02-22 12:37:39 -05:00
const double samples_per_quarter = ( t1 - t0 ) * ppqn ;
2018-09-18 18:51:59 -04:00
2023-02-22 12:37:39 -05:00
_bpm = ( ENGINE - > sample_rate ( ) * 60.0 ) / samples_per_quarter ;
2018-09-18 18:51:59 -04:00
2023-02-23 12:17:47 -05:00
double mr = Config - > get_midi_clock_resolution ( ) ;
if ( mr = = 1. ) {
_bpm = round ( _bpm ) ;
} else if ( mr ! = 0. ) {
_bpm - = fmod ( _bpm , mr ) ;
}
2023-02-22 12:37:39 -05:00
/* when rolling speed is always 1.0. The transport moves at wall-clock
* speed . What changes is the music - time ( BPM ) , not the speed .
2018-09-18 18:51:59 -04:00
*/
2023-02-23 17:22:18 -05:00
if ( _session & & _session - > config . get_external_sync ( ) & & TransportMasterManager : : instance ( ) . current ( ) . get ( ) = = this ) {
2023-02-22 12:37:39 -05:00
/* TODO always set tempo, even when there is a map */
2023-02-23 12:17:47 -05:00
2023-02-22 12:37:39 -05:00
_session - > maybe_update_tempo_from_midiclock_tempo ( _bpm ) ;
2018-09-18 18:51:59 -04:00
}
2023-02-22 12:37:39 -05:00
calculate_one_ppqn_in_samples_at ( current . position ) ;
2018-09-18 18:51:59 -04:00
midi_clock_count + + ;
2023-02-19 09:16:43 -05:00
if ( _running ) {
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " mclock running with speed = %1 bpm = %2 \n " , ( t1 - t0 ) / one_ppqn_in_samples , _bpm ) ) ;
2023-02-22 12:37:39 -05:00
current . update ( current . position + one_ppqn_in_samples , timestamp , 1.0 ) ;
2023-02-19 09:16:43 -05:00
} else {
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " mclock stopped speed = %1 bpm = %2 \n " , ( t1 - t0 ) / one_ppqn_in_samples , _bpm ) ) ;
current . update ( current . position , timestamp , 0 ) ;
}
2018-10-08 12:59:51 -04:00
2009-10-14 12:10:01 -04:00
}
2020-05-27 17:13:19 -04:00
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose (
2023-02-20 18:21:12 -05:00
" clock #%1 @ %2 should-be %3 transport %4 appspeed %5 "
" read-delta %6 should-be-delta %7 t1-t0 %8 t0 %9 t1 %10 sample-rate %11 engine %12 running %13 \n " ,
2020-05-27 17:13:19 -04:00
midi_clock_count , // #
elapsed_since_start , // @
current . position , // should-be
_session - > transport_sample ( ) , // transport
( t1 - t0 ) / one_ppqn_in_samples , // appspeed
timestamp - current . timestamp , // read delta
one_ppqn_in_samples , // should-be delta
( t1 - t0 ) , // t1-t0
t0 , // t0 (current position)
t1 , // t1 (expected next pos)
ENGINE - > sample_rate ( ) , // framerate
ENGINE - > sample_time ( ) ,
_running
2013-12-17 21:55:15 -05:00
2013-12-17 20:26:43 -05:00
) ) ;
2008-08-04 20:14:03 -04:00
}
void
2018-09-18 18:51:59 -04:00
MIDIClock_TransportMaster : : start ( Parser & /*parser*/ , samplepos_t timestamp )
2009-10-14 12:10:01 -04:00
{
2018-09-18 18:51:59 -04:00
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " MIDIClock_TransportMaster got start message at time %1 engine time %2 transport_sample %3 \n " , timestamp , ENGINE - > sample_time ( ) , _session - > transport_sample ( ) ) ) ;
2009-10-14 12:10:01 -04:00
2023-02-19 09:16:43 -05:00
if ( _running ) {
return ;
2009-02-12 05:14:22 -05:00
}
2023-02-19 09:16:43 -05:00
_running = true ;
2023-02-19 16:49:23 -05:00
current . update ( 0 , current . timestamp , 0 ) ;
2009-02-12 05:14:22 -05:00
}
void
2019-01-25 00:05:20 -05:00
MIDIClock_TransportMaster : : reset ( bool with_position )
2009-02-12 05:14:22 -05:00
{
2018-09-18 18:51:59 -04:00
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " MidiClock Master reset(): calculated filter for period size %2 \n " , ENGINE - > samples_per_cycle ( ) ) ) ;
2013-12-17 18:19:21 -05:00
2019-01-25 00:05:20 -05:00
if ( with_position ) {
current . update ( _session - > transport_sample ( ) , 0 , 0 ) ;
} else {
2019-02-04 13:24:23 -05:00
current . reset ( ) ;
2019-01-25 00:05:20 -05:00
}
2009-10-14 12:10:01 -04:00
2018-09-18 18:51:59 -04:00
_running = false ;
_current_delta = 0 ;
2023-02-19 09:16:43 -05:00
midi_clock_count = 0 ;
2008-08-04 20:14:03 -04:00
}
2009-01-01 01:52:18 -05:00
void
2018-09-18 18:51:59 -04:00
MIDIClock_TransportMaster : : contineu ( Parser & /*parser*/ , samplepos_t /*timestamp*/ )
2009-01-01 01:52:18 -05:00
{
2018-09-18 18:51:59 -04:00
DEBUG_TRACE ( DEBUG : : MidiClock , " MIDIClock_TransportMaster got continue message \n " ) ;
2010-01-31 22:36:29 -05:00
2018-09-18 18:51:59 -04:00
_running = true ;
2009-01-01 01:52:18 -05:00
}
2008-08-04 20:14:03 -04:00
void
2018-09-25 17:46:59 -04:00
MIDIClock_TransportMaster : : stop ( Parser & /*parser*/ , samplepos_t timestamp )
2008-08-04 20:14:03 -04:00
{
2018-09-18 18:51:59 -04:00
DEBUG_TRACE ( DEBUG : : MidiClock , " MIDIClock_TransportMaster got stop message \n " ) ;
2009-10-14 12:10:01 -04:00
2018-09-18 18:51:59 -04:00
if ( _running ) {
_running = false ;
2009-10-14 12:10:01 -04:00
2009-02-14 02:18:38 -05:00
// we need to go back to the last MIDI beat (6 ppqn)
// and lets hope the tempo didnt change in the meantime :)
2009-10-14 12:10:01 -04:00
2009-02-14 02:18:38 -05:00
// begin at the should be position, because
// that is the position of the last MIDI Clock
// message and that is probably what the master
// expects where we are right now
2018-09-18 18:51:59 -04:00
//
2009-02-14 02:18:38 -05:00
// find out the last MIDI beat: go back #midi_clocks mod 6
// and lets hope the tempo didnt change in those last 6 beats :)
2023-02-19 09:16:43 -05:00
current . update ( current . position - ( midi_clock_count % 6 ) * one_ppqn_in_samples , current . timestamp , 0 ) ;
2009-02-12 05:14:22 -05:00
}
}
void
2018-09-25 17:46:59 -04:00
MIDIClock_TransportMaster : : position ( Parser & /*parser*/ , MIDI : : byte * message , size_t size , samplepos_t timestamp )
2009-02-12 05:14:22 -05:00
{
2018-09-18 18:51:59 -04:00
// we are not supposed to get position messages while we are running
2009-02-12 05:14:22 -05:00
// so lets be robust and ignore those
2018-09-18 18:51:59 -04:00
if ( _running ) {
2009-02-12 05:14:22 -05:00
return ;
}
2009-10-14 12:10:01 -04:00
2009-02-12 05:14:22 -05:00
assert ( size = = 3 ) ;
2013-08-04 10:36:07 -04:00
MIDI : : byte lsb = message [ 1 ] ;
MIDI : : byte msb = message [ 2 ] ;
2009-02-12 05:14:22 -05:00
assert ( ( lsb < = 0x7f ) & & ( msb < = 0x7f ) ) ;
2009-10-14 12:10:01 -04:00
2023-02-19 09:16:43 -05:00
/* Each MIDI Beat spans 6 MIDI Clocks.
* In other words , each MIDI Beat is a 16 th note ( since there are 24 MIDI
* Clocks in a quarter note , therefore 4 MIDI Beats also fit in a quarter ) .
* So , a master can sync playback to a resolution of any particular 16 th note .
*/
2009-02-12 05:14:22 -05:00
uint16_t position_in_sixteenth_notes = ( uint16_t ( msb ) < < 7 ) | uint16_t ( lsb ) ;
2023-02-19 09:16:43 -05:00
2017-09-18 12:39:17 -04:00
samplepos_t position_in_samples = calculate_song_position ( position_in_sixteenth_notes ) ;
2009-10-14 12:10:01 -04:00
2017-09-18 12:39:17 -04:00
DEBUG_TRACE ( DEBUG : : MidiClock , string_compose ( " Song Position: %1 samples: %2 \n " , position_in_sixteenth_notes , position_in_samples ) ) ;
2009-10-14 12:10:01 -04:00
2023-02-19 16:49:23 -05:00
current . update ( position_in_samples + midi_port_latency . max , current . timestamp , 0 ) ;
2008-08-04 20:14:03 -04:00
}
bool
2018-09-18 18:51:59 -04:00
MIDIClock_TransportMaster : : locked ( ) const
2008-08-04 20:14:03 -04:00
{
2008-10-27 02:49:41 -04:00
return true ;
2008-08-04 20:14:03 -04:00
}
bool
2018-09-18 18:51:59 -04:00
MIDIClock_TransportMaster : : ok ( ) const
2008-08-04 20:14:03 -04:00
{
return true ;
}
2018-10-04 00:40:35 -04:00
ARDOUR : : samplecnt_t
MIDIClock_TransportMaster : : update_interval ( ) const
{
if ( one_ppqn_in_samples ) {
return resolution ( ) ;
}
return AudioEngine : : instance ( ) - > sample_rate ( ) / 120 / 4 ; /* pure guesswork */
}
2017-09-18 12:39:17 -04:00
ARDOUR : : samplecnt_t
2018-09-18 18:51:59 -04:00
MIDIClock_TransportMaster : : resolution ( ) const
2008-08-04 20:14:03 -04:00
{
2009-01-01 01:52:18 -05:00
// one beat
2017-09-18 12:39:17 -04:00
return ( samplecnt_t ) one_ppqn_in_samples * ppqn ;
2008-08-04 20:14:03 -04:00
}
2012-10-17 11:57:51 -04:00
std : : string
2018-09-18 18:51:59 -04:00
MIDIClock_TransportMaster : : position_string ( ) const
{
return std : : string ( ) ;
}
std : : string
MIDIClock_TransportMaster : : delta_string ( ) const
2012-10-17 11:57:51 -04:00
{
2018-10-05 14:14:31 -04:00
SafeTime last ;
current . safe_read ( last ) ;
if ( last . timestamp = = 0 | | starting ( ) ) {
2023-01-16 15:41:09 -05:00
return X_ ( u8 " \u2012 \u2012 \u2012 \u2012 " ) ;
2012-10-17 11:57:51 -04:00
} else {
2020-05-12 08:59:44 -04:00
return format_delta_time ( _current_delta ) ;
2012-10-17 11:57:51 -04:00
}
}
2019-01-25 00:05:20 -05:00
void
MIDIClock_TransportMaster : : unregister_port ( )
{
_midi_port . reset ( ) ;
TransportMaster : : unregister_port ( ) ;
}