Generación de música con Python

Generación de música con Python

 

El reconocimiento de voz se refiere al proceso de reconocer y comprender el lenguaje hablado. La entrada viene en forma de datos de audio, y los reconocedores de voz procesarán estos datos para extraer información significativa de ellos. Esto tiene muchos usos prácticos, como dispositivos controlados por voz, transcripción del lenguaje hablado en palabras, sistemas de seguridad, etc.

Las señales de voz son de naturaleza muy versátil. Existen muchas variaciones del habla en el mismo idioma. Hay diferentes elementos para el habla, como el lenguaje, la emoción, el tono, el ruido, el acento, etc. Es difícil definir rígidamente un conjunto de reglas que puedan constituir discurso. Incluso con todas estas variaciones, los humanos son realmente buenos para comprender todo esto con relativa facilidad. Por lo tanto, necesitamos máquinas para entender el habla de la misma manera.

Durante las últimas décadas, los investigadores han trabajado en varios aspectos del habla, como identificar al hablante, comprender palabras, reconocer acentos, traducir el habla, etc. Entre todas estas tareas, el reconocimiento automático de voz ha sido el punto focal de atención para muchos investigadores. En este tutorial, aprenderemos cómo construir un reconocedor de voz.

Visualizando las señales

Echemos un vistazo a cómo leer un archivo de audio y visualizar la señal. Este será un buen punto de partida, y nos dará una buena comprensión de la estructura básica de las señales de audio. Antes de comenzar, debemos entender que los archivos de audio son versiones digitalizadas de señales de audio reales. Las señales de audio reales son ondas complejas de valor continuo. Para guardar una versión digital, tomamos muestras de la señal y la convertimos en números. Por ejemplo, el habla se muestrea comúnmente a 44100 Hz. Esto significa que cada segundo de la señal se divide en 44100 partes, y los valores en estas marcas de tiempo se almacenan. En otras palabras, almacena un valor cada 1/44100 segundos. Como la frecuencia de muestreo es alta, sentimos que la señal es continua cuando la escuchamos en nuestros reproductores multimedia.

¿Cómo visualizar las señales?

En un python notebook importaremos los paquetes.

%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt
from scipy.io import wavfile

 

Utilizaremos el paquete wavfile para leer el archivo de audio del archivo de entrada input_read.wav . Esto lo podrá obtener en el repositorio clickando aquí.

# Leyendo el archivo wav
sampling_freq, audio = wavfile.read('input_read.wav')

 

Y ahora imprimamos los detalles de nuestro archivo wav.

# Imprimiendo los parámetros
print ('\nShape:', audio.shape)
print ('Datatype:', audio.dtype)
print ('Duration:', round(audio.shape[0] / float(sampling_freq), 3), 'seconds')

 

La señal de audio se almacena como datos enteros con signo de 16 bits. Necesitamos normalizar estos valores:

# Normalizando los valores
audio = audio / (2.**15)

 

Extraigamos los primeros 30 valores para poderlos graficar.

# Extraer los primeros 30 valores para graficar
audio = audio[:30]

 

El eje X es el eje del tiempo. Construyamos este eje, considerando el hecho de que debería escalarse utilizando el factor de frecuencia de muestreo:

# Construyendo el eje del tiempo
x_values = np.arange(0, len(audio), 1) / float(sampling_freq)
# Conviertiendo a segundos
x_values *= 1000

 

Y procedamos a graficar.

# Graficando la señal cortada
plt.plot(x_values, audio, color='black')
plt.xlabel('Tiempo (ms)')
plt.ylabel('Amplitud')
plt.title('Señal de Audio')
plt.show()

 

Obtendremos algo así.

señal de audio

 

Transformada de Fourier

Las señales de audio consisten en una mezcla compleja de ondas sinusoidales de diferentes frecuencias, amplitudes y fases. Las ondas sinusoidales también se conocen como sinusoides. Hay mucha información oculta en el contenido de frecuencia de una señal de audio. De hecho, una señal de audio se caracteriza fuertemente por su contenido de frecuencia. Todo el mundo del habla y la música se basa en este hecho. Antes de continuar, necesitará algunos conocimientos sobre las transformadas de Fourier. Una actualización rápida la puede encontrar aquí. Ahora, echemos un vistazo a cómo transformar una señal de audio en el dominio de frecuencia.

Lea el archivo input_freq.wav que lo encuentra en el repositorio y normalizamos.

La señal de audio es solo una matriz NumPy. Entonces, puede extraer la longitud usando el siguiente código:

# Leyendo el archivo input_freq
sampling_freq, audio = wavfile.read('input_freq.wav')
# Normalizando los valores
audio = audio / (2.**15)
# Extraer longitud
len_audio = len(audio)

 

Apliquemos la transformada de Fourier. La señal de transformación de Fourier se refleja a lo largo del centro, por lo que solo necesitamos tomar la primera mitad de la señal transformada. Nuestro objetivo final es extraer la señal de potencia. Entonces, cuadramos los valores en la señal en preparación para esto:

# Aplicando la transformada de Fourier
transformed_signal = np.fft.fft(audio)
half_length = int(np.ceil((len_audio + 1) / 2.0))
transformed_signal = abs(transformed_signal[0:half_length])
transformed_signal /= float(len_audio)
transformed_signal **= 2

 

Debemos ahora extraer la longitud de la señal transformada, duplicar la señal de acuerdo a la longitud y convertir a decibeles.

# Extraer la longitud de la señal transformada
len_ts = len(transformed_signal)

# Casos pares e impares
if len_audio % 2:
    transformed_signal[1:len_ts] *= 2
else:
    transformed_signal[1:len_ts-1] *= 2


# Extrayendo la potencia en decibeles dB
power = 10 * np.log10(transformed_signal)

 

El eje X es el eje del tiempo. Necesitamos escalar esto de acuerdo con la frecuencia de muestreo y luego convertirlo en segundos para posteriormente graficar:

# Construyendo el eje del tiempo
x_values = np.arange(0, half_length, 1) * (sampling_freq / len_audio) / 1000.0

# Graficando
plt.figure()
plt.plot(x_values, power, color='black')
plt.xlabel('Freq (in kHz)')
plt.ylabel('Power (in dB)')
plt.show()

 

Y nuestra imagen será algo mas o menos así.

fourier

Generando señales de audio

Podemos usar NumPy para generar señales de audio. Como se mencionó anteriormente, las señales de audio son mezclas complejas de sinusoides. Por lo tanto, lo tendremos en cuenta cuando generemos nuestra propia señal de audio.

Necesitamos primero definir el archivo de salida donde se almacenará el audio generado. Lo pueden descargar aquí.

# Archivo que será guardado
output_file = 'output_generated.wav'

 

Especifiquemos los parámetros de generación de audio. Queremos generar una señal larga de tres segundos con una frecuencia de muestreo de 44100 y una frecuencia tonal de 587 Hz. Los valores en el eje de tiempo irán de -2 * pi a 2 * pi.

Tambiéne generemos el eje del tiempo y la señal de audio. La señal de audio es una sinusoide simple con los parámetros mencionados anteriormente y agreguemos un poco de ruido.

 

# Especificando los parámetros del audio
duration = 3  # segundos
sampling_freq = 44100  # Hz
tone_freq = 587
min_val = -2 * np.pi
max_val = 2 * np.pi

# Generar audio
t = np.linspace(min_val, max_val, duration * sampling_freq)
audio = np.sin(2 * np.pi * tone_freq * t)

# Añadir ruido
noise = 0.4 * np.random.rand(duration * sampling_freq)
audio += noise

 

Necesitamos escalar los valores a enteros de 16 bits antes de almacenarlos:

# Escalar a 16 bits los valores enteros
scaling_factor = pow(2,15) - 1
audio_normalized = audio / np.max(np.abs(audio))
audio_scaled = np.int16(audio_normalized * scaling_factor)

# Escribir el archivo de salida
write(output_file, sampling_freq, audio_scaled)

 

Luego hacemos lo que ya hemos hecho anteriormente.

# Extraer los primeros 100 valores
audio = audio[:100]

# Construyendo el eje del tiempo
x_values = np.arange(0, len(audio), 1) / float(sampling_freq)

# Convirtiendo a segundos
x_values *= 1000

# Graficando la señal
plt.plot(x_values, audio, color='black')
plt.xlabel('Tiempo (ms)')
plt.ylabel('Amplitud')
plt.title('Señal de audio')
plt.show()

 

señal generada

 

Generación de música

Ahora que sabemos cómo generar audio, usemos este principio para sintetizar algo de música. Puedes consultar este enlace. Este enlace enumera varias notas, como A, G, D, etc., junto con sus frecuencias correspondientes. Usaremos esto para generar música simple.

Los pasos son los siguientes:

  • Importamos la librería json.
  • Defina una función para sintetizar un tono, en función de los parámetros de entrada.
  • Construya la muestra de audio utilizando los argumentos de entrada, como la amplitud y la frecuencia.
  • Definamos la función principal. En el repositorio encontrará un archivo JSON llamado tone_freq_map.json, que contiene algunas notas junto con sus frecuencias.
  • Generemos algunas notas en secuencia para darle una sensación musical. Defina una secuencia de notas junto con sus duraciones en segundos.
  • Repite esta lista y llama a la función de sintetizador para cada uno de ellos.

 

import json
 
# Sintetizar
def synthesizer(freq, duration, amp=1.0, sampling_freq=44100):
    # Construir el eje del tiempo
    t = np.linspace(0, duration, duration * sampling_freq)

    # Construir la señal de audio
    audio = amp * np.sin(2 * np.pi * freq * t)

    return audio.astype(np.int16) 

if __name__=='__main__':
    # Archivo json que contiene el mapa de las notas
    tone_map_file = 'tone_freq_map.json'
    
    # Leyendo el mapa de frecuencias
    with open(tone_map_file, 'r') as f:
        tone_freq_map = json.loads(f.read())
        
    # Configurando parámetros para la nota G
    input_tone = 'G'
    duration = 2     # seconds
    amplitude = 10000
    sampling_freq = 44100    # Hz

    # Generando el tono
    synthesized_tone = synthesizer(tone_freq_map[input_tone], duration, amplitude, sampling_freq)

    # Escribiendo al archivo de salida
    write('output_tone.wav', sampling_freq, synthesized_tone)

 

Puede abrir el archivo output_tone_seq.wav en su reproductor multimedia y escucharlo. ¡Puedes sentir la música!

Todo el repositorio completo lo puedes encontrar en mi github.

Si te gustó este tutorial o tienes alguna pregunta por favor deja tu comentario.

Previous

Clases en Python [Guía Completa]

La ciencia de datos como una profesión

Next

1 comentario en “Generación de música con Python”

  1. You actually make it seem so easy with your presentation but I find
    this matter to be actually something which I think I would never understand.
    It seems too complicated and extremely broad for me.
    I am looking forward for your next post, I’ll try to
    get the hang of it!

    Responder

Deja un comentario