API

loeric.__main__.check_midi_control(groover: Groover, control2contour: dict[int, str]) Callable[[], None]

Returns a function that associates a contour name (values) for every MIDI control number in the dictionary (keys) and updates the groover accordingly. The value of the contour will be the control value mapped in the interval [0, 1].

Parameters:
  • groover – the groover object.

  • control2contour – a dictionary of control numbers associated to contour names.

Returns:

a callback function that will check for the given values.

loeric.__main__.play(groover, tune, out, args) None

Play the given tune with the given groover.

Parameters:
  • groover – the groover object

  • tune – the tune object

  • out – the output midi port

  • args – the performance arguments

loeric.loeric_utils.get_ports(input_number: int = None, output_number: int = None, list_ports: bool = False)

Return the port names associated to the given indexes. If listing ports, only input and output port names will be printed.

Parameters:
  • input_number – the input port index.

  • output_number – the output port index.

  • list_ports – whether or not to list port names and return.

Returns:

a tuple (input, output) containing the input and output port names.

loeric.loeric_utils.is_note(msg: Message) bool

Check if a midi event is a note event (either note-on or note-off).

Parameters:

msg – the message to check.

Returns:

True if the message is a note event.

loeric.loeric_utils.is_note_off(msg: Message) bool

Check if a midi event is to be considered a note-off event, that is:

  • its type is “note-off” or

  • its type is “note-on” and it has 0 velocity.

Parameters:

msg – the message to check.

Returns:

True if the message is a note on event.

loeric.loeric_utils.is_note_on(msg: Message) bool

Check if a midi event is to be considered a note-on event, that is:

  • its type is “note-on”;

  • it has non-zero velocity.

Parameters:

msg – the message to check.

Returns:

True if the message is a note on event.

class loeric.groover.Groover(tune: Tune, bpm: int = None, midi_channel: int = 0, transpose: int = 0, diatonic_errors: bool = True, random_weight: float = 0, human_impact: float = 0, seed: int = 42, apply_savgol: bool = True, config_file: str = None)

The class responsible for playback, ornamentation and human interaction.

__init__(tune: Tune, bpm: int = None, midi_channel: int = 0, transpose: int = 0, diatonic_errors: bool = True, random_weight: float = 0, human_impact: float = 0, seed: int = 42, apply_savgol: bool = True, config_file: str = None)

Initialize the groover class by setting user-defined parameters and creating the contours. Any parameters set on class instatiation that are also present in the configuration file will be overwritten. To preserve command line arguments, omit the corresponding fields from the configuration file.

Parameters:
  • tune – the tune that will be performed.

  • bpm – the user-defined tempo in bpm for the tune.

  • midi_channel – the midi output channel for all messages.

  • transpose – the number of semitones by which to transpose the tune.

  • diatonic_errors – whether or not error generation should be quantized to the tune’s mode.

  • random_weight – the weight of the random component in contour generation.

  • human_impact – the weight of the external control signal.

  • seed – the random seed of the performance.

  • apply_savgol – whether or not to apply savgol filtering in contour generation. True by default (recommended).

  • config_file – the path to the configuration file (must be a JSON file).

__weakref__

list of weak references to the object (if defined)

property _current_tempo: int
Returns:

the current tempo given the value of the tempo contour. If the option use_old_tempo_warp is set to True the contour affects tempo in terms of percentage of the original one (e.g. 20% faster); otherwise in terms of a fixed amount of bpms (e.g. 10 bpms faster).

property _current_velocity: int
Returns:

the current velocity given the value of the velocity contour.

property _cut_duration
Returns:

the duration of a cut note.

_duration_of(time: float) float

Calculate the duration in seconds in the current tempo of the input duration, given in tune tempo.

Parameters:

time – the input time value in seconds, given the original tempo.

Returns:

the new duration of the input time value in seconds.

property _eight_duration
Returns:

the duration of a eight note in seconds at current tempo.

_instantiate()

Generate all parameter settings following the current configuration.

property _roll_duration
Returns:

the duration of a single note in a roll.

property _slide_duration
Returns:

the duration of a slide.

advance_contours() None

Retrieve the next value of each contour and store it for future use.

approach_from_above(note_number: int, tune: Tune) int

Return the midi note number to approach the given note from above. If no special approach rule is specified in the configuration file, it will return the next note in the scale of the tune’s key from the given note.

Parameters:
  • note_number – the note to approach.

  • tune – the reference tune.

Returns:

the note used the approach the given note from above.

approach_from_below(note_number: int, tune: Tune) int

Return the midi note number to approach the given note from below. If no special approach rule is specified in the configuration file, it will return the previous note in the scale of the tune’s key from the given note.

Parameters:
  • note_number – the note to approach.

  • tune – the reference tune.

Returns:

the note used the approach the given note from below.

can_generate_ornament() bool
Returns:

whether or not to generate an ornament given the current ornament contour.

choose_ornament(message: Message) str

Evaluate the ornament specific rules and chooose how the note will be ornamented.

Parameters:

message – the midi message to ornament.

Returns:

the chosen ornament type.

generate_ornament(message: Message, ornament_type: str) list[Message]

Generate the sequence of notes corresponding to the chosen ornament.

Parameters:
  • message – the midi message to ornament.

  • ornament_type – the type of ornament to generate.

Returns:

the list of midi events corresponding to the chosen ornament.

perform(message: Message) list[Message]

‘Perform’ a single note event by affecting its timing, pitch, velocity and adding ornaments.

Parameters:

message – the midi message to perform.

Returns:

the list of midi messages corresponding to the input message’s performance.

reset() None

Reset all contours so that the next call to next() will yield the first value of each contour.

set_contour_value(contour_name: str, value: float) None

Set the value of a given contour to a given value until the update.

Parameters:
  • contour_name – the name of the contour.

  • value – the value to set the contour to.

Raises:

groover.UnknownContourError – if the contour name does not correspond to any of the Groover’s contours.

property tempo
Returns:

the user-set tempo.

exception loeric.groover.UnknownContourError

Raised if trying to set a contour whose name does not correspond to any of the Groover’s contours.

__weakref__

list of weak references to the object (if defined)

class loeric.contour.Contour

A class representing a note-wise intensity conotour.

__init__()

Initialize the class.

__weakref__

list of weak references to the object (if defined)

calculate(midi: Tune) None

Calculate the intensity contour for the given tune.

Parameters:

midi – the input tune.

next() float

Return the next element (i.e. intensity value) of the intensity contour.

Raises:
Returns:

the next intensity value.

ocanainn_scores(midi: Tune) tuple[array, array, array, array, array]

Computes the individual components for the ocanainn score:

  • frequency score;

  • beat score;

  • ambitus score;

  • leap score;

  • length score.

Parameters:

midi – the input tune used to compute the individual scores.

Returns:

the frequency score, the beat score, the ambitus score, the leap score and the length score.

reset() None

Resets the contour iteration. The next call to next() will return the first element of the contour.

scale_and_savgol(array: ndarray, shift: bool = False) ndarray

Scale the contour, then apply a Savitzky-Golay filter with a window of 15 and order 3. Optionally, shift the array to bring its mean closer to 0.5.

Parameters:
  • array – the input contour.

  • shift – whether or not to shift the filtered array so that its mean is close to 0.5.

Returns:

the filtered array.

class loeric.contour.IntensityContour

A contour given by the weighted sum of O’Canainn components.

__init__()

Initialize the class.

calculate(midi: Tune, weights: array = None, random_weight: float = 0, savgol: bool = True, shift: bool = False) None

Compute the contour as the weighted sum of O’Canainn component. An optional random component can be added.

Parameters:
  • midi – the input tune.

  • weights – the weights for the components, respectively frequency score, beat score, ambitus score, leap score and length score.

  • random_weight – the weight of the random component over the sum of the weighted O’Canainn scores. If None, the components will be averaged together.

  • savgol – whether or not to apply a final savgol filtering step (recommended).

  • shift – whether or not to apply a final shifting step to bring the mean of the array close to 0.5.

exception loeric.contour.InvalidIndexError

Raised if the index of the current value is below 0 or exceeds the length of the contour.

__weakref__

list of weak references to the object (if defined)

class loeric.contour.MessageLengthContour

A contour holding the length of each note in the tune.

__init__()

Initialize the class.

calculate(midi: Tune) None

Calculate the contour as the length of each note message (from each note on message to the next note off message).

Parameters:

midi – the input tune object.

class loeric.contour.PitchDifferenceContour

A contour holding the pitch difference between notes in the tune.

__init__()

Initialize the class.

calculate(midi: Tune) None

Calculate the intensity contour for the given tune.

Parameters:

midi – the input tune.

class loeric.contour.RandomContour

A randomly initialized contour.

__init__()

Initialize the class.

calculate(midi: Tune, extremes: tuple[float, float] = None) None

Compute a random contour following a uniform distribution in the specified range, by default between 0 and 1.

Parameters:
  • midi – the input tune.

  • extremes – the upper and lower bound for the random contour. If None, the range will be (0, 1).

exception loeric.contour.UncomputedContourError

Raised if the contour has not been computed yet.

__weakref__

list of weak references to the object (if defined)

class loeric.tune.Tune(filename: str)

A wrapper for a midi file.

__getitem__(idx: int) Message

Return the item in the midi event list corresponding to the given index.

Parameters:

idx – the element index.

Returns:

the midi message corresponding to that index.

__init__(filename: str)

Initialize the class. A number of properties is computed:

  • the duration of the pickup bar, if there is any;

  • the key signature (only the first encountered is considered, key signature changes are not supported);

  • the time signature (only the first encountered is considered, time signature changes are not supported);

Parameters:

filename – the path to the midi file.

__len__() int

Return the length of the list of midi messages.

Returns:

the number of midi messages in this tune.

__weakref__

list of weak references to the object (if defined)

_get_key_signature() str

Retrieve the key signature of the tune, if there is any. Only the first key signature will be retrieved.

Returns:

the first key signature if there is any, else None.

_get_original_tempo() int

Retrieve the tempo of the tune, if there is any. Only the first tempo change will be retrieved.

Returns:

the first tempo change if there is any, else None.

_get_performance_offset() float

Return the length of the pickup bar, if there is any.

Returns:

the length of the pickup bar in seconds.

_get_time_signature() TimeSignature

Retrieve the time signature of the tune, if there is any. Only the first time signature will be retrieved.

Returns:

the first time signature if there is any, else None.

property _quarter_duration: float

Return the duration of a quarter note in seconds given the current tempo.

Returns:

the amount of seconds corresponding to a quarter note given the current tempo.

property bar_duration: float
Returns:

the tune’s bar duration in seconds.

property beat_duration: float
Returns:

the tune’s beat duration in seconds.

events() Generator[Message, None, None]

A generator returning each midi event in the tune. Each time an event is retrieved, the performance time is updated.

Returns:

the sequence of midi events one by one

filter(filtering_function: Callable[[Message], bool]) list[Message]

Retrieve the midi events that fullfill the given filtering function.

Parameters:

filtering_function – the function filtering the midi events.

Returns:

a list of midi events fullfilling the filtering function.

is_on_a_beat() bool

Decide if we are on a beat or not, given the current cumulative performance time.

Returns:

True if we are on a beat.

property key_signature: str
Returns:

the tune’s key signature.

property offset: float
Returns:

the tune’s performance offset (i.e. the length of the pickup bar) in seconds.

semitones_from_tonic(midi_note: int) int

Compute the distance between the given note and the tonic of the tune in semitones.

Parameters:

midi_note – the input note.

Returns:

the distance between note and the tonic in semitones.

property tempo: int
Returns:

the tune’s tempo in microseconds per quarter.

property time_signature: TimeSignature
Returns:

the tune’s time signature.

class loeric.player.Player(tempo: int, key_signature: str, time_signature: TimeSignature, save: bool, midi_out)

The class responsible for performance playback and saving.

__init__(tempo: int, key_signature: str, time_signature: TimeSignature, save: bool, midi_out)

Initialize the class.

Parameters:
  • tempo – the performance’s tempo in microseconds per quarter note.

  • key_signature – the performance’s key signature.

  • time_signature – the performance’s time signature.

  • save – whether or not to save the performance to a midi file

  • midi_out – the output midi port.

__weakref__

list of weak references to the object (if defined)

play(messages: list[Message]) None

Play the messages in input and append them to the generated performance. If no midi port has been specified, the messages only be saved.

Parameters:

messages – the midi messages to play.

save(filename: str) None

Save the generated performance as a midi file.

Parameters:

filename – the path to the output midi file.