Skip to main content

Tools for generating and manipulating digital signals, particularly sounds.

Project description

Package TestPyPI Documentation Status Maintenance PyPI pyversions PyPI license

slab: easy manipulation of sounds and psychoacoustic experiments in Python

Slab ('es-lab', or sound laboratory) is an open source project and Python package that makes working with sounds and running psychoacoustic experiments simple, efficient, and fun! For instance, it takes just eight lines of code to run a pure tone audiogram using an adaptive staircase:

    import slab
    stimulus = slab.Sound.tone(frequency=500, duration=0.5) # make a 0.5 sec pure tone of 500 Hz
    stairs = slab.Staircase(start_val=50, n_reversals=10) # set up the adaptive staircase
    for level in stairs: # the staircase object returns a value between 0 and 50 dB for each trial
        stimulus.level = level
        stairs.present_tone_trial(stimulus) # plays the tone and records a keypress (1 for 'heard', 2 for 'not heard')
        stairs.print_trial_info() # optionally print information about the current state of the staircase
    print(stairs.threshold()) # print threshold when done

Why slab?

The package aims to lower the entrance barrier for working with sounds in Python and provide easy access to typical operations in psychoacoustics, specifically for students and researchers in the life sciences. The typical BSc or MSc student entering our lab has limited programming and signal processing training and is unable to implement a psychoacoustic experiment from scratch within the time limit of a BSc or MSc thesis. Slab solves this issue by providing easy-to-use building blocks for such experiments. The implementation is well documented and sufficiently simple for curious students to understand. All functions provide sensible defaults and will many cases 'just work' without arguments (vowel = slab.Sound.vowel() gives you a 1-second synthetic vowel 'a', vowel.spectrogram() plots the spectrogram). This turned out to be useful for teaching and demonstrations. Many students in our lab have now used the package to implement their final projects and exit the lab as proficient Python programmers.

Features

Slab represents sounds as Numpy arrays and provides classes and methods to perform typical sound manipulation tasks and psychoacoustic procedures. The main classes are:

Signal: Provides a generic signal object with properties duration, number of samples, sample times, number of channels. Keeps the data in a 'data' property and implements slicing, arithmetic operations, and conversion between sample points and time points.

    sig = slab.Sound.pinknoise(nchannels=2) # make a pink noise
    sig.duration
	out: 1.0
	sig.nsamples
	out: 8000
	sig2 = sig.resample(samplerate=4000) # resample to 4 kHz
	env = sig2.envelope() # returns a new signal containing the lowpass Hilbert envelopes of both channels
	sig.delay(duration=0.0006, channel=0) # delay the first channel by 0.6 ms

Sound: Inherits from Signal and provides methods for generating, manipulating, displaying, and analysing sound stimuli. Can compute descriptive sound features and apply manipulations to all sounds in a folder.

    vowel = slab.Sound.vowel(vowel='a', duration=.5) # make a 0.5-second synthetic vowel sound
    vowel.ramp() # apply default raised-cosine onset and offset ramps
    vowel.filter(kind='bp', f=[50, 3000]) # apply bandpass filter between 50 and 3000 Hz
    vowel.spectrogram() # plot the spectrogram
    vowel.spectrum(low=100, high=4000, log_power=True) # plot a band-limited spectrum
    vowel.waveform(start=0, end=.1) # plot the waveform
	vowel.write('vowel.wav') # save the sound to a WAV file
	vocoded_vowel = vowel.vocode() # run a vocoding algorithm
	vowel.spectral_feature(feature='centroid') # compute the spectral centroid of the sound in Hz

Binaural: Inherits from Sound and provides methods for generating and manipulating binaural sounds, including advanced interaural time and intensity manipulation. Binaural sounds have left and a right channel properties.

    sig = slab.Binaural.pinknoise()
	sig.pulse() # make a 2-channel pulsed pink noise
    sig.nchannels
    out: 2
    right_lateralized = sig.itd(duration=600e-6) # add an interaural time difference of 600 microsec, right channel leading
    # apply a linearly increasing or decreasing interaural time difference.
    # This is achieved by sinc interpolation of one channel with a dynamic delay:
    moving = sig.itd_ramp(from_itd=-0.001, to_itd=0.01)
    lateralized = sig.at_azimuth(azimuth=-45) # add frequency- and headsize-dependent ITD and ILD corresponding to a sound at 45 deg
	external = lateralized.externalize() # add a low resolution HRTF filter that results in the percept of an externalized source (i.e. outside of the head), defaults to the KEMAR HRTF recordings, but any HRTF can be supplied

Filter: Inherits from Signal and provides methods for generating, measuring, and manipulating FIR and FFT filters, filter banks, and transfer functions.

    filt = Filter.rectangular_filter(frequency=15000, kind='hp') # make a highpass filter
	filt.tf() # plot the transfer function
	sig_filt = filt.apply(sig) # apply it to a signal
	# applying a whole filterbank is equally easy:
	fbank = Filter.cos_filterbank(length=sig.nsamples, bandwidth=1/10, low_cutoff=100) # make a cosine filter bank
	fbank.tf() # plot the transfer function of all filters in the bank
	subbands = fbank.apply(sig) # make a multi-channel signal containing the passbands of the filters in the filter bank
	# the subbands could now be manipulated and then combined with the collapse_subbands method
	fbank.filter_bank_center_freqs() # return the centre frequencies of the filters in the filter bank
	fbank = equalizing_filterbank(target, measured) # generates an inverse filter bank for equalizing the differences
	# between measured signals (single- or multi-channel Sound object) and a target signal. Used for equalizing loudspeakers,
	microphones, or speaker arrays.
	fbank.save('equalizing_filters.npy') # saves the filter bank as .npy file.

HRTF: Inherits from Filter, reads .sofa format HRTFs and provides methods for manipulating, plotting, and applying head-related transfer functions.

    hrtf = slab.HRTF(data='mit_kemar_normal_pinna.sofa') # load HRTF from a sofa file (the standard KEMAR data is included)
    print(hrtf) # print information
    <class 'hrtf.HRTF'> sources 710, elevations 14, samples 710, samplerate 44100.0
    sourceidx = hrtf.cone_sources(20) # select sources on a cone of confusion at 20 deg from midline
    hrtf.plot_sources(sourceidx) # plot the sources in 3D, highlighting the selected sources
    hrtf.plot_tf(sourceidx,ear='left') # plot transfer functions of selected sources in a waterfall plot
	hrtf.diffuse_field_equalization() # apply diffuse field equalization to remove non-spatial components of the HRTF

Psychoacoustics: A collection of classes for working trial sequences, adaptive staircases, forced-choice procedures, stimulus presentation and response recording from the keyboard and USB button boxes, handling of precomputed stimulus lists, results files, and experiment configuration files.

    # set up an 1up-2down adaptive weighted staircase with dynamic step sizes:
    stairs = slab.Staircase(start_val=10, max_val=40, n_up=1, n_down=2, step_sizes=[3, 1], step_up_factor=1.5)
    for trial in stairs: # draw a value from the staircase; the loop terminates with the staircase
        response = stairs.simulate_response(30) # simulate a response from a participant using a psychometric function
        print(f'trial # {stairs.this_trial_n}: intensity {trial}, response {response}')
        stairs.add_response(response) # logs the response and advances the staircase
		stairs.plot() # updates a plot of the staircase in each trial to keep an eye on the performance of the listener
    stairs.reversal_intensities # returns a list of stimulus values at the reversal points of the staircase
    stairs.threshold() # computes and returns the final threshold
    stairs.save_json('stairs.json') # the staircase object can be saved as a human readable json file

    # for non-adaptive experiments and all other cases where you need a controlled sequence of stimulus values:
    trials = slab.Trialsequence(conditions=5, n_reps=2) # sequence of 5 conditions, repeated twice, without direct repetitions
    trials = slab.Trialsequence(conditions=['red', 'green', 'blue'], kind='infinite') # infinite sequence of color names
    trials = slab.Trialsequence.mmn_sequence(n_trials=60, deviant_freq=0.12) # stimulus sequence for an oddball design
    trials.transitions() # return the array of transition probabilities between all combinations of conditions.
    trials.condition_probabilities() # return a list of frequencies of conditions
    for trial in trials: # use the trials object in a loop to go through the trials
        print(trial) # here you would generate or select a stimulus according to the condition
        trials.present_afc_trial(target, distractor, isi=0.2) # present a 2-alternative forced-choice trial and record the response

    stims = slab.Precomputed(lambda: slab.Sound.pinknoise(), n=10) # make 10 instances of noise as one Sound-like object
    stims = slab.Precomputed([stim1, stim2, stim3, stim4, stim5]) # or use a list of sound objects, or a list comprehension
    stims.play() # play a random instance
    stims.play() # play another one, guaranteed to be different from the previous one
	stims.sequence # the sequence of instances played so far
    stims.save('stims.zip') # save the sounds as zip file
    stims = slab.Precomputed.read('stims.zip') # reloads the file into a Precomputed object

The basic functionality of the Signal class and many of the sound generation methods in the Sound class were based on the brian.hears Sound class (now brain2hears, an auditory modelling package).

Installation

Install the current stable release from the python package index with pip: pip install soundlab

or get the latest development version directly from GitHub (if you have git) by running: pip install git+https://github.com/DrMarc/soundlab.git

The releases use semantic versioning: major.minor.patch, where major increments for changes that break backwards compatibility, minor increments of added functionality, and patch increases for internal bug fixes. slab.__version__ prints the installed version.

Documentation

ReadTheDocs

Contributing to this project

Anyone and everyone is welcome to contribute. Please take a moment to review the guidelines for contributing.

License

The project is licensed under the MIT license.

forthebadge made-with-python

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

slab-0.8.0.tar.gz (1.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

slab-0.8.0-py3-none-any.whl (1.2 MB view details)

Uploaded Python 3

File details

Details for the file slab-0.8.0.tar.gz.

File metadata

  • Download URL: slab-0.8.0.tar.gz
  • Upload date:
  • Size: 1.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.24.0 setuptools/49.6.0.post20200814 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.8.3

File hashes

Hashes for slab-0.8.0.tar.gz
Algorithm Hash digest
SHA256 3d6db573acda9f3a178e3ac4a9c908ab8328b88d45a2d86362b793feba9bc8db
MD5 dec17348904c39a767632f168519dc7b
BLAKE2b-256 4c807e09422a7ffaaac6ab106798c4232de66a1f4e0524a4b704b9a742c085cd

See more details on using hashes here.

File details

Details for the file slab-0.8.0-py3-none-any.whl.

File metadata

  • Download URL: slab-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.24.0 setuptools/49.6.0.post20200814 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.8.3

File hashes

Hashes for slab-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 516976ac7d16f7c6bd976114d47b79d02b87484e2f488ae9f5ab3d1ea333cc4b
MD5 6a2128f2aac0b025cdead942857bb662
BLAKE2b-256 1d1d039b82724549b9fd2fd983696106682056da7228fdfdd622d1580baf930b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page