clockblocks.tempo_envelope.TempoHistory

class clockblocks.tempo_envelope.TempoHistory(levels: float | Sequence[float] = (60,), durations: Sequence[float] = (), curve_shapes: Sequence[float | str] = None, units: str = 'tempo', duration_units: str = 'beats', beat: float = 0.0)[source]

Bases: TempoEnvelope

Subclass of TempoEnvelope that keeps track of a current beat and time, and provides functionality for moving forward a certain number of beats or seconds, and/or setting tempo target(s) to reach in the future.

Parameters:

Methods

advance(duration[, duration_units])

Advance the current beat/time in the envelope by the given number of beats.

append_envelope(envelope_to_append[, ...])

Append another tempo envelope onto the end of this one, starting from the current beat.

apply_function(func[, domain_start, ...])

Apply a function for this TempoEnvelope to follow.

as_tempo_envelope()

Converts this TempoHistory to a simpler TempoEnvelope (removing reference to current beat and time)

beat_at_time(t)

Determine the beat at the given time.

from_tempo_envelope(tempo_envelope[, beat])

Constructs a TempoHistory from a TempoEnvelope.

go_to_beat(b)

Jump straight to the given beat in this TempoHistory

set_beat_length_target(beat_length_target, ...)

Set a target beat length for this TempoEnvelope to reach in duration beats/seconds (with the unit defined by duration_units).

set_rate_target(rate_target, duration[, ...])

Set a target beat rate for this TempoEnvelope to reach in duration beats/seconds (with the unit defined by duration_units).

set_tempo_target(tempo_target, duration[, ...])

Set a target tempo for this TempoEnvelope to reach in duration beats/seconds (with the unit defined by duration_units).

show_plot([title, resolution, ...])

Shows a plot of this TempoHistory using matplotlib.

stop_follow_function_or_envelope_loop()

If we've applied a function or a looping envelope, this causes us to stop doing so

time_at_beat(beat)

Determine the time at the given beat.

truncate()

Removes all segments after the current beat.

truncate_at(beat)

Removes all segments after the given beat and adds a constant segment if necessary to bring us up to that beat.

Inherited Methods

adsr(attack_length, attack_level, ...[, ...])

Construct a standard attack/decay/sustain/release envelope

append_segment(level, duration[, ...])

Append a segment to the end of the curve ending at level and lasting for duration.

ar(attack_length, release_length[, ...])

Construct an attack/release envelope

asr(attack_length, sustain_level, ...[, ...])

Construct an attack/sustain/release envelope

average_level([t_range])

Returns the average value that the Envelope takes over the given range.

beat_length_at(beat[, from_left])

Get the beat length at the given beat.

convert_durations_to_times()

Warps this tempo_curve so that all the locations of key points get re-interpreted as times instead of beat locations.

convert_units(values, input_units, output_units)

Utility method to convert values between unites of tempo, rate and beat length.

duplicate()

Returns a copy of this object by serializing to and from JSON.

end_level()

Ending value of the Envelope

end_time()

End of the domain on which this Envelope is defined.

extend_to(beat)

Extends the end of this TempoEnvelope to the given beat (if needed) by adding a constant segment at the end.

from_function(function[, domain_start, ...])

Constructs a TempoEnvelope that approximates an arbitrary function.

from_levels(levels[, length, units, ...])

Constructs a TempoEnvelope from the given levels and total length, using the specified units.

from_levels_and_durations([levels, ...])

Constructs a TempoEnvelope from the given levels, durations and curve shapes, using the specified units.

from_list(constructor_list[, units, ...])

Construct a TempoEnvelope from a list that can take a number of formats

from_points(*points[, units, duration_units])

Construct an envelope from a list of (beat/time, tempo/rate/beat length) pairs.

from_segments(segments)

Create a new envelope from a list of EnvelopeSegments.

get_durations([rounded])

Tuple of all the segment lengths.

get_upper_integration_bound(t1, desired_area)

Given a lower integration bound, find the upper bound that will result in the desired integral.

insert(t, level[, curve_shape_in, ...])

Insert a curve point at time t, and set the shape of the curve into and out of it.

insert_interpolated(t[, relative_tolerance])

Insert another curve point at the given time, without changing the shape of the curve.

integrate_interval(t1, t2)

Get the definite integral under this Envelope from t1 to t2

is_default()

True if this is the trivial default tempo — a constant 60 bpm (rate 1.0) with no duration, i.e. structurally identical to a freshly-constructed TempoEnvelope().

is_shifted_version_of(other[, tolerance])

Determines if this segment is simply a shifted version of another segment

json_dumps()

Dump this object as a JSON string.

json_loads(s)

Load this object from a JSON string.

length()

The length of the domain on which this Envelope is defined (end time minus start time).

load_from_json(file_path)

Load this object from a JSON file with the given path.

local_extrema([include_saddle_points])

Returns a list of the times where the curve changes direction.

max_absolute_slope()

Returns the maximum absolute value of the slope over the entire Envelope.

max_level([t_range])

Returns the highest value that the Envelope takes over the given range.

min_level([t_range])

Returns the lowest value that the Envelope takes over the given range.

normalize_to_duration(desired_duration[, ...])

Stretch or squeeze the segments of this Envelope so that it has the desired total duration.

pop_segment()

Remove and return the last segment of this Envelope.

pop_segment_from_start()

Remove and return the first segment of this Envelope.

prepend_envelope(envelope_to_prepend)

Extends this envelope backwards by another one (shifted to end at the start of this one).

prepend_segment(level, duration[, ...])

Prepend a segment to the beginning of the curve, starting at level and lasting for duration.

rate_at(beat[, from_left])

Get the beat rate (in beats/second) at the given beat.

release(duration[, start_level, curve_shape])

Construct an simple decaying envelope

remove_segments_after(t)

Removes all segments after the given time (including a partial segment if t lands in the middle of a segment).

remove_segments_before(t)

Removes all segments before the given time (including a partial segment if t lands in the middle of a segment).

save_to_json(file_path)

Save this object to a JSON file using the given path.

scale_horizontal(amount)

Scales the domain of this Envelope by the specified amount.

scale_vertical(amount)

Scales the levels of this segment by the specified amount.

shift_horizontal(amount)

Shifts the domain of this Envelope by the specified amount.

shift_vertical(amount)

Shifts the levels of this Envelope the specified amount.

simplified([use_curvature, ...])

Simplifies the envelope to only extrema and inflection points.

split_at(t[, change_original, zero_out_offsets])

Splits the Envelope at one or several points and returns a tuple of the pieces

start_level()

Beginning value of the Envelope

start_time()

Beginning of the domain on which this Envelope is defined.

tempo_at(beat[, from_left])

Get the tempo (in beats/minute) at the given beat.

value_at(t[, from_left])

Get the value of this Envelope at the given time.

Attributes

beat

The current beat.

beat_length

The current beat length.

curve_shapes

Tuple of all the segment curve shapes.

durations

Tuple of all the segment lengths.

levels

Tuple of levels at all segment boundary points.

offset

Alias for Envelope.start_time().

rate

The current rate in beats/second

tempo

The current tempo in beats/minute

time

The current time.

times

Tuple of all the segment start times.

follow_func_or_envelope_loop: FunctionFollowInfo | EnvelopeLoopInfo
classmethod from_tempo_envelope(tempo_envelope: TempoEnvelope, beat: float = 0.0)[source]

Constructs a TempoHistory from a TempoEnvelope.

Parameters:
  • tempo_envelope – the TempoEnvelope to copy

  • beat – the beat to start this TempoHistory on

property time

The current time. Time is found by integrating under the beat length curve: seconds/beat * beats = seconds.

property beat

The current beat.

property beat_length

The current beat length.

property rate

The current rate in beats/second

property tempo

The current tempo in beats/minute

time_at_beat(beat)[source]

Determine the time at the given beat.

For beats at or ahead of the committed pointer (the common case, used e.g. by wait()), we integrate forward from the pointer (cheap). For beats behind the pointer (e.g. when resolving TimeStamps) we integrate from the origin instead to avoid a negative integral.

Parameters:

beat – The beat at which to calculate the time.

beat_at_time(t)[source]

Determine the beat at the given time. See time_at_beat() for why we branch on whether the target is ahead of or behind the committed pointer.

Parameters:

t – The time at which to calculate the beat

append_envelope(envelope_to_append: TempoEnvelope, truncate: bool = False, loop: bool = False) → TempoEnvelope[source]

Append another tempo envelope onto the end of this one, starting from the current beat.

Parameters:
  • envelope_to_append – the TempoEnvelope to add on

  • truncate – if True, first discard any existing segments that extend past the current beat, so the appended envelope begins cleanly from now

  • loop – if True, keep repeating envelope_to_append indefinitely from this point on

Returns:

self, for chaining purposes

set_beat_length_target(beat_length_target: float, duration: float, curve_shape: float = 0, alignment_target: float | MetricPhaseTarget | None = None, duration_units: str = 'beats', truncate: bool = True) → None[source]

Set a target beat length for this TempoEnvelope to reach in duration beats/seconds (with the unit defined by duration_units).

Parameters:
  • beat_length_target – The beat length we want to reach

  • duration – How long until we reach that beat length

  • curve_shape – > 0 makes change happen later, < 0 makes change happen sooner. When alignment_target is given, this acts only as a seed for solving the curvature, a suggestion rather than a guaranteed value. (And even then it only makes sense if alignment target is a MetricPhaseTarget; if it’s a fixed time/beat, there’s only one curvature solution, if it exists.)

  • alignment_target – optional constraint on the endpoint’s free axis (the one duration does not pin: time when duration_units is beats, beats when it is time). Either a number (land the free axis exactly on that coordinate, which fully determines the curvature) or a MetricPhaseTarget (snap to the nearest matching phase on the free axis). See _add_segment(). Raises ValueError if unreachable due to the limited flexibility of curvature adjustment.

  • duration_units – one of (“beats”, “time”); defines whether the duration is in beats or in seconds.

  • truncate – Whether or not to truncate this TempoEnvelope to the current beat before setting this target.

set_rate_target(rate_target: float, duration: float, curve_shape: float = 0, alignment_target: float | MetricPhaseTarget | None = None, duration_units: str = 'beats', truncate: bool = True) → None[source]

Set a target beat rate for this TempoEnvelope to reach in duration beats/seconds (with the unit defined by duration_units). See set_beat_length_target().

set_tempo_target(tempo_target: float, duration: float, curve_shape: float = 0, alignment_target: float | MetricPhaseTarget | None = None, duration_units: str = 'beats', truncate: bool = True) → None[source]

Set a target tempo for this TempoEnvelope to reach in duration beats/seconds (with the unit defined by duration_units). See set_beat_length_target().

apply_function(func: Callable[[float], float], domain_start: float = 0, domain_end: float = None, units: str = 'tempo', duration_units: str = 'beats', truncate: bool = False, loop: bool = False, extension_increment: float = 2.0, scanning_step_size: float = 0.05, key_point_resolution_multiple: int = 2, iterations: int = 6, min_key_point_distance: float = 1e-07) → None[source]

Apply a function for this TempoEnvelope to follow. If domain_end is None, this causes us to follow this function indefinitely; if a value is given for domain_end, then this appends an envelope that matches the contour of the prescribed function over a finite domain.

Parameters:
  • func – a function (likely a lambda function) that maps a given beat/time to the desired tempo/rate/beatlength at that moment. See the units and duration_units arguments, which allow you to specify the units of the input and output of the function.

  • domain_start – what part of the function’s domain to start at (defaults to 0)

  • domain_end – what part of the function’s domain to end at (defaults to None, which causes the TempoHistory to follow the function indefinitely, or until stop_follow_function_or_envelope_loop() is called.)

  • units – either “beats” or “time”. If beats, then the func param specifies a mapping from beats to tempo/rate/beatlength; if time, then it specifies a mapping from sections to tempo/rate/beatlength.

  • duration_units – one of (“tempo”, “rate”, “beatlength”). This determines the units of the output of the func parameter.

  • truncate – if True, truncate any current projection of the TempoHistory into the future, and begin following this function from the current moment. If False, start following the function from the end of the current projection of the TempoHistory.

  • loop – Only relevant if domain_end is set. If so, this determines whether or not we loop the segment of function.

  • extension_increment – Only relevant if domain_end is None. When following the tempo/rate/beatlength function indefinitely, we project the function this far into the future, and only extend further as we reach the end of what we have projected.

  • scanning_step_size – see expenvelope.Envelope.from_function()

  • key_point_resolution_multiple – see expenvelope.Envelope.from_function()

  • iterations – see expenvelope.Envelope.from_function()

  • min_key_point_distance – see expenvelope.Envelope.from_function()

stop_follow_function_or_envelope_loop()[source]

If we’ve applied a function or a looping envelope, this causes us to stop doing so

advance(duration: float, duration_units: DurationUnits = 'beats') → tuple[float, float][source]

Advance the current beat/time in the envelope by the given number of beats.

Parameters:
  • duration – how many beats or seconds to advance by

  • duration_units – one of (“beats”, “time”)

Returns:

tuple of delta beats, delta time

go_to_beat(b: float) → TempoEnvelope[source]

Jump straight to the given beat in this TempoHistory

Parameters:

b – the beat to jump to

Returns:

self, for chaining purposes

truncate_at(beat: float) → TempoEnvelope[source]

Removes all segments after the given beat and adds a constant segment if necessary to bring us up to that beat.

Parameters:

beat – the beat that we are truncating the tempo envelope after

Returns:

self, for chaining purposes

truncate() → TempoEnvelope[source]

Removes all segments after the current beat.

Returns:

self, for chaining purposes

classmethod adsr(attack_length: float, attack_level, decay_length: float, sustain_level, sustain_length: float, release_length: float, attack_shape: float | str = None, decay_shape: float | str = None, release_shape: float | str = None) → T

Construct a standard attack/decay/sustain/release envelope

Parameters:
  • attack_length – rise time

  • attack_level – level reached after attack before decay

  • decay_length – length of decay portion of the curve

  • sustain_level – sustain level reached after decay and before release

  • sustain_length – length of sustain portion of curve

  • release_length – release time

  • attack_shape – sets curve shape for attack portion of the curve (see documentation for Envelope.from_levels_and_durations())

  • decay_shape – sets curve shape for decay portion of the curve (see documentation for Envelope.from_levels_and_durations())

  • release_shape – sets curve shape for release portion of the curve (see documentation for Envelope.from_levels_and_durations())

Returns:

an Envelope constructed accordingly

append_segment(level, duration: float, curve_shape: float = None, tolerance: float = 0, halfway_level=None) → None

Append a segment to the end of the curve ending at level and lasting for duration. If we’re adding a linear segment to a linear segment, then we extend the last linear segment instead of adding a new one if the level is within tolerance of where the last one was headed

Parameters:
  • level – the level we’re going to

  • duration – the duration of the new segment

  • curve_shape – defaults to 0 (linear)

  • tolerance – tolerance for extending a linear segment rather than adding a new one

  • halfway_level – alternate way of defining the curve shape. If this is set and the curve shape is not then we use this to determine the curve shape.

classmethod ar(attack_length: float, release_length: float, peak_level=1, attack_shape: float | str = None, release_shape: float | str = None) → T

Construct an attack/release envelope

Parameters:
  • attack_length – rise time

  • release_length – release time

  • peak_level – level reached after attack and before release (see documentation for Envelope.from_levels_and_durations())

  • attack_shape – sets curve shape for attack portion of the curve (see documentation for Envelope.from_levels_and_durations())

  • release_shape – sets curve shape for release portion of the curve (see documentation for Envelope.from_levels_and_durations())

Returns:

an Envelope constructed accordingly

classmethod asr(attack_length: float, sustain_level, sustain_length: float, release_length: float, attack_shape: float | str = None, release_shape: float | str = None) → T

Construct an attack/sustain/release envelope

Parameters:
  • attack_length – rise time

  • sustain_level – sustain level reached after attack and before release

  • sustain_length – length of sustain portion of curve

  • release_length – release time

  • attack_shape – sets curve shape for attack portion of the curve (see documentation for Envelope.from_levels_and_durations())

  • release_shape – sets curve shape for release portion of the curve (see documentation for Envelope.from_levels_and_durations())

Returns:

an Envelope constructed accordingly

average_level(t_range: tuple[float, float] = None)

Returns the average value that the Envelope takes over the given range.

Parameters:

t_range – tuple defining the start and end time of the interval to check. If None, return the average level reached over the entire Envelope.

beat_length_at(beat: float, from_left: bool = False) → float

Get the beat length at the given beat. If the beat length jumps at the given beat, the default is to return the beat length after the jump, though this can be overridden with the from_left argument.

Parameters:
  • beat – the beat at which to get the beat length

  • from_left – whether to evaluate from the right or left-hand side of the beat in question

convert_durations_to_times()

Warps this tempo_curve so that all the locations of key points get re-interpreted as times instead of beat locations. For instance, a tempo curve where the rate hovers around 2 will see a segment of length 3 get stretched into a segment of length 6, since if it’s supposed to take 3 seconds, it would take 6 beats. Pretty confusing, but when we want to construct a tempo curve specifying the times that changes occur rather than the beats, we can first construct it as though the durations were in beats, then call this function to warp it so that the durations are in time.

Returns:

self, altered accordingly

static convert_units(values: float | Sequence[float], input_units: str, output_units: str) → float | Sequence[float]

Utility method to convert values between unites of tempo, rate and beat length.

Parameters:
  • values – value or list of values in terms of the input_units

  • input_units – current units of the given values (either “tempo”, “rate”, or “beat length”)

  • output_units – desired units to convert to (either “tempo”, “rate”, or “beat length”)

Returns:

the list of values, converted to output units

property curve_shapes: Sequence[float | str]

Tuple of all the segment curve shapes.

duplicate() → T

Returns a copy of this object by serializing to and from JSON.

property durations: Sequence[float]

Tuple of all the segment lengths.

end_level()

Ending value of the Envelope

end_time() → float

End of the domain on which this Envelope is defined.

extend_to(beat: float) → TempoEnvelope

Extends the end of this TempoEnvelope to the given beat (if needed) by adding a constant segment at the end.

classmethod from_function(function, domain_start=0, domain_end=1, units: str = 'tempo', duration_units: str = 'beats', scanning_step_size: float = 0.05, key_point_resolution_multiple: int = 2, iterations: int = 6, min_key_point_distance: float = 1e-07) → TempoEnvelope

Constructs a TempoEnvelope that approximates an arbitrary function. The domain of the function is in units defined by the duration_units parameter, and the range is in units defined by the units parameter.

Parameters:
  • function – A function from beat/time to tempo/rate/beat length, as defined by the duration_units and units parameters.

  • domain_start – see from_function()

  • domain_end – see from_function()

  • units – one of “tempo”, “rate” or “beat length”, determining how we interpret the function output

  • duration_units – either “beats” or “time”, determining how we interpret the function input

  • scanning_step_size – when analyzing the function for discontinuities, maxima and minima, inflection points, etc., use this step size for the initial pass.

  • key_point_resolution_multiple – factor by which we add extra key points between the extrema and inflection points to improve the curve fit.

  • iterations – when a potential key point is found, we zoom in and scan again in the viscinity of the point. This determines how many iterations of zooming we do.

  • min_key_point_distance – after scanning for key points, any that are closer than this distance are merged.

Returns:

a TempoEnvelope, constructed accordingly

classmethod from_levels(levels: Sequence[float], length: float = 1.0, units: str = 'tempo', duration_units: str = 'beats') → TempoEnvelope

Constructs a TempoEnvelope from the given levels and total length, using the specified units.

Parameters:
  • levels – levels of the curve segments (i.e. tempo values) in the units specified by the units argument

  • length – total length of the tempo curve, in the units specified by the duration_units argument

  • units – one of “tempo”, “rate” or “beat length”, determining how we interpret the levels given

  • duration_units – either “beats” or “time”, determining how we interpret the durations given

Returns:

a TempoEnvelope, constructed accordingly

classmethod from_levels_and_durations(levels: Sequence = (0, 0), durations: Sequence[float] = (0,), curve_shapes: Sequence[float | str] = None, units: str = 'tempo', duration_units: str = 'beats') → TempoEnvelope

Constructs a TempoEnvelope from the given levels, durations and curve shapes, using the specified units.

Parameters:
  • levels – levels of the curve segments (i.e. tempo values) in the units specified by the units argument

  • durations – durations of the curve segments in the units specified by the duration_units argument

  • curve_shapes – see from_levels_and_durations()

  • units – one of “tempo”, “rate” or “beat length”, determining how we interpret the levels given

  • duration_units – either “beats” or “time”, determining how we interpret the durations given

Returns:

a TempoEnvelope, constructed accordingly

classmethod from_list(constructor_list: Sequence, units: str = 'tempo', duration_units: str = 'beats') → TempoEnvelope

Construct a TempoEnvelope from a list that can take a number of formats

Parameters:
  • constructor_list – see from_list()

  • units – one of “tempo”, “rate” or “beat length”, determining how we interpret the levels given

  • duration_units – either “beats” or “time”, determining how we interpret the durations given

Returns:

a TempoEnvelope, constructed accordingly

classmethod from_points(*points, units: str = 'tempo', duration_units: str = 'beats') → TempoEnvelope

Construct an envelope from a list of (beat/time, tempo/rate/beat length) pairs. Units are defined by the units and duration_units parameters.

Parameters:
  • points – list of points, each of which is of the form (time, value) or (time, value, curve_shape)

  • units – one of “tempo”, “rate” or “beat length”, determining how we interpret the tempo values

  • duration_units – either “beats” or “time”, determining how we interpret the time values

Returns:

a TempoEnvelope, constructed accordingly

classmethod from_segments(segments: Sequence[EnvelopeSegment]) → T

Create a new envelope from a list of EnvelopeSegments.

Parameters:

segments – list of segments

get_durations(rounded: bool = False) → Sequence[float]

Tuple of all the segment lengths.

Segment lengths are derived as end_time - start_time, so an envelope built up on a regular grid (e.g. repeated 0.1-long segments) accumulates floating-point dust in these differences even though each segment was appended with a clean duration. Pass rounded=True to snap each length to a nearby nice decimal — used for serialization / repr so the intended durations show, without disturbing the exact segment boundary times that the curve math relies on.

Parameters:

rounded – if True, snap each duration to a nearby nice decimal (see snap_float_to_nice_decimal())

get_upper_integration_bound(t1: float, desired_area: float, max_error: float = 1e-14) → float

Given a lower integration bound, find the upper bound that will result in the desired integral.

Walks the envelope segment by segment, subtracting each segment’s closed-form area until the remaining area falls within a single segment, then inverts that segment using EnvelopeSegment.get_t_at_integral() — exactly for constant/linear segments, and to within max_error for exponential ones.

Assumes a non-negative integrand, so that the integral increases monotonically (true for tempo and dynamics curves, the primary use). Regions before the first segment and after the last are treated as flat (at the start/end level), matching integrate_interval().

Parameters:
  • t1 – lower bound of integration

  • desired_area – desired value of the integral.

  • max_error – convergence tolerance forwarded to the per-segment inverse for the exponential case; ignored by the (exact) constant and linear cases.

insert(t, level, curve_shape_in=0, curve_shape_out=0) → None

Insert a curve point at time t, and set the shape of the curve into and out of it. This essentially divides the segment at that point in two.

Parameters:
  • t – The time at which to add a point

  • level – The level of the new point we are adding

  • curve_shape_in – the curve shape of the new segment going into the point we are adding

  • curve_shape_out – the curve shape of the new segment going out of the point we are adding

insert_interpolated(t: float, relative_tolerance: float = 1e-07) → float

Insert another curve point at the given time, without changing the shape of the curve. Returns the t value of the new (or already existing) interpolated point.

To avoid manufacturing degenerate, near-zero-width segments due to floating point imprecision, a point is only added if it is at least relative_tolerance * segment_width away from the endpoints of the segment it falls in. If t lands within that tolerance of an existing control point, this function call is assumed to be an idempotent re-insertion of an existing curve point after floating point error has muddied the waters. In this case no point is added, and the existing control point’s time is returned instead.

Parameters:
  • t – the point at which to insert the point

  • relative_tolerance – how close t may come to an existing control point before it is treated as coincident with it, expressed as a fraction of the width of the segment containing t.

Returns:

the t value at which we interpolated. If we snapped to an existing control point, its t is returned; otherwise the passed value of t is returned.

integrate_interval(t1: float, t2: float)

Get the definite integral under this Envelope from t1 to t2

Parameters:
  • t1 – lower bound of integration

  • t2 – upper bound of integration

is_default() → bool

True if this is the trivial default tempo — a constant 60 bpm (rate 1.0) with no duration, i.e. structurally identical to a freshly-constructed TempoEnvelope(). (Note this is stricter than “functionally constant at 60”: a flat-60 envelope that carries a real duration or extra segments is not default (and worth surfacing for debugging)

is_shifted_version_of(other: T, tolerance: float = 1e-10) → bool

Determines if this segment is simply a shifted version of another segment

Parameters:
  • other – another EnvelopeSegment

  • tolerance – how close it needs to be to count as the same

json_dumps() → str

Dump this object as a JSON string. This uses a custom encoder that recognizes and appropriately converts any attributes that are object inheriting from SavesToJSON.

classmethod json_loads(s: str) → T

Load this object from a JSON string. This uses a custom decoder that looks for a “_type” key in any object/dictionary being parsed and converts it to the class specified (assuming it a subclass of SavesToJSON).

Parameters:

s – a string representing this object in JSON format

length() → float

The length of the domain on which this Envelope is defined (end time minus start time).

property levels: Sequence

Tuple of levels at all segment boundary points.

classmethod load_from_json(file_path: str) → T

Load this object from a JSON file with the given path. This uses a custom decoder that looks for a “_type” key in any object/dictionary being parsed and converts it to the class specified (assuming it a subclass of SavesToJSON).

Parameters:

file_path – path for loading the file

local_extrema(include_saddle_points: bool = False) → Sequence[float]

Returns a list of the times where the curve changes direction.

Parameters:

include_saddle_points – if True, also include points where the curve starts or stops plateauing

max_absolute_slope()

Returns the maximum absolute value of the slope over the entire Envelope.

max_level(t_range: tuple[float, float] = None)

Returns the highest value that the Envelope takes over the given range.

Parameters:

t_range – tuple defining the start and end time of the interval to check. If None, return the max level reached over the entire Envelope.

min_level(t_range: tuple[float, float] = None)

Returns the lowest value that the Envelope takes over the given range.

Parameters:

t_range – tuple defining the start and end time of the interval to check. If None, return the max level reached over the entire Envelope.

normalize_to_duration(desired_duration: float, in_place: bool = True) → T

Stretch or squeeze the segments of this Envelope so that it has the desired total duration.

Parameters:
  • desired_duration – the desired new duration of the Envelope

  • in_place – if True, modifies this Envelope in place; if False, makes a copy first

property offset: float

Alias for Envelope.start_time().

pop_segment() → EnvelopeSegment | None

Remove and return the last segment of this Envelope. If there is only one segment, reduce it to length zero and return None.

pop_segment_from_start() → EnvelopeSegment | None

Remove and return the first segment of this Envelope. If there is only one segment, reduce it to length zero and return None.

prepend_envelope(envelope_to_prepend: T) → T

Extends this envelope backwards by another one (shifted to end at the start of this one).

prepend_segment(level, duration: float, curve_shape: float = None, tolerance: float = 0, halfway_level=None) → None

Prepend a segment to the beginning of the curve, starting at level and lasting for duration. If we’re adding a linear segment to a linear segment, then we extend the last linear segment instead of adding a new one if the level is within tolerance of where the last one was headed

Parameters:
  • level – the level that the prepended segment starts at

  • duration – the duration of the new segment

  • curve_shape – defaults to 0 (linear)

  • tolerance – tolerance for extending a linear segment rather than adding a new one

  • halfway_level – alternate way of defining the curve shape. If this is set and the curve shape is not then we use this to determine the curve shape.

rate_at(beat: float, from_left: bool = False) → float

Get the beat rate (in beats/second) at the given beat. If the rate jumps at the given beat, the default is to return the rate after the jump, though this can be overridden with the from_left argument.

Parameters:
  • beat – the beat at which to get the rate

  • from_left – whether to evaluate from the right or left-hand side of the beat in question

classmethod release(duration: float, start_level=1, curve_shape: float | str = None) → T

Construct an simple decaying envelope

Parameters:
  • duration – total decay length

  • start_level – level decayed from

  • curve_shape – shape of the curve (see documentation for Envelope.from_levels_and_durations())

Returns:

an Envelope constructed accordingly

remove_segments_after(t: float) → None

Removes all segments after the given time (including a partial segment if t lands in the middle of a segment).

Parameters:

t – the point at which this Envelope is to be truncated.

remove_segments_before(t: float) → None

Removes all segments before the given time (including a partial segment if t lands in the middle of a segment).

Parameters:

t – the point at which this Envelope is to be truncated.

save_to_json(file_path: str) → None

Save this object to a JSON file using the given path. This uses a custom encoder that recognizes and appropriately converts any attributes that are object inheriting from SavesToJSON.

Parameters:

file_path – path for saving the file

scale_horizontal(amount: float) → T

Scales the domain of this Envelope by the specified amount.

Parameters:

amount – amount to scale domain by

Returns:

self, for chaining purposes

scale_vertical(amount) → T

Scales the levels of this segment by the specified amount.

Parameters:

amount – amount to scale output by

Returns:

self, for chaining purposes

shift_horizontal(amount: float) → T

Shifts the domain of this Envelope by the specified amount.

Parameters:

amount – the amount to shift the domain by

Returns:

self, for chaining purposes

shift_vertical(amount) → T

Shifts the levels of this Envelope the specified amount.

Parameters:

amount – the amount to shift up and down by

Returns:

self, for chaining purposes

show_plot(title=None, resolution=25, show_segment_divisions=True, units='tempo', x_range=None, y_range=None, show_current_beat=True)[source]

Shows a plot of this TempoHistory using matplotlib.

Parameters:
simplified(use_curvature=True, include_saddle_points=True) → T

Simplifies the envelope to only extrema and inflection points.

Parameters:
  • use_curvature – if True, adjusts the curvature of the segments to match the half-way point between key points. If False, linearly interpolate between key points.

  • include_saddle_points – if True, include saddle points as well as extrema

split_at(t: float | Sequence[float], change_original: bool = False, zero_out_offsets: bool = True) → Sequence[T]

Splits the Envelope at one or several points and returns a tuple of the pieces

Parameters:
  • t – either the time t or a tuple/list of times t at which to split the curve

  • change_original – if true, the original Envelope gets turned into the first of the returned tuple

  • zero_out_offsets – if true, each new piece is shifted to start at zero

Returns:

tuple of Envelopes representing the pieces this has been split into

start_level()

Beginning value of the Envelope

start_time() → float

Beginning of the domain on which this Envelope is defined.

tempo_at(beat: float, from_left: bool = False) → float

Get the tempo (in beats/minute) at the given beat. If the tempo jumps at the given beat, the default is to return the tempo after the jump, though this can be overridden with the from_left argument.

Parameters:
  • beat – the beat at which to get the tempo

  • from_left – whether to evaluate from the right or left-hand side of the beat in question

property times: Sequence[float]

Tuple of all the segment start times.

value_at(t: float, from_left: bool = False)

Get the value of this Envelope at the given time.

Parameters:
  • t – the time

  • from_left – if true, get the limit as we approach t from the left. In the case of a zero-length segment, which suddenly changes the value, this tells us what the value was right before the jump instead of right after the jump.

as_tempo_envelope() → TempoEnvelope[source]

Converts this TempoHistory to a simpler TempoEnvelope (removing reference to current beat and time)