Exemplo n.º 1
0
/*****************************************************************************
 *
 * PROCESS_BUFFER()
 *
 * callback for jack to read audio data from ringbuffer
 * jack uses a realtime priority thread for this
 *
 *****************************************************************************/
int 
process_buffer(jack_nframes_t nframes, void *arg) {
    jack_default_audio_sample_t *in1;
    jack_default_audio_sample_t *in2;
    jack_default_audio_sample_t *out1;
    jack_default_audio_sample_t *out2;
    int				portion1;
    int				portion2;
    int             j, osc, lfo;

    /* Get the input and output buffers for audio data */
    in1  = jack_port_get_buffer (input_port1,  nframes);
    in2  = jack_port_get_buffer (input_port2,  nframes);
    out1 = jack_port_get_buffer (output_port1, nframes);
    out2 = jack_port_get_buffer (output_port2, nframes);

    /* check for jack not running or global shutdown so we don't get hung on mutex */
    if (!jack_running || shutdown) {
	return 0;
    }

    /* copy circular buffers and update index */
    /* WARNING:  needs to handle circular buffer properly */
    if ((buffer_read_index + nframes) > buffer_size) {
	portion1 = buffer_size - buffer_read_index;
	portion2 = nframes - portion1;
	memcpy (&(input_buffer1[buffer_read_index]), in1,   sizeof (jack_default_audio_sample_t) * portion1);
	memcpy (&(input_buffer2[buffer_read_index]), in2,   sizeof (jack_default_audio_sample_t) * portion1);
	memcpy (input_buffer1, &(in1[portion1]), sizeof (jack_default_audio_sample_t) * portion2);
	memcpy (input_buffer2, &(in2[portion1]), sizeof (jack_default_audio_sample_t) * portion2);

	memcpy (out1, &(output_buffer1[buffer_read_index]), sizeof (jack_default_audio_sample_t) * portion1);
	memcpy (out2, &(output_buffer2[buffer_read_index]), sizeof (jack_default_audio_sample_t) * portion1);
	memcpy (&(out1[portion1]), output_buffer1, sizeof (jack_default_audio_sample_t) * portion2);
	memcpy (&(out2[portion1]), output_buffer2, sizeof (jack_default_audio_sample_t) * portion2);
    }
    else {
	memcpy (&(input_buffer1[buffer_read_index]), in1,   sizeof (jack_default_audio_sample_t) * nframes);
	memcpy (&(input_buffer2[buffer_read_index]), in2,   sizeof (jack_default_audio_sample_t) * nframes);
	memcpy (out1, &(output_buffer1[buffer_read_index]), sizeof (jack_default_audio_sample_t) * nframes);
	memcpy (out2, &(output_buffer2[buffer_read_index]), sizeof (jack_default_audio_sample_t) * nframes);
    }
    buffer_read_index += nframes;
    buffer_read_index %= buffer_size;

    /* Update buffer full and buffer needed counters */
    buffer_full   -= nframes;
    
    if(setting_jack_transport_mode)
    {
    /* jack transport sync */
    jack_state = jack_transport_query (client, &jack_pos);
    /* reinit sync vars if transport is just started */
    if((jack_prev_state == JackTransportStopped) && (jack_state == JackTransportStarting))
    {
        #ifdef EXTRA_DEBUG
        if (debug)
	    {
	        fprintf (stderr, "Starting sync.\n");
        }
        #endif
        need_resync = 1;
    }
    if(jack_state == JackTransportRolling)
    {
        if(need_resync)
        {
            prev_frame = jack_pos.frame - nframes;
            frames_per_beat = sample_rate / global.bps;
            frames_per_tick = sample_rate / (jack_pos.ticks_per_beat * global.bps);
            current_frame = 0;
            need_resync = 0;
        }
    
        /* Handle BPM change */
        if(jack_pos.beats_per_minute && (global.bps != jack_pos.beats_per_minute / 60.0))
        {
            param[0].cc_val[program_number] = jack_pos.beats_per_minute - 64;
		    param[0].callback (main_window, (gpointer)(&(param[0])));
	    }
	    
	    /* frame-based sync */
	    current_frame = (jack_pos.frame - prev_frame);
	    prev_frame = jack_pos.frame;
	    
	    if(current_frame != nframes)
	    {
	        /* whoooaaaa, we're traveling through time! */
	        phase_correction = current_frame - nframes;
	    }
	    
	    /* do the actual sync */
	    if(phase_correction && (setting_jack_transport_mode == JACK_TRANSPORT_TNP))
	    {
	        #ifdef EXTRA_DEBUG
	        if (debug)
	        {
	            fprintf (stderr, "Out of sync. Phase correction:  %d\n", phase_correction);
            }
            #endif
            
	        part.delay_write_index += phase_correction;
	        while(part.delay_write_index < 0.0)
		        part.delay_write_index += part.delay_bufsize;
	        while(part.delay_write_index >= part.delay_bufsize)
		        part.delay_write_index -= part.delay_bufsize;
	    
	        part.chorus_lfo_index_a += phase_correction * part.chorus_lfo_adjust;
	        while(part.chorus_lfo_index_a < 0.0)
		        part.chorus_lfo_index_a += F_WAVEFORM_SIZE;
	        while(part.chorus_lfo_index_a >= F_WAVEFORM_SIZE)
		        part.chorus_lfo_index_a -= F_WAVEFORM_SIZE;

		    part.chorus_lfo_index_b = part.chorus_lfo_index_a + (F_WAVEFORM_SIZE * 0.25);
	        while(part.chorus_lfo_index_b < 0.0)
		        part.chorus_lfo_index_b += F_WAVEFORM_SIZE;
	        while(part.chorus_lfo_index_b >= F_WAVEFORM_SIZE)
		        part.chorus_lfo_index_b -= F_WAVEFORM_SIZE;

		    part.chorus_lfo_index_c = part.chorus_lfo_index_a + (F_WAVEFORM_SIZE * 0.5);
	        while(part.chorus_lfo_index_c < 0.0)
		        part.chorus_lfo_index_c += F_WAVEFORM_SIZE;
	        while(part.chorus_lfo_index_c >= F_WAVEFORM_SIZE)
		        part.chorus_lfo_index_c -= F_WAVEFORM_SIZE;

		    part.chorus_lfo_index_d = part.chorus_lfo_index_a + (F_WAVEFORM_SIZE * 0.75);
	        while(part.chorus_lfo_index_d < 0.0)
		        part.chorus_lfo_index_d += F_WAVEFORM_SIZE;
	        while(part.chorus_lfo_index_d >= F_WAVEFORM_SIZE)
		        part.chorus_lfo_index_d -= F_WAVEFORM_SIZE;
	    
	        for (osc = 0; osc < NUM_OSCS; osc++) {
				for (j = 0; j < setting_polyphony; j++) {
				    if (patch->osc_freq_base[osc] >= FREQ_BASE_TEMPO) 
				    {
				        switch (patch->freq_mod_type[osc]) {
		                case MOD_TYPE_LFO:
			            tmp_1 = part.lfo_out[patch->freq_lfo[osc]];
			            break;
		                case MOD_TYPE_OSC:
			            tmp_1 = ( voice[j].osc_out1[part.osc_freq_mod[osc]] + voice[j].osc_out2[part.osc_freq_mod[osc]] ) * 0.5;
			            break;
		                case MOD_TYPE_VELOCITY:
			            tmp_1 = voice[j].velocity_coef_linear;
			            break;
		                default:
			            tmp_1 = 0.0;
			            break;
		                }
		                
				        voice[j].index[osc] += phase_correction
				            * halfsteps_to_freq_mult ( ( tmp_1
					        * patch->freq_lfo_amount[osc] )
							   + part.osc_pitch_bend[osc]
							   + patch->osc_transpose[osc] )
			                * voice[j].osc_freq[osc] * wave_period;
				        
				        while (voice[j].index[osc] < 0.0)
			                voice[j].index[osc] += F_WAVEFORM_SIZE;
		                while (voice[j].index[osc] >= F_WAVEFORM_SIZE)
			                voice[j].index[osc] -= F_WAVEFORM_SIZE;
				    }
				}
			}
			for (lfo = 0; lfo < NUM_LFOS; lfo++) {
			    if (patch->lfo_freq_base[lfo] >= FREQ_BASE_TEMPO) 
			    {
				    part.lfo_index[lfo] += phase_correction
				        * part.lfo_freq[lfo]
		                * halfsteps_to_freq_mult (patch->lfo_transpose[lfo] + part.lfo_pitch_bend[lfo])
		                * wave_period;
				    
				    while (part.lfo_index[lfo] < 0.0)
		                part.lfo_index[lfo] += F_WAVEFORM_SIZE;
		            while (part.lfo_index[lfo] >= F_WAVEFORM_SIZE)
		                part.lfo_index[lfo] -= F_WAVEFORM_SIZE;
				}
			}
			phase_correction = 0;
	    }
    }
    else if ((jack_state == JackTransportStopped) && (jack_prev_state == JackTransportRolling))
    {        
        /* send NOTE_OFFs on transport stop */
        engine_notes_off();
    }
    
    jack_prev_state = jack_state;
    } /* if(setting_jack_transport) */

    /* Signal the engine that there's space again */
    if (pthread_mutex_trylock (&buffer_mutex) == 0) {
	pthread_cond_broadcast (&buffer_has_space);
	pthread_mutex_unlock (&buffer_mutex);
    }

    return 0;
}
Exemplo n.º 2
0
    void ModeHandler::process(const jack_nframes_t nframes)
    {
      void* inPortBuf = jack_port_get_buffer(m_inputPort, nframes);
      void* outPortBuf = jack_port_get_buffer(m_outputPort, nframes);

      jack_midi_clear_buffer(outPortBuf);

      const jack_transport_state_t state = jack_transport_query(m_client, nullptr);

      const jack_nframes_t eventCount = jack_midi_get_event_count(inPortBuf);

      for (size_t i = 0; i < eventCount; ++i)
      {
	jack_midi_event_t inEvent;
	jack_midi_event_get(&inEvent, inPortBuf, i);

	const jack_midi_data_t cmd = inEvent.buffer[0] & 0xf0;

	switch (cmd)
	{
	case MIDI_NOTEON:
	case MIDI_NOTEOFF:
	  {
	    const jack_midi_data_t note = inEvent.buffer[1];
	    const jack_midi_data_t velocity = inEvent.buffer[2];

	    int noteToUse = note;

	    // we only map on a note on
	    // on a note off we use the previously mapped note
	    // and only is transport is rolling
	    if (cmd == MIDI_NOTEON && velocity > 0)
	    {
	      if (state == JackTransportRolling)
	      {
		const int newNote = transpose(m_offset, m_quirkOffset, note);

		m_mappedNotes[note] = newNote;
		noteToUse = newNote;
	      }
	    }
	    else
	    {
	      // NOTEOFF
	      if (m_mappedNotes[note] != NOT_MAPPED)
	      {
		noteToUse = m_mappedNotes[note];
		m_mappedNotes[note] = NOT_MAPPED;
	      }
	    }

	    if (noteToUse != SKIP)
	    {
	      jack_midi_data_t data[3];
	      data[0] = inEvent.buffer[0];
	      data[1] = noteToUse;;
	      data[2] = inEvent.buffer[2];

	      jack_midi_event_write(outPortBuf, inEvent.time, data, 3);
	    }
	    break;
	  }
	default:
	  {
	    // just forward everything else
	    jack_midi_event_write(outPortBuf, inEvent.time, inEvent.buffer, inEvent.size);
	  }
	}
      }
    }
Exemplo n.º 3
0
static void do_jack(jack_client_t* client, char *button, int bk)
{
    black_keys = bk;

    // Jack Transport
    if (button[0] && (button[0] != button_prev_val[0])) //select :: Change octave
    {
        if (oct == 0) {
          oct = 1; //C6
          if (debug) printf("STAT: Changed base octave to C6\n");
        } else if (oct == 1) {
          oct = 2; //C7
          if (debug) printf("STAT: Changed base octave to C7\n");
        } else if (oct == 2) {
          oct = -2; //C3
          if (debug) printf("STAT: Changed base octave to C3\n");
        } else if (oct == -2) {
          oct = -1; //C4
          if (debug) printf("STAT: Changed base octave to C4\n");
        } else {
          oct = 0; //C5
          if (debug) printf("STAT: Changed base octave to C5\n");
        }
    }
    else if (button[3] && (button[3] != button_prev_val[3])) //start :: Start/Stop Transport
    {
        state = jack_transport_query(client, NULL);
        if (state) {
          jack_transport_stop(client);
          if (debug) printf("STAT: Transport stopped\n");
        } else {
          jack_transport_start(client);
          if (debug) printf("STAT: Transport started\n");
        }
    }

    if (button[16] && (button[16] != button_prev_val[16])) //PS :: Panic button
    {
        if (debug) printf("STAT: Panic!\n");
        jack_transport_stop(client);
        jack_transport_locate(client, 0);
        jack_transport_stop(client);
        int h;
        for (h=8; h<20; h++) {
            axis[h] = 0;
            axis_prev_velocity[h] = 0;
        }
    }
    else if (button[1]) //L3 :: Move transport backwards
    {
        jack_transport_query(client, &position);
        int prevJackFrame = position.frame - 100000;
        if (prevJackFrame < 0) prevJackFrame = 0;
        jack_transport_locate(client, prevJackFrame);
        if (button[1] != button_prev_val[1])
          if (debug) printf("STAT: Transport backwards...\n");
    }
    else if (button[1] != button_prev_val[1])
    {
          if (debug) printf("STAT: Transport normal\n");
    }
    else if (button[2]) //R3 :: Move transport forwards
    {
        jack_transport_query(client, &position);
        int nextJackFrame = position.frame + 100000;
        jack_transport_locate(client, nextJackFrame);
        if (button[2] != button_prev_val[2])
          if (debug) printf("STAT: Transport forwards...\n");
    }
    else if (button[2] != button_prev_val[2])
    {
          if (debug) printf("STAT: Transport normal\n");
    }

    button_prev_val[0] = button[0];
    button_prev_val[1] = button[1];
    button_prev_val[2] = button[2];
    button_prev_val[3] = button[3];
    button_prev_val[16] = button[16];

}
Exemplo n.º 4
0
int drumkv1_jack::process ( jack_nframes_t nframes )
{
	if (!m_activated)
		return 0;

	const uint16_t nchannels = drumkv1::channels();
	float *ins[nchannels], *outs[nchannels];
	for (uint16_t k = 0; k < nchannels; ++k) {
		ins[k]  = static_cast<float *> (
			::jack_port_get_buffer(m_audio_ins[k], nframes));
		outs[k] = static_cast<float *> (
			::jack_port_get_buffer(m_audio_outs[k], nframes));
	}

	jack_position_t pos;
	jack_transport_query(m_client, &pos);
	if (pos.valid & JackPositionBBT) {
		const float host_bpm = float(pos.beats_per_minute);
		if (paramValue(drumkv1::LFO1_BPMSYNC) > 0.0f) {
		#ifdef CONFIG_LFO_BPMRATEX_0
			const float rate_bpm = lfo_rate_bpm(host_bpm);
			const float rate = paramValue(drumkv1::LFO1_RATE);
			if (::fabsf(rate_bpm - rate) > 0.01f)
				setParamValue(drumkv1::LFO1_RATE, rate_bpm);
		#else
			const float bpm = paramValue(drumkv1::LFO1_BPM);
			if (::fabsf(host_bpm - bpm) > 0.01f)
				setParamValue(drumkv1::LFO1_BPM, host_bpm);
		#endif
		}
		if (paramValue(drumkv1::DEL1_BPMSYNC) > 0.0f) {
			const float bpm = paramValue(drumkv1::DEL1_BPM);
			if (bpm > 0.0f && ::fabsf(host_bpm - bpm) > 0.01f)
				setParamValue(drumkv1::DEL1_BPM, host_bpm);
		}
	}

	uint32_t ndelta = 0;

#ifdef CONFIG_JACK_MIDI
	void *midi_in = ::jack_port_get_buffer(m_midi_in, nframes);
	if (midi_in) {
		const uint32_t nevents = ::jack_midi_get_event_count(midi_in);
		for (uint32_t n = 0; n < nevents; ++n) {
			jack_midi_event_t event;
			::jack_midi_event_get(&event, midi_in, n);
			if (event.time > ndelta) {
				const uint32_t nread = event.time - ndelta;
				if (nread > 0) {
					drumkv1::process(ins, outs, nread);
					for (uint16_t k = 0; k < nchannels; ++k) {
						ins[k]  += nread;
						outs[k] += nread;
					}
				}
			}
			ndelta = event.time;
			drumkv1::process_midi(event.buffer, event.size);
		}
	}
#endif
#ifdef CONFIG_ALSA_MIDI
	const jack_nframes_t buffer_size = ::jack_get_buffer_size(m_client);
	const jack_nframes_t frame_time  = ::jack_last_frame_time(m_client);
	uint8_t event_buffer[1024];
	jack_midi_event_t event;
	while (::jack_ringbuffer_peek(m_alsa_buffer,
			(char *) &event, sizeof(event)) == sizeof(event)) {
		if (event.time > frame_time)
			break;
		jack_nframes_t event_time = frame_time - event.time;
		if (event_time > buffer_size)
			event_time = 0;
		else
			event_time = buffer_size - event_time;
		if (event_time > ndelta) {
			const uint32_t nread = event_time - ndelta;
			if (nread > 0) {
				drumkv1::process(ins, outs, nread);
				for (uint16_t k = 0; k < nchannels; ++k) {
					ins[k]  += nread;
					outs[k] += nread;
				}
			}
			ndelta = event_time;
		}
		::jack_ringbuffer_read_advance(m_alsa_buffer, sizeof(event));
		::jack_ringbuffer_read(m_alsa_buffer, (char *) event_buffer, event.size);
		drumkv1::process_midi(event_buffer, event.size);
	}
#endif // CONFIG_ALSA_MIDI

	if (nframes > ndelta)
		drumkv1::process(ins, outs, nframes - ndelta);

	return 0;
}
Exemplo n.º 5
0
int samplv1_jack::process ( jack_nframes_t nframes )
{
    if (!m_activated)
        return 0;

    const uint16_t nchannels = samplv1::channels();
    float *ins[nchannels], *outs[nchannels];
    for (uint16_t k = 0; k < nchannels; ++k) {
        ins[k]  = static_cast<float *> (
                      ::jack_port_get_buffer(m_audio_ins[k], nframes));
        outs[k] = static_cast<float *> (
                      ::jack_port_get_buffer(m_audio_outs[k], nframes));
    }

    jack_position_t pos;
    jack_transport_query(m_client, &pos);
    if (pos.valid & JackPositionBBT) {
        const float host_bpm = float(pos.beats_per_minute);
        if (::fabsf(host_bpm - samplv1::tempo()) > 0.001f)
            samplv1::setTempo(host_bpm);
    }

    uint32_t ndelta = 0;

#ifdef CONFIG_JACK_MIDI
    void *midi_in = ::jack_port_get_buffer(m_midi_in, nframes);
    if (midi_in) {
        const uint32_t nevents = ::jack_midi_get_event_count(midi_in);
        for (uint32_t n = 0; n < nevents; ++n) {
            jack_midi_event_t event;
            ::jack_midi_event_get(&event, midi_in, n);
            if (event.time > ndelta) {
                const uint32_t nread = event.time - ndelta;
                if (nread > 0) {
                    samplv1::process(ins, outs, nread);
                    for (uint16_t k = 0; k < nchannels; ++k) {
                        ins[k]  += nread;
                        outs[k] += nread;
                    }
                }
            }
            ndelta = event.time;
            samplv1::process_midi(event.buffer, event.size);
        }
    }
#endif
#ifdef CONFIG_ALSA_MIDI
    const jack_nframes_t buffer_size = ::jack_get_buffer_size(m_client);
    const jack_nframes_t frame_time  = ::jack_last_frame_time(m_client);
    uint8_t event_buffer[1024];
    jack_midi_event_t event;
    while (::jack_ringbuffer_peek(m_alsa_buffer,
                                  (char *) &event, sizeof(event)) == sizeof(event)) {
        if (event.time > frame_time)
            break;
        jack_nframes_t event_time = frame_time - event.time;
        if (event_time > buffer_size)
            event_time = 0;
        else
            event_time = buffer_size - event_time;
        if (event_time > ndelta) {
            const uint32_t nread = event_time - ndelta;
            if (nread > 0) {
                samplv1::process(ins, outs, nread);
                for (uint16_t k = 0; k < nchannels; ++k) {
                    ins[k]  += nread;
                    outs[k] += nread;
                }
            }
            ndelta = event_time;
        }
        ::jack_ringbuffer_read_advance(m_alsa_buffer, sizeof(event));
        ::jack_ringbuffer_read(m_alsa_buffer, (char *) event_buffer, event.size);
        samplv1::process_midi(event_buffer, event.size);
    }
#endif // CONFIG_ALSA_MIDI

    if (nframes > ndelta)
        samplv1::process(ins, outs, nframes - ndelta);

    return 0;
}
Exemplo n.º 6
0
void JackAudioDriver::updateTransportInfo()
{
	// The following four lines do only cover the special case of
	// audioEngine_updateNoteQueue() returning -1 in
	// audioEngine_process() and triggering an addition relocation
	// of the transport position to the beginning of the song
	// using locateInNCycles() to possibly keep synchronization
	// with Ardour.
	if ( locate_countdown == 1 )
		locate( locate_frame );
	if ( locate_countdown > 0 )
		locate_countdown--;
	
	if ( Preferences::get_instance()->m_bJackTransportMode !=
	     Preferences::USE_JACK_TRANSPORT ){
		return;
	}
	// jack_transport_query() (jack/transport.h) queries the
	// current transport state and position. If called from the
	// process thread, the second argument, which is a pointer to
	// a structure for returning current transport, corresponds to
	// the first frame of the current cycle and the state returned
	// is valid for the entire cycle. #m_JackTransportPos->valid
	// will show which fields contain valid data. If
	// #m_JackTransportPos is NULL, do not return position
	// information.
	m_JackTransportState = jack_transport_query( m_pClient, &m_JackTransportPos );

	// WARNINGLOG( QString( "[Jack-Query] state: %1, frame: %2, position bit: %3, bpm: %4" )
	// 	 .arg( m_JackTransportState )
	// 	 .arg( m_JackTransportPos.frame )
	// 	 .arg( m_JackTransportPos.valid )
	// 	 .arg( m_JackTransportPos.beats_per_minute ) );
	// Update the TransportInfo in m_transport based on the state
	// returned by jack_transport_query.
	switch ( m_JackTransportState ) {
	case JackTransportStopped: // Transport is halted
		m_transport.m_status = TransportInfo::STOPPED;
		//INFOLOG( "[updateTransportInfo] STOPPED - frames: " + to_string(m_transportPos.frame) );
		break;
		
	case JackTransportRolling: // Transport is playing
		// If the valid member matches the JackPositionBBT
		// bits, there is a JACK timebase master present
		// supplying bar, beat, and tick information along
		// with the plain transport position in frames. We
		// will use it for re-positioning. But only at the end
		// of the next cycle, because this timebase master has
		// to properly initialize its state during this cycle
		// too.
		if ( m_transport.m_status != TransportInfo::ROLLING &&
		     ( m_JackTransportPos.valid & JackPositionBBT ) ) {
			must_relocate = 2;
			//WARNINGLOG( "Jack transport starting: Resyncing in 2 x Buffersize!!" );
		}
		m_transport.m_status = TransportInfo::ROLLING;
		//INFOLOG( "[updateTransportInfo] ROLLING - frames: " + to_string(m_transportPos.frame) );
		break;

	case JackTransportStarting: // Waiting for sync ready. If
				    // there are slow-sync clients,
				    // this can take more than one
				    // cycle.
		m_transport.m_status = TransportInfo::STOPPED;
		//INFOLOG( "[updateTransportInfo] STARTING (stopped) - frames: " + to_string(m_transportPos.frame) );
		break;
		
	default:
		ERRORLOG( "Unknown jack transport state" );
	}

	// Updating TickSize and BPM
	Hydrogen * H = Hydrogen::get_instance();
	// JACK may have re-located us anywhere. Therefore, we have to
	// check for a bpm change every cycle. We will do so by
	// updating both the global speed of the song, as well as the
	// fallback speed (H->getNewBpmJTM) with the local tempo at
	// the current position on the timeline.
	H->setTimelineBpm(); 

	// Check whether another JACK master is present (the second if
	// clause won't evaluate to true if Hydrogen itself is the
	// timebase master) and whether it changed the transport
	// state. Note that only the JACK timebase master and not
	// arbitrary clients can do this. If so, the speed is updated
	// an a relocation according to the bar, beat, and tick
	// information will be triggered right away.
	if ( m_JackTransportPos.valid & JackPositionBBT ) {
		float bpm = ( float )m_JackTransportPos.beats_per_minute;
		if ( m_transport.m_nBPM != bpm ) {
			if ( Preferences::get_instance()->m_bJackMasterMode ==
			     Preferences::NO_JACK_TIME_MASTER ){
				// WARNINGLOG( QString( "Tempo change from jack-transport: %1" ).arg( bpm ) );
				m_transport.m_nBPM = bpm;
				must_relocate = 1; 
			}
		}
	}

        // This clause detects a re-location, which was either
        // triggered by an user-interaction (e.g. clicking the forward
        // button or clicking somewhere on the timeline) or by a
        // different JACK client.
	if ( m_transport.m_nFrames + bbt_frame_offset != m_JackTransportPos.frame ) {
		// Whether there is a JACK timebase master registered
		// but the audio engine was neither (re)started nor a
		// change in the speed was found beforehand.
		if ( ( m_JackTransportPos.valid & JackPositionBBT ) && must_relocate == 0 ) {
			// WARNINGLOG( "Frame offset mismatch; triggering resync in 2 cycles" );
			must_relocate = 2; // re-locate at the end of
					   // the next cycle.
		} else {
			if ( Preferences::get_instance()->m_bJackMasterMode ==
			     Preferences::NO_JACK_TIME_MASTER ) {
				// Just consider the transport
				// position as dirty, reassign the
				// one obtained in the query, and
				// reset the offset.
				m_transport.m_nFrames = m_JackTransportPos.frame;
				bbt_frame_offset = 0;
				// If not registered as JACK time
				// master, the following line is
				// needed to be able to relocate by
				// clicking the song ruler (wired
				// corner case, but still...)
				if ( m_transport.m_status == TransportInfo::ROLLING )
					// Setting
					// H->m_nPatternStartTick = -1
					// if in pattern mode.
					H->triggerRelocateDuringPlay();
			} else {
			        // Fallback to the transport position
			        // of the last cycle.
				m_transport.m_nFrames = H->getHumantimeFrames();
			}
		}
	}
	// Only used if Hydrogen is in JACK timebase master
	// mode. Updated every cycle.
	if ( H->getHumantimeFrames() != m_JackTransportPos.frame ) {
		H->setHumantimeFrames(m_JackTransportPos.frame);
		// WARNINGLOG( QString( "fix Humantime: %1" ).arg( m_JackTransportPos.frame ) );
	}

	// Trigger the re-location based on the information provided
	// by another JACK timebase master.
	if ( must_relocate == 1 ) {
		WARNINGLOG( QString( "Resyncing! bbt_frame_offset: %1" ).arg( bbt_frame_offset ) );
		relocateBBT();
		if ( m_transport.m_status == TransportInfo::ROLLING ) {
			// Setting H->m_nPatternStartTick = -1 if in
			// pattern mode
			H->triggerRelocateDuringPlay();
		}
	}
	
	if ( must_relocate > 0 ) must_relocate--;
}
Exemplo n.º 7
0
Arquivo: jack-pv.c Projeto: EQ4/waonc
/**
 * The process callback for this JACK application is called in a
 * special realtime thread once for each audio cycle.
 *
 * This client follows a simple rule: when the JACK transport is
 * running, copy the input port to the output.  When it stops, exit.
 */
int
my_jack_process (jack_nframes_t nframes, void * arg)
{
   extern FILE * err_log;
   static long play_cur = 0;
   static jack_default_audio_sample_t * in = NULL;
   static jack_nframes_t in_len = 0;
   static double * left  = NULL;
   static double * right = NULL;
   static int hop_res0 = 0;
   static int cur = 0;
   jack_transport_state_t ts;
   jack_default_audio_sample_t * out = NULL;
   struct pv_jack * pv_jack = (struct pv_jack *) arg;

   if (in == NULL)
   {
      in = (jack_default_audio_sample_t *)malloc
           (sizeof (jack_default_audio_sample_t) * nframes);
      in_len = nframes;
   }
   else if (in_len < nframes)
   {
      in = (jack_default_audio_sample_t *)realloc
           (in,
            sizeof (jack_default_audio_sample_t) * nframes);
      in_len = nframes;
   }

   if (left == NULL)
   {
      left  = (double *)malloc (sizeof (double) * pv_jack->pv->hop_res);
      right = (double *)malloc (sizeof (double) * pv_jack->pv->hop_res);
      CHECK_MALLOC (left,  "my_jack_process");
      CHECK_MALLOC (right, "my_jack_process");
      hop_res0 = pv_jack->pv->hop_res;
      cur = hop_res0; /* no data left */
   }
   else if (hop_res0 < pv_jack->pv->hop_res)
   {
      left  = (double *)realloc (left,  sizeof (double) * pv_jack->pv->hop_res);
      right = (double *)realloc (right, sizeof (double) * pv_jack->pv->hop_res);
      CHECK_MALLOC (left,  "my_jack_process");
      CHECK_MALLOC (right, "my_jack_process");
      hop_res0 = pv_jack->pv->hop_res;
      cur = hop_res0; /* no data left */
   }

   /* check */

   fprintf (err_log, "cur = %d\n", cur);

   ts = jack_transport_query (pv_jack->client, NULL);
   if (ts == JackTransportRolling)
   {
      int i, j;
      if (pv_jack->state == Init)
      {
         pv_jack->state = Run;
      }

      out = (jack_default_audio_sample_t *)
           jack_port_get_buffer (pv_jack->out, nframes);

      /* the process for nframes */
      /* paste the data left in left[] and right[] from cur to hop_res0 */

      for (i = 0, j = cur; (j < hop_res0) && (i < (int) nframes); i ++, j ++)
      {
         in[i] = (jack_default_audio_sample_t)(0.5 * (left[j] + right[j]));
      }
      cur = j;
      cur = cur % hop_res0;

      /* if the data is not enough, */

      while (i < (int) nframes)
      {
         int j;

         /* process further data (next hop_res frames) */

         if (cur != 0)
         {
            fprintf (stderr, "cur update failed...\n");
            fprintf (err_log, "cur update failed...\n");
            fprintf (err_log, "cur = %d\n", cur);
            fclose (err_log);
            exit (1);
         }
         jack_pv_complex_play_step (pv_jack->pv, play_cur, left, right);
         play_cur += pv_jack->pv->hop_ana;

         /* then, paste the data in left[] and right[] from 0 to hop_res0 */

         for (j = 0; (j < hop_res0) && (i < (int) nframes); j ++, i ++)
         {
            in[i] = (jack_default_audio_sample_t)(0.5 * (left[j] + right[j]));
         }
         cur = j;
         cur = cur % hop_res0;
      }

      /* now, the data in in[] is enough to pass jack server */

      memcpy (out, in,
              sizeof (jack_default_audio_sample_t) * nframes);
   }
   else if (ts == JackTransportStopped)
   {
      if (pv_jack->state == Run)
      {
         pv_jack->state = Exit;
      }
   }
   return 0;
}
Exemplo n.º 8
0
static int process_cb(jack_nframes_t nframes, void *arg)
{
    struct cbox_jack_io_impl *jii = arg;
    struct cbox_io *io = jii->ioi.pio;
    struct cbox_io_callbacks *cb = io->cb;
    
    io->io_env.buffer_size = nframes;
    for (int i = 0; i < io->io_env.input_count; i++)
        io->input_buffers[i] = jack_port_get_buffer(jii->inputs[i], nframes);
    for (int i = 0; i < io->io_env.output_count; i++)
    {
        io->output_buffers[i] = jack_port_get_buffer(jii->outputs[i], nframes);
        if (!io->output_buffers[i])
            continue;
        for (int j = 0; j < nframes; j ++)
            io->output_buffers[i][j] = 0.f;
    }
    for (GSList *p = io->midi_inputs; p; p = p->next)
    {
        struct cbox_jack_midi_input *input = p->data;
        if (input->hdr.output_set || input->hdr.enable_appsink)
        {
            copy_midi_data_to_buffer(input->port, io->io_env.buffer_size, &input->hdr.buffer);
            if (input->hdr.enable_appsink)
                cbox_midi_appsink_supply(&input->hdr.appsink, &input->hdr.buffer);
        }
        else
            cbox_midi_buffer_clear(&input->hdr.buffer);
    }
    if (cb->on_transport_sync)
    {
        jack_transport_state_t state = jack_transport_query(jii->client, NULL);
        if (state != jii->last_transport_state)
        {
            jack_position_t pos;
            jack_transport_query(jii->client, &pos);
            if (jii->debug_transport)
                g_message("JACK transport: incoming state change, state = %s, last state = %s, pos = %d\n", transport_state_names[state], transport_state_names[(int)jii->last_transport_state], (int)pos.frame);
            if (state == JackTransportStopped)
            {
                if (cb->on_transport_sync(cb->user_data, ts_stopping, pos.frame))
                    jii->last_transport_state = state;
            }
            else
            if (state == JackTransportRolling && jii->last_transport_state == JackTransportStarting)
            {
                if (cb->on_transport_sync(cb->user_data, ts_rolling, pos.frame))
                    jii->last_transport_state = state;
            }
            else
                jii->last_transport_state = state;
        }
    }
    cb->process(cb->user_data, io, nframes);
    for (int i = 0; i < io->io_env.input_count; i++)
        io->input_buffers[i] = NULL;
    for (int i = 0; i < io->io_env.output_count; i++)
        io->output_buffers[i] = NULL;
    for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
    {
        struct cbox_jack_midi_output *midiout = p->data;

        void *pbuf = jack_port_get_buffer(midiout->port, nframes);
        jack_midi_clear_buffer(pbuf);

        cbox_midi_merger_render(&midiout->hdr.merger);
        if (midiout->hdr.buffer.count)
        {
            uint8_t tmp_data[4];
            for (int i = 0; i < midiout->hdr.buffer.count; i++)
            {
                const struct cbox_midi_event *event = cbox_midi_buffer_get_event(&midiout->hdr.buffer, i);
                const uint8_t *pdata = cbox_midi_event_get_data(event);
                if ((pdata[0] & 0xF0) == 0x90 && !pdata[2] && event->size == 3)
                {
                    tmp_data[0] = pdata[0] & ~0x10;
                    tmp_data[1] = pdata[1];
                    tmp_data[2] = pdata[2];
                    pdata = tmp_data;
                }
                if (jack_midi_event_write(pbuf, event->time, pdata, event->size))
                {
                    g_warning("MIDI buffer overflow on JACK output port '%s'", midiout->hdr.name);
                    break;
                }
            }
        }
    }
    return 0;
}
Exemplo n.º 9
0
float AUD_JackDevice::getPlaybackPosition()
{
	jack_position_t position;
	jack_transport_query(m_client, &position);
	return position.frame / (float) m_specs.rate;
}
Exemplo n.º 10
0
void
jack_assistant::position (bool songmode, midipulse tick)
{

#ifdef SEQ64_JACK_SUPPORT

    long current_tick = 0;
    if (songmode)                               /* master in song mode */
    {
        if (! is_null_midipulse(tick))
            current_tick = tick * 10;
    }

    int ticks_per_beat = m_ppqn * 10;
    int beats_per_minute = parent().get_beats_per_minute();
    uint64_t tick_rate = (uint64_t(m_jack_frame_rate) * current_tick * 60.0);
    long tpb_bpm = ticks_per_beat * beats_per_minute * 4.0 / m_beat_width;
    uint64_t jack_frame = tick_rate / tpb_bpm;
    jack_transport_locate(m_jack_client, jack_frame);

#ifdef SEQ64_STAZED_JACK_SUPPORT

#if 0

    /*
     * The call to jack_BBT_position() is not necessary to change JACK
     * position!  Must set these here since they are set in timebase.
     */

    jack_position_t pos;
    double jack_tick = current_tick * m_bw / 4.0;
    pos.ticks_per_beat = m_ppqn * 10;
    pos.beats_per_minute = m_master_bus.get_bpm();
    jack_BBT_position(pos, jack_tick);

    /*
     * Calculate JACK frame to put into pos.frame; it is what matters for
     * position change.  Very similar to the uncommented code above.
     */

    uint64_t tick_rate = ((uint64_t)pos.frame_rate * current_tick * 60.0);
    long tpb_bpm = pos.ticks_per_beat * pos.beats_per_minute *
        4.0 / pos.beat_type;

    pos.frame = tick_rate / tpb_bpm;

    /*
     * ticks * 10 = jack ticks;
     * jack ticks / ticks per beat = num beats;
     * num beats / beats per minute = num minutes
     * num minutes * 60 = num seconds
     * num secords * frame_rate  = frame
     */

    jack_transport_reposition(m_jack_client, &pos);

#endif  // 0

    if (parent().is_running())
        parent().set_reposition(false);

#endif  // SEQ64_STAZED_JACK_SUPPORT

Tutorial code from jack_assistant::position():

#ifdef SAMPLE_AUDIO_CODE    // disabled, shown only for reference & learning
        jack_transport_state_t ts = jack_transport_query(jack->client(), NULL);
        if (ts == JackTransportRolling)
        {
            jack_default_audio_sample_t * in;
            jack_default_audio_sample_t * out;
            if (client_state == Init)
                client_state = Run;

            in = jack_port_get_buffer(input_port, nframes);
            out = jack_port_get_buffer(output_port, nframes);
            memcpy(out, in, sizeof (jack_default_audio_sample_t) * nframes);
        }
        else if (ts == JackTransportStopped)
        {
            if (client_state == Run)
                client_state = Exit;
        }
#endif

}
Exemplo n.º 11
0
AUD_JackDevice::AUD_JackDevice(std::string name, AUD_DeviceSpecs specs, int buffersize)
{
	if(specs.channels == AUD_CHANNELS_INVALID)
		specs.channels = AUD_CHANNELS_STEREO;

	// jack uses floats
	m_specs = specs;
	m_specs.format = AUD_FORMAT_FLOAT32;

	jack_options_t options = JackNullOption;
	jack_status_t status;

	// open client
	m_client = jack_client_open(name.c_str(), options, &status);
	if(m_client == NULL)
		AUD_THROW(AUD_ERROR_JACK, clientopen_error);

	// set callbacks
	jack_set_process_callback(m_client, AUD_JackDevice::jack_mix, this);
	jack_on_shutdown(m_client, AUD_JackDevice::jack_shutdown, this);
	jack_set_sync_callback(m_client, AUD_JackDevice::jack_sync, this);

	// register our output channels which are called ports in jack
	m_ports = new jack_port_t*[m_specs.channels];

	try
	{
		char portname[64];
		for(int i = 0; i < m_specs.channels; i++)
		{
			sprintf(portname, "out %d", i+1);
			m_ports[i] = jack_port_register(m_client, portname,
											JACK_DEFAULT_AUDIO_TYPE,
											JackPortIsOutput, 0);
			if(m_ports[i] == NULL)
				AUD_THROW(AUD_ERROR_JACK, port_error);
		}
	}
	catch(AUD_Exception&)
	{
		jack_client_close(m_client);
		delete[] m_ports;
		throw;
	}

	m_specs.rate = (AUD_SampleRate)jack_get_sample_rate(m_client);

	buffersize *= sizeof(sample_t);
	m_ringbuffers = new jack_ringbuffer_t*[specs.channels];
	for(unsigned int i = 0; i < specs.channels; i++)
		m_ringbuffers[i] = jack_ringbuffer_create(buffersize);
	buffersize *= specs.channels;
	m_deinterleavebuf.resize(buffersize);
	m_buffer.resize(buffersize);

	create();

	m_valid = true;
	m_sync = 0;
	m_syncFunc = NULL;
	m_nextState = m_state = jack_transport_query(m_client, NULL);

	pthread_mutex_init(&m_mixingLock, NULL);
	pthread_cond_init(&m_mixingCondition, NULL);

	// activate the client
	if(jack_activate(m_client))
	{
		jack_client_close(m_client);
		delete[] m_ports;
		for(unsigned int i = 0; i < specs.channels; i++)
			jack_ringbuffer_free(m_ringbuffers[i]);
		delete[] m_ringbuffers;
		pthread_mutex_destroy(&m_mixingLock);
		pthread_cond_destroy(&m_mixingCondition);
		destroy();

		AUD_THROW(AUD_ERROR_JACK, activate_error);
	}

	const char** ports = jack_get_ports(m_client, NULL, NULL,
										JackPortIsPhysical | JackPortIsInput);
	if(ports != NULL)
	{
		for(int i = 0; i < m_specs.channels && ports[i]; i++)
			jack_connect(m_client, jack_port_name(m_ports[i]), ports[i]);

		free(ports);
	}

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	pthread_create(&m_mixingThread, &attr, runMixingThread, this);

	pthread_attr_destroy(&attr);
}
Exemplo n.º 12
0
static void
process_midi_output(jack_nframes_t nframes)
{
	int		i, t, bytes_remaining, track_number;
	unsigned char  *buffer, tmp_status;
	void		*port_buffers[MAX_NUMBER_OF_TRACKS];
	jack_nframes_t	last_frame_time;
	jack_transport_state_t transport_state;
	static jack_transport_state_t previous_transport_state = JackTransportStopped;
	static int previous_playback_started = -1;
	static int previous_playback_paused = 0;

	for (i = 0; i <= smf->number_of_tracks; i++) {
		port_buffers[i] = jack_port_get_buffer(output_ports[i], nframes);

		if (port_buffers[i] == NULL) {
			warn_from_jack_thread_context("jack_port_get_buffer failed, cannot send anything.");
			return;
		}

#ifdef JACK_MIDI_NEEDS_NFRAMES
		jack_midi_clear_buffer(port_buffers[i], nframes);
#else
		jack_midi_clear_buffer(port_buffers[i]);
#endif

		if (just_one_output)
			break;
	}

	if (ctrl_c_pressed) {
		send_all_sound_off(port_buffers, nframes);
		
		/* The idea here is to exit at the second time process_midi_output gets called.
		   Otherwise, All Sound Off won't be delivered. */
		ctrl_c_pressed++;
		if (ctrl_c_pressed >= 3)
			exit(0);

		return;
	}

	// g_debug("PROCESS CALLBACK!!!");

	if (playback_paused) {
		if (!previous_playback_paused) {
			send_all_sound_off(port_buffers, nframes);
		}
		previous_playback_paused = playback_paused;
		return;
	}
	previous_playback_paused = playback_paused;

	if (use_transport) {

		// if (!ready_to_roll) return;

		transport_state = jack_transport_query(jack_client, NULL);

		if (transport_state == JackTransportStopped) {
			if (previous_transport_state == JackTransportRolling) {
				send_all_sound_off(port_buffers, nframes);
			}
			playback_started = -1;
		}

		if (transport_state == JackTransportStarting) {
			playback_started = -1;
		}

		if (transport_state == JackTransportRolling) {
			if (previous_transport_state != JackTransportRolling) {
				jack_position_t position;
				jack_transport_query(jack_client, &position);
				song_position = position.frame;
				playback_started = jack_last_frame_time(jack_client);
			}
		}

		previous_transport_state = transport_state;
	}
	else {
		if (playback_started == -1) {
			if (previous_playback_started >= 0) {
				send_all_sound_off(port_buffers, nframes);
				send_sond_end();
			}
		}
		previous_playback_started = playback_started;
	}


	/* End of song already? */
	if (playback_started < 0)
		return;

	last_frame_time = jack_last_frame_time(jack_client);

	/* We may push at most one byte per 0.32ms to stay below 31.25 Kbaud limit. */
	bytes_remaining = nframes_to_ms(nframes) * rate_limit;

	double loop_offset = loop_song(smf);

	for (;;) {

		smf_event_t *event = smf_peek_next_event(smf);

		int end_of_song = 0;
		int is_meta_event = 0;

		if (event == NULL) {
			end_of_song = 1;
		}
		else if (smf_event_is_metadata(event)) {
			is_meta_event = 1;
			char *decoded = smf_event_decode(event);
			if (decoded) {
				if (!be_quiet)
					g_debug("Metadata: %s", decoded);
				end_of_song = process_meta_event(decoded);
				free(decoded);
			}
		}

		if (end_of_song) {
			if (!be_quiet)
				g_debug("End of song.");
			playback_started = -1;

			if (!use_transport)
				ctrl_c_pressed = 1;
			break;
		}

		if (is_meta_event) {
			smf_event_t *ret = smf_get_next_event(smf);
			assert(ret != 0);
			continue;
		}

		bytes_remaining -= event->midi_buffer_length;

		if (rate_limit > 0.0 && bytes_remaining <= 0) {
			warn_from_jack_thread_context("Rate limiting in effect.");
			break;
		}

		// t = seconds_to_nframes(event->time_seconds) + playback_started - song_position + nframes - last_frame_time;
		t = seconds_to_nframes(event->time_seconds + loop_offset) + playback_started - song_position - last_frame_time;

		/* If computed time is too much into the future, we'll need
		   to send it later. */
		if (t >= (int)nframes)
			break;

		/* If computed time is < 0, we missed a cycle because of xrun. */
		if (t < 0)
			t = 0;

		assert(event->track->track_number >= 0 && event->track->track_number <= MAX_NUMBER_OF_TRACKS);

		/* We will send this event; remove it from the queue. */
		smf_event_t *ret = smf_get_next_event(smf);
		assert(ret != 0);

		/* First, send it via midi_out. */
		track_number = 0;

#ifdef JACK_MIDI_NEEDS_NFRAMES
		buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length, nframes);
#else
		buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length);
#endif

		if (buffer == NULL) {
			warn_from_jack_thread_context("jack_midi_event_reserve failed, NOTE LOST.");
			break;
		}

		memcpy(buffer, event->midi_buffer, event->midi_buffer_length);

		/* Ignore per-track outputs? */
		if (just_one_output)
			continue;

		/* Send it via proper output port. */
		track_number = event->track->track_number;

#ifdef JACK_MIDI_NEEDS_NFRAMES
		buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length, nframes);
#else
		buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length);
#endif

		if (buffer == NULL) {
			warn_from_jack_thread_context("jack_midi_event_reserve failed, NOTE LOST.");
			break;
		}

		/* Before sending, reset channel to 0. XXX: Not very pretty. */
		assert(event->midi_buffer_length >= 1);

		tmp_status = event->midi_buffer[0];

		if (event->midi_buffer[0] >= 0x80 && event->midi_buffer[0] <= 0xEF)
			event->midi_buffer[0] &= 0xF0;

		memcpy(buffer, event->midi_buffer, event->midi_buffer_length);

		event->midi_buffer[0] = tmp_status;
	}
}
Exemplo n.º 13
0
Arquivo: ui.c Projeto: hbkk/sequencer
static int
ui_update(ui_t *ui)
{
    int ret = 0;
    lff_msg_t lff_msg;
    jack_transport_state_t ts;

    while (lff_msg_read(ui->read, &lff_msg)) {
        switch (lff_msg.type) {
        case LFF_MSG_ADD:
            ui_add_note(ui, lff_msg.note, lff_msg.pattern);
            break;
        case LFF_MSG_REMOVE:
            ui_remove_note(ui, lff_msg.note, lff_msg.pattern);
            break;
        case LFF_MSG_CHANGE:
            ui->display->pattern = lff_msg.pattern;
            /* ui_change_pattern(ui, lff_msg.pattern); */
            break;
        case LFF_MSG_VEL:
            break;
        case LFF_MSG_LEN:
            break;
        case LFF_MSG_REC:
            ui->display->rec = lff_msg.value;
            break;
        case LFF_MSG_SWING:
            ui->swing = lff_msg.value;
            break;
        case LFF_MSG_BPM:
            ui->bpm = lff_msg.value;
            break;
        case LFF_MSG_TRANSPORT:
            break;
        case LFF_MSG_MUTE:
            ui->display->mute[lff_msg.value] =
                !ui->display->mute[lff_msg.value];
            break;
        case LFF_MSG_ACC:
            ui->display->acc = lff_msg.value;
            break;
        case LFF_MSG_REQUEST:
            ui_send_request(ui);
            break;
        case LFF_MSG_PSEQ:
            if (lff_msg.pattern < 0) {
                ui->pseq.len = lff_msg.value;
            } else {
                ui->pseq.patterns[lff_msg.value] = lff_msg.pattern;
                if (lff_msg.value >= ui->pseq.len) {
                    ui->pseq.len++;
                }
            }

            break;
        case LFF_MSG_QUIT:
            return -1;
        default:
            break;
        }

        ret = 1;
    }

    ts = jack_transport_query(ui->client, NULL);
    if (ui->ts != ts) {
        ui->ts = ts;

        ret = 1;
    }

    while (lff_msg_read(ui->read_pos, &lff_msg)) {
        if (ui->display->step != lff_msg.value) {
            ui->display->step = lff_msg.value;

            ret = 1;
        }
    }

    return ret;
}
Exemplo n.º 14
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;
}
Exemplo n.º 15
0
    void jackProcess(const jack_nframes_t nframes)
    {
#if DISTRHO_PLUGIN_NUM_INPUTS > 0
        const float* audioIns[DISTRHO_PLUGIN_NUM_INPUTS];

        for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
            audioIns[i] = (const float*)jack_port_get_buffer(fPortAudioIns[i], nframes);
#else
        static const float** audioIns = nullptr;
#endif

#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
        float* audioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS];

        for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
            audioOuts[i] = (float*)jack_port_get_buffer(fPortAudioOuts[i], nframes);
#else
        static float** audioOuts = nullptr;
#endif

#if DISTRHO_PLUGIN_WANT_TIMEPOS
        jack_position_t pos;
        fTimePosition.playing = (jack_transport_query(fClient, &pos) == JackTransportRolling);

        if (pos.unique_1 == pos.unique_2)
        {
            fTimePosition.frame = pos.frame;

            if (pos.valid & JackTransportBBT)
            {
                fTimePosition.bbt.valid = true;

                fTimePosition.bbt.bar  = pos.bar;
                fTimePosition.bbt.beat = pos.beat;
                fTimePosition.bbt.tick = pos.tick;
                fTimePosition.bbt.barStartTick = pos.bar_start_tick;

                fTimePosition.bbt.beatsPerBar = pos.beats_per_bar;
                fTimePosition.bbt.beatType    = pos.beat_type;

                fTimePosition.bbt.ticksPerBeat   = pos.ticks_per_beat;
                fTimePosition.bbt.beatsPerMinute = pos.beats_per_minute;
            }
            else
                fTimePosition.bbt.valid = false;
        }
        else
        {
            fTimePosition.bbt.valid = false;
            fTimePosition.frame = 0;
        }

        fPlugin.setTimePosition(fTimePosition);
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
        void* const midiBuf = jack_port_get_buffer(fPortMidiIn, nframes);

        if (const uint32_t eventCount = jack_midi_get_event_count(midiBuf))
        {
            uint32_t  midiEventCount = 0;
            MidiEvent midiEvents[eventCount];

            jack_midi_event_t jevent;

            for (uint32_t i=0; i < eventCount; ++i)
            {
                if (jack_midi_event_get(&jevent, midiBuf, i) != 0)
                    break;

                MidiEvent& midiEvent(midiEvents[midiEventCount++]);

                midiEvent.frame = jevent.time;
                midiEvent.size  = jevent.size;

                if (midiEvent.size > MidiEvent::kDataSize)
                    midiEvent.dataExt = jevent.buffer;
                else
                    std::memcpy(midiEvent.data, jevent.buffer, midiEvent.size);
            }

            fPlugin.run(audioIns, audioOuts, nframes, midiEvents, midiEventCount);
        }
        else
        {
            fPlugin.run(audioIns, audioOuts, nframes, nullptr, 0);
        }
#else
        fPlugin.run(audioIns, audioOuts, nframes);
#endif
    }
Exemplo n.º 16
0
static int jack_process (jack_nframes_t frames, void * data)
{
	mlt_filter filter = (mlt_filter) data;
 	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
	int channels = mlt_properties_get_int( properties, "channels" );
	int frame_size = mlt_properties_get_int( properties, "_samples" ) * sizeof(float);
	int sync = mlt_properties_get_int( properties, "_sync" );
	int err = 0;
	int i;
	static int total_size = 0;
  
	jack_ringbuffer_t **output_buffers = mlt_properties_get_data( properties, "output_buffers", NULL );
	if ( output_buffers == NULL )
		return 0;
	jack_ringbuffer_t **input_buffers = mlt_properties_get_data( properties, "input_buffers", NULL );
	jack_port_t **jack_output_ports = mlt_properties_get_data( properties, "jack_output_ports", NULL );
	jack_port_t **jack_input_ports = mlt_properties_get_data( properties, "jack_input_ports", NULL );
	float **jack_output_buffers = mlt_properties_get_data( properties, "jack_output_buffers", NULL );
	float **jack_input_buffers = mlt_properties_get_data( properties, "jack_input_buffers", NULL );
	pthread_mutex_t *output_lock = mlt_properties_get_data( properties, "output_lock", NULL );
	pthread_cond_t *output_ready = mlt_properties_get_data( properties, "output_ready", NULL );
	
	for ( i = 0; i < channels; i++ )
	{
		size_t jack_size = ( frames * sizeof(float) );
		size_t ring_size;
		
		// Send audio through out port
		jack_output_buffers[i] = jack_port_get_buffer( jack_output_ports[i], frames );
		if ( ! jack_output_buffers[i] )
		{
			mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for output port %d\n", i );
			err = 1;
			break;
		}
		ring_size = jack_ringbuffer_read_space( output_buffers[i] );
		jack_ringbuffer_read( output_buffers[i], ( char * )jack_output_buffers[i], ring_size < jack_size ? ring_size : jack_size );
		if ( ring_size < jack_size )
			memset( &jack_output_buffers[i][ring_size], 0, jack_size - ring_size );
		
		// Return audio through in port
		jack_input_buffers[i] = jack_port_get_buffer( jack_input_ports[i], frames );
		if ( ! jack_input_buffers[i] )
		{
			mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for input port %d\n", i );
			err = 1;
			break;
		}
		
		// Do not start returning audio until we have sent first mlt frame
		if ( sync && i == 0 && frame_size > 0 )
			total_size += ring_size;
		mlt_log_debug( MLT_FILTER_SERVICE(filter), "sync %d frame_size %d ring_size %zu jack_size %zu\n", sync, frame_size, ring_size, jack_size );
		
		if ( ! sync || ( frame_size > 0  && total_size >= frame_size ) )
		{
			ring_size = jack_ringbuffer_write_space( input_buffers[i] );
			jack_ringbuffer_write( input_buffers[i], ( char * )jack_input_buffers[i], ring_size < jack_size ? ring_size : jack_size );
			
			if ( sync )
			{
				// Tell mlt that audio is available
				pthread_mutex_lock( output_lock);
				pthread_cond_signal( output_ready );
				pthread_mutex_unlock( output_lock);

				// Clear sync phase
				mlt_properties_set_int( properties, "_sync", 0 );
			}
		}
	}

	// Often jackd does not send the stopped event through the JackSyncCallback
	jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL );
	jack_position_t jack_pos;
	jack_transport_state_t state = jack_transport_query( jack_client, &jack_pos );
	int transport_state = mlt_properties_get_int( properties, "_transport_state" );
	if ( state != transport_state )
	{
		mlt_properties_set_int( properties, "_transport_state", state );
		if ( state == JackTransportStopped )
			jack_sync( state, &jack_pos, filter );
	}

	return err;
}
Exemplo n.º 17
0
Arquivo: Client.C Projeto: 0mk/non
 jack_transport_state_t
 Client::transport_query ( jack_position_t *pos )
 {
     return jack_transport_query( _client, pos );
 }
Exemplo n.º 18
0
static gboolean cbox_jackio_get_sync_completed(struct cbox_io_impl *impl)
{
    struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
    return jack_transport_query(jii->client, NULL) != JackTransportStarting;
}
Exemplo n.º 19
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)
{
    jack_nframes_t net_period;
    int rx_bufsize, tx_bufsize;

    jack_default_audio_sample_t *buf;
    jack_port_t *port;
    JSList *node;
    int chn;
    int size, i;
    const char *porttype;
    int input_fd;

    jack_position_t local_trans_pos;

    uint32_t *packet_buf_tx, *packet_bufX;
    uint32_t *rx_packet_ptr;
    jack_time_t packet_recv_timestamp;

    if( bitdepth == 1000 )
	net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8)&(~1) ;
    else
	net_period = (float) nframes / (float) factor;

    rx_bufsize =  get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
    tx_bufsize =  get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header);


    /* Allocate a buffer where both In and Out Buffer will fit */
    packet_buf_tx = alloca (tx_bufsize);

    jacknet_packet_header *pkthdr_tx = (jacknet_packet_header *) packet_buf_tx;

    /*
     * for latency==0 we need to send out the packet before we wait on the reply.
     * but this introduces a cycle of latency, when netsource is connected to itself.
     * so we send out before read only in zero latency mode.
     *
     */

    if( latency == 0 ) {
	    /* reset packet_bufX... */
	    packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t);

	    /* ---------- Send ---------- */
	    render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes,
			    packet_bufX, net_period, dont_htonl_floats);

	    /* fill in packet hdr */
	    pkthdr_tx->transport_state = jack_transport_query (client, &local_trans_pos);
	    pkthdr_tx->transport_frame = local_trans_pos.frame;
	    pkthdr_tx->framecnt = framecnt;
	    pkthdr_tx->latency = latency;
	    pkthdr_tx->reply_port = reply_port;
	    pkthdr_tx->sample_rate = jack_get_sample_rate (client);
	    pkthdr_tx->period_size = nframes;

	    /* playback for us is capture on the other side */
	    pkthdr_tx->capture_channels_audio = playback_channels_audio;
	    pkthdr_tx->playback_channels_audio = capture_channels_audio;
	    pkthdr_tx->capture_channels_midi = playback_channels_midi;
	    pkthdr_tx->playback_channels_midi = capture_channels_midi;
	    pkthdr_tx->mtu = mtu;
	    if( freewheeling!= 0 )
		    pkthdr_tx->sync_state = (jack_nframes_t)MASTER_FREEWHEELS;
	    else
		    pkthdr_tx->sync_state = (jack_nframes_t)deadline_goodness;
	    //printf("goodness=%d\n", deadline_goodness );

	    packet_header_hton (pkthdr_tx);
	    if (cont_miss < 3*latency+5) {
		    int r;
		    for( r=0; r<redundancy; r++ )
			    netjack_sendto (outsockfd, (char *) packet_buf_tx, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu);
	    }
	    else if (cont_miss > 50+5*latency)
	    {
		    state_connected = 0;
		    packet_cache_reset_master_address( packcache );
		    //printf ("Frame %d  \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss);
		    cont_miss = 0;
	    }
    }

    /*
     * ok... now the RECEIVE code.
     *
     */


    if( reply_port )
	input_fd = insockfd;
    else
	input_fd = outsockfd;

    // for latency == 0 we can poll.
    if( (latency == 0) || (freewheeling!=0)  ) {
	jack_time_t deadline = jack_get_time() + 1000000 * jack_get_buffer_size(client)/jack_get_sample_rate(client);
	// Now loop until we get the right packet.
	while(1) {
	    jack_nframes_t got_frame;
	    if ( ! netjack_poll_deadline( input_fd, deadline ) )
		break;

	    packet_cache_drain_socket(packcache, input_fd);

	    if (packet_cache_get_next_available_framecnt( packcache, framecnt - latency, &got_frame ))
		if( got_frame == (framecnt - latency) )
		    break;
	}
    } else {
	// normally:
	// only drain socket.
	packet_cache_drain_socket(packcache, input_fd);
    }

    size = packet_cache_retreive_packet_pointer( packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp );
    /* First alternative : we received what we expected. Render the data
     * to the JACK ports so it can be played. */
    if (size == rx_bufsize)
    {
	uint32_t *packet_buf_rx = rx_packet_ptr;
	jacknet_packet_header *pkthdr_rx = (jacknet_packet_header *) packet_buf_rx;
	packet_bufX = packet_buf_rx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t);
	// calculate how much time there would have been, if this packet was sent at the deadline.

	int recv_time_offset = (int) (jack_get_time() - packet_recv_timestamp);
	packet_header_ntoh (pkthdr_rx);
	deadline_goodness = recv_time_offset - (int)pkthdr_rx->latency;
	//printf( "deadline goodness = %d ---> off: %d\n", deadline_goodness, recv_time_offset );

        if (cont_miss)
        {
            //printf("Frame %d  \tRecovered from dropouts\n", framecnt);
            cont_miss = 0;
        }
        render_payload_to_jack_ports (bitdepth, packet_bufX, net_period,
		capture_ports, capture_srcs, nframes, dont_htonl_floats);

	state_currentframe = framecnt;
	state_recv_packet_queue_time = recv_time_offset;
	state_connected = 1;
        sync_state = pkthdr_rx->sync_state;
	packet_cache_release_packet( packcache, framecnt - latency );
    }
    /* Second alternative : we've received something that's not
     * as big as expected or we missed a packet. We render silence
     * to the ouput ports */
    else
    {
	jack_nframes_t latency_estimate;
	if( packet_cache_find_latency( packcache, framecnt, &latency_estimate ) )
	    //if( (state_latency == 0) || (latency_estimate < state_latency) )
		state_latency = latency_estimate;

	// Set the counters up.
	state_currentframe = framecnt;
	//state_latency = framecnt - pkthdr->framecnt;
	state_netxruns += 1;

        //printf ("Frame %d  \tPacket missed or incomplete (expected: %d bytes, got: %d bytes)\n", framecnt, rx_bufsize, size);
        //printf ("Frame %d  \tPacket missed or incomplete\n", framecnt);
        cont_miss += 1;
        chn = 0;
        node = capture_ports;
        while (node != NULL)
        {
            port = (jack_port_t *) node->data;
            buf = jack_port_get_buffer (port, nframes);
            porttype = jack_port_type (port);
            if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size ()) == 0)
                for (i = 0; i < nframes; i++)
                    buf[i] = 0.0;
            else if (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size ()) == 0)
                jack_midi_clear_buffer (buf);
            node = jack_slist_next (node);
            chn++;
        }
    }
    if( latency != 0 ) {
	    /* reset packet_bufX... */
	    packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t);

	    /* ---------- Send ---------- */
	    render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes,
			    packet_bufX, net_period, dont_htonl_floats);

	    /* fill in packet hdr */
	    pkthdr_tx->transport_state = jack_transport_query (client, &local_trans_pos);
	    pkthdr_tx->transport_frame = local_trans_pos.frame;
	    pkthdr_tx->framecnt = framecnt;
	    pkthdr_tx->latency = latency;
	    pkthdr_tx->reply_port = reply_port;
	    pkthdr_tx->sample_rate = jack_get_sample_rate (client);
	    pkthdr_tx->period_size = nframes;

	    /* playback for us is capture on the other side */
	    pkthdr_tx->capture_channels_audio = playback_channels_audio;
	    pkthdr_tx->playback_channels_audio = capture_channels_audio;
	    pkthdr_tx->capture_channels_midi = playback_channels_midi;
	    pkthdr_tx->playback_channels_midi = capture_channels_midi;
	    pkthdr_tx->mtu = mtu;
	    if( freewheeling!= 0 )
		    pkthdr_tx->sync_state = (jack_nframes_t)MASTER_FREEWHEELS;
	    else
		    pkthdr_tx->sync_state = (jack_nframes_t)deadline_goodness;
	    //printf("goodness=%d\n", deadline_goodness );

	    packet_header_hton (pkthdr_tx);
	    if (cont_miss < 3*latency+5) {
		    int r;
		    for( r=0; r<redundancy; r++ )
			    netjack_sendto (outsockfd, (char *) packet_buf_tx, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu);
	    }
	    else if (cont_miss > 50+5*latency)
	    {
		    state_connected = 0;
		    packet_cache_reset_master_address( packcache );
		    //printf ("Frame %d  \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss);
		    cont_miss = 0;
	    }
    }

    framecnt++;
    return 0;
}
static int
jack_process_cb (jack_nframes_t nframes, void *arg)
{
  GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
  GList *walk;
  int res = 0;
  jack_transport_state_t ts = jack_transport_query (conn->client, NULL);

  if (ts != conn->cur_ts) {
    conn->cur_ts = ts;
    switch (ts) {
      case JackTransportStopped:
        GST_DEBUG ("transport state is 'stopped'");
        conn->transport_state = GST_STATE_PAUSED;
        break;
      case JackTransportStarting:
        GST_DEBUG ("transport state is 'starting'");
        conn->transport_state = GST_STATE_READY;
        break;
      case JackTransportRolling:
        GST_DEBUG ("transport state is 'rolling'");
        conn->transport_state = GST_STATE_PLAYING;
        break;
      default:
        break;
    }
    GST_DEBUG ("num of clients: src=%d, sink=%d",
        g_list_length (conn->src_clients), g_list_length (conn->sink_clients));
  }

  g_mutex_lock (&conn->lock);
  /* call sources first, then sinks. Sources will either push data into the
   * ringbuffer of the sinks, which will then pull the data out of it, or
   * sinks will pull the data from the sources. */
  for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
    GstJackAudioClient *client = (GstJackAudioClient *) walk->data;

    /* only call active clients */
    if ((client->active || client->deactivate) && client->process) {
      res = client->process (nframes, client->user_data);
      if (client->deactivate) {
        client->deactivate = FALSE;
        g_cond_signal (&conn->flush_cond);
      }
    }
  }
  for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
    GstJackAudioClient *client = (GstJackAudioClient *) walk->data;

    /* only call active clients */
    if ((client->active || client->deactivate) && client->process) {
      res = client->process (nframes, client->user_data);
      if (client->deactivate) {
        client->deactivate = FALSE;
        g_cond_signal (&conn->flush_cond);
      }
    }
  }

  /* handle transport state requisition, do sinks first, stop after the first
   * element that handled it */
  if (conn->transport_state != GST_STATE_VOID_PENDING) {
    for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
      if (jack_handle_transport_change ((GstJackAudioClient *) walk->data,
              conn->transport_state)) {
        conn->transport_state = GST_STATE_VOID_PENDING;
        break;
      }
    }
  }
  if (conn->transport_state != GST_STATE_VOID_PENDING) {
    for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
      if (jack_handle_transport_change ((GstJackAudioClient *) walk->data,
              conn->transport_state)) {
        conn->transport_state = GST_STATE_VOID_PENDING;
        break;
      }
    }
  }
  g_mutex_unlock (&conn->lock);

  return res;
}
Exemplo n.º 21
0
void
audioStreamer_JACK::timebase_cb(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos ) {

    static double jack_tick;
    static jack_nframes_t last_frame;
    static jack_nframes_t current_frame;
    jack_position_t cur_pos;
    static jack_transport_state_t state_current;
    static jack_transport_state_t state_last;
    static int locating = 0;

#if 0
    if( state != JackTransportRolling )
    {
      jack_transport_locate( client, 0 );
      jack_transport_start( client );
    }
#endif

    if( !njc ) return;

    int posi, len;
    njc->GetPosition(&posi,&len);
    float bpm = njc->GetActualBPM();

    //posi = njc->GetSessionPosition() * m_srate / 1000;
    //len = (int)(njc->GetBPI() * m_srate * 60 / bpm);

    // sync jack_transport_frame to njframe

    //current_frame = jack_get_current_transport_frame( client );
    jack_transport_query(client, &cur_pos);
    current_frame = cur_pos.frame;

    // FIXME: This will not work right, if there are slow-sync clients....

    int diff = abs(current_frame % len) - (posi % len);

    if( diff > nframes ) {
#if 1
	jack_transport_locate( client, (current_frame / len) * len + (posi%len) + 2*nframes );

	//printf( "no:  current= %d diff = %d\n", (current_frame % len) -  (posi % len), diff );
#endif
    }

    // taken from seq24-0.7.0 perform.cpp

    state_current = state;


    //printf( "jack_timebase_callback() [%d] [%d] [%d]", state, new_pos, current_frame);

    pos->valid = JackPositionBBT;
    pos->beats_per_bar = 4;
    pos->beat_type = 4;
    pos->ticks_per_beat = c_ppqn * 10;
    pos->beats_per_minute = bpm;


    /* Compute BBT info from frame number.  This is relatively
     * simple here, but would become complex if we supported tempo
     * or time signature changes at specific locations in the
     * transport timeline. */

    // if we are in a new position
    if (  state_last    ==  JackTransportStarting &&
          state_current ==  JackTransportRolling ){

        //printf ( "Starting [%d] [%d]\n", last_frame, current_frame );

        jack_tick = 0.0;
        last_frame = current_frame;
    }

    if ( current_frame > last_frame ){

        double jack_delta_tick =
            (current_frame - last_frame) *
            pos->ticks_per_beat *
            pos->beats_per_minute / (pos->frame_rate * 60.0);

        jack_tick += jack_delta_tick;

        last_frame = current_frame;
    }

    long ptick = 0, pbeat = 0, pbar = 0;

    pbar  = (long) ((long) jack_tick / (pos->ticks_per_beat *  pos->beats_per_bar ));

    pbeat = (long) ((long) jack_tick % (long) (pos->ticks_per_beat *  pos->beats_per_bar ));
    pbeat = pbeat / (long) pos->ticks_per_beat;

    ptick = (long) jack_tick % (long) pos->ticks_per_beat;

    pos->bar = pbar + 1;
    pos->beat = pbeat + 1;
    pos->tick = ptick;;
    pos->bar_start_tick = pos->bar * pos->beats_per_bar *
        pos->ticks_per_beat;

    //printf( " bbb [%2d:%2d:%4d]\n", pos->bar, pos->beat, pos->tick );

    state_last = state_current;

}
Exemplo n.º 22
0
void JackOutput::updateTransportInfo()
{
		if ( locate_countdown == 1 )
				locate( locate_frame );
		if ( locate_countdown > 0 )
				locate_countdown--;

		if ( Preferences::get_instance()->m_bJackTransportMode !=  Preferences::USE_JACK_TRANSPORT   ) return;

				m_JackTransportState = jack_transport_query( client, &m_JackTransportPos );


				// update m_transport with jack-transport data
				switch ( m_JackTransportState ) {
				case JackTransportStopped:
						m_transport.m_status = TransportInfo::STOPPED;
						//infoLog( "[updateTransportInfo] STOPPED - frames: " + to_string(m_transportPos.frame) );
						break;

				case JackTransportRolling:
						if ( m_transport.m_status != TransportInfo::ROLLING && ( m_JackTransportPos.valid & JackPositionBBT ) ) {
								must_relocate = 2;
								//WARNINGLOG( "Jack transport starting: Resyncing in 2 x Buffersize!!" );
						}
						m_transport.m_status = TransportInfo::ROLLING;
						//infoLog( "[updateTransportInfo] ROLLING - frames: " + to_string(m_transportPos.frame) );
						break;

				case JackTransportStarting:
						m_transport.m_status = TransportInfo::STOPPED;
						//infoLog( "[updateTransportInfo] STARTING (stopped) - frames: " + to_string(m_transportPos.frame) );
						break;

				default:
						ERRORLOG( "Unknown jack transport state" );
		}


		// FIXME
		// TickSize and BPM
		Hydrogen * H = Hydrogen::get_instance();
		H->setTimelineBpm(); // dlr: fix #168, jack may have re-located us anywhere, check for bpm change every cycle

		if ( m_JackTransportPos.valid & JackPositionBBT ) {
			float bpm = ( float )m_JackTransportPos.beats_per_minute;
			if ( m_transport.m_nBPM != bpm ) {


				if ( Preferences::get_instance()->m_bJackMasterMode == Preferences::NO_JACK_TIME_MASTER ){
					// 					WARNINGLOG( QString( "Tempo change from jack-transport: %1" ).arg( bpm ) );
					m_transport.m_nBPM = bpm;
					must_relocate = 1; // The tempo change has happened somewhere during the previous cycle; relocate right away.

					// This commenting out is rude perhaps, but I cant't figure out what this bit is doing.
					// In any case, setting must_relocate = 1 here causes too many relocates. Jakob Lund
					/*				} else {
	 if ( m_transport.m_status == TransportInfo::STOPPED ) {
	  oldpo = H->getPatternPos();
	  must_relocate = 1;
	  //changer =1;
	 }*/

				}

				// Hydrogen::get_instance()->setBPM( m_JackTransportPos.beats_per_minute ); // unnecessary, as Song->m_BPM gets updated in audioEngine_process_transport (after calling this function)
			}
		}

		if ( m_transport.m_nFrames + bbt_frame_offset != m_JackTransportPos.frame ) {
			if ( ( m_JackTransportPos.valid & JackPositionBBT ) && must_relocate == 0 ) {
				WARNINGLOG( "Frame offset mismatch; triggering resync in 2 cycles" );
				must_relocate = 2;
			} else {
				if ( Preferences::get_instance()->m_bJackMasterMode == Preferences::NO_JACK_TIME_MASTER ) {
					// If There's no timebase_master, and audioEngine_process_checkBPMChanged handled a tempo change during last cycle, the offset doesn't match, but hopefully it was calculated correctly:

					//this perform Jakobs mod in pattern mode, but both m_transport.m_nFrames works with the same result in pattern Mode
					// in songmode the first case dont work.
					//so we can remove this "if query" and only use this old mod: m_transport.m_nFrames = H->getHumantimeFrames();
					//because to get the songmode we have to add this "H2Core::Hydrogen *m_pEngine" to the header file
					//if we remove this we also can remove *m_pEngine from header
#if 0 // dlr: fix #169, why do we have a different behaviour for SONG_MODE?
					if ( m_pEngine->getSong()->get_mode() == Song::PATTERN_MODE  ){
						m_transport.m_nFrames = m_JackTransportPos.frame/* - bbt_frame_offset*/; ///see comment in svn changeset 753
					}
					else
					{
						m_transport.m_nFrames = H->getHumantimeFrames();
					}
#else
					m_transport.m_nFrames = m_JackTransportPos.frame;
					bbt_frame_offset = 0; // dlr: stop re-syncing in every cycle when STOPPED
#endif
					// In jack 'slave' mode, if there's no master, the following line is needed to be able to relocate by clicking the song ruler (wierd corner case, but still...)
					if ( m_transport.m_status == TransportInfo::ROLLING )
						H->triggerRelocateDuringPlay();
				} else {
					///this is experimantal... but it works for the moment... fix me fix :-) wolke
					// ... will this actually happen? keeping it for now ( jakob lund )
					m_transport.m_nFrames = H->getHumantimeFrames();
				}
			}
		}

		// humantime fix
		if ( H->getHumantimeFrames() != m_JackTransportPos.frame ) {
			H->setHumantimeFrames(m_JackTransportPos.frame);
			//WARNINGLOG("fix Humantime " + to_string (m_JackTransportPos.frame));
		}

		if ( must_relocate == 1 ) {
			//WARNINGLOG( "Resyncing!" );
			relocateBBT();
			if ( m_transport.m_status == TransportInfo::ROLLING ) {
				H->triggerRelocateDuringPlay();
			}
		}

		if ( must_relocate > 0 ) must_relocate--;
}
Exemplo n.º 23
0
jack_transport_state_t luajack_transport_query(luajack_t *client, jack_position_t *pos)
	{
	cud_t *cud = get_cud(client);	
	if(!cud) return (jack_transport_state_t)0;
	return jack_transport_query(cud->client, pos);
	}