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 sources submodule: 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:

dict

Todo

  • 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 as lists, with data for each source corresponding to the values. Single sources can be represented as single values.

fromfile(datafile, coldict)[source]

Take input data from ASCII file

Parameters:
  • datafile (str) – path to input data file

  • coldict (dict) – keys are self.mapped_values, with entries integer indexes for their corresponding column.

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 fromfile method

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 either lists or 2D numpy.array objects, with each source corresponding to the entries or columns respectively. Single sources can be represented as single values or 1D numpy.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.

exception strauss.sources.UnrecognisedProperty[source]

Error raised when trying to map unrecognised parameters

Score

The score submodule: musical constraints on what Sources can play

This 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 Score class handle pitch and rhythm assignment from Sources directly, instead of the Sonification class.

  • 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') the chord_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 – (str or list): The chord or chord sequence used for the sonification. If a string, parse using parse_chord_sequence. If a list, each entry is a list of 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 the Synthesiser generator class.

  • length – (str or float): 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 generator submodule: creating sounds for the sonification.

This submodule handles the actual generation of sound for the sonfication, after parametrisation by the Sources and musical choices dictated by the Score.

Todo

  • Consolidate more common code into the Generator parent class.

  • Support more Envelope and LFO types in the play methods (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 generator preset, 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 segment

  • t1 (float) – time of segment endpoint

  • y0 (float) – starting value of segment

  • k (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 index

  • params (dict) – Keys and values of generator parameters

  • etype (optional , str) – type of envelope, indicating which params group to read (i.e. if etype='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 additional use switch, a waveform (wave, e.g. sine), an amplitude (amount), a frequncy in Hz (freq) a frequency shift in octaves (freq_shift) and a phase, either numerical in cycles or 'random' to indicate randomised.

Note

To modulate the frequency of an ocillator, use the freq_shift parameter, rather than freq

Parameters:
  • samp (array-like) – Audio sample index

  • sampfrac (array-like) – Audio sample as fraction of total number of samples

  • params (dict) – Keys and values of generator parameters

  • ltype (optional , str) – type of LFO, indicating which params group to read (i.e. if ltype='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_preset or presets.sampler.load_preset functions. Always load the default preset first to ensure all parameters are defined, and then if necessary reload parameters defined by preset

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>.yml if preset represents 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 new oscillators set for synth).

noise(s, f, p)[source]

White noise oscillator

Note

f and p have no efffect for this oscillator, generating a random value for each sample.

Parameters:
  • s (array-like) – sample index

  • f (float) – unused

  • p (float or str) – 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-in

  • preset (s) –

saw(s, f, p)[source]

Sawtooth-wave oscillator

Parameters:
  • s (array-like) – sample index

  • f (float) – samples per cycle

  • p (float or str) – 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 index

  • f (float) – samples per cycle

  • p (float or str) – if numerical, phase in units of cycles, 'random' indicates randomised.

Returns:

values for each sample

Return type:

v (array-like)

square(s, f, p)[source]

Square-wave oscillator

Parameters:
  • s (array-like) – sample index

  • f (float) – samples per cycle

  • p (float or str) – if numerical, phase in units of cycles, 'random' indicates randomised.

Returns:

values for each sample

Return type:

v (array-like)

tri(s, f, p)[source]

Triangle-wave oscillator

Parameters:
  • s (array-like) – sample index

  • f (float) – samples per cycle

  • p (float or str) – 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 generator preset, 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 sampfiles variable?

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 note

  • start (int) – Sample index at which to start the loop

  • end (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 note

  • start (int) – Sample index at which to start the loop

  • end (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

mapping is a linear dictionary (not nested, as for strauss.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 any Source-mapped parameters (represented as values or interpolation functions for static and evolving parameters, respectively). This is a linear dictionary (not nested, see strauss.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 generator preset, 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 index

  • f (float or str) – 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

mapping is a linear dictionary (not nested, as for strauss.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 any Source-mapped parameters (represented as values or interpolation functions for static and evolving parameters, respectively). This is a linear dictionary (not nested, see strauss.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) and phase, either a number in units of cycles, or a string specifying randomisation ('random'). Sets the self.generate method, using the self.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

strauss.generator.gen_chord(stream, chordname, rootoctv=3)[source]

DEPRECATED CODE: generate chord over entire stream given chord name and optional octave of root note

strauss.generator.legacy_env(t, dur, a, d, s, r)[source]

DEPRECATED CODE: older function for generating envelopes

Channels

channels submodule representing the output audio channels.

This submodule defines objects relevant to the output audio channels, including the audio_channels which defines arrays of microphone objects that are channeled to different speakers in the sonification output.

Todo

  • Allow microphones to have a polar as well as azimuth value, 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 mic objects 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 the mic object, 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 matplotlib figure object, representing a radial plot demonstrating the antennae patterns of each channel

Returns:

figure object that can be shown or saved using the standard matplotlib routines.

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 mic objects, setting the self.mics list attribute to the audio_channels

Parameters:
  • azimuths (list(float)) – list of azimuth values for mic object

  • types (list(float)) – list of mic_types values for mic object.

  • labels (list(float)) – list of label values for mic object

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 mic

  • channel (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 sonification object that can then render and output/save the resultant sonification. This handles feeding of information between strauss modules, including taking the sources mapping, applying any musical constraints from score running the generators to make sound and combining them into the output channels for the overall spatialised sonificiation.

Todo

  • Delegate more musical process to the score module

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-notebook environment

Parameters:
  • score (Score) – Sonification Score object

  • sources (Source) – Sonification Sources child object (Events or Objects)

  • generator (Generator) – Sonification Generator child object (Synthesizer or Sampler)

  • audio_setup (str) – pass to audio_channels

  • samprate (int) – (Hz), typically 44100 or 48000 for 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 Sampler play() functions, and combining these into the output channel streams using any spatialisation for the specified audio_channels.

Parameters:
  • downsamp (optional, int) – Optionally downsample

  • test (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-1

Todo

  • 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 screen

  • master_volume (float) – peak, from 0-1

Todo

  • Either find a way to avoid the need to unscramble channle

    order, or find alternative to save wav files

save_stereo(fname, master_volume=1.0)[source]

Save stereo or mono sonifications

Can use this function to save "stereo" or "mono" sonifications while avoiding ffmpeg processing.

Parameters:
  • fname (str) –

  • master_volume (float) – peak, from 0-1

Todo

  • Support master_volume in decibels