void SetPortValue::execute(ProcessContext& context) { Event::execute(context); assert(_time >= context.start() && _time <= context.end()); if (_port && _port->context() == Context::MESSAGE) return; apply(context); _engine.control_bindings()->port_value_changed(context, _port); }
MD5::MD5 (const String& text) { ProcessContext context; String::CharPointerType t (text.getCharPointer()); while (! t.isEmpty()) { // force the string into integer-sized unicode characters, to try to make it // get the same results on all platforms + compilers. uint32 unicodeChar = ByteOrder::swapIfBigEndian ((uint32) t.getAndAdvance()); context.processBlock (&unicodeChar, sizeof (unicodeChar)); } context.finish (result); }
bool PortImpl::apply_poly(ProcessContext& context, Raul::Maid& maid, uint32_t poly) { if (_parent->path().is_root() || (_type == PortType::ATOM && !_value.is_valid())) { return false; } if (!_prepared_voices) { return true; } assert(poly == _prepared_voices->size()); _poly = poly; // Apply a new set of voices from a preceding call to prepare_poly maid.dispose(set_voices(context, _prepared_voices)); assert(_voices == _prepared_voices); _prepared_voices = NULL; if (is_a(PortType::CONTROL) || is_a(PortType::CV)) { set_control_value(context, context.start(), _value.get<float>()); } assert(_voices->size() >= poly); assert(this->poly() == poly); assert(!_prepared_voices); return true; }
void JackDriver::post_process_port(ProcessContext& context, EnginePort* port) { const SampleCount nframes = context.nframes(); jack_port_t* jack_port = (jack_port_t*)port->handle(); PortImpl* graph_port = port->graph_port(); void* buffer = port->buffer(); if (graph_port->is_input()) { return; } if (!buffer) { // First cycle for a new output, so pre_process wasn't called buffer = jack_port_get_buffer(jack_port, nframes); port->set_buffer(buffer); } graph_port->post_process(context); Buffer* const graph_buf = graph_port->buffer(0).get(); if (graph_port->is_a(PortType::AUDIO)) { memcpy(buffer, graph_buf->samples(), nframes * sizeof(Sample)); } else if (graph_port->buffer_type() == graph_port->bufs().uris().atom_Sequence) { jack_midi_clear_buffer(buffer); LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)graph_buf->atom(); LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body); if (ev->body.type == graph_port->bufs().uris().midi_MidiEvent) { jack_midi_event_write(buffer, ev->time.frames, buf, ev->body.size); } } }
/** Run the patch for the specified number of frames. * * Calls all Nodes in (roughly, if parallel) the order _compiled_patch specifies. */ void PatchImpl::process(ProcessContext& context) { if (!_process) return; NodeImpl::pre_process(context); // Run all nodes if (_compiled_patch && _compiled_patch->size() > 0) { if (context.slaves().size() > 0) { process_parallel(context); } else { process_single(context); } } // Queue any cross-context connections for (CompiledPatch::QueuedConnections::iterator i = _compiled_patch->queued_connections.begin(); i != _compiled_patch->queued_connections.end(); ++i) { (*i)->queue(context); } NodeImpl::post_process(context); }
bool PatchImpl::apply_internal_poly(ProcessContext& context, BufferFactory& bufs, Raul::Maid& maid, uint32_t poly) { ThreadManager::assert_thread(THREAD_PROCESS); // TODO: Subpatch dynamic polyphony (i.e. changing port polyphony) for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) (*i)->apply_poly(maid, poly); for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) { for (uint32_t j = 0; j < (*i)->num_ports(); ++j) { PortImpl* const port = (*i)->port_impl(j); if (port->is_input() && dynamic_cast<InputPort*>(port)->direct_connect()) port->setup_buffers(bufs, port->poly()); port->connect_buffers(context.offset()); } } const bool polyphonic = parent_patch() && (poly == parent_patch()->internal_poly()); for (List<PortImpl*>::iterator i = _output_ports.begin(); i != _output_ports.end(); ++i) (*i)->setup_buffers(bufs, polyphonic ? poly : 1); _internal_poly = poly; return true; }
unsigned PreProcessor::process(ProcessContext& context, PostProcessor& dest, size_t limit) { Event* const head = _head.load(); if (!head) { return 0; } size_t n_processed = 0; Event* ev = head; Event* last = ev; while (ev && ev->is_prepared() && ev->time() < context.end()) { if (ev->time() < context.start()) { // Didn't get around to executing in time, oh well... ev->set_time(context.start()); } ev->execute(context); last = ev; ev = ev->next(); ++n_processed; if (limit && n_processed >= limit) { break; } } if (n_processed > 0) { Event* next = (Event*)last->next(); last->next(NULL); dest.append(context, head, last); // Since _head was not NULL, we know it hasn't been changed since _head = next; /* If next is NULL, then _tail may now be invalid. However, it would cause a race to reset _tail here. Instead, append() checks only _head for emptiness, and resets the tail appropriately. */ } return n_processed; }
void MD5::processStream (InputStream& input, int64 numBytesToRead) { ProcessContext context; if (numBytesToRead < 0) numBytesToRead = std::numeric_limits<int64>::max(); while (numBytesToRead > 0) { uint8 tempBuffer [512]; const int bytesRead = input.read (tempBuffer, (int) jmin (numBytesToRead, (int64) sizeof (tempBuffer))); if (bytesRead <= 0) break; numBytesToRead -= bytesRead; context.processBlock (tempBuffer, bytesRead); } context.finish (result); }
void TimeNode::run(ProcessContext& context) { BufferRef buf = _notify_port->buffer(0); LV2_Atom_Sequence* seq = buf->get<LV2_Atom_Sequence>(); // Initialise output to the empty sequence seq->atom.type = _notify_port->bufs().uris().atom_Sequence; seq->atom.size = sizeof(LV2_Atom_Sequence_Body); seq->body.unit = 0; seq->body.pad = 0; // Ask the driver to append any time events for this cycle context.engine().driver()->append_time_events( context, *_notify_port->buffer(0)); }
void JackDriver::pre_process_port(ProcessContext& context, EnginePort* port) { const SampleCount nframes = context.nframes(); jack_port_t* jack_port = (jack_port_t*)port->handle(); PortImpl* graph_port = port->graph_port(); void* buffer = jack_port_get_buffer(jack_port, nframes); port->set_buffer(buffer); if (!graph_port->is_input()) { graph_port->buffer(0)->clear(); return; } if (graph_port->is_a(PortType::AUDIO)) { Buffer* graph_buf = graph_port->buffer(0).get(); memcpy(graph_buf->samples(), buffer, nframes * sizeof(float)); } else if (graph_port->buffer_type() == graph_port->bufs().uris().atom_Sequence) { Buffer* graph_buf = (Buffer*)graph_port->buffer(0).get(); const jack_nframes_t event_count = jack_midi_get_event_count(buffer); graph_buf->prepare_write(context); // Copy events from Jack port buffer into graph port buffer for (jack_nframes_t i = 0; i < event_count; ++i) { jack_midi_event_t ev; jack_midi_event_get(&ev, buffer, i); if (!graph_buf->append_event( ev.time, ev.size, _midi_event_type, ev.buffer)) { _engine.log().warn("Failed to write to MIDI buffer, events lost!\n"); } } } }
void DelayNode::run(ProcessContext& context) { Buffer* const delay_buf = _delay_port->buffer(0).get(); Buffer* const in_buf = _in_port->buffer(0).get(); Buffer* const out_buf = _out_port->buffer(0).get(); DelayNode* plugin_data = this; const float* const in = in_buf->samples(); float* const out = out_buf->samples(); const float delay_time = delay_buf->samples()[0]; const uint32_t buffer_mask = plugin_data->_buffer_mask; const SampleRate sample_rate = context.engine().driver()->sample_rate(); float delay_samples = plugin_data->_delay_samples; int64_t write_phase = plugin_data->_write_phase; const uint32_t sample_count = context.nframes(); if (write_phase == 0) { _last_delay_time = delay_time; _delay_samples = delay_samples = CALC_DELAY(delay_time); } if (delay_time == _last_delay_time) { const int64_t idelay_samples = (int64_t)delay_samples; const float frac = delay_samples - idelay_samples; for (uint32_t i = 0; i < sample_count; i++) { int64_t read_phase = write_phase - (int64_t)delay_samples; const float read = cube_interp(frac, buffer_at(read_phase - 1), buffer_at(read_phase), buffer_at(read_phase + 1), buffer_at(read_phase + 2)); buffer_at(write_phase++) = in[i]; out[i] = read; } } else { const float next_delay_samples = CALC_DELAY(delay_time); const float delay_samples_slope = (next_delay_samples - delay_samples) / sample_count; for (uint32_t i = 0; i < sample_count; i++) { delay_samples += delay_samples_slope; write_phase++; const int64_t read_phase = write_phase - (int64_t)delay_samples; const int64_t idelay_samples = (int64_t)delay_samples; const float frac = delay_samples - idelay_samples; const float read = cube_interp(frac, buffer_at(read_phase - 1), buffer_at(read_phase), buffer_at(read_phase + 1), buffer_at(read_phase + 2)); buffer_at(write_phase) = in[i]; out[i] = read; } _last_delay_time = delay_time; _delay_samples = delay_samples; } _write_phase = write_phase; }
MD5::MD5 (const void* data, const size_t numBytes) { ProcessContext context; context.processBlock (data, numBytes); context.finish (result); }
//============================================================================== MD5::MD5 (const MemoryBlock& data) { ProcessContext context; context.processBlock (data.getData(), data.getSize()); context.finish (result); }
void DelayNode::process(ProcessContext& context) { AudioBuffer* const delay_buf = (AudioBuffer*)_delay_port->buffer(0).get(); AudioBuffer* const in_buf = (AudioBuffer*)_in_port->buffer(0).get(); AudioBuffer* const out_buf = (AudioBuffer*)_out_port->buffer(0).get(); NodeImpl::pre_process(context); DelayNode* plugin_data = this; const float* const in = in_buf->data(); float* const out = out_buf->data(); const float delay_time = delay_buf->data()[0]; const uint32_t buffer_mask = plugin_data->_buffer_mask; const unsigned int sample_rate = plugin_data->_srate; float delay_samples = plugin_data->_delay_samples; long write_phase = plugin_data->_write_phase; const uint32_t sample_count = context.nframes(); if (write_phase == 0) { _last_delay_time = delay_time; _delay_samples = delay_samples = CALC_DELAY(delay_time); } if (delay_time == _last_delay_time) { const long idelay_samples = (long)delay_samples; const float frac = delay_samples - idelay_samples; for (uint32_t i = 0; i < sample_count; i++) { long read_phase = write_phase - (long)delay_samples; const float read = cube_interp(frac, buffer_at(read_phase - 1), buffer_at(read_phase), buffer_at(read_phase + 1), buffer_at(read_phase + 2)); buffer_at(write_phase++) = in[i]; out[i] = read; } } else { const float next_delay_samples = CALC_DELAY(delay_time); const float delay_samples_slope = (next_delay_samples - delay_samples) / sample_count; for (uint32_t i = 0; i < sample_count; i++) { delay_samples += delay_samples_slope; write_phase++; const long read_phase = write_phase - (long)delay_samples; const long idelay_samples = (long)delay_samples; const float frac = delay_samples - idelay_samples; const float read = cube_interp(frac, buffer_at(read_phase - 1), buffer_at(read_phase), buffer_at(read_phase + 1), buffer_at(read_phase + 2)); buffer_at(write_phase) = in[i]; out[i] = read; } _last_delay_time = delay_time; _delay_samples = delay_samples; } _write_phase = write_phase; NodeImpl::post_process(context); }
/** Signal the end of a cycle that has produced messages. * AUDIO THREAD ONLY. */ inline void signal(ProcessContext& context) { ThreadManager::assert_thread(THREAD_PROCESS); const Request cycle_end_request(context.end(), NULL); _requests.write(sizeof(Request), &cycle_end_request); _sem.post(); }
void PatchImpl::process_parallel(ProcessContext& context) { size_t n_slaves = context.slaves().size(); CompiledPatch* const cp = _compiled_patch; /* Start p-1 slaves */ if (n_slaves >= cp->size()) n_slaves = cp->size()-1; if (n_slaves > 0) { for (size_t i = 0; i < cp->size(); ++i) (*cp)[i].node()->reset_input_ready(); for (size_t i = 0; i < n_slaves; ++i) context.slaves()[i]->whip(cp, i+1, context); } /* Process ourself until everything is done * This is analogous to ProcessSlave::_whipped(), but this is the master * (i.e. what the main Jack process thread calls). Where ProcessSlave * waits on input, this just skips the node and tries the next, to avoid * waiting in the Jack thread which pisses Jack off. */ size_t index = 0; size_t num_finished = 0; // Number of consecutive finished nodes hit while (num_finished < cp->size()) { CompiledNode& n = (*cp)[index]; if (n.node()->process_lock()) { if (n.node()->n_inputs_ready() == n.n_providers()) { n.node()->process(context); /* Signal dependants their input is ready */ for (uint32_t i = 0; i < n.dependants().size(); ++i) n.dependants()[i]->signal_input_ready(); ++num_finished; } else { n.node()->process_unlock(); num_finished = 0; } } else { if (n.node()->n_inputs_ready() == n.n_providers()) ++num_finished; else num_finished = 0; } index = (index + 1) % cp->size(); } /* Tell slaves we're done in case we beat them, and pray they're * really done by the start of next cycle. * FIXME: This probably breaks (race) at extremely small nframes where * ingen is the majority of the DSP load. */ for (uint32_t i = 0; i < n_slaves; ++i) context.slaves()[i]->finish(); }