/** 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); }
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(); }