Source code for nussl.core.mixing

"""
Small collection of utilities for altering and remixing
AudioSignal objects. 

TODO: add pitch_shift, time_stretch, dynamic_range_compression, and 
apply_impulse_response
"""
import copy

import numpy as np

from . import AudioSignal


[docs]def pan_audio_signal(audio_signal, angle_in_degrees): """ Pans an audio signal left or right by the desired number of degrees. This returns a copy of the input audio signal. Use negative numbers to pan left, positive to pan right. Angles outside of the range [-45, 45] raise an error. Args: audio_signal (AudioSignal): Audio signal to be panned. angle_in_degrees (float): Angle in degrees to pan by, between -45 and 45. Raises: ValueError: Angles outside of the range [-45, 45] raise an error. Returns: AudioSignal: Audio signal panned by `angle_in_degrees`. """ if angle_in_degrees < -45 or angle_in_degrees > 45: raise ValueError( "Angle must be between -45 and 45! -45 means " "all the way to the left, 45 means all the way " "to the right, and 0 is center.") panned_signal = copy.deepcopy(audio_signal) panned_signal.to_mono() panned_signal.audio_data = np.concatenate([ panned_signal.audio_data, panned_signal.audio_data ], axis=0) angle = np.deg2rad(angle_in_degrees) left_scale = ( np.sqrt(2)/2 * (np.cos(angle) - np.sin(angle))) right_scale = ( np.sqrt(2)/2 * (np.cos(angle) + np.sin(angle))) panned_signal.audio_data[0] *= left_scale panned_signal.audio_data[1] *= right_scale return panned_signal
[docs]def delay_audio_signal(audio_signal, delays_in_samples): """ Delays an audio signal by the desired number of samples per channel. This returns a copy of the input audio signal. Delay must be positive. The end of the audio signal is truncated for that channel so that the length remains the same as the original. Args: audio_signal (AudioSignal): Audio signal to be panned. delays_in_samples (list of int): List of delays to apply to each channel. Should have the same length as number of channels in the AudioSignal. Raises: ValueError: If length of `delays_in_samples`does not match number of channels in the audio signal. Or if any items in `delays_in_samples` are float type. Or if any delays are negative. Returns: AudioSignal: Audio signal with each channel delayed by the specified number samples in `delays_in_samples`. """ if any([not isinstance(x, int) for x in delays_in_samples]): raise ValueError("All items in delay_in_samples must be integers.") if any([x < 0 for x in delays_in_samples]): raise ValueError("All items in delay_in_samples must be non-negative.") if len(delays_in_samples) != audio_signal.num_channels: raise ValueError( "Number of items in delays_in_samples must match number of " "channels in audio_signal.") delayed_signal = copy.deepcopy(audio_signal) for i, delay in enumerate(delays_in_samples): if delay > 0: _audio_data = delayed_signal.audio_data[i] original_length = _audio_data.shape[-1] _audio_data = np.pad(_audio_data, (delay, 0)) _audio_data = _audio_data[:original_length] delayed_signal.audio_data[i] = _audio_data return delayed_signal