relic_synthvoice
Advanced synthio voices
Author(s): Cooper Dalrymple
Implementation Notes
Hardware:
Software and Dependencies:
Adafruit CircuitPython firmware for the supported boards: https://circuitpython.org/downloads
CircuitPython Waveform library: https://github.com/relic-se/CircuitPython_Waveform
- class relic_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.Noteobject other than amplitude which acceptsynthio.BlockInputvalues.- 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.BlockInputobject to be applied to a parameter.
- property blocks: tuple[synthio.BlockInput]
Get all
synthio.BlockInputobjects. In order for it to function properly, these blocks must be added to the primarysynthio.Synthesizerobject using synth.blocks.append(…).
- press()
Active the envelope by setting it into the “pressed” state. The envelope’s attack phase will start immediately.
- release()
Deactivate the envelope by setting it into the “released” state. The envelope’s release phase will start immediately.
- class relic_synthvoice.LerpBlockInput(rate: float = 0.05, value: float = 0.0)
Creates and manages a
synthio.BlockInputobject 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.Noteobject.
- property blocks: tuple[synthio.BlockInput]
Get all
synthio.BlockInputobjects. In order for it to function properly, these blocks must be added to the primarysynthio.Synthesizerobject using synth.blocks.append(…).
- class relic_synthvoice.Voice(synthesizer: synthio.Synthesizer)
A “voice” to be used with a
synthio.Synthesizerobject. Manages one or multiplesynthio.Noteobjects.The standard
Voiceclass 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 asynthio.Synthesizerobject.- Parameters:
synthesizer – The
synthio.Synthesizerobject 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.BlockInputobjects 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.Noteobjects 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.Noteobjects 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
intvalue is used, it will be divided by 127 assuming that it is a midi velocity value.
- release() bool
Release the voice if a note is currently being played. Returns
Trueif a note was released andFalseif not.
- class relic_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.Synthesizerobject this voice will be used with.root – The root frequency used to calculate tuning. Defaults to 440.0hz. Changing this value will affect 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
amplitudefrom 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
bendproperty in octaves. Can be positive or negative, and thebendproperty can scale this range in both directions. Defaults to 0.0Example 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.BlockInputobjects 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_levelof 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_frequencyin hertz after the filter envelope attack time has passed. This value will be sustained untilrelease()is called. Defaults to 0hz.
- property filter_attack_time: float
The rate of attack of the filter frequency envelope from
filter_frequencytofilter_frequencyplusfilter_amountin 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_frequencyin hertz in both positive and negative directions. Defaults to 0.0hz.
- 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_release_time: float
The rate of release of the filter frequency envelope back to
filter_frequencyin 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 activate 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.Noteobjects 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 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_slewadjustment. 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
Trueif a note was released andFalseif 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
amplitudefrom 0.0 to 1.0. The note will sustain with this level untilrelease()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 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 waveform: array | bytearray | bytes | memoryview | rgbmatrix.RGBMatrix | ulab.numpy.ndarray | None
The waveform of the oscillator.
- class relic_synthvoice.sample.Sample(synthesizer: synthio.Synthesizer, looping: bool = True, file: str = 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
relic_synthvoice.oscillator.Oscillator.- Parameters:
synthesizer – The
synthio.Synthesizerobject 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
intvalue is used, it will be divided by 127 assuming that it is a midi velocity value.
- relic_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.int16orulab.numpy.uint16or else aValueErrorwill 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.
- relic_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.int16orulab.numpy.uint16or else aValueErrorwill be raised.sample_rate – The rate at which the data was recorded in hertz.
- relic_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.int16or else aValueErrorwill be raised.
- class relic_synthvoice.drone.Drone(synthesizer: synthio.Synthesizer, max_oscillators: int = 3, root: float = 130.81)
A multi-oscillator voice intended to generate “droning” synthesizer sounds with the following features:
per-oscillator tuning and detuning
amplitude & filter envelopes
LFOs (low-frequency oscillators) for amplitude (tremolo), filter, & pitch (vibrato)
pitch glide
- Parameters:
synthesizer – The
synthio.Synthesizerobject this voice will be used with.max_oscillators – The maximum number of oscillators to control with this voice. Must be greater than 1.
root – The root frequency used to calculate tuning. Defaults to 440.0hz. Changing this value will affect tuning properties.
- property amplitude: float
The relative amplitude of the oscillators from 0.0 to 1.0. An amplitude of 0 makes the oscillators inaudible. Defaults to 1 divided by the number of oscillators (ie: 0.333 if using 3 oscillators).
- property attack_time: float
The rate of attack of the amplitude envelope to 1.0 after
press()is called in seconds. Must be greater than 0.0s. Defaults to 0.001s.
- property blocks: tuple[synthio.BlockInput]
Get all
synthio.BlockInputobjects attributed to this voice.
- property detune: float | tuple
The amount of detuning from the root frequency and tune of the oscillators (typically 440.0hz) in octaves. Ie: 1.0 = 880.hz, -2.0 = 110.0hz. To assign individual values for each drone voice, provide a tuple of float values. Defaults to 0.0.
- property filter_amount: float
The level to add to the
filter_frequencyin hertz after the filter envelope attack time has passed. This value will be sustained untilrelease()is called. Defaults to 0hz.
- property filter_attack_time: float
The rate of attack of the filter frequency envelope from
filter_frequencytofilter_frequencyplusfilter_amountin 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_frequencyin hertz in both positive and negative directions. Defaults to 0.0hz.
- 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_release_time: float
The rate of release of the filter frequency envelope back to
filter_frequencyin seconds. Must be greater than 0.0s. Defaults to 0.001s.
- property filter_resonance: float
The resonance of the filter (or Q factor) as a number starting from 0.7. Defaults to 0.7.
- property frequency: float
The frequency in hertz to set the oscillators to. Updating this value will activate 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 oscillators to “glide” (transition) between frequencies in seconds.
- property notes: tuple[synthio.Note]
Get all active
synthio.Noteobjects attributed to this voice.
- property oscillators: int
The number of active oscillators from 1 up to the maximum number of oscillators defined in the constructor. If the voice is pressed and this value is changed, any oscillators added will be pressed and any oscillators removed will be released.
- press(notenum: int | None = None, 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. If this parameter is not provided, the root frequency will be used.
velocity – The strength at which the note was received, between 0.0 and 1.0. Although, velocity is not utilized by this voice.
- release() bool
Release the voice if a note is currently being played. Returns
Trueif a note was released andFalseif 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 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 tune: float | tuple
The amount of tuning from the root frequency of the oscillators (typically 440.0hz) in octaves. Ie: 1.0 = 880.hz, -2.0 = 110.0hz. To assign individual values for each drone voice, provide a tuple of float values. Defaults to 0.0.
- 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 waveform: array | bytearray | bytes | memoryview | rgbmatrix.RGBMatrix | ulab.numpy.ndarray | None
The waveform of the oscillators.
- class relic_synthvoice.percussive.ClosedHat(synthesizer: synthio.Synthesizer)
A single-shot “analog” drum voice representing a closed hi-hat cymbal using noise waveforms.
- class relic_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 relic_synthvoice.percussive.FloorTom(synthesizer: synthio.Synthesizer)
A single-shot “analog” drum voice representing a low or floor tom drum.
- class relic_synthvoice.percussive.HighTom(synthesizer: synthio.Synthesizer)
A single-shot “analog” drum voice representing a high or left rack tom drum.
- class relic_synthvoice.percussive.Kick(synthesizer: synthio.Synthesizer)
A single-shot “analog” drum voice representing a low frequency sine-wave kick drum.
- class relic_synthvoice.percussive.MidTom(synthesizer: synthio.Synthesizer)
A single-shot “analog” drum voice representing a middle or right rack tom drum.
- class relic_synthvoice.percussive.OpenHat(synthesizer: synthio.Synthesizer)
A single-shot “analog” drum voice representing an open hi-hat cymbal using noise waveforms.
- class relic_synthvoice.percussive.Ride(synthesizer: synthio.Synthesizer)
A single-shot “analog” drum voice representing a ride cymbal using noise waveforms.
- class relic_synthvoice.percussive.Snare(synthesizer: synthio.Synthesizer)
A single-shot “analog” drum voice representing a snare drum using sine and noise waveforms.
- class relic_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 relic_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.Noteobjects.- Parameters:
count – The number of
synthio.Noteobjects 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.Noteobjects in hertz. Defaults to 20000hz.frequencies – A list of the frequencies corresponding to each
synthio.Noteobject 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.Noteobjects’ amplitude envelope in seconds. Defaults to 1.0s for all notes if not provided.waveforms – A list of waveforms corresponding to each
synthio.Noteobject asnumpy.int16arrays. Defaults to a square waveform for each note.
- property blocks: tuple[synthio.BlockInput]
Get all
synthio.BlockInputobjects 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 notes: tuple[synthio.Note]
Get all
synthio.Noteobjects attributed to this voice.
- 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.
relic_synthvoice.percussive.Voiceobjects typically don’t implement this operation because of their “single-shot” nature and will always returnFalse.
- 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.ndarrayobjects with theulab.numpy.int16data type.