6.0.0-rc4Source

QtFM::Patch Class

The Patch class holds one complete, self-describing sound. More…

Header#include <QtFM>
CMaketarget_link_libraries(app PRIVATE Nt::FM)
ModuleNt FM C++ Classes

List of all members, including inherited members

Public Functions

Patch()
Patch(const Patch &other)
Patch(Patch &&other)
Patch &operator=(const Patch &other)
Patch &operator=(Patch &&other)
~Patch()
QByteArraytoJson() const
QByteArraytoCbor() const
QByteArraytoChipInstrument(InstrumentFormat format, QString *error = nullptr) const
Patchmutated(float amount, quint32 seed) const
boolfitsChip(ChipType chip, QStringList *violations = nullptr) const
boolisValid() const
QStringname() const
QStringcategory() const
ChipTypechip() const
intoperatorCount() const
boolisLoop() const
floatduration() const
booloperator==(const Patch &other) const
booloperator!=(const Patch &other) const

Static Public Members

PatchfromJson(const QByteArray &json, QString *error = nullptr)
PatchfromCbor(const QByteArray &cbor, QString *error = nullptr)
PatchfromChipInstrument(const QByteArray &data, InstrumentFormat format, QString *error = nullptr)
Patchgenerate(Category category, quint32 seed, ChipType target = ChipType::None)

Detailed Description

A patch describes four operators and their routing, envelopes, pitch movement, an LFO, noise, a filter, a bit crusher and a block of random variance. It plays at any pitch and length, and is stored as JSON of a few hundred bytes:

const char *laserJson = R"({
  "format": "qtfm-patch", "version": 1, "name": "laser-small", "category": "laser",
  "algorithm": 5, "feedback": 3,
  "operators": [
    { "ratio": 1.0, "level": 1.0, "env": { "a": 0, "d": 0.12, "s": 0, "r": 0.05 } },
    { "ratio": 3.5, "level": 0.6, "env": { "a": 0, "d": 0.08, "s": 0, "r": 0.02 } },
    { "ratio": 1.0, "level": 0.8, "env": { "a": 0, "d": 0.15, "s": 0, "r": 0.05 } },
    { "ratio": 7.0, "level": 0.3, "env": { "a": 0, "d": 0.05, "s": 0, "r": 0.02 } }
  ],
  "pitch": { "base": "A5", "env": { "start": 12, "end": -24, "time": 0.18, "curve": -2 } },
  "filter": { "type": "lowpass", "cutoff": 8000, "resonance": 0.2 },
  "random": { "pitch.base": 2, "operators.1.ratio": 0.25 },
  "gain": -6
})";

Patch is a value type and implicitly shared. A default-constructed patch is invalid; make one with fromJson(), fromCbor(), fromChipInstrument() or generate(). Unknown JSON keys are ignored, missing keys take their defaults, and out-of-range values are clamped, so isValid() is false only for a document that is not a patch at all.

See also QtFM::Engine and Using Nt FM.

Differences from Qt

A patch cannot yet be edited field by field from C++: edit its JSON. Only the SBI instrument format is imported, and patches are not yet exported to chip formats.

Member Function Documentation

QtFM::Patch::Patch()

Constructs an invalid patch.

QtFM::Patch::Patch(const Patch &other)

Constructs a copy of other.

QtFM::Patch::Patch(Patch &&other)

Move-constructs a patch from other.

QtFM::Patch::~Patch()

Destroys the patch.

QString QtFM::Patch::category() const

Returns the category of the patch, such as laser, as written in its category field.

ChipType QtFM::Patch::chip() const

Returns the chip that the patch targets, or ChipType::None.

float QtFM::Patch::duration() const

Returns the length of a note in seconds before it is released, or -1 if the patch has no fixed length: it then runs through its envelopes once, or sustains if isLoop().

bool QtFM::Patch::fitsChip(ChipType chip, QStringList *violations = nullptr) const

Returns true if the patch can be played by chip as it is: its operator count, waveforms, multipliers, feedback and envelopes are within the chip's limits, and it uses no noise, filter, crusher or modulation-index envelope. The fields that are not are appended to violations. Every patch fits ChipType::None.

[static] Patch QtFM::Patch::fromCbor(const QByteArray &cbor, QString *error = nullptr)

Returns the patch in the CBOR encoding cbor, as toCbor() writes it, or an invalid patch, with the reason in error.

[static] Patch QtFM::Patch::fromChipInstrument(const QByteArray &data, InstrumentFormat format, QString *error = nullptr)

Returns the native patch of a chip instrument in data, stored in format, or an invalid patch, with the reason in error. The parameters map onto the native engine: an OPL2 instrument becomes a two-operator patch with the same multipliers, waveforms, feedback, connection and envelopes. The result sounds close to the chip, without its quantisation.

[static] Patch QtFM::Patch::fromJson(const QByteArray &json, QString *error = nullptr)

Returns the patch in the JSON document json, or an invalid patch, with the reason in error, if it is not a patch.

See also toJson().

[static] Patch QtFM::Patch::generate(Category category, quint32 seed, ChipType target = ChipType::None)

Returns a random but plausible patch of category, drawn from seed: the same seed always gives the same patch. If target is a chip, the patch keeps to that chip's limits (two operators and the OPL waveforms for ChipType::OPL2, no noise or filter), for authentic chip sounds.

const Patch blip = Patch::generate(Category::Blip, 8);

bool QtFM::Patch::isLoop() const

Returns true if the patch sustains until it is stopped.

bool QtFM::Patch::isValid() const

Returns true if the patch holds a sound.

Patch QtFM::Patch::mutated(float amount, quint32 seed) const

Returns a variation of the patch: its times, ratios, levels, pitch movement and cutoff are each scaled by a random factor of up to amount (0.1 for 10%), drawn from seed. A patch for a chip keeps its ratios on the chip's multipliers.

QString QtFM::Patch::name() const

Returns the name of the patch.

bool QtFM::Patch::operator!=(const Patch &other) const

Returns true if this patch and other differ.

Patch & QtFM::Patch::operator=(const Patch &other)

Assigns other to this patch and returns a reference to it.

Patch & QtFM::Patch::operator=(Patch &&other)

Move-assigns other to this patch and returns a reference to it.

bool QtFM::Patch::operator==(const Patch &other) const

Returns true if this patch and other hold the same sound.

int QtFM::Patch::operatorCount() const

Returns the number of operators of the patch: 2 or 4.

QByteArray QtFM::Patch::toCbor() const

Returns the patch encoded as CBOR, a smaller form for embedded targets.

See also fromCbor().

QByteArray QtFM::Patch::toChipInstrument(InstrumentFormat format, QString *error = nullptr) const

Returns the patch as a chip instrument in format, or an empty array, with the reason in error, if the patch cannot be expressed in it. Only InstrumentFormat::Sbi is a single instrument; it needs a patch of two operators, and maps it to the nearest OPL2 values.

See also fitsChip() and QtFM::PatchBank::toChipBank().

QByteArray QtFM::Patch::toJson() const

Returns the JSON document of the patch, with every field written, so that fromJson() gives back an equal patch. Returns an empty array for an invalid patch.