Logo Search packages:      
Sourcecode: jack-tools version File versions  Download package

jack.clock.c

/***** jack.clock.c - (c) rohan drape, 2004 *****/

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <pthread.h>

#define REQUEST_JCK_TK  0x00000001
#define REQUEST_JCK_PL  0x00000002
#define REQUEST_JCK_DC  0x00000004
#define REQUEST_JCK_MC  0x00000008
#define REQUEST_JCK_TC  0x00000010
#define REQUEST_JCK_RC  0x00000020
#define REQUEST_JCK_FC  0x00000040
#define REQUEST_JCK_ALL 0xFFFFFFFF
#define FAILURE         exit( EXIT_FAILURE )

#include "byte-order.c"
#include "client.c"
#include "jack.c"
#include "memory.c"
#include "network.c"
#include "osc.c"
#include "signal.c"
#include "time.c"

typedef struct
{
  double fps ;                /* Frames per second (ie. sample rate) */
  double spf ;                /* Seconds per frame */
  double ppc ;                /* Pulses per cycle */
  double pt ;                 /* Pulse type */
  double ppm ;                /* Pulses per minute */
  double ppf ;                /* Pulses per frame */
  double tpf ;                /* Ticks per frame */
  double pulse ;        /* Pulse clock */
  int64_t frm ;               /* Frame clock (jack.clock) */
  int64_t j_frm ;       /* Frame clock (jackd) */
  uint64_t ntp ;        /* NTP clock */
  double utc ;                /* UTC clock */
  int8_t roll ;
  int32_t correct_interval ; 
  int32_t correct_n ;
  int8_t fps_alt ;
  jack_client_t *client ;
  int fd ;
  client_register_t *cr ;
  pthread_t osc_thread ;
}
jackclock_t ;

#include "send_osc.c"

void *
jackclock_osc_thread_procedure ( void *PTR )
{
  jackclock_t *d = (jackclock_t *) PTR;
  while ( ! interrupt_received ) {
    struct sockaddr_in addr ;
    socklen_t addr_len = sizeof(addr) ;
    char msg[64] ;
    int msg_len = xrecvfrom ( d->fd , msg , 64 , 0 , (struct sockaddr *)&addr , &addr_len ) ;
    osc_data_t o[4] ;
    if ( osc_parse_message ( "/jck_rn" , ",i" , msg , msg_len , o ) ) {
      edit_client_register ( d->cr , addr , o[0].i ) ;
    } else if ( osc_parse_message ( "/jck_ra" , ",iis" , msg , msg_len , o ) ) {
      struct sockaddr_in ra_addr ;
      init_sockaddr_in ( &ra_addr , o[2].s , (int16_t)o[1].i ) ;
      edit_client_register ( d->cr , ra_addr , o[0].i ) ;
    } else if ( osc_parse_message ( "/jck_rs" , "," , msg , msg_len , o ) ) {
      send_jck_st ( d->fd , addr , d->fps , d->ppm , d->ppc , d->pt , d->roll ) ;
    } else if ( osc_parse_message ( "/jck_ru" , "," , msg , msg_len , o ) ) {
      send_jck_tk_to ( d->fd , addr , d->ntp , d->utc , d->frm , d->j_frm , d->pulse ) ;
    } else if ( osc_parse_message ( "/jck_rt" , ",i" , msg , msg_len , o ) ) {
      o[0].i ? jack_transport_start ( d->client ) : jack_transport_stop ( d->client ) ;
    } else if ( osc_parse_message ( "/jck_rl" , ",f" , msg , msg_len , o ) ) {
      jack_transport_locate ( d->client , o[0].f * d->fps ) ;
    } else {
      fprintf ( stderr , "jack.clock: dropped packet: %8s\n" , msg ) ;
    }
  }
  return NULL ;
}

inline double 
get_ticks_per_frame ( double ticks_per_pulse , double pulses_per_minute , double frames_per_second )
{
  double pulses_per_second = pulses_per_minute / 60.0 ;
  double ticks_per_second = ticks_per_pulse * pulses_per_second ;
  return ticks_per_second / frames_per_second ; 
}

inline double 
get_pulses_per_frame ( double pulses_per_minute , double frames_per_second )
{
  double pulses_per_second = pulses_per_minute / 60.0 ;
  return pulses_per_second / frames_per_second ; 
}

int
jackclock_process ( jack_nframes_t nframes , void *PTR )
{
  jackclock_t *d = ( jackclock_t *) PTR ;
  if ( d->correct_n >= d->correct_interval ) {
    struct timeval t = get_current_time () ;
    uint64_t c_ntp = timeval_to_ntp ( t ) ;
    double c_utc = timeval_to_real_utc ( t ) ;
    int64_t c_ntp_dif = c_ntp - d->ntp ;
    double c_utc_dif = c_utc - d->utc ;
    send_jck_dc ( d , d->ntp , d->utc , d->frm , c_ntp_dif , c_utc_dif ) ;
    d->ntp = c_ntp ;
    d->utc = c_utc ;
    d->correct_n = 0 ;
  }
  jack_position_t p ;
  jack_transport_state_t s = jack_transport_query ( d->client , &p ) ;
  if ( ( s & JackTransportRolling ) != d->roll ) {
    d->roll = s & JackTransportRolling ;
    send_jck_rc ( d , d->ntp , d->utc , d->frm , d->roll ) ;
  }
  if ( d->fps_alt ) {
    d->ppf = get_pulses_per_frame ( d->ppm , d->fps ) ;
    d->tpf = get_ticks_per_frame ( p.ticks_per_beat , d->ppm , d->fps ) ;
    send_jck_fc ( d , d->ntp , d->utc , d->frm , d->fps ) ;
    d->fps_alt = 0 ;
  }
  if ( ( p.valid & JackPositionBBT ) ) {
    if ( d->ppm != p.beats_per_minute ) {
      d->ppm = p.beats_per_minute ;
      d->ppf = get_pulses_per_frame ( d->ppm , d->fps ) ;
      d->tpf = get_ticks_per_frame ( p.ticks_per_beat , d->ppm , d->fps ) ;
      send_jck_tc ( d , d->ntp , d->utc , d->frm , d->ppm ) ;
    }
    if ( d->ppc != p.beats_per_bar || d->pt != p.beat_type ) {
      d->ppc = p.beats_per_bar ;
      d->pt = p.beat_type ;
      send_jck_mc ( d , d->ntp , d->utc , d->frm , d->ppc , d->pt ) ;
    }
    if ( d->roll && 
       ( p.tick == 0 || 
         ( (double)p.tick + ( floorf ( (double)nframes * d->tpf ) ) ) > (double)p.ticks_per_beat ) ) {
      int32_t p_tick_off = ( p.tick == 0 ) ? 0 : p.ticks_per_beat - p.tick ;
      double p_frm_off = (double)p_tick_off * d->tpf ;
      double p_frm = (double)d->frm + p_frm_off ;
      double p_utc = d->utc + ( p_frm_off * d->spf ) ;
      uint64_t p_ntp = real_utc_to_ntp ( p_utc ) ;
      int32_t p_pulse = ( p.tick == 0 ) ? p.beat : p.beat + 1 ;
      if ( (double)p_pulse > d->ppc ) {
      p_pulse = 1 ;
      }
      send_jck_pl ( d , d->ntp , d->utc , d->frm , p_ntp , p_utc , (int64_t) floor ( p_frm ) , p_pulse ) ;
      /* Correct pulse accumulator. */
      d->pulse = (double)p_pulse - ( ceil ( p_frm_off ) * d->ppf ) ;
      if ( d->pulse < 1.0 ) {
      d->pulse += d->ppc ;
      }
    }
    /* jck_tk is sent after jck_pl to report the corrected pulse. */
    send_jck_tk ( d , d->ntp , d->utc , d->frm , (int64_t)p.frame , d->pulse ) ;
  }
  d->frm += nframes ;
  d->j_frm = (int64_t)p.frame ;
  d->utc += (double)nframes * d->spf ;
  d->ntp = real_utc_to_ntp ( d->utc ) ;
  d->pulse += (double)nframes * d->ppf ;
  if ( d->pulse > d->ppc + 1.0 ) {
    d->pulse -= d->ppc ;
  }
  d->correct_n += 1 ;
  return 0 ;
}

int
jackclock_fps_handler ( jack_nframes_t fps , void *PTR )
{
  jackclock_t *d = ( jackclock_t *) PTR ;
  d->fps = (double) fps ;
  d->fps_alt = 1 ;
  return 0 ;
}

void
jackclock_usage (void)
{
  printf ( "Usage: jack.clock [ options ]\n" ) ;
  printf ( "   -c  Set the drift correction interval in periods (default=64).\n" ) ;
  printf ( "   -p  Set the port number (default=57130).\n" ) ;
  FAILURE ;
}

int
main ( int argc , char *argv[] )
{
  install_signal_handlers () ;
  jackclock_t d ;
  d.ppc = 0.0 ;
  d.pt = 0.0 ;
  d.ppm = 0.0 ;
  d.ppf = 0.0 ;
  d.tpf = 0.0 ;
  d.pulse = 0.0 ;
  d.frm = 0 ;
  d.ntp = 0 ;
  d.utc = 0.0 ;
  d.roll = 0 ;
  /* Ensure that a correction occurs when the process starts. */
  d.correct_interval = 64 ;
  d.correct_n = 64 ;
  d.cr = alloc_client_register ( 16 ) ;
  int port_n = 57130 ;
  int c ;
  while ( ( c = getopt ( argc , argv , "c:hp:" ) ) != -1 ) {
    switch ( c ) {
    case 'c':
      d.correct_interval = atoi ( optarg ) ;
      d.correct_n = d.correct_interval ;
      break;
    case 'h':
      jackclock_usage () ;
      break;
    case 'p':
      port_n = atoi ( optarg ) ;
      break;
    default:
      printf ("jack.clock: Illegal option %c.\n" , c ) ;
      jackclock_usage () ;
      break;
    }
  }
  d.fd = socket_udp ( 0 ) ;
  bind_inet ( d.fd , NULL , port_n ) ;
  d.client = xjack_client_new ( "jack.clock" ) ;
  jack_set_error_function ( jack_minimal_error_handler ) ;
  jack_set_sample_rate_callback ( d.client , jackclock_fps_handler , &d ) ;
  jack_on_shutdown ( d.client , jack_minimal_shutdown_handler , 0 ) ;
  jack_set_process_callback ( d.client , jackclock_process , &d ) ;
  d.fps = jack_get_sample_rate ( d.client ) ;
  d.fps_alt = 0 ;
  d.spf = 1.0 / d.fps ;
  xjack_activate ( d.client ) ;
  pthread_create ( &(d.osc_thread) , NULL , jackclock_osc_thread_procedure , &d ) ;
  pthread_join ( d.osc_thread , NULL ) ;
  jack_client_close ( d.client ) ;
  free_client_register ( d.cr ) ;
  exit ( 0 ) ;
  return 0 ;
}  

Generated by  Doxygen 1.6.0   Back to index