synthvoice

Advanced synthio voices

  • Author(s): Cooper Dalrymple

Implementation Notes

Hardware:

Software and Dependencies:

class synthvoice.AREnvelope(attack_time: float = 0.05, release_time: float = 0.05, amount: float = 1.0)

A simple attack, sustain and release envelope using linear interpolation. Useful for controlling parameters of a synthio.Note object other than amplitude which accept synthio.BlockInput values.

Parameters:
  • attack – The amount of time to go from 0.0 to the specified amount in seconds when the envelope is pressed. Must be greater than 0.0s. Default is 0.05s.

  • release – The amount of time to go from the specified amount back to 0.0 in seconds when the envelope is released. Must be greater than 0.0s. Default is 0.05s

  • amount – The level at which to rise or fall to when the envelope is pressed. Value is arbitrary and can be positive or negative, but 0.0 will result in no change. Default is 1.0.

property amount: float

The level at which to rise or fall to when the envelope is pressed (or sustained value). If the envelope is currently in the attack/press state, the targeted value will be updated immediately. Valu7e is arbitrary and can be positive or negative, but 0.0 will result in no change.

property attack_time: float

The rate of attack in seconds. When changing if the envelope is currently in the attack state, it will update the rate immediately. Must be greater than 0.0s.

property block: synthio.BlockInput

Get the synthio.BlockInput object to be applied to a parameter.

property blocks: tuple[synthio.BlockInput]

Get all synthio.BlockInput objects. In order for it to function properly, these blocks must be added to the primary synthio.Synthesizer object using synth.blocks.append(…).

press()

Active the envelope by setting it into the “pressed” state. The envelope’s attack phase will start immediately.

property pressed: bool

Whether or not the envelope is currently in a “pressed” state.

release()

Deactivate the envelope by setting it into the “released” state. The envelope’s release phase will start immediately.

property release_time: float

The rate of release in seconds. If the envelope is currently in the release state, it will update the rate immediately. Must be greater than 0.0s.

property value: float

Get the current value of the envelope.

class synthvoice.LerpBlockInput(rate: float = 0.05, value: float = 0.0)

Creates and manages a synthio.BlockInput object to “lerp” (linear interpolation) between an old value and a new value. Useful for note frequency “glide” and custom envelopes.

Parameters:
  • rate – The speed at which to go between values, in seconds. Must be greater than 0.0s. Defaults to 0.05s.

  • value – The initial value. Defaults to 0.0.

Constructor method

property block: synthio.BlockInput

Get the block input to be used with a synthio.Note object.

property blocks: tuple[synthio.BlockInput]

Get all synthio.BlockInput objects. In order for it to function properly, these blocks must be added to the primary synthio.Synthesizer object using synth.blocks.append(…).

property rate: float

The rate of change of interpolation in seconds. Must be greater than 0.001s.

property value: float

Get the current value of the linear interpolation output or set a new value to begin interpolation to from the current value state. Causes the interpolation process to retrigger.

class synthvoice.Voice(synthesizer: synthio.Synthesizer)

A “voice” to be used with a synthio.Synthesizer object. Manages one or multiple synthio.Note objects.

The standard Voice class is not meant to be used directly but instead inherited by one of the provided voice classes or within a custom class. This class helps manage note frequency, velocity, and filter state and provides an interface with a synthio.Synthesizer object.

Parameters:

synthesizer – The synthio.Synthesizer object this voice will be used with.

property amplitude: float

The volume of the voice from 0.0 to 1.0. This method should be implemented within the child class.

property blocks: tuple[synthio.BlockInput]

Get all synthio.BlockInput objects attributed to this voice.

property filter_frequency: float

The frequency of the filter in hertz. The maximum value allowed and default is half of the sample rate (the Nyquist frequency).

property filter_mode: synthio.FilterMode

The type of the filter. Defaults to synthio.FilterMode.LOW_PASS.

property filter_resonance: float

The resonance of the filter (or Q factor) as a number starting from 0.7. Defaults to 0.7.

property notes: tuple[synthio.Note]

Get all synthio.Note objects attributed to this voice.

press(notenum: int, velocity: float | int = 1.0) bool

Update the voice to be “pressed” with a specific MIDI note number and velocity. Returns whether or not a new note is received to avoid unnecessary retriggering. The envelope is updated with the new velocity value regardless. Updating synthio.Note objects should typically occur within the child class after calling this method and checking its return value.

Parameters:
  • notenum – The MIDI note number representing the note frequency.

  • velocity – The strength at which the note was received, between 0.0 and 1.0. Defaults to 1.0. If an int value is used, it will be divided by 127 assuming that it is a midi velocity value.

property pressed: bool

Whether or not the voice is currently in a “pressed” state.

release() bool

Release the voice if a note is currently being played. Returns True if a note was released and False if not.

update() None

Update all time-based voice logic controlled outside of synthio such as filter modulation.

property velocity_amount: float

The amount that this voice will respond to note velocity, from 0.0 to 1.0. A value of 0.0 represents no response to velocity. The voice will be at full level regardless of note velocity. Whereas a value of 1.0 represents full response to velocity.

class synthvoice.oscillator.Oscillator(synthesizer: synthio.Synthesizer, root: float = 440.0)

A complex single-voice Oscillator with the following features: - amplitude & filter envelopes - LFOs (low-frequency oscillators) for amplitude (tremolo), filter, pitch (vibrato), & panning - pitch glide - waveform looping

Parameters:
  • synthesizer – The synthio.Synthesizer object this voice will be used with.

  • root – The root frequency used to calculate tuning. Defaults to 440.0hz. Changing this value will effect tuning properties.

property amplitude: float

The relative amplitude of the oscillator from 0.0 to 1.0. An amplitude of 0 makes the oscillator inaudible. Defaults to 1.0.

property attack_level: float

The level that the amplitude envelope will reach after the attack time has passed as a relative value of amplitude from 0.0 to 1.0. Defaults to 1.0.

property attack_time: float

The rate of attack of the amplitude envelope in seconds. Must be greater than 0.0s. Defaults to 0.001s.

property bend: float

The pitch bend value which changes the oscillator frequency by a relative amount. Positive and negative range is defined by bend_range. Defaults to 0.0.

property bend_range: float

The maximum amount the oscillator frequency will “bend” when setting the bend property in octaves. Can be positive or negative, and the bend property can scale this range in both directions. Defaults to 0.0

Example settings: - 2.0 = up two octaves - -1.0 = down one octave - 1.0/12.0 = up one semitone (chromatic note)

property blocks: tuple[synthio.BlockInput]

Get all synthio.BlockInput objects attributed to this voice.

property coarse_tune: float

The amount of tuning from the root frequency of the oscillator (typically 440.0hz) in octaves. Ie: 1.0 = 880.hz, -2.0 = 110.0hz. Defaults to 0.0.

property decay_time: float

The rate of decay after reaching the attack_level of the amplitude envelope in seconds. Must be greater than 0.0s. Defaults to 0.001s.

property filter_amount: float

The level to add to the filter_frequency in hertz after the filter envelope attack time has passed. This value will be sustained until release() is called. Defaults to 0hz.

property filter_attack_time: float

The rate of attack of the filter frequency envelope from filter_frequency to filter_frequency plus filter_amount in seconds. Must be greater than 0.0s. Defaults to 0.001s.

property filter_delay: float

The amount of time to gradually increase the depth of the filter LFO in seconds. Must be greater than 0.0s. Defaults to 0.001s.

property filter_depth: float

The maximum level of the filter LFO to add to filter_frequency in hertz in both positive and negative directions. Defaults to 0.0hz.

property filter_rate: float

The rate in hertz of the filter frequency LFO. Defaults to 1.0hz.

property filter_release_time: float

The rate of release of the filter frequency envelope back to filter_frequency in seconds. Must be greater than 0.0s. Defaults to 0.001s.

property fine_tune: float

The amount of tuning from the root frequency of the oscillator (typically 440.0hz) in semitones (1/12 of an octave). Ie: 1.0 = 466.16hz (A#4) and -1.0 = 415.30hz (G#4). Defaults to 0.0.

property frequency: float

The frequency in hertz to set the oscillator to. Updating this value will active the frequency lerp block to gradually change the note frequency based on the glide settings of this voice.

property glide: float

The length of time it takes for the oscillator to “glide” (transition) between frequencies in seconds.

property notes: tuple[synthio.Note]

Get all synthio.Note objects attributed to this voice.

property pan: float

The distribution of the oscillator amplitude in the channel(s) output from -1.0 (left) to 1.0 (right). Defaults to 0.0.

property pan_delay: float

The amount of time to gradually increase the depth of the panning LFO in seconds. Must be greater than 0.0s. Defaults to 0.001s.

property pan_depth: float

The depth of the panning LFO from 0.0 to 1.0. This value is added to pan. Negative values are allowed and will flip the phase of the LFO. Defaults to 0.0.

property pan_rate: float

The rate of the panning LFO in hertz. Defaults to 1.0.

property pitch_slew: float

The pitch offset in octaves at which the voice starts relative to the desired frequency when first pressed. Can be either positive or negative. Defaults to 0.0.

property pitch_slew_time: float

The amount of time in seconds it takes for the voice to reach the desired pitch after starting with a relative pitch_slew adjustment. Must be greater than 0.0s. Defaults to 0.001s.

press(notenum: int, velocity: float | int = 1.0) bool

Update the voice to be “pressed” with a specific MIDI note number and velocity. Returns whether or not a new note is received to avoid unnecessary retriggering. The envelope is updated with the new velocity value regardless.

Parameters:
  • notenum – The MIDI note number representing the note frequency.

  • velocity – The strength at which the note was received, between 0.0 and 1.0.

release() bool

Release the voice if a note is currently being played. Returns True if a note was released and False if not.

property release_time: float

The rate of decay of the amplitude envelope to 0.0 after release() is called in seconds. Must be greater than 0.0s. Defaults to 0.001s.

property sustain_level: float

The level that the amplitude envelope will reach after the decay time has passed as a relative value of amplitude from 0.0 to 1.0. The note will sustain with this level until release() is called. Defaults to 0.75.

property tremolo_delay: float

The amount of time to gradually increase the depth of the amplitude LFO in seconds. Must be greater than 0.0s. Defaults to 0.001s.

property tremolo_depth: float

The depth of the amplitude LFO. This value is added to amplitude. Defaults to 0.0.

property tremolo_rate: float

The rate of the amplitude LFO in hertz. Defaults to 1.0hz.

property vibrato_delay: float

The amount of time to gradually increase the depth of the frequency LFO in seconds. Must be greater than 0.0s. Defaults to 0.001s.

property vibrato_depth: float

The depth of the frequency LFO in octaves relative to the current note frequency and bend. Defaults to 0.0.

property vibrato_rate: float

The rate of the frequency LFO in hertz. Defaults to 1.0hz.

property waveform: array | bytearray | bytes | memoryview | rgbmatrix.RGBMatrix | ulab.numpy.ndarray | None

The waveform of the oscillator.

property waveform_loop: tuple[float, float]

The start and stop points of which to loop waveform data as a tuple of two floats from 0.0 to 1.0. The end value must be greater than the start value. Default is (0.0, 1.0) or the full range of the waveform.

class synthvoice.sample.Sample(synthesizer: synthio.Synthesizer, looping: bool = True, file: str | None = None, max_size: int = 4096)

Voice which will play back an audio file. Handles pitch, looping points, and “.wav” file loading and inherits all properties and functionality of synthvoice.oscillator.Oscillator.

Parameters:
  • synthesizer – The synthio.Synthesizer object this voice will be used with.

  • looping – Whether or not to continuously loop the sample or play it once when the voice is pressed. Defaults to true.

  • file – The path to the compatible audio file (16-bit integer “.wav”). Leave unset to initialize the voice without a specified sample. Defaults to None.

  • max_size – The maximum number of samples to load into the waveform from the sample file.

property duration: float

The length of the audio sample given the current state (includes note bend properties).

property file: str | None

The path to a 16-bit signed integer audio “.wav” file within the virtual file system. The audio sample rate and root frequency will automatically be calculated bye the file properties and with an FFT algorithm. An invalid file type will raise ValueError.

looping: bool = True

Whether or not to continuously loop the sample or play it once when the voice is pressed.

press(notenum: int, velocity: float | int = 1.0) bool

Update the voice to be “pressed” with a specific MIDI note number and velocity. Returns whether or not a new note is received to avoid unnecessary retriggering. The envelope is updated with the new velocity value regardless.

Parameters:
  • notenum – The MIDI note number representing the note frequency.

  • velocity – The strength at which the note was received, between 0.0 and 1.0. Defaults to 1.0. If an int value is used, it will be divided by 127 assuming that it is a midi velocity value.

property sample_rate: int

The recorded audio sample rate of the waveform data in hertz.

update()

Update sample timing when looping is set to False.

property waveform_loop: tuple[float, float]

The start and stop points of which to loop the sample as a tuple of two floats from 0.0 to 1.0. The end value must be greater than the start value. Default is (0.0, 1.0) or the full length of the sample.

synthvoice.sample.fft(data: ulab.numpy.ndarray, log: bool = True, length: int = 1024) ulab.numpy.ndarray

Perform the Fourier Fast Transform (FFT) on data.

Parameters:
  • data – The data to be processed, typically audio samples. The data type must be either ulab.numpy.int16 or ulab.numpy.uint16 or else a ValueError will be raised.

  • log – Use the logarithmic function on the output to convert the result to decibels. Defaults to True.

  • length – The resulting length of the spectrogram array. A larger value will be more precise but require more processing and RAM usage.

synthvoice.sample.fftfreq(data: ulab.numpy.ndarray, sample_rate: int)

Use the Fast Fourier Transform to determine the peak frequency of the signal.

Parameters:
  • data – The data to be processed, typically audio samples. The data type must be either ulab.numpy.int16 or ulab.numpy.uint16 or else a ValueError will be raised.

  • sample_rate – The rate at which the data was recorded in hertz.

synthvoice.sample.normalize(data: ulab.numpy.ndarray) ulab.numpy.ndarray

Scale the data so that it reaches the maximum peak capable of the data type (+32767 for ulab.numpy.int16).

Parameters:

data – The data to be normalized, typically audio samples. The data type must be ulab.numpy.int16 or else a ValueError will be raised.

class synthvoice.percussive.ClosedHat(synthesizer: synthio.Synthesizer)

A single-shot “analog” drum voice representing a closed hi-hat cymbal using noise waveforms.

class synthvoice.percussive.Cymbal(synthesizer: synthio.Synthesizer, time: float, frequency: float = 9500.0)

The base class to create cymbal sounds with variable timing.

Parameters:
  • min_time – The minimum decay time in seconds. Must be greater than 0.0s.

  • max_time – The maximum decay time in seconds. Must be greater than min_time.

class synthvoice.percussive.FloorTom(synthesizer: synthio.Synthesizer)

A single-shot “analog” drum voice representing a low or floor tom drum.

class synthvoice.percussive.HighTom(synthesizer: synthio.Synthesizer)

A single-shot “analog” drum voice representing a high or left rack tom drum.

class synthvoice.percussive.Kick(synthesizer: synthio.Synthesizer)

A single-shot “analog” drum voice representing a low frequency sine-wave kick drum.

class synthvoice.percussive.MidTom(synthesizer: synthio.Synthesizer)

A single-shot “analog” drum voice representing a middle or right rack tom drum.

class synthvoice.percussive.OpenHat(synthesizer: synthio.Synthesizer)

A single-shot “analog” drum voice representing an open hi-hat cymbal using noise waveforms.

class synthvoice.percussive.Ride(synthesizer: synthio.Synthesizer)

A single-shot “analog” drum voice representing a ride cymbal using noise waveforms.

class synthvoice.percussive.Snare(synthesizer: synthio.Synthesizer)

A single-shot “analog” drum voice representing a snare drum using sine and noise waveforms.

class synthvoice.percussive.Tom(synthesizer: synthio.Synthesizer, time: float, frequency: float)

The base class to create tom drum sounds with variable timing and frequency.

Parameters:
  • min_time – The minimum decay time in seconds. Must be greater than 0.0s.

  • max_time – The maximum decay time in seconds. Must be greater than min_time.

  • min_frequency – The minimum frequency in hertz.

  • max_frequency – The maximum frequency in hertz.

class synthvoice.percussive.Voice(synthesizer: synthio.Synthesizer, count: int = 3, filter_mode: synthio.FilterMode = synthio.FilterMode.LOW_PASS, filter_frequency: float = 20000.0, frequencies: tuple[float] = [], times: tuple[float] = [], waveforms: tuple[array | bytearray | bytes | memoryview | rgbmatrix.RGBMatrix | ulab.numpy.ndarray] | array | bytearray | bytes | memoryview | rgbmatrix.RGBMatrix | ulab.numpy.ndarray = [])

Base single-shot “analog” drum voice used by other classes within the percussive module. Handles envelope times, tuning, waveforms, etc. for multiple synthio.Note objects.

Parameters:
  • count – The number of synthio.Note objects to generate. Defaults to 3.

  • filter_mode – The type of filter to use. Defaults to synthio.FilterMode.LOW_PASS.

  • filter_frequency – The exact frequency of the filter of all synthio.Note objects in hertz. Defaults to 20000hz.

  • frequencies – A list of the frequencies corresponding to each synthio.Note object in hertz. Voice doesn’t respond to the note frequency when pressed and instead uses these constant frequencies. Defaults to 440.0hz if not provided.

  • times – A list of decay times corresponding to each synthio.Note objects’ amplitude envelope in seconds. Defaults to 1.0s for all notes if not provided.

  • waveforms – A list of waveforms corresponding to each synthio.Note object as numpy.int16 arrays. Defaults to a square waveform for each note.

property amplitude: float

The volume of the voice from 0.0 to 1.0.

property attack_level: float

The level of attack of the amplitude envelope from 0.0 to 1.0.

property blocks: tuple[synthio.BlockInput]

Get all synthio.BlockInput objects attributed to this voice.

property decay_time: float

The amount of decay of the amplitude envelope relative to the initial decay time. 0.0 is the default amount of decay, 1.0 is double the decay, and -1.0 is half the decay.

property frequencies: tuple[float]

The base frequencies in hertz.

property notes: tuple[synthio.Note]

Get all synthio.Note objects attributed to this voice.

property pan: float

The stereo panning of the voice from -1.0 (left) to 1.0 (right).

press(velocity: float | int = 1.0) bool

Update the voice to be “pressed”. For percussive voices, this will begin the playback of the voice.

Parameters:

velocity – The strength at which the note was received, between 0.0 and 1.0.

release() bool

Release the voice. synthvoice.percussive.Voice objects typically don’t implement this operation because of their “single-shot” nature and will always return False.

property times: tuple[float]

The decay times of the amplitude envelopes.

property tune: float

The amount of tuning form the root frequencies of the voice in semitones (1/12 of an octave). Defaults to 0.0.

property waveforms: tuple[array | bytearray | bytes | memoryview | rgbmatrix.RGBMatrix | ulab.numpy.ndarray]

The note waveforms as ulab.numpy.ndarray objects with the ulab.numpy.int16 data type.