Pattern
A run of rows that a node plays: one value per parameter per row.
| Declared in | src/libs/libbahn/bahn/tracker/pattern/Pattern.hpp |
| Group | bahn |
Detailed description
A pattern belongs to one bahn::Node. Each row holds one value for each of the node's parameters, and one more set of values for each lane, in the order of the node's schema. The sequencer plays one row per tick.
A row can be null. A null row is an empty row, and it says nothing to the node. setRow() fills a gap with null rows, and insertRow() and removeRow() write null rows. newRow() makes a row in which every value is the parameter's "no value".
A pattern has a name and a unique ID. The ID is made when the pattern is made, and a copy gets a new one.
See also bahn::Node, Sequence.
Member function documentation
copy
QSharedPointer<Pattern> Pattern::copy(QString name) const
Copy this pattern, empty rows and all.
The copy gets the name name, or the name of this pattern when name is empty. It gets a new unique ID, the same node, the same length and the same lane count. Each row is copied, so an edit to the copy does not change this pattern.
A row can be null, and most of this file knows it
setRow grows mRows with resize, which fills the gap with default-constructed shared pointers. So typing a hit on row four of a fresh pattern leaves rows zero to three null. insertRow and removeRow write nulls deliberately, and the stream operator below has always tested nullptr != row before writing one.
This loop did not, and copying any pattern with an untouched row above it dereferenced null and took the program with it. Reported from the desk 2026-09-30, copying a Taiko pattern; the playback it happened during was incidental, and a sparse pattern is the normal case rather than an unusual one.
An empty row stays empty in the copy. Filling it in would change the pattern, and a copy that is not the same pattern is not a copy.