#include #include #include #include #include #include #include #include #include #include #include typedef struct _thread_info { pthread_t thread_id; SNDFILE *sf; jack_nframes_t pos; jack_client_t *client; unsigned int channels; volatile int can_process; volatile int read_done; volatile int play_done; } thread_info_t; pthread_mutex_t disk_thread_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER; #define RB_SIZE 16384 jack_ringbuffer_t *rb; jack_port_t **output_port; jack_default_audio_sample_t **outs; const size_t sample_size = sizeof(jack_default_audio_sample_t); int process(jack_nframes_t nframes, void *arg) { int i,n; thread_info_t *info = (thread_info_t *) arg; jack_default_audio_sample_t buf[info->channels]; if (!info->can_process) return 0; for(n=0;nchannels;n++) outs[n] = jack_port_get_buffer (output_port[n], nframes); for(i=0;ichannels); if(read_cnt==0 && info->read_done) { // file is done, so stop the main loop. info->play_done = 1; return 0; } // update play-position counter info->pos += read_cnt/(sample_size*info->channels); // output each channel of the frame for(n=0;nchannels;n++) outs[n][i]=buf[n]; } // wake up the disk thread to read more data if (pthread_mutex_trylock (&disk_thread_lock) == 0) { pthread_cond_signal (&data_ready); pthread_mutex_unlock (&disk_thread_lock); } return 0; } void *disk_thread (void *arg) { thread_info_t *info = (thread_info_t *) arg; sf_count_t buf_avail, read_frames; jack_ringbuffer_data_t vec[2]; size_t bytes_per_frame = sample_size*info->channels; pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_mutex_lock (&disk_thread_lock); while (1) { jack_ringbuffer_get_write_vector(rb, vec); read_frames = 0; if(vec[0].len) { // fill the first part of the ringbuffer buf_avail = vec[0].len / bytes_per_frame; read_frames = sf_readf_float(info->sf, (float*)vec[0].buf, buf_avail); if(vec[1].len) { // fill the second part of the ringbuffer? buf_avail = vec[1].len / bytes_per_frame; read_frames += sf_readf_float(info->sf, (float*)vec[1].buf, buf_avail); } } if(read_frames==0) break; // end of file? jack_ringbuffer_write_advance(rb,read_frames*bytes_per_frame); // tell process that we've filled the ringbuffer info->can_process = 1; // wait for the process thread to wake us up pthread_cond_wait (&data_ready, &disk_thread_lock); } // tell that we're done reading the file info->read_done = 1; pthread_mutex_unlock (&disk_thread_lock); return 0; } void jack_shutdown(void *arg) { exit(1); } void print_time(jack_nframes_t pos, int sr) { float sec = pos/(float)sr; int min = sec/60; fprintf(stderr,"%02d:%05.2f",min,fmod(sec,60)); } int main(int narg, char **args) { int i; SNDFILE *sf; SF_INFO sfinfo; jack_client_t *client; thread_info_t info; int sr; if(narg<2) { fprintf(stderr,"no soundfile given\n"); return 1; } // create jack client if ((client = jack_client_new("jackplay")) == 0) { fprintf(stderr, "jack server not running?\n"); return 1; } sr = jack_get_sample_rate(client); // open the soundfile sfinfo.format = 0; sf = sf_open(args[1],SFM_READ,&sfinfo); if(sf==0) { fprintf(stderr,"Could not open soundfile %s\n",args[1]); return 1; } fprintf(stderr,"channels: %d\nsamplerate: %d Hz\nduration: ",sfinfo.channels,sfinfo.samplerate); print_time(sfinfo.frames,sfinfo.samplerate); fprintf(stderr,"\n"); if(sfinfo.samplerate!=sr) fprintf(stderr, "Warning: samplerate of soundfile does not match jack server\n"); // init the thread info struct memset (&info, 0, sizeof (info)); info.can_process = 0; info.read_done = 0; info.play_done = 0; info.sf = sf; info.channels = sfinfo.channels; info.client = client; info.pos = 0; // set up callbacks jack_set_process_callback (client, process, &info); jack_on_shutdown (client, jack_shutdown, 0); // allocate output ports output_port = (jack_port_t **) malloc(sfinfo.channels*sizeof(jack_port_t*)); outs = (jack_default_audio_sample_t **) malloc(sfinfo.channels*sizeof(jack_default_audio_sample_t*)); for(i=0; ibuf, 0, rb->size); // activate client if (jack_activate (client)) { fprintf(stderr, "cannot activate client\n"); return 1; } // auto connect all channels for(i=0; i "); print_time(info.pos,sr); fflush(stdout); usleep(50000); } jack_client_close(client); jack_ringbuffer_free(rb); free(outs); free(output_port); exit(0); }