Example #1
0
/**
 * process this MIDI input: pack LV2 input buffer from EventBuffer + EventConnection
 */
void Lv2MidiInput::process(bool rolling, jack_position_t &pos, jack_nframes_t nframes, jack_nframes_t time) {
    // clear atom sequence
    lv2_atom_sequence_clear(atomSequence);

    // send all notes off messages if newly stopped
    if(localRolling && !rolling) {
        Lv2MidiEvent lv2Event;
        lv2Event.event.time.frames = 0;
        lv2Event.buffer[1] = 0x7b; // CC 123 = all notes off
        lv2Event.buffer[2] = 0;
        for(uint8_t channel = 0; channel < 16; channel++) {
            lv2Event.buffer[0] = MidiEvent::TYPE_CONTROL + channel;
            lv2_atom_sequence_append_event(atomSequence, CAPACITY, &lv2Event.event);
        }
    }
    localRolling = rolling;

    // get connection and event count
    MidiConnection *connection = eventConnector.getConnection();
    uint32_t eventCount = 0;
    if(connection) {
        connection->getSource()->process(rolling, pos, nframes, time);
        eventCount = connection->getEventCount();
    }

    // get top events from buffer + connection
    MidiEvent* bufferEvent = eventBuffer.getNextEvent(rolling, pos, nframes);
    MidiEvent *connectionEvent = eventCount ? connection->getEvent(0) : 0;
    uint32_t eventIndex = 1;

    // loop while events on either buffer or connection
    while(bufferEvent || connectionEvent) {
        bool bufferNext = bufferEvent &&
                (!connectionEvent || bufferEvent->getFrameOffset() < connectionEvent->getFrameOffset());
        MidiEvent *event = bufferNext ? bufferEvent : connectionEvent;
        // lv2 event
        Lv2MidiEvent lv2Event;
        long frame = event->getFrameOffset();
        lv2Event.event.time.frames = frame >= 0 ? frame : 0;
        // copy event data
        event->pack(&lv2Event.buffer);
        // append this event to sequence
        lv2_atom_sequence_append_event(atomSequence, CAPACITY, &lv2Event.event);
        // get next event
        if(bufferNext) {
            // recycle and get next buffer event
            ObjectCollector::scriptCollector().recycle(bufferEvent);
            bufferEvent = eventBuffer.getNextEvent(rolling, pos, nframes);
        } else {
            connectionEvent = eventIndex < eventCount ? connection->getEvent(eventIndex++) : 0;
        }
    }
}
Example #2
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;
}
Example #3
0
void Note2midi::run(LV2_Handle instance, uint32_t SampleCount)
{
    Note2midi *plugin = (Note2midi *) instance;

    unsigned int new_onset_method = (unsigned int)(*plugin->_onset_method);
    unsigned int new_pitch_method = (unsigned int)(*plugin->_pitch_method);
    char_t* on_meth;
    char_t* pi_meth;

    silence_threshold = *(plugin->_silence_threshold);

    aubio_onset_set_threshold(plugin->o, *plugin->_onset_threshold);
    aubio_pitch_set_tolerance(plugin->pitch, *plugin->_pitch_method);

    if(0 <= new_onset_method && 16 >= new_onset_method &&
        new_onset_method != plugin->current_onset_method){ 
        
        del_aubio_onset(plugin->o);

        switch(new_onset_method){
            case ONSET_METHOD_ENERGY:
            on_meth = "energy";
            break;
            case ONSET_METHOD_SPECDIFF:
            on_meth = "specdiff";
            break;
            case ONSET_METHOD_HFC:
            on_meth = "hfc";
            break;
            case ONSET_METHOD_COMPLEXDOMAIN:
            on_meth = "complexdomain";
            break;
            case ONSET_METHOD_COMPLEX:
            on_meth = "complex";
            break;
            case ONSET_METHOD_PHASE:
            on_meth = "phase";
            break;
            case ONSET_METHOD_MKL:
            on_meth = "mkl";
            break;
            case ONSET_METHOD_KL:
            on_meth = "kl";
            break;
            case ONSET_METHOD_SPECFLUX:
            on_meth = "specflux";
            break;
            case ONSET_METHOD_CENTROID:
            on_meth = "centroid";
            break;
            case ONSET_METHOD_SPREAD:
            on_meth = "spread";
            break;
            case ONSET_METHOD_SKEWNESS:
            on_meth = "skewness";
            break;
            case ONSET_METHOD_KURTOSIS:
            on_meth = "kurtosis";
            break;
            case ONSET_METHOD_SLOPE:
            on_meth = "slope";
            break;
            case ONSET_METHOD_DECREASE:
            on_meth = "decrease";
            break;
            case ONSET_METHOD_ROLLOFF:
            on_meth = "rolloff";
            break;
            default:
            on_meth = "default";
            break;
        }


        plugin->o = new_aubio_onset (on_meth, PARAM_BUFFER_SIZE, PARAM_HOP_SIZE_ONSET, plugin->samplerate);
        
        plugin->current_onset_method = new_onset_method;
    }

    if(0 <= new_pitch_method && 6 >= new_pitch_method &&
        new_pitch_method != plugin->current_pitch_method){
        del_aubio_pitch(plugin->pitch);

        switch(new_pitch_method){
            case PITCH_METHOD_MCOMB:
            pi_meth = "mcomb";
            break;
            case PITCH_METHOD_YINFFT:
            pi_meth = "yinfft";
            break;
            case PITCH_METHOD_YIN:
            pi_meth = "yin";
            break;
            case PITCH_METHOD_SCHMITT:
            pi_meth = "schmitt";
            break;
            case PITCH_METHOD_FCOMB:
            pi_meth = "fcomb";
            break;
            case PITCH_METHOD_SPECACF:
            pi_meth = "specacf";
            break;
            default:
            pi_meth = "default";
            break;
        }


        plugin->pitch = new_aubio_pitch (pi_meth, PARAM_BUFFER_SIZE * PARAM_PITCH_BUFF_TIMES, PARAM_HOP_SIZE_PITCH, plugin->samplerate);
     
        // aubio_pitch_set_unit (plugin->pitch, plugin->pitch_unit);

        plugin->current_pitch_method = new_pitch_method;
    }

    out_capacity = plugin->out->atom.size;

    plugin->out->atom.type = plugin->atom_sequence;
    lv2_atom_sequence_clear(plugin->out);

    plugin->ibuf->data = (smpl_t *) plugin->in;

    counter++;

    if(counter++ >= PARAM_BUFFER_SIZE)
        counter = 0;

    plugin->process_block();
}