#SHARED UTILITY TOOLS AND VARIABLES
import numpy
import scipy.io.wavfile
[docs]def pad_signal(signal, sampling_rate, time_step = 0.01, frame_window = 0.025):
"""segement a signal, 1D audio signal, into frames, such that:
output: N by M matrix, in which:
each row is a segment of frame_window's audio signal
"""
T = int(sampling_rate * time_step)
Fr = int(sampling_rate * frame_window)
Fr +=int(sampling_rate * frame_window > Fr)
signal = numpy.append(signal, numpy.zeros(Fr-len(signal)%T))
return signal
[docs]def compress_pause_to_time(signal, sampling_rate, time_step = 0.01, frame_window = 0.025):
"""compress pause index to time
Args:
signal (numpy.array(bool)): A list of pause sequence. True indicating pause.
sampling_rate (int): sampling frequency in Hz.
time_step (float, optional): The time interval (in seconds) between two pauses. Default to 0.01.
frame_window (float, optional): The length of speech (in seconds) used to estimate pause. Default to 0.025.
Returns:
numpy.array(bool): compressed pause.
"""
T = int(sampling_rate * time_step)
Fr = int(sampling_rate * frame_window)
Fr +=int(sampling_rate * frame_window > Fr)
length = (len(signal) - Fr)//T + 1
pause = numpy.full( length, False )
for i in range(length):
if len(numpy.where(signal[i*T:(i+1)*T])[0]) > T/2:
pause[i] = True
return pause
[docs]def is_upper_triangular( AA ):
"""Check if a matrix is upper triangular.
Args:
AA (numpy.array): a 2D matrix.
Returns:
bool:
"""
return numpy.allclose(AA, numpy.triu(AA))
[docs]def is_lower_triangular( AA ):
"""Check if a matrix is lower triangular.
Args:
AA (numpy.array): a 2D matrix.
Returns:
bool:
"""
return numpy.allclose(AA, numpy.tril(AA))
[docs]def read_wavfile( filename, channel=0 ):
"""Read in a audio file (in .wav format) and enforce the output as mono-channel.
Args:
filename (str): path to the audio file.
channel(int, optional): indicate which channel to read in. Defaults to 0.
Returns:
int: sampling frequency.
numpy.array: audio data.
"""
sampling_rate, datas = scipy.io.wavfile.read(filename)
datas = datas.astype(float)
if channel > len( datas.shape ):
print("Error: Channel {} does not exist. Note: first channel is channel 0.".format(channel))
return
elif len(datas.shape)>1:
return sampling_rate, datas[:,channel]
return sampling_rate, datas
[docs]def write_wavfile(filename, fs, data):
scipy.io.wavfile.write(filename, fs, data)
[docs]def merge_pitch_profile( pitches, speaker_id ):
"""merges n-pitch profiles into one sound based on speaker_id.
Args:
pitches (list-like(float)): a sequence of pitches.
speaker_id (list-like(int)): a list of speakers' id.
Returns:
numpy.array: merged pitch profile.
"""
N = len( speaker_id )
merged_pitch_profile = numpy.empty( N )
for i in range(N):
merged_pitch_profile[i] = pitches[speaker_id[i]][i]
return merged_pitch_profile
[docs]def artificial_signal( frequencys, sampling_frequency=16000, duration=0.025 ):
"""Concatonates a sequence of sinusoids of frequency f in frequencies.
Args:
frequencys (list-like(int)): sequence of frequencies of sinusoidual signals in Hz.
sampling_frequency (int, optional): sampling frequency in Hz. Defaults to 16000.
duration (float, optional): duration of the output sinusoid in seconds. Defaults to 0.025.
Returns:
numpy.array: artificially generated sinusoidal signal.
"""
sins = map( lambda f : sinusoid(f, sampling_frequency, duration), frequencys)
return numpy.concatenate( tuple(sins) )
[docs]def sinusoid( frequency, sampling_frequency=16000, duration=0.025 ):
"""Generate a sinusoid signal.
Args:
frequency (int): the frequency of the sinusoidal signal.
sampling_frequency (int, optional): sampling frequency in Hz. Defaults to 16000.
duration (float, optional): duration of the output sinusoid in seconds. Defaults to 0.025.
Returns:
numpy.array: a sinusoid.
"""
times = numpy.arange(int(sampling_frequency * duration))
return numpy.sin(2 * numpy.pi * frequency * times / sampling_frequency)
[docs]def random_symbols( distribution, length ):
if sum(distribution) != 1:
print("Warning: probabilites must sum to 1")
return
return numpy.random.choice( len(distribution), length, p=distribution )
[docs]def random_run( distributions, length, min_run=100, max_more=100 ):
ans = list()
k, N, M = 0, length, len(distributions)
while True:
more = numpy.random.randint(0,max_more) if max_more else 0
ext_length = min_run + more
ext_length = min( ext_length, N )
ans.extend( random_symbols( distributions[k % M], ext_length ) )
k += 1 % M
N -= ext_length
if N <= 0: return ans