static snd_pcm_sframes_t snd_pcm_file_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) { snd_pcm_file_t *file = pcm->private_data; snd_pcm_sframes_t err; snd_pcm_uframes_t n; n = snd_pcm_frames_to_bytes(pcm, frames); if (n > file->wbuf_used_bytes) frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes); err = snd_pcm_rewind(file->gen.slave, frames); if (err > 0) { file->appl_ptr = (file->appl_ptr - err + file->wbuf_size) % file->wbuf_size; n = snd_pcm_frames_to_bytes(pcm, err); file->wbuf_used_bytes -= n; } return err; }
/** * The process callback for this JACK application. * It is called by JACK at the appropriate times. */ int process (jack_nframes_t nframes, void *arg) { int rlen; int err; snd_pcm_sframes_t delay = target_delay; int i; delay = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ; delay -= jack_frames_since_cycle_start( client ); // Do it the hard way. // this is for compensating xruns etc... if( delay > (target_delay+max_diff) ) { snd_pcm_rewind( alsa_handle, delay - target_delay ); output_new_delay = (int) delay; delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. // first look at the PI controller, this code is just a special case, which should never execute once // everything is swung in. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } if( delay < (target_delay-max_diff) ) { output_new_delay = (int) delay; while ((target_delay-delay) > 0) { snd_pcm_uframes_t to_write = ((target_delay-delay) > 512) ? 512 : (target_delay-delay); snd_pcm_writei( alsa_handle, tmpbuf, to_write ); delay += to_write; } delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } /* ok... now we should have target_delay +- max_diff on the alsa side. * * calculate the number of frames, we want to get. */ double offset = delay - target_delay; // Save offset. offset_array[(offset_differential_index++)% smooth_size ] = offset; // Build the mean of the windowed offset array // basically fir lowpassing. double smooth_offset = 0.0; for( i=0; i<smooth_size; i++ ) smooth_offset += offset_array[ (i + offset_differential_index-1) % smooth_size] * window_array[i]; smooth_offset /= (double) smooth_size; // this is the integral of the smoothed_offset offset_integral += smooth_offset; // Clamp offset. // the smooth offset still contains unwanted noise // which would go straigth onto the resample coeff. // it only used in the P component and the I component is used for the fine tuning anyways. if( fabs( smooth_offset ) < pclamp ) smooth_offset = 0.0; // ok. now this is the PI controller. // u(t) = K * ( e(t) + 1/T \int e(t') dt' ) // K = 1/catch_factor and T = catch_factor2 double current_resample_factor = static_resample_factor - smooth_offset / (double) catch_factor - offset_integral / (double) catch_factor / (double)catch_factor2; // now quantize this value around resample_mean, so that the noise which is in the integral component doesnt hurt. current_resample_factor = floor( (current_resample_factor - resample_mean) * controlquant + 0.5 ) / controlquant + resample_mean; // Output "instrumentatio" gonna change that to real instrumentation in a few. output_resampling_factor = (float) current_resample_factor; output_diff = (float) smooth_offset; output_integral = (float) offset_integral; output_offset = (float) offset; // Clamp a bit. if( current_resample_factor < resample_lower_limit ) current_resample_factor = resample_lower_limit; if( current_resample_factor > resample_upper_limit ) current_resample_factor = resample_upper_limit; // Now Calculate how many samples we need. rlen = ceil( ((double)nframes) * current_resample_factor )+2; assert( rlen > 2 ); // Calculate resample_mean so we can init ourselves to saner values. resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; /* * now this should do it... */ outbuf = alloca( rlen * formats[format].sample_size * num_channels ); resampbuf = alloca( rlen * sizeof( float ) ); /* * render jack ports to the outbuf... */ int chn = 0; JSList *node = playback_ports; JSList *src_node = playback_srcs; SRC_DATA src; while ( node != NULL) { jack_port_t *port = (jack_port_t *) node->data; float *buf = jack_port_get_buffer (port, nframes); SRC_STATE *src_state = src_node->data; src.data_in = buf; src.input_frames = nframes; src.data_out = resampbuf; src.output_frames = rlen; src.end_of_input = 0; src.src_ratio = current_resample_factor; src_process( src_state, &src ); formats[format].jack_to_soundcard( outbuf + format[formats].sample_size * chn, resampbuf, src.output_frames_gen, num_channels*format[formats].sample_size, NULL); src_node = jack_slist_next (src_node); node = jack_slist_next (node); chn++; } // now write the output... again: err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); //err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); if( err < 0 ) { printf( "err = %d\n", err ); if (xrun_recovery(alsa_handle, err) < 0) { printf("Write error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } goto again; } return 0; }
snd_pcm_sframes_t snd_pcm_generic_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) { snd_pcm_generic_t *generic = pcm->private_data; return snd_pcm_rewind(generic->slave, frames); }