static void forge_message_str(B3S *b3s, LV2_URID uri, const char *msg) { LV2_Atom_Forge_Frame frame; lv2_atom_forge_frame_time(&b3s->forge, 0); x_forge_object(&b3s->forge, &frame, 1, uri); lv2_atom_forge_property_head(&b3s->forge, b3s->uris.sb3_uimsg, 0); lv2_atom_forge_string(&b3s->forge, msg, strlen(msg)); lv2_atom_forge_pop(&b3s->forge, &frame); }
/** 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 void mcc_cb(const char *fnname, const unsigned char chn, const unsigned char cc, const unsigned char flags, void *arg) { B3S* b3s = (B3S*)arg; char mmv[20]; sprintf(mmv, "%d|%d ", chn, cc); LV2_Atom_Forge_Frame frame; lv2_atom_forge_frame_time(&b3s->forge, 0); x_forge_object(&b3s->forge, &frame, 1, b3s->uris.sb3_uimccset); lv2_atom_forge_property_head(&b3s->forge, b3s->uris.sb3_cckey, 0); lv2_atom_forge_string(&b3s->forge, fnname, strlen(fnname)); lv2_atom_forge_property_head(&b3s->forge, b3s->uris.sb3_ccval, 0); lv2_atom_forge_string(&b3s->forge, mmv, strlen(mmv)); lv2_atom_forge_pop(&b3s->forge, &frame); }
/** forge atom-vector of raw data */ static void tx_rawaudio(LV2_Atom_Forge *forge, ScoLV2URIs *uris, const int32_t channel, const size_t n_samples, void *data) { LV2_Atom_Forge_Frame frame; /* forge container object of type 'rawaudio' */ lv2_atom_forge_frame_time(forge, 0); x_forge_object(forge, &frame, 1, uris->rawaudio); /* add integer attribute 'channelid' */ lv2_atom_forge_property_head(forge, uris->channelid, 0); lv2_atom_forge_int(forge, channel); /* add vector of floats raw 'audiodata' */ lv2_atom_forge_property_head(forge, uris->audiodata, 0); lv2_atom_forge_vector(forge, sizeof(float), uris->atom_Float, n_samples, data); /* close off atom-object */ lv2_atom_forge_pop(forge, &frame); }
static void pgm_cb(int num, int pc, const char *name, void *arg) { B3S* b3s = (B3S*)arg; char tmp[256]; int pco = pc - b3s->inst->progs->MIDIControllerPgmOffset; #ifdef DEBUGPRINT fprintf(stderr, "PGM CB %d %d %s\n",num, pc, name); #endif LV2_Atom_Forge_Frame frame; lv2_atom_forge_frame_time(&b3s->forge, 0); x_forge_object(&b3s->forge, &frame, 1, b3s->uris.sb3_midipgm); lv2_atom_forge_property_head(&b3s->forge, b3s->uris.sb3_cckey, 0); lv2_atom_forge_int(&b3s->forge, pco); lv2_atom_forge_property_head(&b3s->forge, b3s->uris.sb3_ccval, 0); lv2_atom_forge_string(&b3s->forge, name, strlen(name)); formatProgram(&b3s->inst->progs->programmes[pc], tmp, 256); lv2_atom_forge_property_head(&b3s->forge, b3s->uris.sb3_ccdsc, 0); lv2_atom_forge_string(&b3s->forge, tmp, strlen(tmp)); lv2_atom_forge_pop(&b3s->forge, &frame); }
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); }
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); } }
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 }