scamp.performance.Performance

class scamp.performance.Performance(parts: Optional[Sequence[PerformancePart]] = None, tempo_envelope: Optional[TempoEnvelope] = None)[source]

Bases: SavesToJSON, _NoteFiltersMixin

Representation of note playback events, usually a transcription of the notes played by an Ensemble. Operates in continuous time, without regard to any particular way of notating it. (As opposed to a Score, which represents the notated music.)

Parameters:
  • parts – list of parts (PerformancePart objects) to start with (defaults to empty list)

  • tempo_envelope – a tempo_envelope to associate with this performance

Variables:
  • parts – list of parts (PerformancePart objects) in this Performance

  • tempo_envelope – the tempo_envelope associated this performance and used for playback by default

Methods

add_part(part)

Add the given PerformancePart to this performance

export_to_midi_file(output_file[, ...])

Exports the Performance to a MIDI file.

get_note_iterator([start_beat, stop_beat, ...])

Returns an iterator returning all the notes from start_beat to stop_beat in the selected voices, in all parts.

get_part_by_index(index)

Get the part with the given index (Parts are numbered starting with 0, in order that they are added/created.)

get_parts_by_instrument(instrument)

Get all parts with the given instrument

get_parts_by_name(name)

Get all parts with the given name

is_quantized()

Checks if this Performance has been quantized

length()

Total length of this performance.

new_part([instrument])

Construct and add a new PerformancePart to this Performance

num_measures()

If this Performance has been quantized, gets the number of measures

play([start_beat, stop_beat, ensemble, ...])

Play back this Performance (or a selection of it)

quantize([quantization_scheme, ...])

Quantizes all parts according to the quantization_scheme

quantized([quantization_scheme, ...])

Same as quantize, except that it returns a new copy, rather than changing this Performance in place.

remap_to_tempo(tempo)

Remaps this performance to use the given tempo or tempo envelope.

set_instruments_from_ensemble(ensemble[, ...])

Set the playback instruments for each part in this Performance by their best match in the ensemble given.

to_score([quantization_scheme, ...])

Convert this Performance (list of note events in continuous time and pitch) to a Score object, which represents the music in traditional western notation.

Inherited Methods

apply_note_filter(filter_function[, ...])

Applies a filter function to every note in this Performance.

apply_pitch_filter(filter_function[, ...])

Applies a filter function to transform the pitch of every note in this Performance.

apply_volume_filter(filter_function[, ...])

Applies a filter function to transform the volume of every note in this Performance.

duplicate()

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

json_dumps()

Dump this object as a JSON string.

json_loads(s)

Load this object from a JSON string.

load_from_json(file_path)

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

save_to_json(file_path)

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

transpose(interval)

Transposes all notes in this Performance up or down by the desired interval.

Attributes

end_beat

The end beat of this performance.

new_part(instrument: Optional[ScampInstrument] = None) PerformancePart[source]

Construct and add a new PerformancePart to this Performance

Parameters:

instrument – the instrument to use as a default for playing back the part

Returns:

the newly constructed part

add_part(part: PerformancePart) None[source]

Add the given PerformancePart to this performance

Parameters:

part – a PerformancePart to add

get_part_by_index(index: int) PerformancePart[source]

Get the part with the given index (Parts are numbered starting with 0, in order that they are added/created.)

Parameters:

index – the index of the part in question

Returns:

the PerformancePart

get_parts_by_name(name: str) Sequence[PerformancePart][source]

Get all parts with the given name

Parameters:

name – the part name to search for

Returns:

a list of parts with this name

get_parts_by_instrument(instrument: ScampInstrument) Sequence[PerformancePart][source]

Get all parts with the given instrument

Parameters:

instrument – the instrument to search for

Returns:

a list of parts with this instrument

property end_beat: float

The end beat of this performance. (i.e. the beat corresponding to the end of the last note)

Returns:

float representing the beat at which all notes are done playing

length() float[source]

Total length of this performance. (Identical to Performance.end_beat)

Returns:

float representing the total length of the Performance

get_note_iterator(start_beat: float = 0, stop_beat: Optional[float] = None, selected_voices: Optional[Sequence[str]] = None) Iterator[PerformanceNote][source]

Returns an iterator returning all the notes from start_beat to stop_beat in the selected voices, in all parts. In order of start time, jumping from part to part as needed.

Parameters:
  • start_beat – beat to start on

  • stop_beat – beat to stop on (None keeps going until the end of the part)

  • selected_voices – which voices to take notes from (defaults to all if None)

Returns:

an iterator

remap_to_tempo(tempo: TempoEnvelope | float)[source]

Remaps this performance to use the given tempo or tempo envelope. All notes will happen at the same time, but on different beats.

Parameters:

tempo – the new tempo envelope to use

Returns:

self, for chaining purposes

play(start_beat: float = 0, stop_beat: Optional[float] = None, ensemble: Ensemble = 'auto', clock: Clock = 'auto', blocking: bool = True, tempo_envelope: TempoEnvelope = 'auto', note_filter: Optional[Callable[[PerformanceNote], PerformanceNote]] = None) Clock[source]

Play back this Performance (or a selection of it)

Parameters:
  • start_beat – Place to start playing from

  • stop_beat – Place to stop playing at

  • ensemble – The Ensemble whose instruments to use for playback. If “auto”, checks to see if we are operating in a particular Session, and uses those instruments if so.

  • clock – clock to use for playback

  • blocking – if True, don’t return until the part is done playing; if False, return immediately

  • tempo_envelope – the TempoEnvelope with which to play back this performance. The default value of “auto” uses the tempo_envelope associated with the performance, and None uses a flat tempo of rate 60bpm

  • note_filter – a function that takes the PerformanceNote about to be played and returns a modified PerformanceNote to play. NB: this will modify the original note unless the input to the function is duplicated and left unaltered!

Returns:

the clock on which this performance is playing back

set_instruments_from_ensemble(ensemble: Ensemble, override: bool = True) Performance[source]

Set the playback instruments for each part in this Performance by their best match in the ensemble given. If override is False, only set the instrument for parts that don’t already have one set.

Parameters:
  • ensemble – the Ensemble in which to search for instruments

  • override – Whether or not to override any instruments already assigned to parts

Returns:

self

quantize(quantization_scheme: QuantizationScheme = 'default', onset_weighting: float = 'default', termination_weighting: float = 'default') Performance[source]

Quantizes all parts according to the quantization_scheme

Parameters:
  • quantization_scheme – the QuantizationScheme to use. If “default”, uses the default time signature defined in the quantization_settings.

  • onset_weighting – how much to weight note onsets in the quantization. If “default”, uses the default value defined in the quantization_settings.

  • termination_weighting – how much to weight note terminations in the quantization. If “default”, uses the default value defined in the quantization_settings.

Returns:

this Performance, having been quantized

quantized(quantization_scheme: QuantizationScheme = 'default', onset_weighting: float = 'default', termination_weighting: float = 'default') Performance[source]

Same as quantize, except that it returns a new copy, rather than changing this Performance in place.

Parameters:
  • quantization_scheme – the QuantizationScheme to use. If “default”, uses the default time signature defined in the quantization_settings.

  • onset_weighting – how much to weight note onsets in the quantization. If “default”, uses the default value defined in the quantization_settings.

  • termination_weighting – how much to weight note terminations in the quantization. If “default”, uses the default value defined in the quantization_settings.

Returns:

a quantized copy of this Performance

is_quantized() bool[source]

Checks if this Performance has been quantized

Returns:

True if all parts are quantized, False if not

num_measures() int[source]

If this Performance has been quantized, gets the number of measures

Returns:

number of measures

export_to_midi_file(output_file, flatten_tempo_changes=False, max_channels: int = 16, ring_time: float = 0.5, pitch_bend_range: float = 2, envelope_precision: float = 0.01, tempo_precision: float = 0.1)[source]

Exports the Performance to a MIDI file.

Parameters:
  • output_file – path of the MIDI file to create and write to.

  • flatten_tempo_changes – If True, then everything is flattened to a tempo of 60bpm, and notes at a faster tempo are simply made shorter. If False, tempo changes are exported as part of the MIDI file.

  • max_channels – maximum number of channels to use for different notes. By default, notes with different pitch bends and cc messages will be placed on different channels to avoid interference.

  • ring_time – When multiple channels are used for juggling different pitch bends and cc messages, channels are reused when the notes on them have finished. However, if they’re reused right away, this can cause the note that just finished and is perhaps ringing/reverberating to get altered undesirably. ring_time is the amount of time that we wait before reassigning a channel.

  • pitch_bend_range – By default +- 2 semitones. If a greater pitch bend is needed, this parameter will scale all pitch bend messages accordingly. It will also attempt to send RPN messages to let the synthesizer know, though in practice many softsynths ignore this and will need to have their pitch bend range set manually.

  • envelope_precision – For glissandi, volume curves, and any other parameter that is being given an Envelope, this is the temporal precision of the corresponding midi events.

  • tempo_precision – if flatten_tempo_changes is False, then this determines the precision of tempo change MIDI events during gradual accelerandi/ritardandi.

apply_note_filter(filter_function: Callable[[PerformanceNote], None], start_beat: float = 0, stop_beat: Optional[float] = None, selected_voices: Optional[Sequence[str]] = None)

Applies a filter function to every note in this Performance. This can be used to apply a transformation to the entire Performance on a note-by-note basis.

Parameters:
  • filter_function – function taking a PerformanceNote object and modifying it in place

  • start_beat – beat to start on

  • stop_beat – beat to stop on (None keeps going until the end of the part)

  • selected_voices – which voices to take notes from (defaults to all if None)

Returns:

self, for chaining purposes

apply_pitch_filter(filter_function: Callable[[Envelope | float], Envelope | float], start_beat: float = 0, stop_beat: Optional[float] = None, selected_voices: Optional[Sequence[str]] = None)

Applies a filter function to transform the pitch of every note in this Performance.

Parameters:
  • filter_function – function taking a pitch (can be envelope, float, or even a chord tuple) and returning another pitch-like object. If the performance hasn’t been quantized and you’re not using any glissandi, though, you can assume the pitch is a float.

  • start_beat – beat to start on

  • stop_beat – beat to stop on (None keeps going until the end of the part)

  • selected_voices – which voices to take notes from (defaults to all if None)

Returns:

self, for chaining purposes

apply_volume_filter(filter_function: Callable[[Envelope | float], Envelope | float], start_beat: float = 0, stop_beat: Optional[float] = None, selected_voices: Optional[Sequence[str]] = None)

Applies a filter function to transform the volume of every note in this Performance.

Parameters:
  • filter_function – function taking a volume (can be envelope or float) and returning another volume-like object. If you haven’t used any envelopes, though, you can assume the pitch is a float.

  • start_beat – beat to start on

  • stop_beat – beat to stop on (None keeps going until the end of the part)

  • selected_voices – which voices to take notes from (defaults to all if None)

Returns:

self, for chaining purposes

duplicate() T

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

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

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

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

to_score(quantization_scheme: Optional[QuantizationScheme] = None, time_signature: Optional[Union[str, Sequence]] = None, bar_line_locations: Optional[Sequence[float]] = None, max_divisor: Optional[int] = None, max_divisor_indigestibility: Optional[int] = None, simplicity_preference: Optional[float] = None, title: str = 'default', composer: str = 'default') Score[source]

Convert this Performance (list of note events in continuous time and pitch) to a Score object, which represents the music in traditional western notation. In the process, the music must be quantized, for which two different options are available: one can either pass a QuantizationScheme to the first argument, which is very flexible but rather verbose to create, or one can specify arguments such as time signature and max divisor directly.

Parameters:
  • quantization_scheme – The quantization scheme to be used when converting this performance into a score. If this is defined, none of the other quantization-related arguments should be defined.

  • time_signature – the time signature to be used, represented as a string, e.g. “3/4”, or a tuple, e.g. (3, 2). Alternatively, a list of time signatures can be given. If this list ends in “loop”, then the pattern specified by the list will be looped. For example, [“4/4”, “2/4”, “3/4”, “loop”] will cause the fourth measure to be in “4/4”, the fifth in “2/4”, etc. If the list does not end in “loop”, all measures after the final time signature specified will continue to be in that time signature.

  • bar_line_locations – As an alternative to defining the time signatures, a list of numbers representing the bar line locations can be given. For instance, [4.5, 6.5, 8, 11] would result in bars of time signatures 9/8, 2/4, 3/8, and 3/4

  • max_divisor – The largest divisor that will be allowed to divide the beat.

  • max_divisor_indigestibility – Indigestibility, devised by composer Clarence Barlow, is a measure of the “primeness” of a beat divisor, and therefore of its complexity from the point of view of a performer. For instance, it is easier to divide a beat in 8 than in 7, even though 7 is a smaller number. See Clarence’s paper here: https://mat.ucsb.edu/Publications/Quantification_of_Harmony_and_Metre.pdf. By setting a max indigestibility, we can allow larger divisions of the beat, but only so long as they are easy ones. For instance, a max_divisor of 16 and a max_divisor_indigestibility of 8 would allow the beat to be divided in 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, and 16.

  • simplicity_preference – This defines the degree to which the quantizer will favor simple divisors. The higher the simplicity preference, the more precisely the notes have to fit for you to get a divisor like 7. Simplicity preference can range from 0 (in which case the divisor is chosen purely based on the lowest error) to infinity, with a typical value somewhere around 1.

  • title – Title of the piece to be printed on the score.

  • composer – Composer of the piece to be printed on the score.

Returns:

the resulting Score object, which can then be rendered either as XML or LilyPond

transpose(interval: float)

Transposes all notes in this Performance up or down by the desired interval. For greater flexibility, use the apply_pitch_filter and apply_note_filter methods.

Parameters:

interval – the interval by which to transpose this Performance

Returns:

self, for chaining purposes