static GstFlowReturn gst_lv2_filter_transform_data (GstLV2Filter * self, GstMapInfo * in_map, GstMapInfo * out_map) { GstAudioFilterClass *audiofilter_class; GstLV2FilterClass *lv2_class; GstLV2FilterGroup *lv2_group; GstLV2FilterPort *lv2_port; guint j, nframes, samples, out_samples; gfloat *in = NULL, *out = NULL; nframes = in_map->size / sizeof (float); audiofilter_class = GST_AUDIO_FILTER_GET_CLASS (self); lv2_class = (GstLV2FilterClass *) audiofilter_class; samples = nframes / lv2_class->in_group.ports->len; /* multi channel inputs */ lv2_group = &lv2_class->in_group; in = g_new0 (gfloat, nframes); if (lv2_group->ports->len > 1) gst_lv2_filter_deinterleave_data (lv2_group->ports->len, in, samples, (gfloat *) in_map->data); for (j = 0; j < lv2_group->ports->len; ++j) { lv2_port = &g_array_index (lv2_group->ports, GstLV2FilterPort, j); lilv_instance_connect_port (self->instance, lv2_port->index, in + (j * samples)); } lv2_group = &lv2_class->out_group; out_samples = nframes / lv2_group->ports->len; out = g_new0 (gfloat, samples * lv2_group->ports->len); for (j = 0; j < lv2_group->ports->len; ++j) { lv2_port = &g_array_index (lv2_group->ports, GstLV2FilterPort, j); lilv_instance_connect_port (self->instance, lv2_port->index, out + (j * out_samples)); } lilv_instance_run (self->instance, samples); if (lv2_group->ports->len > 1) gst_lv2_filter_interleave_data (lv2_group->ports->len, (gfloat *) out_map->data, out_samples, out); g_free (out); g_free (in); return GST_FLOW_OK; }
void LV2Module::run (uint32 nframes) { if (worker) worker->processWorkResponses(); lilv_instance_run (instance, nframes); if (worker) worker->endRun(); }
void EFFECT_LV2::process(void) { for(unsigned long m = 0; m < plugins_rep.size(); m++) lilv_instance_run(plugins_rep[m]->me, buffer_repp->length_in_samples()); }
bool LV2Effect::ProcessStereo(int count, WaveTrack *left, WaveTrack *right, sampleCount lstart, sampleCount rstart, sampleCount len) { /* Allocate buffers */ if (mBlockSize == 0) { mBlockSize = left->GetMaxBlockSize() * 2; fInBuffer = new float *[mAudioInputs.GetCount()]; for (size_t i = 0; i < mAudioInputs.GetCount(); i++) { fInBuffer[i] = new float[mBlockSize]; } fOutBuffer = new float *[mAudioOutputs.GetCount()]; for (size_t i = 0; i < mAudioOutputs.GetCount(); i++) { fOutBuffer[i] = new float[mBlockSize]; } } /* Instantiate the plugin */ LilvInstance *handle = lilv_plugin_instantiate(mData, left->GetRate(), gLV2Features); if (!handle) { wxMessageBox(wxString::Format(_("Unable to load plug-in %s"), pluginName.c_str())); return false; } /* Write the Note On to the MIDI event buffer and connect it */ LV2_Event_Buffer *midiBuffer = NULL; int noteOffTime; if (mMidiInput) { midiBuffer = lv2_event_buffer_new(40, 2); LV2_Event_Iterator iter; lv2_event_begin(&iter, midiBuffer); uint8_t noteOn[] = { 0x90, mNoteKey, mNoteVelocity }; lv2_event_write(&iter, 0, 0, 1, 3, noteOn); noteOffTime = mNoteLength * left->GetRate(); if (noteOffTime < len && noteOffTime < mBlockSize) { uint8_t noteOff[] = { 0x80, mNoteKey, 64 }; lv2_event_write(&iter, noteOffTime, 0, 1, 3, noteOff); } lilv_instance_connect_port(handle, mMidiInput->mIndex, midiBuffer); } for (size_t p = 0; p < mAudioInputs.GetCount(); p++) { lilv_instance_connect_port(handle, mAudioInputs[p].mIndex, fInBuffer[p]); } for (size_t p = 0; p < mAudioOutputs.GetCount(); p++) { lilv_instance_connect_port(handle, mAudioOutputs[p].mIndex, fOutBuffer[p]); } for (size_t p = 0; p < mControlInputs.GetCount(); p++) { lilv_instance_connect_port(handle, mControlInputs[p].mIndex, &mControlInputs[p].mControlBuffer); } for (size_t p = 0; p < mControlOutputs.GetCount(); p++) { lilv_instance_connect_port(handle, mControlOutputs[p].mIndex, &mControlOutputs[p].mControlBuffer); } float latency = 0.0; if (mLatencyPortIndex >= 0) { lilv_instance_connect_port(handle, mLatencyPortIndex, &latency); } lilv_instance_activate(handle); // Actually perform the effect here sampleCount originalLen = len; sampleCount ls = lstart; sampleCount rs = rstart; sampleCount ols = ls; sampleCount ors = rs; bool noteOver = false; sampleCount delayed = 0; sampleCount delay = 0; bool cleared = false; while (len || delayed) { int block = mBlockSize; if (len) { if (block > len) { block = len; } if (left && mAudioInputs.GetCount() > 0) { left->Get((samplePtr)fInBuffer[0], floatSample, ls, block); } if (right && mAudioInputs.GetCount() > 1) { right->Get((samplePtr)fInBuffer[1], floatSample, rs, block); } } else if (delayed) { // At the end if we don't have enough left for a whole block if (block > delayed) { block = delayed; } // Clear the input buffer so that we only pass zeros to the effect. if (!cleared) { for (int i = 0; i < mBlockSize; i++) { fInBuffer[0][i] = 0.0; } if (right) { memcpy(fInBuffer[1], fOutBuffer[0], mBlockSize); } cleared = true; } } lilv_instance_run(handle, block); if (delayed == 0 && latency != 0) { delayed = delay = latency; } if (delay >= block) { delay -= block; } else if (delay > 0) { sampleCount oblock = block - delay; if (left && mAudioOutputs.GetCount() > 0) { left->Set((samplePtr)(fOutBuffer[0] + delay), floatSample, ols, oblock); } if (right && mAudioOutputs.GetCount() > 1) { right->Set((samplePtr)(fOutBuffer[1] + delay), floatSample, ors, oblock); } ols += oblock; ors += oblock; delay = 0; } else { if (left && mAudioOutputs.GetCount() > 0) { left->Set((samplePtr)fOutBuffer[0], floatSample, ols, block); } if (right && mAudioOutputs.GetCount() > 1) { right->Set((samplePtr)fOutBuffer[1], floatSample, ors, block); } ols += block; ors += block; } if (len) { len -= block; noteOffTime -= block; // Clear the event buffer and add the note off event if needed if (mMidiInput) { lv2_event_buffer_reset(midiBuffer, 1, (uint8_t *)midiBuffer + sizeof(LV2_Event_Buffer)); if (!noteOver && noteOffTime < len && noteOffTime < block) { LV2_Event_Iterator iter; lv2_event_begin(&iter, midiBuffer); uint8_t noteOff[] = { 0x80, mNoteKey, 64 }; lv2_event_write(&iter, noteOffTime, 0, 1, 3, noteOff); noteOver = true; } } } else if (delayed) { delayed -= block; } ls += block; rs += block; if (mAudioInputs.GetCount() > 1) { if (TrackGroupProgress(count, (ls-lstart)/(double)originalLen)) { return false; } } else { if (TrackProgress(count, (ls-lstart)/(double)originalLen)) { return false; } } } lilv_instance_deactivate(handle); lilv_instance_free(handle); return true; }
static GstFlowReturn gst_lv2_source_fill (GstBaseSrc * base, guint64 offset, guint length, GstBuffer * buffer) { GstLV2Source *lv2 = (GstLV2Source *) base; GstLV2SourceClass *klass = (GstLV2SourceClass *) GST_BASE_SRC_GET_CLASS (lv2); GstLV2Class *lv2_class = &klass->lv2; GstLV2Group *lv2_group; GstLV2Port *lv2_port; GstClockTime next_time; gint64 next_sample, next_byte; guint bytes, samples; GstElementClass *eclass; GstMapInfo map; gint samplerate, bpf; guint j, k, l; gfloat *out = NULL, *cv = NULL, *mem; gfloat val; /* example for tagging generated data */ if (!lv2->tags_pushed) { GstTagList *taglist; taglist = gst_tag_list_new (GST_TAG_DESCRIPTION, "lv2 wave", NULL); eclass = GST_ELEMENT_CLASS (parent_class); if (eclass->send_event) eclass->send_event (GST_ELEMENT (base), gst_event_new_tag (taglist)); else gst_tag_list_unref (taglist); lv2->tags_pushed = TRUE; } if (lv2->eos_reached) { GST_INFO_OBJECT (lv2, "eos"); return GST_FLOW_EOS; } samplerate = GST_AUDIO_INFO_RATE (&lv2->info); bpf = GST_AUDIO_INFO_BPF (&lv2->info); /* if no length was given, use our default length in samples otherwise convert * the length in bytes to samples. */ if (length == -1) samples = lv2->samples_per_buffer; else samples = length / bpf; /* if no offset was given, use our next logical byte */ if (offset == -1) offset = lv2->next_byte; /* now see if we are at the byteoffset we think we are */ if (offset != lv2->next_byte) { GST_DEBUG_OBJECT (lv2, "seek to new offset %" G_GUINT64_FORMAT, offset); /* we have a discont in the expected sample offset, do a 'seek' */ lv2->next_sample = offset / bpf; lv2->next_time = gst_util_uint64_scale_int (lv2->next_sample, GST_SECOND, samplerate); lv2->next_byte = offset; } /* check for eos */ if (lv2->check_seek_stop && (lv2->sample_stop > lv2->next_sample) && (lv2->sample_stop < lv2->next_sample + samples) ) { /* calculate only partial buffer */ lv2->generate_samples_per_buffer = lv2->sample_stop - lv2->next_sample; next_sample = lv2->sample_stop; lv2->eos_reached = TRUE; GST_INFO_OBJECT (lv2, "eos reached"); } else { /* calculate full buffer */ lv2->generate_samples_per_buffer = samples; next_sample = lv2->next_sample + (lv2->reverse ? (-samples) : samples); } bytes = lv2->generate_samples_per_buffer * bpf; next_byte = lv2->next_byte + (lv2->reverse ? (-bytes) : bytes); next_time = gst_util_uint64_scale_int (next_sample, GST_SECOND, samplerate); GST_LOG_OBJECT (lv2, "samplerate %d", samplerate); GST_LOG_OBJECT (lv2, "next_sample %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT, next_sample, GST_TIME_ARGS (next_time)); gst_buffer_set_size (buffer, bytes); GST_BUFFER_OFFSET (buffer) = lv2->next_sample; GST_BUFFER_OFFSET_END (buffer) = next_sample; if (!lv2->reverse) { GST_BUFFER_TIMESTAMP (buffer) = lv2->timestamp_offset + lv2->next_time; GST_BUFFER_DURATION (buffer) = next_time - lv2->next_time; } else { GST_BUFFER_TIMESTAMP (buffer) = lv2->timestamp_offset + next_time; GST_BUFFER_DURATION (buffer) = lv2->next_time - next_time; } gst_object_sync_values (GST_OBJECT (lv2), GST_BUFFER_TIMESTAMP (buffer)); lv2->next_time = next_time; lv2->next_sample = next_sample; lv2->next_byte = next_byte; GST_LOG_OBJECT (lv2, "generating %u samples at ts %" GST_TIME_FORMAT, samples, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); gst_buffer_map (buffer, &map, GST_MAP_WRITE); /* multi channel outputs */ lv2_group = &lv2_class->out_group; if (lv2_group->ports->len > 1) { out = g_new0 (gfloat, samples * lv2_group->ports->len); for (j = 0; j < lv2_group->ports->len; ++j) { lv2_port = &g_array_index (lv2_group->ports, GstLV2Port, j); lilv_instance_connect_port (lv2->lv2.instance, lv2_port->index, out + (j * samples)); GST_LOG_OBJECT (lv2, "connected port %d/%d", j, lv2_group->ports->len); } } else { lv2_port = &g_array_index (lv2_group->ports, GstLV2Port, 0); lilv_instance_connect_port (lv2->lv2.instance, lv2_port->index, (gfloat *) map.data); GST_LOG_OBJECT (lv2, "connected port 0"); } /* cv ports */ cv = g_new (gfloat, samples * lv2_class->num_cv_in); for (j = k = 0; j < lv2_class->control_in_ports->len; j++) { lv2_port = &g_array_index (lv2_class->control_in_ports, GstLV2Port, j); if (lv2_port->type != GST_LV2_PORT_CV) continue; mem = cv + (k * samples); val = lv2->lv2.ports.control.in[j]; /* FIXME: use gst_control_binding_get_value_array */ for (l = 0; l < samples; l++) mem[l] = val; lilv_instance_connect_port (lv2->lv2.instance, lv2_port->index, mem); k++; } lilv_instance_run (lv2->lv2.instance, samples); if (lv2_group->ports->len > 1) { gst_lv2_source_interleave_data (lv2_group->ports->len, (gfloat *) map.data, samples, out); g_free (out); } g_free (cv); gst_buffer_unmap (buffer, &map); return GST_FLOW_OK; }
void Lv2Plugin::doProcess(bool rolling, jack_position_t &pos, jack_nframes_t nframes, jack_nframes_t time) { // pull in new control mappings Lv2ControlMapping *freshMapping; while(newControlMappingsQueue.pop(freshMapping)) { freshMapping->getConnection()->addMapping(freshMapping); } // process MIDI inputs Lv2MidiInput *midiInput = midiInputList.getFirst(); while(midiInput) { midiInput->process(rolling, pos, nframes, time); midiInput = midiInputList.getNext(midiInput); } // process and connect audio inputs for(uint32_t i = 0; i < audioInputCount; i++) { AudioConnection *connection = audioInput[i].getConnection(); if(connection) { connection->getSource()->process(rolling, pos, nframes, time); lilv_instance_connect_port(instance, audioInputIndex[i], connection->getAudio()); } else { lilv_instance_connect_port(instance, audioInputIndex[i], AudioConnection::getDummyBuffer()); } } // update control port values from scheduled control events Lv2ControlEvent* evt = controlBuffer.getNextEvent(rolling, pos, nframes); while(evt) { evt->getPort()->value = evt->getValue(); ObjectCollector::scriptCollector().recycle(evt); evt = controlBuffer.getNextEvent(rolling, pos, nframes); } // process control connections Lv2ControlConnection *connection = this->controlConnections.getFirst(); while(connection) { connection->process(rolling, pos, nframes, time); connection = controlConnections.getNext(connection); } // clear event output buffers Lv2MidiOutput *midiOutput = midiOutputList.getFirst(); while(midiOutput) { midiOutput->clear(); midiOutput = midiOutputList.getNext(midiOutput); } // set up audio output buffers for(uint32_t i = 0; i < audioOutputCount; i++) { lilv_instance_connect_port(instance, audioOutputIndex[i], audioOutput[i]->getAudio()); } // run the plugin lilv_instance_run(instance, nframes); // fire MIDI events fireMidiEvents(pos); // emit worker responses if(worker) { worker->respond(); } }
static double bench(const LilvPlugin* p, uint32_t sample_count, uint32_t block_size) { URITable uri_table; uri_table_init(&uri_table); LV2_URID_Map map = { &uri_table, uri_table_map }; LV2_Feature map_feature = { LV2_URID_MAP_URI, &map }; LV2_URID_Unmap unmap = { &uri_table, uri_table_unmap }; LV2_Feature unmap_feature = { LV2_URID_UNMAP_URI, &unmap }; const LV2_Feature* features[] = { &map_feature, &unmap_feature, NULL }; float* const buf = (float*)calloc(block_size * 2, sizeof(float)); float* const in = buf; float* const out = buf + block_size; if (!buf) { fprintf(stderr, "Out of memory\n"); return 0.0; } LV2_Atom_Sequence seq = { { sizeof(LV2_Atom_Sequence_Body), uri_table_map(&uri_table, LV2_ATOM__Sequence) }, { 0, 0 } }; const char* uri = lilv_node_as_string(lilv_plugin_get_uri(p)); LilvNodes* required = lilv_plugin_get_required_features(p); LILV_FOREACH(nodes, i, required) { const LilvNode* feature = lilv_nodes_get(required, i); if (!lilv_node_equals(feature, urid_map)) { fprintf(stderr, "<%s> requires feature <%s>, skipping\n", uri, lilv_node_as_uri(feature)); free(buf); uri_table_destroy(&uri_table); return 0.0; } } LilvInstance* instance = lilv_plugin_instantiate(p, 48000.0, features); if (!instance) { fprintf(stderr, "Failed to instantiate <%s>\n", lilv_node_as_uri(lilv_plugin_get_uri(p))); free(buf); uri_table_destroy(&uri_table); return 0.0; } float* controls = (float*)calloc( lilv_plugin_get_num_ports(p), sizeof(float)); lilv_plugin_get_port_ranges_float(p, NULL, NULL, controls); const uint32_t n_ports = lilv_plugin_get_num_ports(p); for (uint32_t index = 0; index < n_ports; ++index) { const LilvPort* port = lilv_plugin_get_port_by_index(p, index); if (lilv_port_is_a(p, port, lv2_ControlPort)) { lilv_instance_connect_port(instance, index, &controls[index]); } else if (lilv_port_is_a(p, port, lv2_AudioPort) || lilv_port_is_a(p, port, lv2_CVPort)) { if (lilv_port_is_a(p, port, lv2_InputPort)) { lilv_instance_connect_port(instance, index, in); } else if (lilv_port_is_a(p, port, lv2_OutputPort)) { lilv_instance_connect_port(instance, index, out); } else { fprintf(stderr, "<%s> port %d neither input nor output, skipping\n", uri, index); lilv_instance_free(instance); free(buf); free(controls); uri_table_destroy(&uri_table); return 0.0; } } else if (lilv_port_is_a(p, port, atom_AtomPort)) { lilv_instance_connect_port(instance, index, &seq); } else { fprintf(stderr, "<%s> port %d has unknown type, skipping\n", uri, index); lilv_instance_free(instance); free(buf); free(controls); uri_table_destroy(&uri_table); return 0.0; } } lilv_instance_activate(instance); struct timespec ts = bench_start(); for (uint32_t i = 0; i < (sample_count / block_size); ++i) { lilv_instance_run(instance, block_size); } const double elapsed = bench_end(&ts); lilv_instance_deactivate(instance); lilv_instance_free(instance); uri_table_destroy(&uri_table); if (full_output) { printf("%d %d ", block_size, sample_count); } printf("%lf %s\n", elapsed, uri); free(buf); free(controls); return elapsed; }