Síntesis de audio Python

Mehvish Ashiq 16 febrero 2024
  1. Síntesis de audio Python
  2. Utilice IPython.display para la síntesis aditiva en Python
  3. Cree varias formas de onda básicas con síntesis aditiva en Python
  4. Use pyaudio para generar síntesis de audio en Python
Síntesis de audio Python

Hoy aprenderemos sobre la síntesis de audio y cómo podemos generar sonido usando Python.

Síntesis de audio Python

La síntesis de sonido o síntesis de audio genera sonido electrónicamente (usando hardware o software) que imita la voz humana o instrumentos musicales.

La síntesis es principalmente para música, donde un dispositivo/instrumento electrónico conocido como sintetizador se usa para grabar e interpretar música.

Ahora, el punto es ¿podemos usar Python para generar este tipo de sonidos simples, por ejemplo, onda sinusoidal? ¿Tenemos algún módulo para eso, o cómo podemos crear uno propio?

Aprendamos las diferentes formas a continuación.

Utilice IPython.display para la síntesis aditiva en Python

  • Primero, importamos los módulos y bibliotecas necesarios. Importamos IPython para mostrar el reproductor de sonido, numpy para trabajar con matrices, matplotlib para trazar gráficos (lo haremos mientras generamos formas de onda básicas) y math para usar funciones matemáticas.
    import IPython.display as ipd
    import numpy
    import math
    import matplotlib.pyplot as plt
    
  • Establezca la frecuencia de muestreo. Aquí, establecemos el sample_rate con 22050.
    sample_rate = 22050
    
  • Haz la forma de onda sinusoidal.
    def makesine(frequency, duration):
        t = numpy.linspace(0, duration, math.ceil(sample_rate * duration))
        x = numpy.sin(2 * numpy.pi * frequency * t)
        return x
    

    En este paso, definimos una función makesine(), que toma frecuencia y duración como parámetros. Utilizamos los métodos duration en numpy.linspace() y frequency en numpy.sin() para reutilizar formas de onda sinusoidales puras.

    Tenga en cuenta que numpy.linspace() crea secuencias numéricas, o podemos decir que devuelve números/muestras espaciados uniformemente w.r.t. intervalo (comienzo, parada). Es similar a numpy.arange() pero toma un número de muestra (num) como parámetro en lugar de paso.

    Puedes encontrar más sobre eso aquí.

    Por otro lado, numpy.sin() calcula el seno trigonométrico para todas las x especificadas (una matriz de elementos).

  • Ejecute makesine().
    output = numpy.array(())
    y = makesine(261.63, 0.5)  # C for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    y = makesine(293.66, 0.5)  # D for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    y = makesine(329.63, 0.5)  # E for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    ipd.Audio(output, rate=sample_rate)
    

    A continuación, ejecutamos makesine() varias veces para formar una nueva forma de onda con una frecuencia y una duración especificadas. Después de eso, usamos numpy.concatenate() para colocarlos todos juntos.

    Puede encontrar el código fuente de trabajo completo a continuación con la salida respectiva.

  • Aquí está el código fuente completo.
    import IPython.display as ipd
    import matplotlib.pyplot as plt
    import numpy
    import math
    
    sample_rate = 22050
    
    
    def makesine(frequency, duration):
        t = numpy.linspace(0, duration, math.ceil(sample_rate * duration))
        x = numpy.sin(2 * numpy.pi * frequency * t)
        return x
    
    
    output = numpy.array(())
    y = makesine(261.63, 0.5)  # C for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    y = makesine(293.66, 0.5)  # D for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    y = makesine(329.63, 0.5)  # E for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    ipd.Audio(output, rate=sample_rate)
    

    PRODUCCIÓN:

    síntesis de audio de Python - ipython display.wav

Cree varias formas de onda básicas con síntesis aditiva en Python

Hemos terminado con la forma de onda sinusoidal básica. Experimentemos con varias formas de onda básicas con frecuencias en múltiplos enteros usando frecuencia * i; aquí, i es el contador de 1 y se incrementa en 1 cada vez.

Necesitamos suavizar estas ondas sinusoidales en amplitudes predefinidas (amplist), que luego se apilan en la “salida”. Para que eso suceda, debemos crear una función llamada addsyn() de la siguiente manera:

def addsyn(frequency, duration, amplist):
    i = 1
    t = numpy.linspace(0, duration, math.ceil(sample_rate * duration))
    output = numpy.zeros(t.size)

    for amp in amplist:
        x = numpy.multiply(makesine(frequency * i, duration), amp)
        output = output + x
        i += 1

    if numpy.max(output) > abs(numpy.min(output)):
        output = output / numpy.max(output)
    else:
        output = output / -numpy.min(output)
    return output

Dentro de addsyn(), inicializamos una nueva salida. Dentro del ciclo for, hacemos la forma de onda sinusoidal con una amplitud máxima (amp); aquí, frecuencia es un múltiplo entero.

Luego, lo sumamos a la salida y lo guardamos en la variable salida. A continuación, nos aseguramos de que la amplitud máxima no supere 1 y devolvemos la salida.

Ahora, podemos ejecutar el siguiente fragmento de código para hacer solo una onda sinusoidal armónica y hacer un gráfico para ella que muestre solo 0.005 segundos para ver esta forma de onda.

t = numpy.linspace(0, 1, sample_rate)
sinewave = addsyn(440, 1, [1])
plt.plot(t, sinewave)
plt.xlim(0, 0.005)
ipd.Audio(sinewave, rate=sample_rate)

El código fuente completo sería el siguiente.

Código de ejemplo:

import IPython.display as ipd
import matplotlib.pyplot as plt
import numpy
import math

sample_rate = 22050


def addsyn(frequency, duration, amplist):
    i = 1
    t = numpy.linspace(0, duration, math.ceil(sample_rate * duration))
    output = numpy.zeros(t.size)

    for amp in amplist:
        x = numpy.multiply(makesine(frequency * i, duration), amp)
        output = output + x
        i += 1

    if numpy.max(output) > abs(numpy.min(output)):
        output = output / numpy.max(output)
    else:
        output = output / -numpy.min(output)
    return output


t = numpy.linspace(0, 1, sample_rate)
sinewave = addsyn(440, 1, [1])
plt.plot(t, sinewave)
plt.xlim(0, 0.005)
ipd.Audio(sinewave, rate=sample_rate)

PRODUCCIÓN:

síntesis de audio de Python - forma de onda sinusoidal básica armónica.wav

Síntesis de audio de Python: gráfico armónico de forma de onda sinusoidal básica

Ahora, podemos jugar con diferentes valores de la función addsyn() para obtener diferentes resultados. Vea otro ejemplo para crear una onda cuadrada a continuación.

Código de ejemplo:

import IPython.display as ipd
import matplotlib.pyplot as plt
import numpy
import math

sample_rate = 22050


def addsyn(frequency, duration, amplist):
    i = 1
    t = numpy.linspace(0, duration, math.ceil(sample_rate * duration))
    output = numpy.zeros(t.size)

    for amp in amplist:
        x = numpy.multiply(makesine(frequency * i, duration), amp)
        output = output + x
        i += 1

    if numpy.max(output) > abs(numpy.min(output)):
        output = output / numpy.max(output)
    else:
        output = output / -numpy.min(output)
    return output


t = numpy.linspace(0, 1, sample_rate)
square_wave = addsyn(440, 1, [1, 0, 0.349, 0, 0.214, 0, 0.156, 0, 0.121, 0])
plt.plot(t, square_wave)
plt.xlim(0, 0.005)
ipd.Audio(square_wave, rate=sample_rate)

PRODUCCIÓN:

síntesis de audio de Python: forma de onda sinusoidal básica cuadrada.wav

Síntesis de audio de Python: gráfico cuadrado de forma de onda sinusoidal básica

Use pyaudio para generar síntesis de audio en Python

Aquí, usaremos pyaudio, un módulo de Python que graba audio con Python.

  • Primero, importamos las bibliotecas necesarias: math para realizar funciones matemáticas y pyaudio para generar ondas.
    import math  # import needed modules
    import pyaudio  # sudo apt-get install python-pyaudio
    
  • Inicializa pyaudio.
    PyAudio = pyaudio.PyAudio
    
  • Inicializar variables.
    bit_rate = 16000
    frequency = 500
    length = 1
    
    bit_rate = max(bit_rate, frequency + 100)
    number_of_frames = int(bit_rate * length)
    rest_frames = number_of_frames % bit_rate
    wave_data = ""
    

    Aquí, inicializamos el bit_rate con 16000, que muestra el número de fotogramas por segundo. La frecuencia se establece en 500 Hz que denota las ondas por segundo (261.63=nota C4) mientras que la longitud se inicializa con 1.

    Después de eso, usamos la función max() para encontrar el máximo de bit_rate y frequency+100 y asignamos el valor máximo a bit_rate. Luego, multiplicamos el bit_rate y la longitud, lo convertimos al tipo int usando la función int() y lo asignamos a number_of_frames.

    A continuación, usamos el operador de módulo (%) para dividir number_of_frames con bit_rate y asignamos el resto a rest_frames. Finalmente, inicializamos wave_data con una cadena vacía.

  • Generar ondas.
    for x in range(number_of_frames):
        wave_data = wave_data + chr(
            int(math.sin(x / ((bit_rate / frequency) / math.pi)) * 127 + 128)
        )
    
    for x in range(rest_frames):
        wave_data = wave_data + chr(128)
    

    Aquí, usamos dos bucles for que iteran hasta el number_of_frames para generar ondas.

  • Grabar audio.
    p = PyAudio()
    stream = p.open(
        format=p.get_format_from_width(1), channels=1, rate=bit_rate, output=True
    )
    stream.write(wave_data)
    stream.stop_stream()
    stream.close()
    p.terminate()
    

    Aquí, creamos una instancia de PyAudio, guardamos la referencia en p, y usamos esa referencia para abrir una secuencia usando el método open(), que grabará audio. A continuación, escribimos wave_data, detuvimos la transmisión y la cerramos. Finalmente, termine también la instancia PyAudio (p).

    Puede leer sobre open(), write(), stop_stream() y close() aquí en detalle.

  • Aquí está el código fuente completo.
    import math
    import pyaudio
    
    PyAudio = pyaudio.PyAudio
    
    bit_rate = 16000
    frequency = 500
    length = 1
    
    bit_rate = max(bit_rate, frequency + 100)
    number_of_frames = int(bit_rate * length)
    rest_frames = number_of_frames % bit_rate
    wave_data = ""
    
    for x in range(number_of_frames):
        wave_data = wave_data + chr(
            int(math.sin(x / ((bit_rate / frequency) / math.pi)) * 127 + 128)
        )
    
    for x in range(rest_frames):
        wave_data = wave_data + chr(128)
    
    p = PyAudio()
    stream = p.open(
        format=p.get_format_from_width(1), channels=1, rate=bit_rate, output=True
    )
    
    stream.write(wave_data)
    stream.stop_stream()
    stream.close()
    p.terminate()
    

    Una vez que ejecutamos el código anterior, podemos escuchar una onda. Tenga en cuenta que no estamos guardando esta ola en un archivo .wav.

    Puede leer aquí para aprender a guardar en un archivo .wav.

Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook

Artículo relacionado - Python Audio