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

jack.scope.c

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

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <getopt.h>

#define FAILURE      exit(EXIT_FAILURE)

#define SIGNAL_MODE  0
#define EMBED_MODE   1

#define DOT_STYLE    0
#define FILL_STYLE   1
#define LINE_STYLE   2

#define MAX_CHANNELS 4

#include "byte-order.c"
#include "dsp.c"
#include "file.c"
#include "img.c"
#include "jack.c"
#include "memory.c"
#include "network.c"
#include "osc.c"
#include "signal.c"
#include "ximg.c"

typedef struct 
{
  int channels ;
  int window_size ;
  int data_samples ;
  int data_frames ;
  int draw_frames ;
  float *data ;
  float *share ;
  int write_head ;
  jack_port_t *port[MAX_CHANNELS] ;
  pthread_t draw_thread ;
  pthread_t osc_thread ;
  float fps ;
  float delay_msec ;
  int delay_frames ;
  int delay_cnt ;
  int mode ;
  int embedding ;
  float incr ;
  int style ;
  int pipe[2] ;
  char *image_directory ;
  int image_cnt ;
  int fd ;
} 
jackscope_t;

#include "draw-embed.c"
#include "draw-signal.c"

void
set_mode ( jackscope_t *d , const char *mode )
{
  if ( strncmp ( "signal" , mode , 6 ) == 0 ) {
    d->mode = SIGNAL_MODE ;
  } else if ( strncmp ( "embed" , mode , 5 ) == 0 ) {
    d->mode = EMBED_MODE ;
  } else {
    fprintf ( stderr , "jack.scope: illegal mode, %s\n" , mode ) ;
  }
}

void
set_style ( jackscope_t *d , const char *style )
{
  if ( strcmp ( "dot" , style ) == 0 ) {
    d->style = DOT_STYLE ;
  } else if ( strcmp ( "fill" , style ) == 0 ) {
    d->style = FILL_STYLE ;
  } else if ( strcmp ( "line" , style ) == 0 ) {
    d->style = LINE_STYLE ;
  } else {
    fprintf ( stderr , "jack.scope: illegal style, %s\n" , style ) ;
  }
}

void *
jackscope_osc_thread_procedure ( void *PTR )
{
  jackscope_t *d = (jackscope_t *) PTR;
  while ( 1 ) {
    char msg[32] ;
    int msg_len = xrecv ( d->fd , msg , 32 , 0 ) ;
    osc_data_t o[1] ;
    if ( osc_parse_message ( "/jsc_fs" , ",i" , msg , msg_len , o ) ) {
      d->draw_frames = o[0].i > d->data_frames ? d->data_frames : o[0].i ;
    } else if ( osc_parse_message ( "/jsc_ef" , ",i" , msg , msg_len , o ) ) {
      d->embedding = o[0].i ;
    } else if ( osc_parse_message ( "/jsc_ei" , ",f" , msg , msg_len , o ) ) {
      d->incr = o[0].f ;
    } else if ( osc_parse_message ( "/jsc_md" , ",s" , msg , msg_len , o ) ) {
      set_mode ( d , o[0].s ) ;
    } else if ( osc_parse_message ( "/jsc_st" , ",s" , msg , msg_len , o ) ) {
      set_style ( d , o[0].s ) ;
    } else if ( osc_parse_message ( "/jsc_ri" , ",f" , msg , msg_len , o ) ) {
      d->delay_msec = o[0].f ;
      d->delay_frames = floorf ( ( d->delay_msec / 1000.0 ) * d->fps ) ;
    } else {
      fprintf ( stderr , "jack.scope: dropped packet: %8s\n" , msg ) ; 
    }
  }
  return NULL ;
}
    
/* The data is channel separated into a local buffer, 'local'.  The
   image data 'image' is cleared and a user selected drawing procedure
   is invoked.  The draw procedure must accept any combination of
   window size and frame count, and any number of channels.  */

void *
jackscope_draw_thread_procedure ( void *PTR )
{
  jackscope_t *d = (jackscope_t *) PTR;
  Ximg_t *x = ximg_open ( d->window_size , d->window_size , "jack.scope" ) ;
  int image_n = d->window_size * d->window_size * 3 ;
  uint8_t *image = xmalloc ( image_n ) ;
  float *local = xmalloc ( d->data_samples * sizeof(float) ) ;
  uint8_t color[12] = { 128 , 32 , 32 , 
                  32 , 32 , 128 , 
                  128 , 224 , 224 , 
                  224 , 224 , 128 } ;
  while ( ! end_of_process_signaled () ) {
    char b ;
    xread ( d->pipe[0] , &b , 1 ) ;
    signal_uninterleave ( local , d->share , d->data_frames , d->channels ) ;
    memset ( image , 255 , image_n ) ;
    switch ( d->mode ) {
    case SIGNAL_MODE:
      jackscope_draw_signal ( image , d->window_size , local , d->data_frames , d->draw_frames , d->channels , color , d->style ) ;
      break ;
    case EMBED_MODE:
      jackscope_draw_embed ( image , d->window_size , local , d->data_frames , d->draw_frames , d->channels , color , d->embedding , d->incr ) ;
      break ;
    }
    ximg_blit ( x , image ) ;
    if ( d->image_directory ) {
      char name[256] ;
      snprintf ( name , 256 , "%s/jack.scope.%06d.ppm" , d->image_directory , d->image_cnt ) ;
      img_write_ppm_file ( image , d->window_size , d->window_size , name ) ;
    }
    d->image_cnt++ ;
  }
  ximg_close ( x ) ;
  free ( image ) ;
  free ( local ) ;
  return NULL ;
}

int
jackscope_process ( jack_nframes_t nframes , void *PTR )
{
  jackscope_t *d = (jackscope_t *) PTR ;
  sample_t *in[MAX_CHANNELS];
  int i ;
  for ( i = 0 ; i < d->channels ; i++ ) {
    in[i] = (sample_t *) jack_port_get_buffer ( d->port[i] , nframes ) ;
  }
  int k = d->write_head ;
  int l = d->delay_cnt ;
  for ( i = 0 ; i < nframes ; i++ ) {
    int j ;
    for ( j = 0 ; j < d->channels ; j++ ) {
      d->data[k++] = (float) in[j][i] ;
      if ( k >= d->data_samples ) {
      k = 0 ;
      }
    }
    l++ ;
    if ( l >= d->delay_frames ) {
      signal_copy_circular ( d->share , d->data , d->data_samples , d->write_head ) ;
      l = 0 ;
      char b = 1;
      xwrite ( d->pipe[1] , &b , 1 ) ;
    }
  }
  d->write_head = k ;
  d->delay_cnt = l ;
  return 0 ;
}

void
jackscope_usage (void)
{
  fprintf (stderr, "Usage: jack.scope [ options ] sound-file\n");
  fprintf (stderr, "   -b  Set the scope size in frames (default=512).\n");
  fprintf (stderr, "   -d  Set the delay time in ms between scope udpates (default=100.0).\n");
  fprintf (stderr, "   -e  Set the embedding length (default=6).\n");
  fprintf (stderr, "   -f  Request that image files be stored at this location (default=NULL).\n");
  fprintf (stderr, "   -i  Set the embedding mode intepolation increment (default=1.0).\n");  
  fprintf (stderr, "   -m  Set the scope operating mode (default=signal).\n");
  fprintf (stderr, "   -n  Set the number of channels (default=1).\n");
  fprintf (stderr, "   -p  Set the port number to listen for OSC packets on (default=57140).\n");
  fprintf (stderr, "   -s  Set the drawing style (default=dot).\n");
  fprintf (stderr, "   -w  Set the scope size in pixels (default=512).\n");
  FAILURE;
}

int
main ( int argc , char **argv )
{
  install_signal_handlers () ;
  jackscope_t d;
  d.window_size = 512 ;
  d.data_frames = 512 ;
  d.data_samples = 0 ;
  d.draw_frames = 0 ;
  d.write_head = 0 ;
  d.delay_msec = 100.0 ;
  d.delay_cnt = 0 ;
  d.channels = 1 ;
  d.mode = SIGNAL_MODE ;
  d.style = DOT_STYLE ;
  d.embedding = 6 ;
  d.incr = 1.0 ;
  d.image_directory = NULL ;
  d.image_cnt = 0 ;
  int port_n = 57140 ;
  int c;
  while ((c = getopt (argc, argv, "b:d:e:f:hi:m:n:s:w:")) != -1) {
    switch (c) {
    case 'b':
      d.data_frames = atoi ( optarg ) ;
      break;
    case 'd':
      d.delay_msec = atof ( optarg ) ;
      break;
    case 'e':
      d.embedding = atoi ( optarg ) ;
      break;
    case 'f':
      d.image_directory = optarg ;
      break;
    case 'h':
      jackscope_usage ();
      break;
    case 'i':
      d.incr = atof ( optarg ) ;
      break;
    case 'm':
      set_mode ( &d , optarg ) ;
      break ;
    case 'n':
      d.channels = atoi ( optarg ) ;
      if (d.channels > MAX_CHANNELS) {
      fprintf ( stderr , "illegal channel count: %d" , d.channels ) ;
      FAILURE ;
      }
      break;
    case 'p':
      port_n = atoi ( optarg ) ;
      break;
    case 's':
      set_style ( &d , optarg ) ;
      break ;
    case 'w':
      d.window_size = atoi ( optarg ) ;
      break;
    default:
      fprintf (stderr, "jack.scope: illegal option, %c\n" , (char) c);
      jackscope_usage ();
      break;
    }
  }
  d.draw_frames = d.data_frames ;
  d.data_samples = d.data_frames * d.channels ;
  d.data = xmalloc ( d.data_samples * sizeof (float) ) ;
  d.share = xmalloc ( d.data_samples * sizeof (float) ) ;
  d.fd = socket_udp ( 0 ) ;
  bind_inet ( d.fd , NULL , port_n ) ;
  xpipe ( d.pipe ) ;
  pthread_create ( &(d.osc_thread) , NULL , jackscope_osc_thread_procedure , &d ) ;
  pthread_create ( &(d.draw_thread) , NULL , jackscope_draw_thread_procedure , &d ) ;
  jack_client_t *client = jack_client_uniq ( "jack.scope" ) ;
  jack_set_process_callback ( client , jackscope_process , &d ) ;
  jack_set_error_function ( jack_minimal_error_handler ) ;
  jack_on_shutdown ( client , jack_minimal_shutdown_handler , 0 ) ;
  d.fps = (float)jack_get_sample_rate ( client ) ;
  d.delay_frames = floorf ( ( d.delay_msec / 1000.0 ) * d.fps ) ;
  jack_make_standard_ports ( client , d.port , d.channels , 0 ) ;
  xjack_activate ( client ) ;
  pthread_join ( d.draw_thread , NULL ) ;
  jack_client_close (client);
  close ( d.pipe[0] ) ;
  close ( d.pipe[1] ) ;
  free ( d.data ) ;
  free ( d.share ) ;
  return EXIT_SUCCESS ;
}

Generated by  Doxygen 1.6.0   Back to index