Esempio n. 1
0
void
play_music()
{
    uint32_t counter=0;
    LV2_Atom_Forge_Frame midi_seq_frame;
    int buffer_processed = 0;
    const Lv2Plugin *plugin;
    plugin = lv2_world->plugin_list;

    DISABLE_IRQ();

    lv2_port *output_left = new_lv2_port(lv2_audio_port, 1);
    lv2_port *output_right = new_lv2_port(lv2_audio_port, 2);
    lv2_port *midi_in = new_lv2_port(lv2_atom_port, 3);

    plugin->descriptor->connect_port(plugin->handle, midi_in->id, midi_in->buffer);
    plugin->descriptor->connect_port(plugin->handle, output_left->id, output_left->buffer);
    plugin->descriptor->connect_port(plugin->handle, output_right->id, output_right->buffer);

    lv2_atom_forge_set_buffer(&forge,
                              midi_in->buffer,
                              LV2_ATOM_BUFFER_SIZE);
    lv2_atom_forge_sequence_head(&forge, &midi_seq_frame, 0);
    
    init_midi_source(&forge);
    
    while (1) {

    DISABLE_IRQ();

        if (!buffer_processed) {
	  forge_midi_input();


            lv2_atom_forge_pop(&forge, &midi_seq_frame);

            plugin->descriptor->run(plugin->handle, LV2_AUDIO_BUFFER_SIZE);

            lv2_atom_forge_set_buffer(&forge,
                                      midi_in->buffer,
                                      sizeof(uint8_t) * midi_in->buffer_sz);
            lv2_atom_forge_sequence_head(&forge, &midi_seq_frame, 0);
            buffer_processed = 1;
        }

        if (buffer_processed && audio_buffer_free_space() > LV2_AUDIO_BUFFER_SIZE * 2) {
            audio_buffer_write(output_left->buffer, output_right->buffer, output_left->buffer_sz);
            buffer_processed = 0;
            counter++;
        }
	ENABLE_IRQ();
    }
}
Esempio n. 2
0
static void forge_message_kv (BITui* ui, LV2_URID uri, int key, float value) {
	uint8_t obj_buf[1024];
	if (ui->disable_signals) return;

	lv2_atom_forge_set_buffer (&ui->forge, obj_buf, 1024);
	LV2_Atom* msg = forge_kvcontrolmessage (&ui->forge, &ui->uris, uri, key, value);
	ui->write (ui->controller, 0, lv2_atom_total_size (msg), ui->uris.atom_eventTransfer, msg);
}
Esempio n. 3
0
/** notify backend that UI is active:
 * request state and enable data-transmission */
static void ui_enable(LV2UI_Handle handle)
{
	SFSUI* ui = (SFSUI*)handle;
	uint8_t obj_buf[64];
	lv2_atom_forge_set_buffer(&ui->forge, obj_buf, 64);
	LV2_Atom_Forge_Frame frame;
	lv2_atom_forge_frame_time(&ui->forge, 0);
	LV2_Atom* msg = (LV2_Atom*)x_forge_object(&ui->forge, &frame, 1, ui->uris.ui_on);
	lv2_atom_forge_pop(&ui->forge, &frame);
	ui->write(ui->controller, 0, lv2_atom_total_size(msg), ui->uris.atom_eventTransfer, msg);
}
static inline void
_write_event(UI *ui, chimaera_event_t *cev)
{
	uint8_t buf[512];

	lv2_atom_forge_set_buffer(&ui->cforge.forge, buf, 512);
	chimaera_event_forge(&ui->cforge, cev);

	ui->write_function(ui->controller, ui->control_port, ui->cforge.forge.offset,
		ui->uris.event_transfer, buf);
}
Esempio n. 5
0
/**
   Callback for preset combobox changed
*/
static void on_changed(GtkWidget *widget, void *handle)
{
    FluidUI *self = (FluidUI *)handle;
    uint8_t obj_buf[OBJ_BUF_SIZE];

    int selected = gtk_combo_box_get_active((GtkComboBox *)widget);

    lv2_atom_forge_set_buffer(&self->forge, obj_buf, OBJ_BUF_SIZE);
    LV2_Atom *patch_set = write_patch_set(&self->forge, &self->uris, selected);

    /* Send preset setting to synth plugin */
    self->write(self->controller, INPUT_PORT, lv2_atom_total_size(patch_set),
                self->uris.atom_event_transfer, patch_set);
}
Esempio n. 6
0
/**
   Instantiate the user interface
*/
static LV2UI_Handle instantiate(const LV2UI_Descriptor *descriptor,
                                const char *plugin_uri,
                                const char *bundle_path,
                                LV2UI_Write_Function write_function,
                                LV2UI_Controller controller,
                                LV2UI_Widget *widget,
                                const LV2_Feature *const *features)
{
    /* Create object data */
    FluidUI *self = malloc(sizeof(FluidUI));

    self->write = write_function;
    self->controller = controller;

    for (int i = 0; features[i]; i++) {
        if (strcmp(features[i]->URI, LV2_URID__map) == 0)
            self->map = (LV2_URID_Map *)features[i]->data;
    }
    map_uris(self->map, &self->uris);
    lv2_atom_forge_init(&self->forge, self->map);

    /* Create GUI */
    self->box = gtk_hbox_new(FALSE, 4);
    self->label = gtk_label_new("Preset");
    self->combo_box  = gtk_combo_box_text_new();

    get_presets(self);

    gtk_box_pack_start(GTK_BOX(self->box), self->label, TRUE, TRUE, 4);
    gtk_box_pack_start(GTK_BOX(self->box), self->combo_box, FALSE, TRUE, 4);

    g_signal_connect(self->combo_box, "changed", G_CALLBACK(on_changed), self);

    *widget = self->box;

    /* Send patch get to synth plug to get current preset setting */
    uint8_t obj_buf[OBJ_BUF_SIZE];
    lv2_atom_forge_set_buffer(&self->forge, obj_buf, OBJ_BUF_SIZE);

    LV2_Atom *patch_get = write_patch_get(&self->forge, &self->uris);

    self->write(self->controller, INPUT_PORT, lv2_atom_total_size(patch_get),
                self->uris.atom_event_transfer, patch_get);

    return self;
}
static void
on_load_clicked(GtkWidget* widget,
                void*      handle)
{
	FeedbackSuppressorUI* ui = (FeedbackSuppressorUI*)handle;

	/* Create a dialog to select a sample file. */
	GtkWidget* dialog = gtk_file_chooser_dialog_new(
		"Load Sample",
		NULL,
		GTK_FILE_CHOOSER_ACTION_OPEN,
		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
		GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
		NULL);

	GtkFileFilter *filter = gtk_file_filter_new();
	gtk_file_filter_set_name(filter, "Filter Lists");
	gtk_file_filter_add_pattern(filter,"*.ofs");
	gtk_file_chooser_add_filter((GtkFileChooser *) dialog,filter);

	/* Run the dialog, and return if it is cancelled. */
	if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) {
		gtk_widget_destroy(dialog);
		return;
	}

	/* Get the file path from the dialog. */
	char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));

	/* Got what we need, destroy the dialog and filter. */
	gtk_widget_destroy(dialog);

#define OBJ_BUF_SIZE 1024
	uint8_t obj_buf[OBJ_BUF_SIZE];
	lv2_atom_forge_set_buffer(&ui->forge, obj_buf, OBJ_BUF_SIZE);

	LV2_Atom* msg = write_set_file(&ui->forge, &ui->uris,
	                               filename, strlen(filename));

	ui->write(ui->controller, 0, lv2_atom_total_size(msg),
	          ui->uris.atom_eventTransfer,
	          msg);

	g_free(filename);
}
Esempio n. 8
0
static void
run(LV2_Handle handle, uint32_t n_samples)
{
  SiSco* self = (SiSco*)handle;
  const uint32_t size = (sizeof(float) * n_samples + 80) * self->n_channels;
  const uint32_t capacity = self->notify->atom.size;
  bool capacity_ok = true;

  /* check if atom-port buffer is large enough to hold
   * all audio-samples and configuration settings */
  if (capacity < size + 216 + self->n_channels * 16) {
    capacity_ok = false;
    if (!self->printed_capacity_warning) {
      fprintf(stderr, "SiSco.lv2 error: LV2 comm-buffersize is insufficient %d/%d bytes.\n",
	  capacity, size + 216 + self->n_channels * 16);
      self->printed_capacity_warning = true;
    }
  }

  /* prepare forge buffer and initialize atom-sequence */
  lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, capacity);
  lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0);

  /* Send settings to UI */
  if (self->send_settings_to_ui && self->ui_active) {
    self->send_settings_to_ui = false;
    /* forge container object of type 'ui_state' */
    LV2_Atom_Forge_Frame frame;
    lv2_atom_forge_frame_time(&self->forge, 0);
    x_forge_object(&self->forge, &frame, 1, self->uris.ui_state);
    /* forge attributes for 'ui_state' */
    lv2_atom_forge_property_head(&self->forge, self->uris.samplerate, 0);
    lv2_atom_forge_float(&self->forge, capacity_ok ? self->rate : 0);

    lv2_atom_forge_property_head(&self->forge, self->uris.ui_state_grid, 0);
    lv2_atom_forge_int(&self->forge, self->ui_grid);

    lv2_atom_forge_property_head(&self->forge, self->uris.ui_state_trig, 0);
    lv2_atom_forge_vector(&self->forge, sizeof(float), self->uris.atom_Float,
	sizeof(struct triggerstate) / sizeof(float), &self->triggerstate);

    lv2_atom_forge_property_head(&self->forge, self->uris.ui_state_curs, 0);
    lv2_atom_forge_vector(&self->forge, sizeof(int32_t), self->uris.atom_Int,
	sizeof(struct cursorstate) / sizeof(int32_t), &self->cursorstate);

    lv2_atom_forge_property_head(&self->forge, self->uris.ui_state_chn, 0);
    lv2_atom_forge_vector(&self->forge, sizeof(float), self->uris.atom_Float,
	self->n_channels * sizeof(struct channelstate) / sizeof(float), self->channelstate);

    lv2_atom_forge_property_head(&self->forge, self->uris.ui_state_misc, 0);
    lv2_atom_forge_int(&self->forge, self->ui_misc);

    /* close-off frame */
    lv2_atom_forge_pop(&self->forge, &frame);
  }

  /* Process incoming events from GUI */
  if (self->control) {
    LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(self->control)->body);
    /* for each message from UI... */
    while(!lv2_atom_sequence_is_end(&(self->control)->body, (self->control)->atom.size, ev)) {
      /* .. only look at atom-events.. */
      if (ev->body.type == self->uris.atom_Blank || ev->body.type == self->uris.atom_Object) {
	const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
	/* interpret atom-objects: */
	if (obj->body.otype == self->uris.ui_on) {
	  /* UI was activated */
	  self->ui_active = true;
	  self->send_settings_to_ui = true;
	} else if (obj->body.otype == self->uris.ui_off) {
	  /* UI was closed */
	  self->ui_active = false;
	} else if (obj->body.otype == self->uris.ui_state) {
	  /* UI sends current settings */
	  const LV2_Atom* grid = NULL;
	  const LV2_Atom* trig = NULL;
	  const LV2_Atom* curs = NULL;
	  const LV2_Atom* misc = NULL;
	  const LV2_Atom* chn = NULL;
	  lv2_atom_object_get(obj,
	      self->uris.ui_state_grid, &grid,
	      self->uris.ui_state_trig, &trig,
	      self->uris.ui_state_curs, &curs,
	      self->uris.ui_state_misc, &misc,
	      self->uris.ui_state_chn, &chn,
	      0);
	  if (grid && grid->type == self->uris.atom_Int) {
	    self->ui_grid = ((LV2_Atom_Int*)grid)->body;
	  }
	  if (misc && misc->type == self->uris.atom_Int) {
	    self->ui_misc = ((LV2_Atom_Int*)misc)->body;
	  }
	  if (trig && trig->type == self->uris.atom_Vector) {
	    LV2_Atom_Vector *vof = (LV2_Atom_Vector*)LV2_ATOM_BODY(trig);
	    if (vof->atom.type == self->uris.atom_Float) {
	      struct triggerstate *ts = (struct triggerstate *) LV2_ATOM_BODY(&vof->atom);
	      memcpy(&self->triggerstate, ts, sizeof(struct triggerstate));
	    }
	  }
	  if (curs && curs->type == self->uris.atom_Vector) {
	    LV2_Atom_Vector *vof = (LV2_Atom_Vector*)LV2_ATOM_BODY(curs);
	    if (vof->atom.type == self->uris.atom_Int) {
	      struct cursorstate *cs = (struct cursorstate *) LV2_ATOM_BODY(&vof->atom);
	      memcpy(&self->cursorstate, cs, sizeof(struct cursorstate));
	    }
	  }
	  if (chn && chn->type == self->uris.atom_Vector) {
	    LV2_Atom_Vector *vof = (LV2_Atom_Vector*)LV2_ATOM_BODY(chn);
	    if (vof->atom.type == self->uris.atom_Float) {
	      struct channelstate *cs = (struct channelstate *) LV2_ATOM_BODY(&vof->atom);
	      memcpy(self->channelstate, cs, self->n_channels * sizeof(struct channelstate));
	    }
	  }
	}
      }
      ev = lv2_atom_sequence_next(ev);
    }
  }

  /* process audio data */
  for (uint32_t c = 0; c < self->n_channels; ++c) {
    if (self->ui_active && capacity_ok) {
      /* if UI is active, send raw audio data to UI */
      tx_rawaudio(&self->forge, &self->uris, c, n_samples, self->input[c]);
    }
    /* if not processing in-place, forward audio */
    if (self->input[c] != self->output[c]) {
      memcpy(self->output[c], self->input[c], sizeof(float) * n_samples);
    }
  }

  /* close off atom-sequence */
  lv2_atom_forge_pop(&self->forge, &self->frame);
}
Esempio n. 9
0
File: lv2.c Progetto: aelse/setBfree
static void
run(LV2_Handle instance, uint32_t n_samples)
{
  B3S* b3s = (B3S*)instance;
  float* audio[2];

  audio[0] = b3s->outL;
  audio[1] = b3s->outR;

  /* prepare outgoing MIDI */
  const uint32_t capacity = b3s->midiout->atom.size;

  static bool warning_printed = false;
  if (!warning_printed && capacity < 4096) {
    warning_printed = true;
    fprintf(stderr, "B3LV2: LV message buffer is only %d bytes. Expect problems.\n", capacity);
    fprintf(stderr, "B3LV2: if your LV2 host allows one to configure a buffersize use at least 4kBytes.\n");

  }
  lv2_atom_forge_set_buffer(&b3s->forge, (uint8_t*)b3s->midiout, capacity);
  lv2_atom_forge_sequence_head(&b3s->forge, &b3s->frame, 0);

  uint32_t written = 0;

  if (b3s->queue_panic) {
	  b3s->queue_panic = 0;
	  midi_panic(b3s->inst);
  }

  /* Process incoming events from GUI and handle MIDI events */
  if (b3s->midiin) {
    LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(b3s->midiin)->body);
    while(!lv2_atom_sequence_is_end(&(b3s->midiin)->body, (b3s->midiin)->atom.size, ev)) {
      if (ev->body.type == b3s->uris.midi_MidiEvent) {
	/* process midi messages from player */
	if (written + BUFFER_SIZE_SAMPLES < ev->time.frames
	    && ev->time.frames < n_samples) {
	  /* first syntheize sound up until the message timestamp */
	  written = synthSound(b3s, written, ev->time.frames, audio);
	}
	/* send midi message to synth, CC's will trigger hook -> update GUI */
	parse_raw_midi_data(b3s->inst, (uint8_t*)(ev+1), ev->body.size);
      } else if (ev->body.type == b3s->uris.atom_Blank || ev->body.type == b3s->uris.atom_Object) {
	/* process messages from GUI */
	const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
	if (obj->body.otype == b3s->uris.sb3_uiinit) {
	  b3s->update_gui_now = 1;
	} else if (obj->body.otype == b3s->uris.sb3_uimccquery) {
	  midi_loopCCAssignment(b3s->inst->midicfg, 7, mcc_cb, b3s);
	} else if (obj->body.otype == b3s->uris.sb3_uimccset) {
	  const LV2_Atom* cmd = NULL;
	  const LV2_Atom* flags = NULL;
	  lv2_atom_object_get(obj, b3s->uris.sb3_cckey, &flags, b3s->uris.sb3_ccval, &cmd, 0);
	  if (cmd && flags) {
	    midi_uiassign_cc(b3s->inst->midicfg, (const char*)LV2_ATOM_BODY(cmd), ((LV2_Atom_Int*)flags)->body);
	  }
	} else if (obj->body.otype == b3s->uris.sb3_midipgm) {
	  const LV2_Atom* key = NULL;
	  lv2_atom_object_get(obj, b3s->uris.sb3_cckey, &key, 0);
	  if (key) {
	    installProgram(b3s->inst, ((LV2_Atom_Int*)key)->body);
	  }
	} else if (obj->body.otype == b3s->uris.sb3_midisavepgm) {
	  const LV2_Atom* pgm = NULL;
	  const LV2_Atom* name = NULL;
	  lv2_atom_object_get(obj, b3s->uris.sb3_cckey, &pgm, b3s->uris.sb3_ccval, &name, 0);
	  if (pgm && name) {
	    saveProgramm(b3s->inst, (int) ((LV2_Atom_Int*)pgm)->body, (char*) LV2_ATOM_BODY(name), 0);
	    b3s->update_pgm_now = 1;
	  }
	} else if (obj->body.otype == b3s->uris.sb3_loadpgm) {
	  iowork(b3s, obj, CMD_LOADPGM);
	} else if (obj->body.otype == b3s->uris.sb3_loadcfg) {
	  iowork(b3s, obj, CMD_LOADCFG);
	} else if (obj->body.otype == b3s->uris.sb3_savepgm) {
	  iowork(b3s, obj, CMD_SAVEPGM);
	} else if (obj->body.otype == b3s->uris.sb3_savecfg) {
	  iowork(b3s, obj, CMD_SAVECFG);
	} else if (obj->body.otype == b3s->uris.sb3_cfgstr) {
	  if (!b3s->inst_offline) {
	    advanced_config_set(b3s, obj);
	  }
	} else if (obj->body.otype == b3s->uris.sb3_control) {
	  b3s->suspend_ui_msg = 1;
	  const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
	  char *k; int v;
	  if (!get_cc_key_value(&b3s->uris, obj, &k, &v)) {
#ifdef DEBUGPRINT
	    fprintf(stderr, "B3LV2: callMIDIControlFunction(..,\"%s\", %d);\n", k, v);
#endif
	    callMIDIControlFunction(b3s->inst->midicfg, k, v);
	  }
	  b3s->suspend_ui_msg = 0;
	}
      }
      ev = lv2_atom_sequence_next(ev);
    }
  }

  /* synthesize [remaining] sound */
  synthSound(b3s, written, n_samples, audio);

  /* send active keys to GUI - IFF changed */
  bool keychanged = false;
  for (int i = 0 ; i < MAX_KEYS/32; ++i) {
    if (b3s->active_keys[i] != b3s->inst->synth->_activeKeys[i]) {
      keychanged = true;
    }
    b3s->active_keys[i] = b3s->inst->synth->_activeKeys[i];
  }
  if (keychanged) {
    LV2_Atom_Forge_Frame frame;
    lv2_atom_forge_frame_time(&b3s->forge, 0);
    x_forge_object(&b3s->forge, &frame, 1, b3s->uris.sb3_activekeys);
    lv2_atom_forge_property_head(&b3s->forge, b3s->uris.sb3_keyarrary, 0);
    lv2_atom_forge_vector(&b3s->forge, sizeof(unsigned int), b3s->uris.atom_Int, MAX_KEYS/32, b3s->active_keys);
    lv2_atom_forge_pop(&b3s->forge, &frame);
  }

  /* check for new instances */
  postrun(b3s);

  if (b3s->update_gui_now) {
    b3s->update_gui_now = 0;
    b3s->update_pgm_now = 1;
    b3s->suspend_ui_msg = 1;
    rc_loop_state(b3s->inst->state, rc_cb, b3s);
    b3s->suspend_ui_msg = 0;
    forge_kvconfigmessage(&b3s->forge, &b3s->uris, b3s->uris.sb3_cfgkv, "lv2.info", b3s->lv2nfo);
    forge_kvcontrolmessage(&b3s->forge, &b3s->uris, "special.init", (int32_t) b3s->thirtysec);
  } else if (b3s->update_pgm_now) {
    b3s->update_pgm_now = 0;
    loopProgammes(b3s->inst->progs, 1, pgm_cb, b3s);
  }
}
Esempio n. 10
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;
}
Esempio n. 11
0
      /** Set the forge's buffer

          @param buf The buffer to use
          @param size The size of the buffer
       */
      inline void
      set_buffer (uint8_t* buf, uint32_t size)
      {
         lv2_atom_forge_set_buffer (this, buf, size);
      }
Esempio n. 12
0
/** ==== Run Method ==== */
static void
run(LV2_Handle handle, uint32_t n_samples)
{
	EgScope* self = (EgScope*)handle;

	/* Ensure notify port buffer is large enough to hold all audio-samples and
	   configuration settings.  A minimum size was requested in the .ttl file,
	   but check here just to be sure.

	   TODO: Explain these magic numbers.
	*/
	const size_t   size  = (sizeof(float) * n_samples + 64) * self->n_channels;
	const uint32_t space = self->notify->atom.size;
	if (space < size + 128) {
		/* Insufficient space, report error and do nothing.  Note that a
		   real-time production plugin mustn't call log functions in run(), but
		   this can be useful for debugging and example purposes.
		*/
		lv2_log_error(&self->logger, "Buffer size is insufficient\n");
		return;
	}

	// Prepare forge buffer and initialize atom-sequence
	lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, space);
	lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0);

	/* Send settings to UI

	   The plugin can continue to run while the UI is closed and re-opened.
	   The state and settings of the UI are kept here and transmitted to the UI
	   every time it asks for them or if the user initializes a 'load preset'.
	*/
	if (self->send_settings_to_ui && self->ui_active) {
		self->send_settings_to_ui = false;
		// Forge container object of type 'ui_state'
		LV2_Atom_Forge_Frame frame;
		lv2_atom_forge_frame_time(&self->forge, 0);
		lv2_atom_forge_object(&self->forge, &frame, 0, self->uris.ui_State);

		// Add UI state as properties
		lv2_atom_forge_key(&self->forge, self->uris.ui_spp);
		lv2_atom_forge_int(&self->forge, self->ui_spp);
		lv2_atom_forge_key(&self->forge, self->uris.ui_amp);
		lv2_atom_forge_float(&self->forge, self->ui_amp);
		lv2_atom_forge_key(&self->forge, self->uris.param_sampleRate);
		lv2_atom_forge_float(&self->forge, self->rate);
		lv2_atom_forge_pop(&self->forge, &frame);
	}

	// Process incoming events from GUI
	if (self->control) {
		const LV2_Atom_Event* ev = lv2_atom_sequence_begin(
			&(self->control)->body);
		// For each incoming message...
		while (!lv2_atom_sequence_is_end(
			       &self->control->body, self->control->atom.size, ev)) {
			// If the event is an atom:Blank object
			if (ev->body.type == self->uris.atom_Blank) {
				const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body;
				if (obj->body.otype == self->uris.ui_On) {
					// If the object is a ui-on, the UI was activated
					self->ui_active           = true;
					self->send_settings_to_ui = true;
				} else if (obj->body.otype == self->uris.ui_Off) {
					// If the object is a ui-off, the UI was closed
					self->ui_active = false;
				} else if (obj->body.otype == self->uris.ui_State) {
					// If the object is a ui-state, it's the current UI settings
					const LV2_Atom* spp = NULL;
					const LV2_Atom* amp = NULL;
					lv2_atom_object_get(obj, self->uris.ui_spp, &spp,
					                    self->uris.ui_amp, &amp,
					                    0);
					if (spp) {
						self->ui_spp = ((const LV2_Atom_Int*)spp)->body;
					}
					if (amp) {
						self->ui_amp = ((const LV2_Atom_Float*)amp)->body;
					}
				}
			}
			ev = lv2_atom_sequence_next(ev);
		}
	}

	// Process audio data
	for (uint32_t c = 0; c < self->n_channels; ++c) {
		if (self->ui_active) {
			// If UI is active, send raw audio data to UI
			tx_rawaudio(&self->forge, &self->uris, c, n_samples, self->input[c]);
		}
		// If not processing audio in-place, forward audio
		if (self->input[c] != self->output[c]) {
			memcpy(self->output[c], self->input[c], sizeof(float) * n_samples);
		}
	}

	// Close off sequence
	lv2_atom_forge_pop(&self->forge, &self->frame);
}
Esempio n. 13
0
static void
run (LV2_Handle instance, uint32_t n_samples)
{
	MidiMap* self = (MidiMap*)instance;
	if (!self->midiout || !self->midiin) {
		return;
	}

	/* prepare midiout port */
	const uint32_t capacity = self->midiout->atom.size;
	lv2_atom_forge_set_buffer (&self->forge, (uint8_t*)self->midiout, capacity);
	lv2_atom_forge_sequence_head (&self->forge, &self->frame, 0);

	/* update internal frame counter (host only sends update on change) */
	if (self->transport_rolling) {
		self->transport_frame += n_samples * self->transport_speed;
	} else {
		self->play_cnt = 0;
	}

	/* inform the GUI */
	if (self->inform_ui) {
		self->inform_ui = false;
		inform_ui (self);
	}

	uint32_t gen_n_samples = 0;

	/* Process incoming midi events */
	LV2_Atom_Event* ev = lv2_atom_sequence_begin (&(self->midiin)->body);
	while (!lv2_atom_sequence_is_end (&(self->midiin)->body, (self->midiin)->atom.size, ev)) {
		if (ev->body.type == self->uris.midi_MidiEvent) {
			/* generate signals until current time */
			generate_until (self, gen_n_samples, ev->time.frames);
			gen_n_samples = ev->time.frames;
			/* process midi event */
			filter_midimessage (self, ev->time.frames, (uint8_t*)(ev+1), ev->body.size);
		} else if (ev->body.type == self->uris.atom_Blank || ev->body.type == self->uris.atom_Object) {
			/* schedule loading config file */
			const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
			if (obj->body.otype == self->uris.time_Position) {
				parse_host_transport (self, obj);
			}
			else if (obj->body.otype == self->uris.patch_Set) {
				self->schedule->schedule_work (self->schedule->handle, lv2_atom_total_size (&ev->body), &ev->body);
			}
		}
		ev = lv2_atom_sequence_next (ev);
	}

	/* generate remaining events */
	generate_until (self, gen_n_samples, n_samples);

	/* keep track of position (for generator) */
	self->monotonic_cnt += n_samples;
	if (self->transport_rolling) {
		self->play_cnt += n_samples;
	}

	/* report active rules */
	*self->p_rulecount = self->rules ? self->rules->count : 0;
}
Esempio n. 14
0
int32_t notmain (uint32_t earlypc) {
    hardware_init();
    int32_t samplerate = audio_init();
    Lv2World *lv2_world = lv2_init(samplerate);
    led_init();
    switch_init();

    printf("\r\nPiTracker console\r\n");
    printf("Samplerate: %d\r\n", samplerate);

    uint32_t inkey;
    uint32_t counter=0;
    LV2_Atom_Forge_Frame midi_seq_frame;
    int buffer_processed = 0;
    const Lv2Plugin *plugin;
    plugin = lv2_world->plugin_list;

    lv2_port *output_left = new_lv2_port(lv2_audio_port, 1);
    lv2_port *output_right = new_lv2_port(lv2_audio_port, 2);
    lv2_port *midi_in = new_lv2_port(lv2_atom_port, 3);

    plugin->descriptor->connect_port(plugin->handle, midi_in->id, midi_in->buffer);
    plugin->descriptor->connect_port(plugin->handle, output_left->id, output_left->buffer);
    plugin->descriptor->connect_port(plugin->handle, output_right->id, output_right->buffer);

    lv2_atom_forge_set_buffer(&forge,
                              midi_in->buffer,
                              LV2_ATOM_BUFFER_SIZE);
    lv2_atom_forge_sequence_head(&forge, &midi_seq_frame, 0);
    
    init_midi_source(&forge);
    
    while (1) {
#ifdef DEBUG
        if(kbhit()) {
            inkey = readch();
            //printf("%x", inkey);
            switch(inkey) {
                case 0x03:
#ifdef RASPBERRY_PI
                    printf("Rebooting\r\n");
                    usleep(2);
                    reboot();
#else
                    printf("Exiting\r\n");
                    close_keyboard();
                    exit(0);
#endif
                    break;
                case 0x31:
                    if (plugin->next) plugin = plugin->next;
                    else plugin = lv2_world->plugin_list;
                    plugin->descriptor->connect_port(plugin->handle, midi_in->id, midi_in->buffer);
                    plugin->descriptor->connect_port(plugin->handle, output_left->id, output_left->buffer);
                    plugin->descriptor->connect_port(plugin->handle, output_right->id, output_right->buffer);
                    break;
                case 0x0d:
                    printf("\r\n");
                    break;
                default:
                    putc(inkey, stdout);
#ifdef LINUX
                    fflush(stdout);
#endif
                    break;
            }
        }
#endif

        if (!buffer_processed) {
            forge_midi_input();

            lv2_atom_forge_pop(&forge, &midi_seq_frame);
            plugin->descriptor->run(plugin->handle, LV2_AUDIO_BUFFER_SIZE);
            lv2_atom_forge_set_buffer(&forge,
                                      midi_in->buffer,
                                      sizeof(uint8_t) * midi_in->buffer_sz);
            lv2_atom_forge_sequence_head(&forge, &midi_seq_frame, 0);
            buffer_processed = 1;
        }

        if (buffer_processed && audio_buffer_free_space() > LV2_AUDIO_BUFFER_SIZE * 2) {
            audio_buffer_write(output_left->buffer, output_right->buffer, output_left->buffer_sz);
            buffer_processed = 0;
            counter++;
        }
    }
}
Esempio n. 15
0
static void
bim_run(LV2_Handle instance, uint32_t n_samples)
{
	LV2meter* self = (LV2meter*)instance;

	const uint32_t capacity = self->notify->atom.size;
	assert(capacity > 920);
	lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, capacity);
	lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0);

	if (self->send_state_to_ui && self->ui_active) {
		self->send_state_to_ui = false;
		forge_kvcontrolmessage(&self->forge, &self->uris, self->uris.mtr_control, CTL_SAMPLERATE, self->rate);
	}

	/* Process incoming events from GUI */
	if (self->control) {
		LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(self->control)->body);
		while(!lv2_atom_sequence_is_end(&(self->control)->body, (self->control)->atom.size, ev)) {
			if (ev->body.type == self->uris.atom_Blank || ev->body.type == self->uris.atom_Object) {
				const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
				if (obj->body.otype == self->uris.mtr_meters_on) {
					self->ui_active = true;
					self->send_state_to_ui = true;
				}
				else if (obj->body.otype == self->uris.mtr_meters_off) {
					self->ui_active = false;
				}
				else if (obj->body.otype == self->uris.mtr_meters_cfg) {
					int k; float v;
					get_cc_key_value(&self->uris, obj, &k, &v);
					switch (k) {
						case CTL_START:
							self->ebu_integrating = true;
							break;
						case CTL_PAUSE:
							self->ebu_integrating = false;
							break;
						case CTL_RESET:
							bim_reset(self);
							self->send_state_to_ui = true;
							break;
						case CTL_AVERAGE:
							self->bim_average = true;
							break;
						case CTL_WINDOWED:
							self->bim_average = false;
							break;
						default:
							break;
					}
				}
			}
			ev = lv2_atom_sequence_next(ev);
		}
	}
#if 0
	static uint32_t max_post = 0;
	if (self->notify->atom.size > max_post) {
		max_post = self->notify->atom.size;
		printf("new post parse: %d\n", max_post);
	}
#endif


	/* process */

	if (self->ebu_integrating && self->integration_time < 2147483647) {
		/* currently 'self->histS' is int32,
		 * the max peak that can be recorded is 2^31,
		 * for now we simply limit data-acquisition to at
		 * most 2^31 points.
		 */
		if (self->integration_time > 2147483647 - n_samples) {
			self->integration_time = 2147483647;
		} else {
			for (uint32_t s = 0; s < n_samples; ++s) {
				float_stats(self, self->input[0] + s);
			}
			self->integration_time += n_samples;
		}
	}

	const int fps_limit = n_samples * ceil(self->rate / (5.f * n_samples)); // ~ 5fps
	self->radar_resync += n_samples;

	if (self->radar_resync >= fps_limit || self->send_state_to_ui) {
		self->radar_resync = self->radar_resync % fps_limit;

		if (self->ui_active && (self->ebu_integrating || self->send_state_to_ui)) {
			LV2_Atom_Forge_Frame frame;
			lv2_atom_forge_frame_time(&self->forge, 0);
			x_forge_object(&self->forge, &frame, 1, self->uris.bim_stats);

			lv2_atom_forge_property_head(&self->forge, self->uris.ebu_integr_time, 0);
			lv2_atom_forge_long(&self->forge, self->integration_time);

			lv2_atom_forge_property_head(&self->forge, self->uris.bim_zero, 0);
			lv2_atom_forge_int(&self->forge, self->bim_zero);
			lv2_atom_forge_property_head(&self->forge, self->uris.bim_pos, 0);
			lv2_atom_forge_int(&self->forge, self->bim_pos);

			lv2_atom_forge_property_head(&self->forge, self->uris.bim_max, 0);
			lv2_atom_forge_double(&self->forge, self->bim_max);
			lv2_atom_forge_property_head(&self->forge, self->uris.bim_min, 0);
			lv2_atom_forge_double(&self->forge, self->bim_min);
			lv2_atom_forge_property_head(&self->forge, self->uris.bim_nan, 0);
			lv2_atom_forge_int(&self->forge, self->bim_nan);
			lv2_atom_forge_property_head(&self->forge, self->uris.bim_inf, 0);
			lv2_atom_forge_int(&self->forge, self->bim_inf);
			lv2_atom_forge_property_head(&self->forge, self->uris.bim_den, 0);
			lv2_atom_forge_int(&self->forge, self->bim_den);

			lv2_atom_forge_property_head(&self->forge, self->uris.bim_data, 0);
			lv2_atom_forge_vector(&self->forge, sizeof(int32_t), self->uris.atom_Int, BIM_LAST, self->histS);
			lv2_atom_forge_pop(&self->forge, &frame);
		}

		if (self->ui_active) {
			LV2_Atom_Forge_Frame frame;
			lv2_atom_forge_frame_time(&self->forge, 0);
			x_forge_object(&self->forge, &frame, 1, self->uris.bim_information);
			lv2_atom_forge_property_head(&self->forge, self->uris.ebu_integrating, 0);
			lv2_atom_forge_bool(&self->forge, self->ebu_integrating);
			lv2_atom_forge_property_head(&self->forge, self->uris.bim_averaging, 0);
			lv2_atom_forge_bool(&self->forge, self->bim_average);
			lv2_atom_forge_pop(&self->forge, &frame);
		}

		if (!self->bim_average) {
			bim_clear (self);
		}
	}

	/* foward audio-data */
	if (self->input[0] != self->output[0]) {
		memcpy(self->output[0], self->input[0], sizeof(float) * n_samples);
	}

#if 0
	//printf("forged %d bytes\n", self->notify->atom.size);
	static uint32_t max_cap = 0;
	if (self->notify->atom.size > max_cap) {
		max_cap = self->notify->atom.size;
		printf("new max: %d (of %d avail)\n", max_cap, capacity);
	}
#endif
}
Esempio n. 16
0
static void
run(LV2_Handle instance, uint32_t n_samples)
{
	uint32_t i,c;
	BalanceControl* self = (BalanceControl*)instance;
	const float balance = *self->balance;
	const float trim = db_to_gain(*self->trim);
	float gain_left  = 1.0;
	float gain_right = 1.0;

	const int ascnt = self->samplerate / UPDATE_FREQ;

  const uint32_t capacity = self->notify->atom.size;
  lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, capacity);
  lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0);

  /* reset after state restore */
	if (self->queue_stateswitch) {
		self->queue_stateswitch = 0;
		self->peak_integrate_pref = self->state[0] * self->samplerate;
		self->meter_falloff = self->state[1] / UPDATE_FREQ;
		self->peak_hold = self->state[2] * UPDATE_FREQ;

		self->peak_integrate_pref = MAX(0, self->peak_integrate_pref);
		self->peak_integrate_pref = MIN(self->peak_integrate_pref, self->peak_integrate_max);

		self->meter_falloff = MAX(0, self->meter_falloff);
		self->meter_falloff = MIN(self->meter_falloff, 1000);

		self->peak_hold = MAX(0, self->peak_hold);
		self->peak_hold = MIN(self->peak_hold, 60 * UPDATE_FREQ);
		reset_uicom(self);
		send_cfg_to_ui(self);
	}

  /* Process incoming events from GUI */
  if (self->control) {
    LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(self->control)->body);
    while(!lv2_atom_sequence_is_end(&(self->control)->body, (self->control)->atom.size, ev)) {
      if (ev->body.type == self->uris.atom_Blank || ev->body.type == self->uris.atom_Object) {
				const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
				if (obj->body.otype == self->uris.blc_meters_on) {
					if (self->uicom_active == 0) {
						reset_uicom(self);
						send_cfg_to_ui(self);
						self->uicom_active = 1;
					}
				}
				if (obj->body.otype == self->uris.blc_meters_off) {
					self->uicom_active = 0;
				}
				if (obj->body.otype == self->uris.blc_meters_cfg) {
					const LV2_Atom* key = NULL;
					const LV2_Atom* value = NULL;
					lv2_atom_object_get(obj, self->uris.blc_cckey, &key, self->uris.blc_ccval, &value, 0);
					if (value && key) {
						update_meter_cfg(self, ((LV2_Atom_Int*)key)->body, ((LV2_Atom_Float*)value)->body);
					}
				}
			}
      ev = lv2_atom_sequence_next(ev);
    }
	}

	/* pre-calculate parameters */
	if (balance < 0) {
		gain_right = 1.0 + RAIL(balance, -1.0, 0.0);
	} else if (balance > 0) {
		gain_left = 1.0 - RAIL(balance, 0.0, 1.0);
	}

	switch ((int) *self->unitygain) {
		case 1:
			{
				/* maintain amplitude sum */
				const double gaindiff = (gain_left - gain_right);
				gain_left = 1.0 + gaindiff;
				gain_right = 1.0 - gaindiff;
			}
			break;
		case 2:
			{
				/* equal power*/
				if (balance < 0) {
					gain_right = MAX(.5, gain_right);
					gain_left = db_to_gain(-gain_to_db(gain_right));
				} else {
					gain_left = MAX(.5, gain_left);
					gain_right = db_to_gain(-gain_to_db(gain_left));
				}
			}
		case 0:
			/* 'tradidional' balance */
			break;
	}

	if (*(self->phase[C_LEFT])) gain_left *=-1;
	if (*(self->phase[C_RIGHT])) gain_right *=-1;

	/* keep track of input levels -- only if GUI is visiable */
	if (self->uicom_active) {
		for (c=0; c < CHANNELS; ++c) {
			for (i=0; i < n_samples; ++i) {
				/* input peak meter */
				const float ps = fabsf(self->input[c][i]);
				if (ps > self->p_peak_in[c]) self->p_peak_in[c] = ps;

				if (self->peak_integrate_pref < 1) {
					const float psm = ps * ps;
					if (psm > self->p_peak_inM[c]) self->p_peak_inM[c] = psm;
					continue;
				}

				/* integrated level, peak */
				const int pip = (self->peak_integrate_pos + i ) % self->peak_integrate_pref;
				const double p_sig = SQUARE(self->input[c][i]);
				self->p_peak_inP[c] += p_sig - self->p_peak_inPi[c][pip];
				self->p_peak_inPi[c][pip] = p_sig;
				/* peak of integrated signal */
				const float psm = self->p_peak_inP[c] / (double) self->peak_integrate_pref;
				if (psm > self->p_peak_inM[c]) self->p_peak_inM[c] = psm;
			}
		}
	}

	/* process audio -- delayline + balance & gain */
	process_channel(self, gain_left * trim,  C_LEFT, n_samples);
	process_channel(self, gain_right * trim, C_RIGHT, n_samples);

	/* swap/assign channels */
	uint32_t pos = 0;

	if (self->c_monomode != (int) *self->monomode) {
		/* smooth change */
		const uint32_t fade_len = (n_samples >= FADE_LEN) ? FADE_LEN : n_samples;
		for (; pos < fade_len; pos++) {
			const float gain = (float)pos / (float)fade_len;
			float x1[CHANNELS], x2[CHANNELS];
			channel_map_change(self, self->c_monomode, pos, x1);
			channel_map_change(self, (int) *self->monomode, pos, x2);
			self->output[C_LEFT][pos] = x1[C_LEFT] * (1.0 - gain) + x2[C_LEFT] * gain;
			self->output[C_RIGHT][pos] = x1[C_RIGHT] * (1.0 - gain) + x2[C_RIGHT] * gain;
		}
	}

	channel_map(self, (int) *self->monomode, pos, n_samples);
	self->c_monomode = (int) *self->monomode;

	/* audio processing done */

	if (!self->uicom_active) {
		return;
	}

	/* output peak meter */
	for (c=0; c < CHANNELS; ++c) {
		for (i=0; i < n_samples; ++i) {
			/* peak */
			const float ps = fabsf(self->output[c][i]);
			if (ps > self->p_peak_out[c]) self->p_peak_out[c] = ps;

				if (self->peak_integrate_pref < 1) {
				const float psm = ps * ps;
				if (psm > self->p_peak_outM[c]) self->p_peak_outM[c] = psm;
				continue;
			}

			/* integrated level, peak */
			const int pip = (self->peak_integrate_pos + i ) % self->peak_integrate_pref;
			const double p_sig = SQUARE(self->output[c][i]);
			self->p_peak_outP[c] += p_sig - self->p_peak_outPi[c][pip];
			self->p_peak_outPi[c][pip] = p_sig;
			/* peak of integrated signal */
			const float psm = self->p_peak_outP[c] / (double) self->peak_integrate_pref;
			if (psm > self->p_peak_outM[c]) self->p_peak_outM[c] = psm;
		}
	}
	if (self->peak_integrate_pref > 0) {
		self->peak_integrate_pos = (self->peak_integrate_pos + n_samples ) % self->peak_integrate_pref;
	}

	/* simple output phase correlation */
	for (i=0; i < n_samples; ++i) {
		const double p_pos = SQUARE(self->output[C_LEFT][i] + self->output[C_RIGHT][i]);
		const double p_neg = SQUARE(self->output[C_LEFT][i] - self->output[C_RIGHT][i]);

		/* integrate over 500ms */
		self->p_phase_outP += p_pos - self->p_phase_outPi[self->phase_integrate_pos];
		self->p_phase_outN += p_neg - self->p_phase_outNi[self->phase_integrate_pos];
		self->p_phase_outPi[self->phase_integrate_pos] = p_pos;
		self->p_phase_outNi[self->phase_integrate_pos] = p_neg;
		self->phase_integrate_pos = (self->phase_integrate_pos + 1) % self->phase_integrate_max;
	}

/* abs peak hold */
#define PKM(A,CHN,ID) \
{ \
	const float peak = VALTODB(self->p_peak_##A[CHN]); \
	if (peak > self->p_max_##A[CHN]) { \
		self->p_max_##A[CHN] = peak; \
		self->p_tme_##A[CHN] = 0; \
		forge_kvcontrolmessage(&self->forge, &self->uris, ID, self->p_max_##A[CHN]); \
	} else if (self->peak_hold <= 0) { \
		(self->p_tme_##A[CHN])=0; /* infinite hold */ \
	} else if (self->p_tme_##A[CHN] <= self->peak_hold) { \
		(self->p_tme_##A[CHN])++; \
	} else if (self->meter_falloff == 0) { \
		self->p_max_##A[CHN] = peak; \
		forge_kvcontrolmessage(&self->forge, &self->uris, ID, self->p_max_##A[CHN]); \
	} else { \
		self->p_max_##A[CHN] -= self->meter_falloff; \
		self->p_max_##A[CHN] = MAX(peak, self->p_max_##A[CHN]); \
		forge_kvcontrolmessage(&self->forge, &self->uris, ID, self->p_max_##A[CHN]); \
	} \
}

/* RMS meter */
#define PKF(A,CHN,ID) \
{ \
	float dbp = VALTODB(sqrt(2.0 * self->p_peak_##A##M[CHN])); \
	if (dbp > self->p_vpeak_##A[CHN]) { \
		self->p_vpeak_##A[CHN] = dbp; \
	} else if (self->meter_falloff == 0) { \
		self->p_vpeak_##A[CHN] = dbp; \
	} else { \
		self->p_vpeak_##A[CHN] -= self->meter_falloff; \
		self->p_vpeak_##A[CHN] = MAX(dbp, self->p_vpeak_##A[CHN]); \
	} \
	forge_kvcontrolmessage(&self->forge, &self->uris, ID, (self->p_vpeak_##A [CHN])); \
}

	/* report peaks to UI */
	self->p_peakcnt += n_samples;
	if (self->p_peakcnt > ascnt) {

		PKF(in,  C_LEFT,  METER_IN_LEFT)
		PKF(in,  C_RIGHT, METER_IN_RIGHT);
		PKF(out, C_LEFT,  METER_OUT_LEFT);
		PKF(out, C_RIGHT, METER_OUT_RIGHT);

		PKM(in,  C_LEFT,  PEAK_IN_LEFT);
		PKM(in,  C_RIGHT, PEAK_IN_RIGHT);
		PKM(out, C_LEFT,  PEAK_OUT_LEFT);
		PKM(out, C_RIGHT, PEAK_OUT_RIGHT);

#define RMSF(A) sqrt( ( (A) / (double)self->phase_integrate_max ) + 1.0e-12 )
		double phase = 0.0;
		const double phasdiv = self->p_phase_outP + self->p_phase_outN;
		if (phasdiv >= 1.0e-6) {
			phase = (RMSF(self->p_phase_outP) - RMSF(self->p_phase_outN)) / RMSF(phasdiv);
		} else if (self->p_phase_outP > .001 && self->p_phase_outN > .001) {
			phase = 1.0;
		}

		forge_kvcontrolmessage(&self->forge, &self->uris, PHASE_OUT, phase);

		self->p_peakcnt -= ascnt;
		for (c=0; c < CHANNELS; ++c) {
			self->p_peak_in[c] = -INFINITY;
			self->p_peak_out[c] = -INFINITY;
			self->p_peak_inM[c] = -INFINITY;
			self->p_peak_outM[c] = -INFINITY;
		}
	}

	/* report values to UI - if changed*/
	float bal = gain_to_db(fabsf(gain_left));
	if (bal != self->p_bal[C_LEFT]) {
		forge_kvcontrolmessage(&self->forge, &self->uris, GAIN_LEFT, bal);
	}
	self->p_bal[C_LEFT] = bal;

	bal = gain_to_db(fabsf(gain_right));
	if (bal != self->p_bal[C_RIGHT]) {
		forge_kvcontrolmessage(&self->forge, &self->uris, GAIN_RIGHT, bal);
	}
	self->p_bal[C_RIGHT] = bal;

	if (self->p_dly[C_LEFT] != self->c_dly[C_LEFT]) {
		forge_kvcontrolmessage(&self->forge, &self->uris, DELAY_LEFT, (float) self->c_dly[C_LEFT] / self->samplerate);
	}
	self->p_dly[C_LEFT] = self->c_dly[C_LEFT];

	if (self->p_dly[C_RIGHT] != self->c_dly[C_RIGHT]) {
		forge_kvcontrolmessage(&self->forge, &self->uris, DELAY_RIGHT, (float) self->c_dly[C_RIGHT] / self->samplerate);
	}
	self->p_dly[C_RIGHT] = self->c_dly[C_RIGHT];

}