void AtomWriter::delta(const Raul::URI& uri, const Resource::Properties& remove, const Resource::Properties& add) { LV2_Atom_Forge_Frame msg; forge_request(&msg, _uris.patch_Patch); lv2_atom_forge_key(&_forge, _uris.patch_subject); forge_uri(uri); lv2_atom_forge_key(&_forge, _uris.patch_remove); LV2_Atom_Forge_Frame remove_obj; lv2_atom_forge_object(&_forge, &remove_obj, 0, 0); forge_properties(remove); lv2_atom_forge_pop(&_forge, &remove_obj); lv2_atom_forge_key(&_forge, _uris.patch_add); LV2_Atom_Forge_Frame add_obj; lv2_atom_forge_object(&_forge, &add_obj, 0, 0); forge_properties(add); lv2_atom_forge_pop(&_forge, &add_obj); lv2_atom_forge_pop(&_forge, &msg); finish_msg(); }
/** ==== Utility Function: `tx_rawaudio` ==== This function forges a message for sending a vector of raw data. The object is a http://lv2plug.in/ns/ext/atom#Blank[Blank] with a few properties, like: [source,n3] -------- [] a sco:RawAudio ; sco:channelID 0 ; sco:audioData [ 0.0, 0.0, ... ] . -------- where the value of the `sco:audioData` property, `[ 0.0, 0.0, ... ]`, is a http://lv2plug.in/ns/ext/atom#Vector[Vector] of http://lv2plug.in/ns/ext/atom#Float[Float]. */ static void tx_rawaudio(LV2_Atom_Forge* forge, ScoLV2URIs* uris, const int32_t channel, const size_t n_samples, const float* data) { LV2_Atom_Forge_Frame frame; // Forge container object of type 'RawAudio' lv2_atom_forge_frame_time(forge, 0); lv2_atom_forge_object(forge, &frame, 0, uris->RawAudio); // Add integer 'channelID' property lv2_atom_forge_key(forge, uris->channelID); lv2_atom_forge_int(forge, channel); // Add vector of floats 'audioData' property lv2_atom_forge_key(forge, uris->audioData); lv2_atom_forge_vector( forge, sizeof(float), uris->atom_Float, n_samples, data); // Close off object lv2_atom_forge_pop(forge, &frame); }
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); }
void AtomWriter::put(const Raul::URI& uri, const Resource::Properties& properties, Resource::Graph ctx) { LV2_Atom_Forge_Frame msg; forge_request(&msg, _uris.patch_Put); lv2_atom_forge_key(&_forge, _uris.patch_subject); forge_uri(uri); lv2_atom_forge_key(&_forge, _uris.patch_body); LV2_Atom_Forge_Frame body; lv2_atom_forge_object(&_forge, &body, 0, 0); forge_properties(properties); lv2_atom_forge_pop(&_forge, &body); lv2_atom_forge_pop(&_forge, &msg); finish_msg(); }
void AtomWriter::get(const Raul::URI& uri) { LV2_Atom_Forge_Frame msg; forge_request(&msg, _uris.patch_Get); lv2_atom_forge_key(&_forge, _uris.patch_subject); forge_uri(uri); lv2_atom_forge_pop(&_forge, &msg); finish_msg(); }
/** Write the patch get message */ static LV2_Atom *write_patch_get(LV2_Atom_Forge *forge, Fluid_URIs *uris) { LV2_Atom_Forge_Frame get_frame; LV2_Atom_Forge_Frame body_frame; LV2_Atom_Forge_Ref ref = lv2_atom_forge_blank(forge, &get_frame, 1, uris->patch_get); lv2_atom_forge_property_head(forge, uris->patch_body, 0); lv2_atom_forge_blank(forge, &body_frame, 2, 0); lv2_atom_forge_property_head(forge, uris->patch_subject, 0); lv2_atom_forge_int(forge, uris->fluid_preset); lv2_atom_forge_pop(forge, &body_frame); lv2_atom_forge_pop(forge, &get_frame); return lv2_atom_forge_deref(forge, ref); }
static LV2_Atom_Forge_Ref _trans_event(prog_t *prog, LV2_Atom_Forge *forge, int rolling, jack_position_t *pos) { LV2_Atom_Forge_Frame frame; LV2_Atom_Forge_Ref ref = lv2_atom_forge_frame_time(forge, 0); if(ref) ref = lv2_atom_forge_object(forge, &frame, 0, prog->time_position); { if(ref) ref = lv2_atom_forge_key(forge, prog->time_frame); if(ref) ref = lv2_atom_forge_long(forge, pos->frame); if(ref) ref = lv2_atom_forge_key(forge, prog->time_speed); if(ref) ref = lv2_atom_forge_float(forge, rolling ? 1.0 : 0.0); if(pos->valid & JackPositionBBT) { float bar_beat = pos->beat - 1 + (pos->tick / pos->ticks_per_beat); float bar = pos->bar - 1; if(ref) ref = lv2_atom_forge_key(forge, prog->time_barBeat); if(ref) ref = lv2_atom_forge_float(forge, bar_beat); if(ref) ref = lv2_atom_forge_key(forge, prog->time_bar); if(ref) ref = lv2_atom_forge_long(forge, bar); if(ref) ref = lv2_atom_forge_key(forge, prog->time_beatUnit); if(ref) ref = lv2_atom_forge_int(forge, pos->beat_type); if(ref) ref = lv2_atom_forge_key(forge, prog->time_beatsPerBar); if(ref) ref = lv2_atom_forge_float(forge, pos->beats_per_bar); if(ref) ref = lv2_atom_forge_key(forge, prog->time_beatsPerMinute); if(ref) ref = lv2_atom_forge_float(forge, pos->beats_per_minute); } } if(ref) lv2_atom_forge_pop(forge, &frame); return ref; }
void AtomWriter::disconnect_all(const Raul::Path& graph, const Raul::Path& path) { LV2_Atom_Forge_Frame msg; forge_request(&msg, _uris.patch_Delete); lv2_atom_forge_key(&_forge, _uris.patch_subject); forge_uri(Node::path_to_uri(graph)); lv2_atom_forge_key(&_forge, _uris.patch_body); LV2_Atom_Forge_Frame arc; lv2_atom_forge_object(&_forge, &arc, 0, _uris.ingen_Arc); lv2_atom_forge_key(&_forge, _uris.ingen_incidentTo); forge_uri(Node::path_to_uri(path)); lv2_atom_forge_pop(&_forge, &arc); lv2_atom_forge_pop(&_forge, &msg); finish_msg(); }
void AtomWriter::disconnect(const Raul::Path& tail, const Raul::Path& head) { LV2_Atom_Forge_Frame msg; forge_request(&msg, _uris.patch_Delete); lv2_atom_forge_key(&_forge, _uris.patch_body); forge_arc(tail, head); lv2_atom_forge_pop(&_forge, &msg); finish_msg(); }
/** 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); }
void AtomWriter::forge_arc(const Raul::Path& tail, const Raul::Path& head) { LV2_Atom_Forge_Frame arc; lv2_atom_forge_object(&_forge, &arc, 0, _uris.ingen_Arc); lv2_atom_forge_key(&_forge, _uris.ingen_tail); forge_uri(Node::path_to_uri(tail)); lv2_atom_forge_key(&_forge, _uris.ingen_head); forge_uri(Node::path_to_uri(head)); lv2_atom_forge_pop(&_forge, &arc); }
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(); } }
void AtomWriter::connect(const Raul::Path& tail, const Raul::Path& head) { LV2_Atom_Forge_Frame msg; forge_request(&msg, _uris.patch_Put); lv2_atom_forge_key(&_forge, _uris.patch_subject); forge_uri(Node::path_to_uri(Raul::Path::lca(tail, head))); lv2_atom_forge_key(&_forge, _uris.patch_body); forge_arc(tail, head); lv2_atom_forge_pop(&_forge, &msg); finish_msg(); }
void AtomWriter::move(const Raul::Path& old_path, const Raul::Path& new_path) { LV2_Atom_Forge_Frame msg; forge_request(&msg, _uris.patch_Move); lv2_atom_forge_key(&_forge, _uris.patch_subject); forge_uri(Node::path_to_uri(old_path)); lv2_atom_forge_key(&_forge, _uris.patch_destination); forge_uri(Node::path_to_uri(new_path)); lv2_atom_forge_pop(&_forge, &msg); finish_msg(); }
/** generate a file path message, * send current state to GUI */ static void inform_ui (MidiMap* self) { if (!self->cfg_file_path) { return; } const MidiMapURIs* uris = &self->uris; lv2_atom_forge_frame_time (&self->forge, 0); LV2_Atom_Forge_Frame frame; lv2_atom_forge_object (&self->forge, &frame, 1, uris->patch_Set); lv2_atom_forge_property_head (&self->forge, uris->patch_property, 0); lv2_atom_forge_urid (&self->forge, uris->mem_cfgfile); lv2_atom_forge_property_head (&self->forge, uris->patch_value, 0); lv2_atom_forge_path (&self->forge, self->cfg_file_path, strlen (self->cfg_file_path)); lv2_atom_forge_pop (&self->forge, &frame); }
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); }
void AtomWriter::set_property(const Raul::URI& subject, const Raul::URI& predicate, const Atom& value) { LV2_Atom_Forge_Frame msg; forge_request(&msg, _uris.patch_Set); lv2_atom_forge_key(&_forge, _uris.patch_subject); forge_uri(subject); lv2_atom_forge_key(&_forge, _uris.patch_property); lv2_atom_forge_urid(&_forge, _map.map_uri(predicate.c_str())); lv2_atom_forge_key(&_forge, _uris.patch_value); lv2_atom_forge_atom(&_forge, value.size(), value.type()); lv2_atom_forge_write(&_forge, value.get_body(), value.size()); lv2_atom_forge_pop(&_forge, &msg); finish_msg(); }
/** 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); }
void AtomWriter::response(int32_t id, Status status, const std::string& subject) { if (!id) { return; } LV2_Atom_Forge_Frame msg; forge_request(&msg, _uris.patch_Response); lv2_atom_forge_key(&_forge, _uris.patch_request); lv2_atom_forge_int(&_forge, id); if (!subject.empty() && Raul::URI::is_valid(subject)) { lv2_atom_forge_key(&_forge, _uris.patch_subject); lv2_atom_forge_uri(&_forge, subject.c_str(), subject.length()); } lv2_atom_forge_key(&_forge, _uris.patch_body); lv2_atom_forge_int(&_forge, static_cast<int>(status)); lv2_atom_forge_pop(&_forge, &msg); finish_msg(); }
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); } }
// 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; }
/** Pop a forge frame @param frame The frame to pop */ inline void pop_frame (ForgeFrame& frame) { lv2_atom_forge_pop (this, &frame); }
/** ==== 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, &, 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); }
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 }
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++; } } }