Source code for pybpod_soundcard_module.utils.generate_sound

import math
import numpy as np


[docs]class WindowConfiguration: def __init__(self, left_duration=0.1, left_apply_window_start=True, left_apply_window_end=True, left_window_function='Hanning', right_duration=0.1, right_apply_window_start=True, right_apply_window_end=True, right_window_function='Hanning'): """ :param left_duration: (Optional) Duration of the window in seconds, for the left channel. If zero, no window will be created for this channel. Default: 0.1s :param left_apply_window_start: (Optional) True if the window should be applied to the **start** of the sound for the left channel, False otherwise. Default: True :param left_apply_window_end: (Optional) True if the window should be applied to the **end** of the sound for the left channel, False otherwise. Default: True :param left_window_function: (Optional) Window function that should be used for the left channel. Possible values accepted: 'Hanning', 'Hamming', 'Blackman', 'Bartlett'. Default: 'Hanning" :param right_duration: (Optional) Duration of the window in seconds, for the right channel. If zero, no window will be created for this channel. Default: 0.1s :param right_apply_window_start: (Optional) True if the window should be applied to the **start** of the sound, for the right channel, False otherwise. Default: True :param right_apply_window_end: (Optional) True if the window should be applied to the **end** of the sound for the right channel, False otherwise. Default: True :param right_window_function: (Optional) Window function that should be used for the left channel. Possible values accepted: 'Hanning', 'Hamming', 'Blackman', 'Bartlett'. Default: 'Hanning" """ self.left_duration = left_duration self.right_duration = right_duration self.left_apply_window_start = left_apply_window_start self.right_apply_window_start = right_apply_window_start self.left_apply_window_end = left_apply_window_end self.right_apply_window_end = right_apply_window_end self.left_window_function = left_window_function self.right_window_function = right_window_function
[docs]def generate_sound(filename=None, fs=96000, duration=1, frequency_left=1000, frequency_right=1000, window_configuration:WindowConfiguration=None): """ Helper method to dynamically generated a sound that can be used in with the Sound Card module. :param filename: (Optional) :param fs: (Optional) number of samples per second (standard) :param duration: (Optional) sound duration in seconds :param frequency_left: (Optional) number of cycles per second (Hz) (frequency of the sine wave for the left channel) :param frequency_right: (Optional) number of cycles per second (Hz) (frequency of the sine wave for the right channel) :param window_configuration: (Optional) WindowConfiguration object to apply to the generated sound. :return: Returns the **flatten** generated sound as a numpy array (as np.int8) """ amplitude24bits = math.pow(2, 31) - 1 samples = np.arange(0, duration, 1 / fs) wave_left = amplitude24bits * np.sin(2 * math.pi * frequency_left * samples) wave_right = amplitude24bits * np.sin(2 * math.pi * frequency_right * samples) if window_configuration: wave_left = generate_window(fs, wave_left, window_configuration.left_duration, window_configuration.left_apply_window_start, window_configuration.left_apply_window_end, window_configuration.left_window_function) wave_right = generate_window(fs, wave_right, window_configuration.right_duration, window_configuration.right_apply_window_start, window_configuration.right_apply_window_end, window_configuration.right_window_function) stereo = np.stack((wave_left, wave_right), axis=1) wave_int = stereo.astype(np.int32) if filename: with open(filename, 'wb') as f: wave_int.tofile(f) return wave_int.flatten()
[docs]def generate_window(fs, wave_int, duration, apply_start, apply_end, window_function): """ :param fs: number of samples per second (standard) :param wave_int: base sound where the window will be applied :param duration: duration of the window (it will be the same on the start and end) :param apply_start: True if the window should be created at the start, False otherwise. :param apply_end: True if the window should be created at the end, False otherwise. :param window_function: window function to be generated. Possible values accepted: 'Hanning', 'Hamming', 'Blackman', 'Bartlett'. It will revert to 'Hanning' if an unknown option is given. :return: Returns the modified sound with the window applied to it. """ len_fade = int(duration * fs) if window_function == 'Hanning': fade_io = np.hanning(len_fade * 2) elif window_function == 'Hamming': fade_io = np.hamming(len_fade * 2) elif window_function == 'Blackman': fade_io = np.blackman(len_fade * 2) elif window_function == 'Bartlett': fade_io = np.bartlett(len_fade * 2) else: # default fade_io = np.hanning(len_fade * 2) fadein = fade_io[:len_fade] fadeout = fade_io[len_fade:] win = np.ones(len(wave_int)) if apply_start: win[:len_fade] = fadein if apply_end: win[-len_fade:] = fadeout wave_int = wave_int * win return wave_int