Exemple #1
0
/*****************************************************************************
 * Process: callback for JACK
 *****************************************************************************/
int Process( jack_nframes_t i_frames, void *p_arg )
{
    unsigned int i, j, i_nb_samples = 0;
    audio_output_t *p_aout = (audio_output_t*) p_arg;
    struct aout_sys_t *p_sys = p_aout->sys;
    jack_sample_t *p_src = NULL;

    jack_nframes_t dframes = p_sys->latency
                             - jack_frames_since_cycle_start( p_sys->p_jack_client );

    jack_time_t dtime = dframes * 1000 * 1000 / jack_get_sample_rate( p_sys->p_jack_client );
    mtime_t play_date = mdate() + (mtime_t) ( dtime );

    /* Get the next audio data buffer */
    aout_buffer_t *p_buffer = aout_PacketNext( p_aout, play_date );

    if( p_buffer != NULL )
    {
        p_src = (jack_sample_t *)p_buffer->p_buffer;
        i_nb_samples = p_buffer->i_nb_samples;
    }

    /* Get the JACK buffers to write to */
    for( i = 0; i < p_sys->i_channels; i++ )
    {
        p_sys->p_jack_buffers[i] = jack_port_get_buffer( p_sys->p_jack_ports[i],
                                                         i_frames );
    }

    /* Copy in the audio data */
    for( j = 0; j < i_nb_samples; j++ )
    {
        for( i = 0; i < p_sys->i_channels; i++ )
        {
            jack_sample_t *p_dst = p_sys->p_jack_buffers[i];
            p_dst[j] = *p_src;
            p_src++;
        }
    }

    /* Fill any remaining buffer with silence */
    if( i_nb_samples < i_frames )
    {
        for( i = 0; i < p_sys->i_channels; i++ )
        {
            memset( p_sys->p_jack_buffers[i] + i_nb_samples, 0,
                    sizeof( jack_sample_t ) * (i_frames - i_nb_samples) );
        }
    }

    if( p_buffer )
    {
        aout_BufferFree( p_buffer );
    }
    return 0;
}
static int process_callback(jack_nframes_t nframes, void *arg)
{
    /* Warning: this function runs in realtime. One mustn't allocate memory here
     * or do any other thing that could block. */

    int i, j;
    JackData *self = arg;
    float * buffer;
    jack_nframes_t latency, cycle_delay;
    AVPacket pkt;
    float *pkt_data;
    double cycle_time;

    if (!self->client)
        return 0;

    /* The approximate delay since the hardware interrupt as a number of frames */
    cycle_delay = jack_frames_since_cycle_start(self->client);

    /* Retrieve filtered cycle time */
    cycle_time = ff_timefilter_update(self->timefilter,
                                      av_gettime() / 1000000.0 - (double) cycle_delay / self->sample_rate,
                                      self->buffer_size);

    /* Check if an empty packet is available, and if there's enough space to send it back once filled */
    if ((av_fifo_size(self->new_pkts) < sizeof(pkt)) || (av_fifo_space(self->filled_pkts) < sizeof(pkt))) {
        self->pkt_xrun = 1;
        return 0;
    }

    /* Retrieve empty (but allocated) packet */
    av_fifo_generic_read(self->new_pkts, &pkt, sizeof(pkt), NULL);

    pkt_data  = (float *) pkt.data;
    latency   = 0;

    /* Copy and interleave audio data from the JACK buffer into the packet */
    for (i = 0; i < self->nports; i++) {
        latency += jack_port_get_total_latency(self->client, self->ports[i]);
        buffer = jack_port_get_buffer(self->ports[i], self->buffer_size);
        for (j = 0; j < self->buffer_size; j++)
            pkt_data[j * self->nports + i] = buffer[j];
    }

    /* Timestamp the packet with the cycle start time minus the average latency */
    pkt.pts = (cycle_time - (double) latency / (self->nports * self->sample_rate)) * 1000000.0;

    /* Send the now filled packet back, and increase packet counter */
    av_fifo_generic_write(self->filled_pkts, &pkt, sizeof(pkt), NULL);
    sem_post(&self->packet_count);

    return 0;
}
Exemple #3
0
/**
 * 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;      
}
Exemple #4
0
// rt
static int
_process(jack_nframes_t nsamples, void *data)
{
	prog_t *handle = data;
	bin_t *bin = &handle->bin;
	sp_app_t *app = bin->app;

#if defined(JACK_HAS_CYCLE_TIMES)
	clock_gettime(CLOCK_REALTIME, &handle->ntp);
	handle->ntp.tv_sec += JAN_1970; // convert NTP to OSC time
	jack_nframes_t offset = jack_frames_since_cycle_start(handle->client);

	float T;
	jack_get_cycle_times(handle->client, &handle->cycle.cur_frames,
		&handle->cycle.cur_usecs, &handle->cycle.nxt_usecs, &T);
	(void)T;
	
	handle->cycle.ref_frames = handle->cycle.cur_frames + offset;

	// calculate apparent period
	double diff = 1e-6 * (handle->cycle.nxt_usecs - handle->cycle.cur_usecs);

	// calculate apparent samples per period
	handle->cycle.dT = nsamples / diff;
	handle->cycle.dTm1 = 1.0 / handle->cycle.dT;
#endif

	// get transport position
	jack_position_t pos;
	jack_transport_state_t rolling = jack_transport_query(handle->client, &pos) == JackTransportRolling;
	int trans_changed = (rolling != handle->trans.rolling)
		|| (pos.frame != handle->trans.frame)
		|| (pos.beats_per_bar != handle->trans.beats_per_bar)
		|| (pos.beat_type != handle->trans.beat_type)
		|| (pos.ticks_per_beat != handle->trans.ticks_per_beat)
		|| (pos.beats_per_minute != handle->trans.beats_per_minute);

	const size_t sample_buf_size = sizeof(float) * nsamples;
	const sp_app_system_source_t *sources = sp_app_get_system_sources(app);
	const sp_app_system_sink_t *sinks = sp_app_get_system_sinks(app);

	if(sp_app_bypassed(app)) // aka loading state
	{
		//fprintf(stderr, "app is bypassed\n");

		// clear output buffers
		for(const sp_app_system_sink_t *sink=sinks;
			sink->type != SYSTEM_PORT_NONE;
			sink++)
		{
			switch(sink->type)
			{
				case SYSTEM_PORT_NONE:
				case SYSTEM_PORT_CONTROL:
				case SYSTEM_PORT_COM:
					break;

				case SYSTEM_PORT_AUDIO:
				case SYSTEM_PORT_CV:
				{
					void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples);
					memset(out_buf, 0x0, sample_buf_size);
					break;
				}
				case SYSTEM_PORT_MIDI:
				case SYSTEM_PORT_OSC:
				{
					void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples);
					jack_midi_clear_buffer(out_buf);
					break;
				}
			}
		}

		bin_process_pre(bin, nsamples, true);
		bin_process_post(bin);

		return 0;
	}

	//TODO use __builtin_assume_aligned

	// fill input buffers
	for(const sp_app_system_source_t *source=sources;
		source->type != SYSTEM_PORT_NONE;
		source++)
	{
		switch(source->type)
		{
			case SYSTEM_PORT_NONE:
			case SYSTEM_PORT_CONTROL:
				break;

			case SYSTEM_PORT_AUDIO:
			case SYSTEM_PORT_CV:
			{
				const void *in_buf = jack_port_get_buffer(source->sys_port, nsamples);
				memcpy(source->buf, in_buf, sample_buf_size);
				break;
			}
			case SYSTEM_PORT_MIDI:
			{
				void *in_buf = jack_port_get_buffer(source->sys_port, nsamples);
				void *seq_in = source->buf;

				LV2_Atom_Forge *forge = &handle->forge;
				LV2_Atom_Forge_Frame frame;
				lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE);
				LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0);

				if(ref && trans_changed)
					ref = _trans_event(handle, forge, rolling, &pos);

				int n = jack_midi_get_event_count(in_buf);
				for(int i=0; i<n; i++)
				{
					jack_midi_event_t mev;
					jack_midi_event_get(&mev, in_buf, i);

					//add jack midi event to in_buf
					if(ref)
						ref = lv2_atom_forge_frame_time(forge, mev.time);
					if(ref)
						ref = lv2_atom_forge_atom(forge, mev.size, handle->midi_MidiEvent);
					if(ref)
						ref = lv2_atom_forge_raw(forge, mev.buffer, mev.size);
					if(ref)
						lv2_atom_forge_pad(forge, mev.size);
				}
				if(ref)
					lv2_atom_forge_pop(forge, &frame);
				else
					lv2_atom_sequence_clear(seq_in);

				break;
			}

			case SYSTEM_PORT_OSC:
			{
				void *in_buf = jack_port_get_buffer(source->sys_port, nsamples);
				void *seq_in = source->buf;

				LV2_Atom_Forge *forge = &handle->forge;
				LV2_Atom_Forge_Frame frame;
				lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE);
				LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0);

				if(ref && trans_changed)
					ref = _trans_event(handle, forge, rolling, &pos);

				int n = jack_midi_get_event_count(in_buf);	
				for(int i=0; i<n; i++)
				{
					jack_midi_event_t mev;
					jack_midi_event_get(&mev, (void *)in_buf, i);

					//add jack osc event to in_buf
					if(osc_check_packet(mev.buffer, mev.size))
					{
						if(ref)
							ref = lv2_atom_forge_frame_time(forge, mev.time);
						handle->ref = ref;
						osc_dispatch_method(mev.buffer, mev.size, methods,
							_bundle_in, _bundle_out, handle);
						ref = handle->ref;
					}
				}
				if(ref)
					lv2_atom_forge_pop(forge, &frame);
				else
					lv2_atom_sequence_clear(seq_in);

				break;
			}

			case SYSTEM_PORT_COM:
			{
				void *seq_in = source->buf;

				LV2_Atom_Forge *forge = &handle->forge;
				LV2_Atom_Forge_Frame frame;
				lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE);
				LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0);

				const LV2_Atom_Object *obj;
				size_t size;
				while((obj = varchunk_read_request(bin->app_from_com, &size)))
				{
					if(ref)
						ref = lv2_atom_forge_frame_time(forge, 0);
					if(ref)
						ref = lv2_atom_forge_raw(forge, obj, size);
					if(ref)
						lv2_atom_forge_pad(forge, size);

					varchunk_read_advance(bin->app_from_com);
				}
				if(ref)
					lv2_atom_forge_pop(forge, &frame);
				else
					lv2_atom_sequence_clear(seq_in);

				break;
			}
		}
	}

	// update transport state
	handle->trans.rolling = rolling;
	handle->trans.frame = rolling
		? handle->trans.frame + nsamples
		: pos.frame;
	handle->trans.beats_per_bar = pos.beats_per_bar;
	handle->trans.beat_type = pos.beat_type;
	handle->trans.ticks_per_beat = pos.ticks_per_beat;
	handle->trans.beats_per_minute = pos.beats_per_minute;

	bin_process_pre(bin, nsamples, false);

	// fill output buffers
	for(const sp_app_system_sink_t *sink=sinks;
		sink->type != SYSTEM_PORT_NONE;
		sink++)
	{
		switch(sink->type)
		{
			case SYSTEM_PORT_NONE:
			case SYSTEM_PORT_CONTROL:
				break;

			case SYSTEM_PORT_AUDIO:
			case SYSTEM_PORT_CV:
			{
				void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples);
				memcpy(out_buf, sink->buf, sample_buf_size);
				break;
			}
			case SYSTEM_PORT_MIDI:
			{
				void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples);
				const LV2_Atom_Sequence *seq_out = sink->buf;

				// fill midi output buffer
				jack_midi_clear_buffer(out_buf);
				if(seq_out)
				{
					LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev)
					{
						const LV2_Atom *atom = &ev->body;

						if(atom->type != handle->midi_MidiEvent)
							continue; // ignore non-MIDI events

						jack_midi_event_write(out_buf, ev->time.frames,
							LV2_ATOM_BODY_CONST(atom), atom->size);
					}
				}

				break;
			}

			case SYSTEM_PORT_OSC:
			{
				void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples);
				const LV2_Atom_Sequence *seq_out = sink->buf;

				// fill midi output buffer
				jack_midi_clear_buffer(out_buf);
				if(seq_out)
				{
					LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev)
					{
						const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;

						handle->osc_ptr = handle->osc_buf;
						handle->osc_end = handle->osc_buf + OSC_SIZE;

						osc_atom_event_unroll(&handle->oforge, obj, _bundle_push_cb,
							_bundle_pop_cb, _message_cb, handle);

						size_t size = handle->osc_ptr
							? handle->osc_ptr - handle->osc_buf
							: 0;

						if(size)
						{
							jack_midi_event_write(out_buf, ev->time.frames,
								handle->osc_buf, size);
						}
					}
				}

				break;
			}

			case SYSTEM_PORT_COM:
			{
				const LV2_Atom_Sequence *seq_out = sink->buf;

				LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev)
				{
					const LV2_Atom *atom = (const LV2_Atom *)&ev->body;

					// try do process events directly
					bin->advance_ui = sp_app_from_ui(bin->app, atom);
					if(!bin->advance_ui) // queue event in ringbuffer instead
					{
						//fprintf(stderr, "plugin ui direct is blocked\n");

						void *ptr;
						size_t size = lv2_atom_total_size(atom);
						if((ptr = varchunk_write_request(bin->app_from_app, size)))
						{
							memcpy(ptr, atom, size);
							varchunk_write_advance(bin->app_from_app, size);
						}
						else
						{
							//fprintf(stderr, "app_from_ui ringbuffer full\n");
							//FIXME
						}
					}
				}
				break;
			}
		}
	}
	
	bin_process_post(bin);

	return 0;
}
Exemple #5
0
void SC_JackDriver::Run()
{
	jack_client_t* client = mClient;
	World* world = mWorld;

#ifdef SC_JACK_USE_DLL
	mDLL.Update(secondsSinceEpoch(getTime()));
#if SC_JACK_DEBUG_DLL
	static int tick = 0;
	if (++tick >= 10) {
		tick = 0;
		scprintf("DLL: t %.6f p %.9f sr %.6f e %.9f avg(e) %.9f inc %.9f\n",
				 mDLL.PeriodTime(), mDLL.Period(), mDLL.SampleRate(),
				 mDLL.Error(), mDLL.AvgError(), mOSCincrement * kOSCtoSecs);
	}
#endif
#else
	HostTime hostTime = getTime();

	double hostSecs = secondsSinceEpoch(hostTime);
	double sampleTime = (double)(jack_frame_time(client) + jack_frames_since_cycle_start(client));

	if (mStartHostSecs == 0) {
		mStartHostSecs = hostSecs;
		mStartSampleTime = sampleTime;
	} else {
		double instSampleRate = (sampleTime - mPrevSampleTime) / (hostSecs - mPrevHostSecs);
		double smoothSampleRate = mSmoothSampleRate;
		smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
		if (fabs(smoothSampleRate - mSampleRate) > 10.) {
			smoothSampleRate = mSampleRate;
		}
		mOSCincrement = (int64)(mOSCincrementNumerator / smoothSampleRate);
		mSmoothSampleRate = smoothSampleRate;
#if 0
		double avgSampleRate = (sampleTime - mStartSampleTime)/(hostSecs - mStartHostSecs);
		double jitter = (smoothSampleRate * (hostSecs - mPrevHostSecs)) - (sampleTime - mPrevSampleTime);
		double drift = (smoothSampleRate - mSampleRate) * (hostSecs - mStartHostSecs);
#endif
	}

	mPrevHostSecs = hostSecs;
	mPrevSampleTime = sampleTime;
#endif

	try {
		mFromEngine.Free();
		mToEngine.Perform();
		mOscPacketsToEngine.Perform();

		int numInputs = mInputList->mSize;
		int numOutputs = mOutputList->mSize;
		jack_port_t **inPorts = mInputList->mPorts;
		jack_port_t **outPorts = mOutputList->mPorts;
		sc_jack_sample_t **inBuffers = mInputList->mBuffers;
		sc_jack_sample_t **outBuffers = mOutputList->mBuffers;

		int numSamples = NumSamplesPerCallback();
		int bufFrames = mWorld->mBufLength;
		int numBufs = numSamples / bufFrames;

		float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames;
		float *outBuses = mWorld->mAudioBus;
		int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs;
		int32 *outTouched = mWorld->mAudioBusTouched;

		int minInputs = sc_min(numInputs, (int)mWorld->mNumInputs);
		int minOutputs = sc_min(numOutputs, (int)mWorld->mNumOutputs);

		int bufFramePos = 0;

		// cache I/O buffers
		for (int i = 0; i < minInputs; ++i) {
			inBuffers[i] = (sc_jack_sample_t*)jack_port_get_buffer(inPorts[i], numSamples);
		}

		for (int i = 0; i < minOutputs; ++i) {
			outBuffers[i] = (sc_jack_sample_t*)jack_port_get_buffer(outPorts[i], numSamples);
		}

		// main loop
#ifdef SC_JACK_USE_DLL
		int64 oscTime = mOSCbuftime = (int64)((mDLL.PeriodTime() - mMaxOutputLatency) * kSecondsToOSCunits + .5);
// 		int64 oscInc = mOSCincrement = (int64)(mOSCincrementNumerator / mDLL.SampleRate());
		int64 oscInc = mOSCincrement = (int64)((mDLL.Period() / numBufs) * kSecondsToOSCunits + .5);
		mSmoothSampleRate = mDLL.SampleRate();
		double oscToSamples = mOSCtoSamples = mSmoothSampleRate * kOSCtoSecs /* 1/pow(2,32) */;
#else
		int64 oscTime = mOSCbuftime = OSCTime(hostTime) - (int64)(mMaxOutputLatency * kSecondsToOSCunits + .5);
		int64 oscInc = mOSCincrement;
		double oscToSamples = mOSCtoSamples;
#endif

		for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames) {
			int32 bufCounter = mWorld->mBufCounter;
			int32 *tch;

			// copy+touch inputs
			tch = inTouched;
			for (int k = 0; k < minInputs; ++k) {
				sc_jack_sample_t *src = inBuffers[k] + bufFramePos;
				float *dst = inBuses + k * bufFrames;
				for (int n = 0; n < bufFrames; ++n) {
					*dst++ = *src++;
				}
				*tch++ = bufCounter;
			}

			// run engine
			int64 schedTime;
			int64 nextTime = oscTime + oscInc;

			while ((schedTime = mScheduler.NextTime()) <= nextTime) {
				float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
				float diffTimeFloor = floor(diffTime);
				world->mSampleOffset = (int)diffTimeFloor;
				world->mSubsampleOffset = diffTime - diffTimeFloor;

				if (world->mSampleOffset < 0) world->mSampleOffset = 0;
				else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;

				SC_ScheduledEvent event = mScheduler.Remove();
				event.Perform();
			}

			world->mSampleOffset = 0;
			world->mSubsampleOffset = 0.f;
			World_Run(world);

			// copy touched outputs
			tch = outTouched;
			for (int k = 0; k < minOutputs; ++k) {
				sc_jack_sample_t *dst = outBuffers[k] + bufFramePos;
				if (*tch++ == bufCounter) {
					float *src = outBuses + k * bufFrames;
					for (int n = 0; n < bufFrames; ++n) {
						*dst++ = *src++;
					}
				} else {
					for (int n = 0; n < bufFrames; ++n) {
						*dst++ = 0.0f;
					}
				}
			}

			// advance OSC time
			mOSCbuftime = oscTime = nextTime;
		}
	} catch (std::exception& exc) {
		scprintf("%s: exception in real time: %s\n", kJackDriverIdent, exc.what());
	} catch (...) {
		scprintf("%s: unknown exception in real time\n", kJackDriverIdent);
	}

	double cpuUsage = (double)jack_cpu_load(mClient);
	mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
	if (cpuUsage > mPeakCPU || --mPeakCounter <= 0) {
		mPeakCPU = cpuUsage;
		mPeakCounter = mMaxPeakCounter;
	}

	mAudioSync.Signal();
}
//================================================================
int process(jack_nframes_t nframes, void *arg)
{
	//fprintf(stderr,".");
	//return 0;

	//if shutting down fill buffers with 0 and return
	if(shutdown_in_progress==1)
	{
		int i;
		for(i=0; i < output_port_count; i++)
		{
			sample_t *o1;
			o1=(sample_t*)jack_port_get_buffer(ioPortArray[i], nframes);
			//memset(o1, 0, bytes_per_sample*nframes);
			//always 4 bytes, 32 bit float
			memset(o1, 0, 4*nframes);
		}
		return 0;
	}

	if(process_enabled==1)
	{
		//if no data for this cycle(all channels) 
		//is available(!), fill buffers with 0 or re-use old buffers and return
		if(jack_ringbuffer_read_space(rb) < port_count * bytes_per_sample*nframes)
		{
			int i;
			for(i=0; i < output_port_count; i++)
			{
				if(shutdown_in_progress==1 || process_enabled!=1)
				{
					return 0;
				}

				if(zero_on_underflow==1)
				{
					sample_t *o1;
					o1=(sample_t*)jack_port_get_buffer(ioPortArray[i], nframes);

					//memset(o1, 0, bytes_per_sample*nframes);
					//always 4 bytes, 32 bit float
					memset(o1, 0, 4*nframes);
				}
				print_info();
			}

			multi_channel_drop_counter++;

			if(rebuffer_on_underflow==1)
			{
				pre_buffer_counter=0;
				process_enabled=0;
			}

			//reset avg calculation
			time_interval_avg=0;
			msg_received_counter=0;
			fscs_avg_counter=0;

			return 0;
		}//end not enough data available in ringbuffer

		process_cycle_counter++;

		if(process_cycle_counter>receive_max-1 && test_mode==1)
		{
			last_test_cycle=1;
		}

		//init to 0. increment before use
		fscs_avg_counter++;

		frames_since_cycle_start_sum+=frames_since_cycle_start;
		frames_since_cycle_start_avg=frames_since_cycle_start_sum/fscs_avg_counter;

		//check and reset after use
		if(fscs_avg_calc_interval>=fscs_avg_counter)
		{
			fscs_avg_counter=0;
			frames_since_cycle_start_sum=0;	
		}

		//if sender sends more channels than we have output channels, ignore them
		int i;
		for(i=0; i<port_count; i++)
		{
			if(shutdown_in_progress==1 || process_enabled!=1)
			{
				return 0;
			}

			sample_t *o1;
			o1=(sample_t*)jack_port_get_buffer(ioPortArray[i], nframes);

			int16_t *o1_16;

			if(bytes_per_sample==2)
			{
				o1_16=malloc(bytes_per_sample*nframes);
			}

			//32 bit float
			if(bytes_per_sample==4)
			{
				jack_ringbuffer_read(rb, (char*)o1, bytes_per_sample*nframes);
			}
			//16 bit pcm
			else
			{
				jack_ringbuffer_read(rb, (char*)o1_16, bytes_per_sample*nframes);

				int x;
				for(x=0;x<nframes;x++)
				{
					o1[x]=(float)MIN_(MAX_((float)o1_16[x]/32760,-1.0f),1.0f);
				}

				free(o1_16);
			}

			/*
			fprintf(stderr,"\rreceiving from %s:%s",
				sender_host,sender_port
			);
			*/

			print_info();

		}//end for i < port_count

		//requested via /buffer, for test purposes (make buffer "tight")
		if(requested_drop_count>0)
		{
			uint64_t drop_bytes_count=requested_drop_count
				*port_count*period_size*bytes_per_sample;

			jack_ringbuffer_read_advance(rb,drop_bytes_count);

			requested_drop_count=0;
			multi_channel_drop_counter=0;
		}
	}//end if process_enabled==1
	else //if process_enabled==0
	{
		int i;
		for(i=0; i<port_count; i++)
		{
			if(shutdown_in_progress==1 || process_enabled!=1)
			{
				return 0;
			}

			sample_t *o1;
			o1=(sample_t*)jack_port_get_buffer(ioPortArray[i], nframes);

			//this is per channel, not per cycle. *port_count
			if(relaxed_display_counter>=update_display_every_nth_cycle*port_count
				|| last_test_cycle==1
			)
			{
				//only for init
				if((int)message_number<=0 && starting_transmission==0)
				{
					if(shutup==0 && quiet==0)
					{
						fprintf(stderr,"\rwaiting for audio input data...");
					}
					io_simple("/wait_for_input");
				}
				else
				{
					if(shutup==0 && quiet==0)
					{
						fprintf(stderr,"\r# %" PRId64 " buffering... mc periods to go: %" PRId64 "%s",
							message_number,
							pre_buffer_size-pre_buffer_counter,
							"\033[0J"
						);
					}

					if(io_())
					{
						lo_message msgio=lo_message_new();

						lo_message_add_int64(msgio,message_number);
						lo_message_add_int64(msgio,pre_buffer_size-pre_buffer_counter);

						lo_send_message(loio, "/buffering", msgio);
						lo_message_free(msgio);
					}
				}

				fflush(stderr);

				relaxed_display_counter=0;
			}
			relaxed_display_counter++;

			//set output buffer silent
			//memset(o1, 0, port_count*bytes_per_sample*nframes);
			//always 4 bytes, 32 bit float
			memset(o1, 0, port_count*4*nframes);
		}//end for i < port_count
	}//end process_enabled==0

	//tasks independent of process_enabled 0/1

	//if sender sends less channels than we have output channels, wee need to fill them with 0
	if(input_port_count < output_port_count)
	{
		int i;
		for(i=0;i < (output_port_count-input_port_count);i++)
		{
			//sample_t *o1;
			//o1=(sample_t*)
			/////?
			jack_port_get_buffer(ioPortArray[input_port_count+i], nframes);
		}
	}

	if(last_test_cycle==1)
	{
		if(shutup==0)
		{
			fprintf(stderr,"\ntest finished after %" PRId64 " process cycles\n",process_cycle_counter);
			fprintf(stderr,"(waiting and buffering cycles not included)\n");
		}

		io_simple_long("/test_finished",process_cycle_counter);

		shutdown_in_progress=1;
	}

	//simulate long cycle process duration
	//usleep(1000);

	frames_since_cycle_start=jack_frames_since_cycle_start(client);

	return 0;
} //end process()
Exemple #7
0
static int JackCallback( jack_nframes_t frames, void *userData )
{
    PaJackStream *stream = (PaJackStream*)userData;
    PaStreamCallbackTimeInfo timeInfo;
    int callbackResult;
    int chn;
    int framesProcessed;

    /* TODO: make this a lot more accurate */
    PaTime now = GetStreamTime(stream);
    timeInfo.currentTime = now;
    timeInfo.outputBufferDacTime = now;
    timeInfo.inputBufferAdcTime = now;

    if( stream->t0 == -1 )
    {
        if( stream->num_outgoing_connections == 0 )
        {
            /* TODO: how to handle stream time for capture-only operation? */
        }
        else
        {
            /* the beginning time needs to be initialized */
            stream->t0 = jack_frame_time( stream->jack_client ) -
                         jack_frames_since_cycle_start( stream->jack_client) +
                         jack_port_get_total_latency( stream->jack_client,
                                                      stream->local_output_ports[0] );
        }
    }

    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
            0 /* @todo pass underflow/overflow flags when necessary */ );

    for( chn = 0; chn < stream->num_incoming_connections; chn++ )
    {
        jack_default_audio_sample_t *channel_buf;
        channel_buf = (jack_default_audio_sample_t*)
            jack_port_get_buffer( stream->local_input_ports[chn],
                                  frames );

        PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor,
                                              chn,
                                              channel_buf );
    }

    for( chn = 0; chn < stream->num_outgoing_connections; chn++ )
    {
        jack_default_audio_sample_t *channel_buf;
        channel_buf = (jack_default_audio_sample_t*)
            jack_port_get_buffer( stream->local_output_ports[chn],
                                  frames );

        PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor,
                                               chn,
                                               channel_buf );
    }

    if( stream->num_incoming_connections > 0 )
        PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames );

    if( stream->num_outgoing_connections > 0 )
        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames );

    callbackResult = paContinue;
    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
                                                  &callbackResult );

    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
    stream->total_frames_sent += frames;


    if( callbackResult == paContinue )
    {
        /* nothing special */
    }
    else if( callbackResult == paAbort )
    {
        /* finish playback immediately  */

        /* TODO: memset 0 the outgoing samples to "cancel" them */

        stream->is_active = FALSE;

        /* return nonzero so we get deactivated (and the callback won't
         * get called again) */
        return 1;
    }
    else
    {
        /* User callback has asked us to stop with paComplete or other non-zero value. */

        stream->is_active = FALSE;

        /* return nonzero so we get deactivated (and the callback won't
         * get called again) */
        return 1;
    }
    return 0;
}
Exemple #8
0
jack_nframes_t luajack_frames_since_cycle_start(luajack_t *client) 
	{
	cud_t *cud = get_cud(client);	
	if(!cud) return 0;
	return jack_frames_since_cycle_start(cud->client);
	}