QuantizationProfile

class maelzel.scoring.quant.QuantizationProfile(nestedTuplets=False, gridErrorWeight=1, gridErrorExp=0.85, divisionErrorWeight=0.002, maxDivPenalty=0.1, maxGridDensity=0, rhythmComplexityWeight=0.001, offsetErrorWeight=1.0, restOffsetErrorWeight=0.5, durationErrorWeight=0.2, graceDuration=Fraction(1, 32), graceErrorWeight=0, divisionDefs=<factory>, divisionPenaltyMap=<factory>, divisionCardinalityPenaltyMap=<factory>, numNestedTupletsPenalty=(0.0, 0.1, 0.4, 0.5, 0.8, 0.8), complexNestedTupletsFactor=1.8, numSubdivsPenaltyMap=<factory>, divisionPenaltyWeight=1.0, cardinalityPenaltyWeight=0.1, numNestedTupletsPenaltyWeight=1.0, numSubdivisionsPenaltyWeight=0.2, outerTupletMatchFactor=0.01, syncopPartMinFraction=Fraction(1, 8), syncopMinFraction=Fraction(1, 3), syncopMaxAsymmetry=4.0, syncopExcludeSymDurs=(5, 7, 15), mergedTupletsMaxDuration=Fraction(2, 1), mergeTupletsDifferentDur=False, allowNestedTupletsAcrossBeat=False, allowedTupletsAcrossBeat=(1, 2, 3, 4, 5, 8), allowedNestedTupletsAcrossBeat=((3, 3), (3, 5), (5, 3)), breakLongGlissandi=True, maxPenalty=1.0, debug=False, debugMaxDivisions=20, blacklist=(), name='', breakSyncopationsLevel='strong', tiedSnappedGracenoteMinRealDuration=Fraction(1, 1000), beatWeightTempoThresh=52, subdivTempoThresh=96, _cachedDivisionsByTempo=<factory>, _cachedDivisionPenalty=<factory>)[source]

Bases: object

A QuantizationProfile is used to configure quantization

To construct a QuantiztationProfile based on a preset, use QuantizationProfile.fromPreset()

Most important parameters:

  • nestedTuplets: if True, allow nested tuplets. NB: musicxml rendered via MuseScore does not support nested tuplets

  • gridErrorWeight: a weight to control the overall effect of offset and duration errors when fitting events to a grid. A higher weight will cause quantization to minimize offset and duration errors, at the cost of choosing more complex divisions

  • divisionErrorWeight: also a weight to controll all effect dealing with the complexity of a given division/subdivision

Lower level parameters to calculate grid error:

  • offsetErrorWeight: the importance of offset errors to calculate the best subdivision of a beat

  • restOffsetErrorWeight: how relevant should be the offset error in the case of rests

  • durationErrorWeight: relevance of duration error when selecting the best subdivision

  • graceDuration: if a note is considered a grace note (which have no duration per se), should we still account for this duration?

  • syncopMinFraction: when merging durations across beats, a merged duration can’t be smaller than this duration. This is to prevent joining durations across beats which might result in high rhythmic complexity

  • tupletsAllowedAcrossBeats: list of tuplets allowed across a beat

  • tupletMaxDur: the max quarternote duration for a merged subdivision

Lower level parameters to calculate division complexity:

  • numNestedTupletsPenaltyWeight: how

Attributes Summary

allowNestedTupletsAcrossBeat

Allow merging nested tuplets across the beat

allowedNestedTupletsAcrossBeat

Which nested tuplets are allowed to cross the beat?

allowedTupletsAcrossBeat

Which tuplets are allowed to cross the beat

beatWeightTempoThresh

blacklist

A set of divisions which should never be considered

breakLongGlissandi

When a glissando extends over a quarternote, break it into quarter notes

breakSyncopationsLevel

break at all beats, 'strong': only strong beats, 'weak': ??)

cardinalityPenaltyWeight

Weight of cardinality

complexNestedTupletsFactor

For certain combinations of nested tuplets an extra complexity factor can be applied.

debug

Turns on debugging

debugMaxDivisions

Max number of quantization possibilities to display when debugging

divisionErrorWeight

Weight of the division complexity

divisionPenaltyWeight

Weight of division penalty

durationErrorWeight

Weight of the difference in duration resulting from quantization

graceDuration

A duration to assume for grace notes

graceErrorWeight

gridErrorExp

An exponent applied to the grid error.

gridErrorWeight

Weight of the overall effect of offset and duration errors when fitting events to a grid.

maxDivPenalty

A max.

maxGridDensity

If given (higher than 0) it discards any division of the beat with a higher number of slots than this value.

maxPenalty

A max.

mergeTupletsDifferentDur

Allow merging tuplets which have different total durations?

mergedTupletsMaxDuration

How long can a tuplet over the beat be

name

A name for this profile, if needed

nestedTuplets

Are nested tuplets allowed?

numNestedTupletsPenalty

Penalty applied to nested levels by level

numNestedTupletsPenaltyWeight

Weight of sublevel penalty

numSubdivisionsPenaltyWeight

Weight to penalize the number of subdivisions

offsetErrorWeight

Weight of the offset between original start and makeSnappedNotation start

outerTupletMatchFactor

A factor applied to the division penalty when a div matches the outer tuplet of an adjacent beat

restOffsetErrorWeight

Similar to offsetErrorWeight but for rests

rhythmComplexityIrregularDurationsWeight

When calculating rhythm complexity this weight is applied to the penalty of notes whose duration is irregular (durations of 5 or 9 units, which need ties to be represented)

rhythmComplexityNotesAcrossSubdivisionWeight

When calculating rhythm complexity this weight is applied to the penalty of notes extending over subdivisions of the beat (inner-beat syncopes)

rhythmComplexityWeight

Weight of the actual quantized rhythm.

subdivTempoThresh

syncopExcludeSymDurs

Symbolic numerators excluded from being syncopated (3=dotted, 7=double dotted, etc.)

syncopMaxAsymmetry

The max.

syncopMinFraction

Min.

syncopPartMinFraction

How long can any part of a synchopation be, in terms of the length of the beat

tiedSnappedGracenoteMinRealDuration

The min.

Methods Summary

breakSyncopationsMinWeight([level])

Returns the min.

copy()

default()

divisionPenalty(division)

A penalty based on the complexity of the division of the pulse alone

divisionsByTempo()

fromPreset([complexity, nestedTuplets, ...])

Create a QuantizationProfile from a preset

keys()

modified()

This method needs to be called after self is modified in order to clear caches

possibleBeatDivisionsForTempo(tempo)

The possible divisions of the pulse for the given tempo

Attributes Documentation

allowNestedTupletsAcrossBeat: bool = False

Allow merging nested tuplets across the beat

allowedNestedTupletsAcrossBeat: tuple[tuple[int, int], ...] = ((3, 3), (3, 5), (5, 3))

Which nested tuplets are allowed to cross the beat?

Nested tuplets are those which are non-binary at more than one level, like a triplet with a quintuplet inside. For example a value of (3, 3) indicates that a big triplet with a triplet inside which both go across the beat (for example the rhythm 2/3, 2/9, 2/9, 2/9, 2/3) would be allowed

allowedTupletsAcrossBeat: tuple[int, ...] = (1, 2, 3, 4, 5, 8)

Which tuplets are allowed to cross the beat

beatWeightTempoThresh: int = 52
blacklist: tuple[tuple[int, ...], ...] = ()

A set of divisions which should never be considered

breakLongGlissandi: bool = True

When a glissando extends over a quarternote, break it into quarter notes

If the noteheads are hidden, a glissando over a half-note cannot be differentiated from a glissando over a quarternote. If this option is True, such a long glissando is broken into quarternotes in order to prevent this misinterpretation

breakSyncopationsLevel: str = 'strong'

break at all beats, ‘strong’: only strong beats, ‘weak’: ??)

Type:

Break syncopations at beat boundaries (‘none’

Type:

do not break syncopations, ‘all’

cardinalityPenaltyWeight: float = 0.1

Weight of cardinality

complexNestedTupletsFactor: float = 1.8

For certain combinations of nested tuplets an extra complexity factor can be applied. If this factor is 1.0, then no extra penalty is calculated. Any number above 1 will penalize complex nested tuplets (prefer (5, 5, 5) over (3, 3, 3, 3, 3)).

debug: bool = False

Turns on debugging

debugMaxDivisions: int = 20

Max number of quantization possibilities to display when debugging

divisionErrorWeight: float = 0.002

Weight of the division complexity

divisionPenaltyWeight: float = 1.0

Weight of division penalty

durationErrorWeight: float = 0.2

Weight of the difference in duration resulting from quantization

graceDuration: Fraction = Fraction(1, 32)

A duration to assume for grace notes

graceErrorWeight: float = 0
gridErrorExp: float = 0.85

An exponent applied to the grid error. Since this values is always between 0 and 1, an exponent less than 1 makes the effects of grid errors grow faster

gridErrorWeight: float = 1

Weight of the overall effect of offset and duration errors when fitting events to a grid. A higher weight minimizes offset and duration errors at the cost of more complex divisions

maxDivPenalty: float = 0.1

A max. division penalty, will discard any divisions which have a penalty higher than this value. This can be used to further customize the quantization process

maxGridDensity: int = 0

If given (higher than 0) it discards any division of the beat with a higher number of slots than this value. For example, a division of (3, 4, 4) has a density of 12, since the highest subdivision, 4, applied to the entire beat would result in 12 notes per beat

maxPenalty: float = 1.0

A max. penalty when quantizing a beat, to limit the search space

mergeTupletsDifferentDur: bool = False

Allow merging tuplets which have different total durations?

mergedTupletsMaxDuration: Fraction = Fraction(2, 1)

How long can a tuplet over the beat be

name: str = ''

A name for this profile, if needed

nestedTuplets: bool = False

Are nested tuplets allowed?

numNestedTupletsPenalty: tuple[float, ...] = (0.0, 0.1, 0.4, 0.5, 0.8, 0.8)

Penalty applied to nested levels by level

numNestedTupletsPenaltyWeight: float = 1.0

Weight of sublevel penalty

numSubdivisionsPenaltyWeight: float = 0.2

Weight to penalize the number of subdivisions

offsetErrorWeight: float = 1.0

Weight of the offset between original start and makeSnappedNotation start

outerTupletMatchFactor: float = 0.01

A factor applied to the division penalty when a div matches the outer tuplet of an adjacent beat

restOffsetErrorWeight: float = 0.5

Similar to offsetErrorWeight but for rests

rhythmComplexityIrregularDurationsWeight = 0.8

When calculating rhythm complexity this weight is applied to the penalty of notes whose duration is irregular (durations of 5 or 9 units, which need ties to be represented)

rhythmComplexityNotesAcrossSubdivisionWeight = 0.2

When calculating rhythm complexity this weight is applied to the penalty of notes extending over subdivisions of the beat (inner-beat syncopes)

rhythmComplexityWeight: float = 0.001

Weight of the actual quantized rhythm. This includes evaluating synchopes, ties, etc.

subdivTempoThresh: int = 96
syncopExcludeSymDurs: tuple[int, ...] = (5, 7, 15)

Symbolic numerators excluded from being syncopated (3=dotted, 7=double dotted, etc.)

syncopMaxAsymmetry: float = 4.0

The max. ratio between the longer and the shorter parts to be mergeable as a syncopation

syncopMinFraction: Fraction = Fraction(1, 3)

Min. fraction of a beat for the whole duration of a syncopation

syncopPartMinFraction: Fraction = Fraction(1, 8)

How long can any part of a synchopation be, in terms of the length of the beat

tiedSnappedGracenoteMinRealDuration: Fraction = Fraction(1, 1000)

The min. real duration of a tied snapped gracenote in order for it NOT to be removed

Methods Documentation

breakSyncopationsMinWeight(level='')[source]

Returns the min. weight of a beat in order to break syncopations across its boundary

Converts the setting .breakSyncopationsLevel, which is one of ‘none’, ‘strong’, ‘weak’, ‘all’ to the weight a beat must have in order to break any notation across its boundary.

Return type:

int

Returns:

the min. weight of the beat, as an int

copy()[source]
Return type:

QuantizationProfile

default()[source]
Return type:

QuantizationProfile

divisionPenalty(division)[source]

A penalty based on the complexity of the division of the pulse alone

Parameters:

division (tuple[int, ...]) – the division to rate

Returns:

float, debuginfo: str), where the penalty is an arbitrary number (lower=simpler division, higher=more complex) and debuginfo can be used to query how this penalty was calculated (debuginfo will only be filled if .debug is True)

Return type:

a tuple (penalty

divisionsByTempo()[source]
Return type:

dict[int, tuple[tuple[int, ...], ...]]

static fromPreset(complexity='high', nestedTuplets=None, blacklist=(), **kws)[source]

Create a QuantizationProfile from a preset

Parameters:
  • complexity – complexity presets, one of ‘low’, ‘medium’, ‘high’, ‘highest’ (see maelzel.scoring.quantdata.presets)

  • nestedTuplets (Optional[bool]) – if True, allow nested tuplets.

  • blacklist (Sequence[tuple[int, ...]]) – if given, a sequence of divisions to exclude

  • kws – any keywords passed to QuantizationProfile

Return type:

QuantizationProfile

Returns:

the quantization preset

keys()[source]
Return type:

set[str]

modified()[source]

This method needs to be called after self is modified in order to clear caches

possibleBeatDivisionsForTempo(tempo)[source]

The possible divisions of the pulse for the given tempo

Parameters:

tempo (Union[int, float, Fraction]) – the tempo to calculate divisions for. A profile can define different divisions according to different tempi (simpler divisions if the tempo is fast, more complex if the tempo is slow).

Return type:

list[tuple[int, ...]]

Returns:

a list of possible divisions for the given tempo.