Detailed Documentation¶
STRAUSS (Sonification Tools and Resources for Astronomer Using Sound Synthesis)
This module provides a toolkit for sonification, i.e. the representation of data using sound.
Sources¶
The
sourcessubmodule: representing data as sound sources.This submodule deals with the mapping of input datasets to the parameters controlling sound in the eventual sonification.
- strauss.sources.mappable¶
List of strings indicating possible sonification parameters to which data can be mapped.
- Type:
list(str)
- strauss.sources.evolvable¶
List of strings indicating the subset of mappable parameters that can be evolved continuosly for an individual Source.
- Type:
list(str)
- strauss.sources.param_limits¶
List of tuples indicating the default numerical ranges bounding corresponding mappable parameter (e.g. 0-1 for volume).
- Type:
list(tuple)
- strauss.sources.param_lim_dict¶
Dictionary combining mappable (keys) and param_limits (items).
- Type:
dictTodo
Store mappable, evolvable and parameter ranges in YAML files (cleaner).
Specialised Event and Object child classes (eg. spectralisation).
- class strauss.sources.Events(mapped_quantities)[source]¶
Represent data as time-discrete events.
Child class of Source, for Event-type sources. Each Event is discrete in time with single data values mapped to each sonification parameter.
- fromdict(datadict)[source]¶
Take input data from dictionary
- Parameters:
datadict (
dict) – keys are self.mapped_values, with entries corresponding to the input data. Multiple sources are provided aslists, with data for each source corresponding to the values. Single sources can be represented as single values.
- class strauss.sources.Objects(mapped_quantities)[source]¶
Represent data as time-continuous objects.
Child class of Source. In addition to supporting single values for each parameter (see Events class), objects also support time evolution for evolvable parameters, given a time-evo mapping.
Todo
implement
fromfilemethod
- fromdict(datadict)[source]¶
Take input data from dictionary
- Parameters:
datadict (
dict) – keys are self.mapped_values, with entries corresponding to the input data. Multiple sources are provided as eitherlistsor 2Dnumpy.arrayobjects, with each source corresponding to the entries or columns respectively. Single sources can be represented as single values or 1Dnumpy.array(for evolving parameters).
- class strauss.sources.Source(mapped_quantities)[source]¶
Generic source class defining common methods/attributes
Source and its child classes represent the input data, and its mapping to sonification parameters.
Note
Source isn’t used directly, instead use child classes Events or Objects.
- Parameters:
mapped_quantities (
list(str)) – The subset of parameters to which data will be mapped.- Raises:
UnrecognisedProperty – if mapped_quantities entry not in mappable.
- apply_mapping_functions(map_funcs={}, map_lims={}, param_lims={})[source]¶
Taking input data and mapping to parameters.
This function does the bulk of the work for Source classes, taking each input data variable and applying the mapping function (x’ = x by default), descaling by the x’ upper and lower limits and rescaling to the sonification parameter limits. These values are stored for non-evolving parameters, while for evolving properties are converted to interpolation functions.
- Parameters:
map_funcs (
dict, optional) – dict with keys that must be a subset self.mapped_quantities. Entries are then function-like objects for converting input data (e.g. taking log of a data set). If not provided, each conversion function is assumed to be f(x) = x.map_lims (
dict, optional) – dict with keys that must be a subset self.mapped_quantities. Entries are tuples indicating the lower (index 0) and upper (index 1) limits on the converted input data values. numerical values indicate absolute limits, while strings indicate percentiles [e.g. (‘10’,’95’)]. converted data values are clipped to these limits. If not provided, (0,1) is assumed.param_lims (
dict, optional) – dict with keys that must be a subset self.mapped_quantities. Entries are tuples indicating the lower (index 0) and upper (index 1) limits of the mapped sonification parameters. The map_lims ranges are resaled to these ranges to give the parameter values. If not provided, the default param_lim_dict values are taken.Note
There is special behaviour for the polar and azimuth parameters, to ensure shortest angular distance when interpolating across the 0-2pi and 0-pi boundaries.
Score¶
The
scoresubmodule: musical constraints on whatSourcescan playThis submodule is intended to control any musical aspects of the sonification, by providing constraints on harmonic and rhythmic aspects.
Todo
Incorporate more rhythmic options, such as quantisation
Have the
Scoreclass handle pitch and rhythm assignment fromSourcesdirectly, instead of theSonificationclass.Support chord change intervals as a mapped parameter
Provide template chord charts for users
- class strauss.score.Score(chord_sequence, length)[source]¶
Class defining the musical score for the sonification
The Score class controls the musical aspects of the sonification. Currently supports a chordal score, defining a set of notes that can be played for each section of the simulation. The score also controls the length of the sonification.
Note
Currently, no rhythmic constraints are incorporated in the score. Chords are divided evenly over the length of the sonification. For example for a one minute sonification (
length = '1m 0s') thechord_sequence = "Am7_3 | D9_3 | Gmaj7_2"plays each chord for 20s each. Chaining the same chord can be used to change intervals, (e.g.chord_sequence = "F_3 | F_3 | C_4"plays F for 40s and C for 20s.)
- Parameters:
chord_sequence – (
strorlist): The chord or chord sequence used for the sonification. If a string, parse usingparse_chord_sequence. If alist, each entry is alistof strings or floats, representing the notes of a chord. notes are represented as strings using scientific notation, e.g.[['C3','E3', 'G3'], ['C3', 'F3', 'A4']]. If floats, take values as note frequency in Hz. NOTE: currently only supported in compination with theSynthesisergenerator class.length – (
strorfloat): the length of the sonification. If a string, parse minutes and seconds from format ‘Xm Y.Zs’. If a float read as seconds.
- strauss.score.parse_chord_sequence(chord_sequence)[source]¶
parse a chord sequence from a string
- Parameters:
chord_sequence (
str) – chord sequence to parse, with chord names appended with ‘_N’ where N is the root octave of the chord, and each chord is separated by a pipe character, ‘|’.- Returns:
- the chord sequence represented as
a list of lists, where each sub-list is a chord comprised of strings representing each note in scentific notation (e.g. ‘A4’)
- Return type:
note_list (
list(list))
Generator¶
The
generatorsubmodule: creating sounds for the sonification.This submodule handles the actual generation of sound for the sonfication, after parametrisation by the
Sourcesand musical choices dictated by theScore.Todo
Consolidate more common code into the
Generatorparent class.Support more Envelope and LFO types in the
playmethods (want pitch, volume and filter options for each)
- class strauss.generator.Generator(params={}, samprate=48000)[source]¶
Generic generator Class, defining common code for child classes
Generators have common initialisation and methods that are defined by this parent class.
- Parameters:
params (optional,
dict) – any generator parameters that differ from the generatorpreset, where keys and values are parameters names and values respectively.samprate (optional,
int) – the sample rate of the generated audio in samples per second (Hz)
- env_segment_curve(t, t1, y0, k)[source]¶
formula for segments of the envelope function
Function to evaluate the segments of the envelope, allowing for curvature, i.e. concave & convex envelope segments.
- Parameters:
t (
float) – time of each sample along segmentt1 (
float) – time of segment endpointy0 (
float) – starting value of segmentk (
float) – curvature value of segment, from (-1,1), with positive values indicating concave and negative convex curvature.
- envelope(samp, params, etype='volume')[source]¶
Envelope function for modulating a single note
The envelope function takes the pre-defined envelope parameters for the specified envelope type and returns the envelope value at each sample. envelopes are defined by attack, decay, sustain and release (
'A','D','S' & 'R) values, as well as segment curvatures ('Ac','Dc', & 'Rc) and a normalisation'level'.
- Parameters:
samp (
array-like) – Audio sample indexparams (
dict) – Keys and values of generator parametersetype (optional ,
str) – type of envelope, indicating whichparamsgroup to read (i.e. ifetype='volume', read from :obj:`volume_envelope)
- lfo(samp, sampfrac, params, ltype='pitch')[source]¶
Low-Frequency oscillator (LFO)
This function takes the pre-defined LFO parameters (if switched on) for the specified LFO type and returns the LFO value at each sample. LFOs are defined by the same values as
strauss.generator.envelope(), with an additionaluseswitch, a waveform (wave, e.g.sine), an amplitude (amount), a frequncy in Hz (freq) a frequency shift in octaves (freq_shift) and aphase, either numerical in cycles or'random'to indicate randomised.Note
To modulate the frequency of an ocillator, use the
freq_shiftparameter, rather thanfreq
- Parameters:
samp (
array-like) – Audio sample indexsampfrac (
array-like) – Audio sample as fraction of total number of samplesparams (
dict) – Keys and values of generator parametersltype (optional ,
str) – type of LFO, indicating whichparamsgroup to read (i.e. ifltype='volume', read `from :obj:`pitch_envelope)- Returns:
amplitude of LFO at each input sample
- Return type:
v (
array-like)
- load_preset(preset='default')[source]¶
load parameters from a preset YAML file.
Wrapper method for the
presets.synth.load_presetorpresets.sampler.load_presetfunctions. Always load thedefaultpreset first to ensure all parameters are defined, and then if necessary reload parameters defined bypreset
- Parameters:
preset (
str) – name of the preset. built-in presets can be named directly and looks to import the preset from the<MODULE_PATH>/presets/<GENERATOR>/directory as<preset>.yml, where<GENERATOR>is either synth or sampler,<MODULE_PATH>is the path to the strauss module (i.e.strauss.__file__). Custom presets can also be loaded from<preset>.ymlifpresetrepresents a path containing file separators.
- modify_preset(parameters, cleargroup=[])[source]¶
modify parameters within current preset
method allows user to tweak generator parameters directly, using a dictionary of parameters and their values. subgroups within the preset are represented as nested dictionaries.
- Parameters:
parameters (
dict) – keys and items are the preset parameter names and new values. Nested dictionaries are used to redefine grouped parameters, e.g.{'volume_envelope':{'A':0.5}}cleargroup (optional
list(str)) – if required, list of the group names to be completely reset (e.g. if defining newoscillatorsset for synth).
- noise(s, f, p)[source]¶
White noise oscillator
Note
fandphave no efffect for this oscillator, generating a random value for each sample.
- Parameters:
s (
array-like) – sample indexf (
float) – unusedp (
floatorstr) – unused- Returns:
values for each sample
- Return type:
v (
array-like)
- preset_details(term='*')[source]¶
Print the names and descriptions of presets
Wrapper for preset_details function. lists the name and description of built-in presets with names matching the search term.
- Parameters:
term (optional,
str) – name or glob term for built-inpreset (s) –
- saw(s, f, p)[source]¶
Sawtooth-wave oscillator
- Parameters:
s (
array-like) – sample indexf (
float) – samples per cyclep (
floatorstr) – if numerical, phase in units of cycles,'random'indicates randomised.- Returns:
values for each sample
- Return type:
v (
array-like)
- sine(s, f, p)[source]¶
Sine-wave oscillator
- Parameters:
s (
array-like) – sample indexf (
float) – samples per cyclep (
floatorstr) – if numerical, phase in units of cycles,'random'indicates randomised.- Returns:
values for each sample
- Return type:
v (
array-like)
- class strauss.generator.Sampler(sampfiles, params=None, samprate=48000)[source]¶
Sampler generator class
This generator class generates sound using pre-loaded audio samples, representing different notes. The relative frequency, phase and amplitude of these oscillators are defined in the preset, and linearly combined to produce the sound. defines attribute
self.gtype = 'synth'.
- Parameters:
() (sampfiles) –
params (optional,
dict) – any generator parameters that differ from the generatorpreset, where keys and values are parameters names and values respectively.samprate (optional,
int) – the sample rate of the generated audio in samples per second (Hz)Todo
Add zone mapping for samples (e.g. allow a sample to define a range of notes played at different speeds).
Support non-scientifically named notes? (e.g
'cymbal','snare').Have sample loading defined via the preset rather than the
sampfilesvariable?
- forward_back_loopsamp(s, start, end)[source]¶
Looping samples forward-backward alternately using indexing
From a list of samples and start and end loop-points, return a new list of samples that index the audio file samples to create a back and forth looping effect.
- Parameters:
s (
array-like) – Sample indexes for the duration of a source’s notestart (
int) – Sample index at which to start the loopend (
int) – Sample index at which to end the loop- Returns:
- new sample indices to create a
back and forth looping effect
- Return type:
s_new (
array-like)
- forward_loopsamp(s, start, end)[source]¶
Looping samples forward using indexing
From a list of samples and start and end loop-points, return a new list of samples that index the audio file samples to create a forward-looping effect.
- Parameters:
s (
array-like) – Sample indexes for the duration of a source’s notestart (
int) – Sample index at which to start the loopend (
int) – Sample index at which to end the loop- Returns:
- new sample indices to create a
forward-looping effect
- Return type:
s_new (
array-like)
- load_samples()[source]¶
Load audio samples into the sampler.
Read audio samples in from a specified directory or via a dictionary of filepaths, generate interpolation functions for each, and assign them to a named note in scientific notation (e.g.
'A4').
- play(mapping)[source]¶
Play the sound for a given source.
Play a given source and return the sample values for combination into the overall sonification.
Note
mappingis a linear dictionary (not nested, as forstrauss.generator.modify_preset()) where group members are indicated using'/'notation (e.g.{'volume_envelope/A': 0.5, ...).
- Parameters:
mapping (
dict) – keys and items are generator parameter names and their values. This combines all the preset mapped parameters, overwritten by anySource-mapped parameters (represented as values or interpolation functions for static and evolving parameters, respectively). This is a linear dictionary (not nested, seestrauss.generator.modify_preset()) where group members are indicated using'/'notation (e.g.{'volume_envelope/A': 0.5, ...).
- class strauss.generator.Synthesizer(params=None, samprate=48000)[source]¶
Synthesizer generator class
This generator class synthesises sound using mathmatically generated waveforms or ‘oscillators’, from a combination of oscillator methods defined in the parent class. The relative frequency, phase and amplitude of these oscillators are defined in the preset, and linearly combined to produce the sound. defines attribute
self.gtype = 'synth'.
- Parameters:
params (optional,
dict) – any generator parameters that differ from the generatorpreset, where keys and values are parameters names and values respectively.samprate (optional,
int) – the sample rate of the generated audio in samples per second (Hz)Todo
Add other synthesiser types, aside from additive (e.g. FM, vector, wavetable)?
- combine_oscs(s, f)[source]¶
Evaluate and linearly combine oscillators.
- Parameters:
s (
array-like) – Sample indexf (
floatorstr) – If numerical, frequency in cycles per second, if string, note name in scientific notation (e.g.'A4')- Returns:
values for each sample
- Return type:
tot (
array-like)
- modify_preset(parameters, clear_oscs=True)[source]¶
Synthesizer-specific wrapper for the modify_preset method.
- Parameters:
parameters (
dict) – keys and items are the preset parameter names and new values. Nested dictionaries are used to redefine grouped parameters, e.g.{'volume_envelope':{'A':0.5}}clear_oscs (optional,
bool) – if True, clear all oscillators from the existing preset. Turn off if just wishing to tweak non-oscillator parameters.
- play(mapping)[source]¶
Play the sound for a given source.
Play a given source and return the sample values for combination into the overall sonification.
Note
mappingis a linear dictionary (not nested, as forstrauss.generator.modify_preset()) where group members are indicated using'/'notation (e.g.{'volume_envelope/A': 0.5, ...).
- Parameters:
mapping (
dict) – keys and items are generator parameter names and their values. This combines all the preset mapped parameters, overwritten by anySource-mapped parameters (represented as values or interpolation functions for static and evolving parameters, respectively). This is a linear dictionary (not nested, seestrauss.generator.modify_preset()) where group members are indicated using'/'notation (e.g.{'volume_envelope/A': 0.5, ...).
- setup_oscillators()[source]¶
Setup and consolidate oscs into a two-variable function.
Reads the parametrisation of each oscillator from the preset, specifying their waveform (
wave), relative amplitude (level), detuning in cents (det) andphase, either a number in units of cycles, or a string specifying randomisation ('random'). Sets theself.generatemethod, using theself.combine_oscs.
- strauss.generator.detuned_saw(samples, freqsamp, oscdets=[1, 1.005, 0.995])[source]¶
DEPRECATED CODE: Three oscillator sawtooth wave generator with slight detuning for texture
Channels¶
channelssubmodule representing the output audio channels.This submodule defines objects relevant to the output audio channels, including the
audio_channelswhich defines arrays of microphone objects that are channeled to different speakers in the sonification output.Todo
Allow microphones to have a
polaras well asazimuthvalue, to place them anywhere on a sphere around a listener.parameterise the
"soundsphere"standard setup, for VR applications (in development).
- class strauss.channels.audio_channels(setup='stereo', custom_setup={})[source]¶
Representing output audio channels.
Data object representing the output channels of the sonification for preset common audio setups, or a custom setup. Stores an array of
micobjects for each output channel.
- Parameters:
setup (
str) – Type of audio setup. Supported options are"mono","stereo","5p1"and"7p1", or"custom".custom_setup (
dict) – Dictionary defining a customised audio setup, containing keys for"azimuths","types"and"labels", containing lists parametrising the first three arguments of themicobject, respectively in the order of their channel index. Also optionally an forder list to unscramble any channel order scrambling done by ffmpeg processing in the sonification sae routines (this may need to be found empirically, awaiting better multichannel save routine).- Raises:
Exception – If custom requested but no parameters provided, or custom parameters provided without requesting a custom setup.
- plot_antenna()[source]¶
Plot antennae patterns for chosen audio setup
Make a
matplotlibfigure object, representing a radial plot demonstrating the antennae patterns of each channel
- Returns:
figure object that can be shown or saved using the standard
matplotlibroutines.- Return type:
fig (
matplotlib.pyplot.figure)
- setup_channels(azimuths, types, labels)[source]¶
initialise audio channel setup for lists of properties
Subroutine for setting up the audio_channels as arrays of
micobjects, setting theself.micslist attribute to theaudio_channels
- class strauss.channels.mic(azimuth, mic_type='directional', label='C', channel=1)[source]¶
Microphone / sound detector object
This class represents a microphone, or sound-detector, corresponding to a particular output channel for audio spatialisation in the sonicfication.
- Parameters:
azimuth (
float) – Angular position of the microphone on the horizontal plane, from 0 to 2pi with 0.5 pi being to the left and 1.5 pi being to the right.mic_type (
str) – Type of microphone, choose from"directional"(collects using a cardioid antenna pattern),"omni"(collects sound from all directions equally) and"mute"(collects no sound useful for e.g. muting auxillary channels)label (
str) – A label for the micchannel (
int) – channel ordering in the output (starting from 0 e.g. stereo L=0, R=1)- Raises:
Exception – if mic_type not in allowed options
Sonification¶
sonification: generate sonification, combining submodules.This Submodule handles the combining of all the constituent subroutines into a single
sonificationobject that can then render and output/save the resultant sonification. This handles feeding of information betweenstraussmodules, including taking thesourcesmapping, applying any musical constraints fromscorerunning thegeneratorsto make sound and combining them into the output channels for the overall spatialised sonificiation.Todo
Delegate more musical process to the
scoremodule
- class strauss.sonification.Sonification(score, sources, generator, audio_setup='stereo', samprate=48000)[source]¶
Representing the overall sonification
This class combines the data sources, musical score constraints and generator together to generate and render the ultimate sonification for saving or playing in the
jupyter-notebookenvironment
- Parameters:
score (
Score) – SonificationScoreobjectsources (
Source) – SonificationSourceschild object (EventsorObjects)generator (
Generator) – SonificationGeneratorchild object (SynthesizerorSampler)audio_setup (
str) – pass toaudio_channelssamprate (
int) – (Hz), typically44100or48000for most audio applications.Todo
Support custom audio setups here too.
- notebook_display()[source]¶
plot the waveforms and embed player in the notebook
Show waveforms and embed an audio player in the python notebook for direct playback. the notebook player only supports up to stereo, so if more than two channels, only the first two are used as left and right.
- render(downsamp=1)[source]¶
Render the sonification.
Generates the sonification by running the Synthesizer
play()or Samplerplay()functions, and combining these into the output channel streams using any spatialisation for the specifiedaudio_channels.
- Parameters:
downsamp (optional,
int) – Optionally downsampletest (sources for multi-source sonifications for a quicker) –
factor. (render by some integer) –
- save(fname, master_volume=1.0)[source]¶
Save render as a combined multi-channel wav file
Can use this function to save sonification of any audio_setup to a 32-bit depth WAV using scipy.io.wavfile
- Parameters:
fname (
str) –master_volume (
float) – peak, from 0-1Todo
Raise scipy issue if common 24-bit WAV can be supported
- save_combined(fname, ffmpeg_output=False, master_volume=1.0)[source]¶
Save render as a combined multi-channel wav file
Can use this function to save sonification of any audio_setup, using ffmpeg processing, and unscrampling to the correct channel order.
- Parameters:
fname (
str) –ffmpeg_output (
bool) – output to screenmaster_volume (
float) – peak, from 0-1Todo
- Either find a way to avoid the need to unscramble channle
order, or find alternative to save wav files