2010-02-09 14 views
6

Estoy tratando de escribir un programa para mostrar datos de PCM. Estuve muy frustrado tratando de encontrar una biblioteca con el nivel correcto de abstracción, pero encontré la biblioteca de ondas python y la he estado usando. Sin embargo, no estoy seguro de cómo interpretar los datos.Interpretación de datos WAV

La función wave.getparams devuelve (2 canales, 2 bytes, 44100 Hz, 96333 cuadros, Sin compresión, Sin compresión). Todo esto parece alegre, pero luego intenté imprimir un solo cuadro: '\ xc0 \ xff \ xd0 \ xff' que es de 4 bytes. Supongo que es posible que un marco sea de 2 muestras, pero las ambigüedades no terminan ahí.

96.333 marcos * 2 muestras/cuadro * (1/44.1k seg/muestra) = 4.3688 segundos

Sin embargo, iTunes informa el tiempo que más cerca de 2 segundos y los cálculos basados ​​en el tamaño del archivo y la tasa de bits están en la estadio de béisbol de 2.7 segundos. ¿Que está pasando aqui?

Además, ¿cómo puedo saber si los bytes están firmados o sin firmar?

¡Muchas gracias!

Respuesta

8

"Dos canales" significa estéreo, por lo que no tiene sentido suma duración de cada canal, por lo que está desactivado en un factor de dos (2.18 segundos, no 4.37). En cuanto a los de signo, como se explica por ejemplo here, y cito:

8-bits muestras se almacenan como bytes sin signo , que van de 0 a 255. 16 bits muestras se almacenan como complemento a 2 firmado enteros, que van desde -32768 a 32767.

Esto es parte de las especificaciones del formato WAV (en realidad de su superconjunto RIFF) y por lo tanto no depende de lo que la biblioteca está utilizando para hacer frente a un archivo WAV .

+0

¡Gracias! Solo puedo esperar que fue mi falta de sueño lo que me impidió ver el número de estéreo ;-) – SapphireSun

2

Cada muestra es de 16 bits y allí 2 canales, por lo que el bastidor de toma 4 bytes

2

La duración es simplemente el número de tramas divididas por el número de cuadros por segundo. A partir de sus datos esto es: 96333/44100 = 2.18 seconds.

4

Sé que ya se ha aceptado una respuesta, pero hice algunas cosas con audio hace un tiempo y tienes que descomprimir la onda haciendo algo como esto.

pcmdata = wave.struct.unpack("%dh"%(wavedatalength),wavedata) 

Además, un paquete que usé se llamaba PyAudio, aunque todavía tenía que usar el paquete de onda con él.

17

¡Gracias por su ayuda! Lo tengo trabajo y voy a publicar aquí la solución para que todos puedan usar en caso de que alguna otra pobre alma lo necesita:

import wave 
import struct 

def pcm_channels(wave_file): 
    """Given a file-like object or file path representing a wave file, 
    decompose it into its constituent PCM data streams. 

    Input: A file like object or file path 
    Output: A list of lists of integers representing the PCM coded data stream channels 
     and the sample rate of the channels (mixed rate channels not supported) 
    """ 
    stream = wave.open(wave_file,"rb") 

    num_channels = stream.getnchannels() 
    sample_rate = stream.getframerate() 
    sample_width = stream.getsampwidth() 
    num_frames = stream.getnframes() 

    raw_data = stream.readframes(num_frames) # Returns byte data 
    stream.close() 

    total_samples = num_frames * num_channels 

    if sample_width == 1: 
     fmt = "%iB" % total_samples # read unsigned chars 
    elif sample_width == 2: 
     fmt = "%ih" % total_samples # read signed 2 byte shorts 
    else: 
     raise ValueError("Only supports 8 and 16 bit audio formats.") 

    integer_data = struct.unpack(fmt, raw_data) 
    del raw_data # Keep memory tidy (who knows how big it might be) 

    channels = [ [] for time in range(num_channels) ] 

    for index, value in enumerate(integer_data): 
     bucket = index % num_channels 
     channels[bucket].append(value) 

    return channels, sample_rate 
1

Sobre la base de this answer, se puede conseguir un buen aumento de rendimiento mediante el uso de numpy.fromstring o numpy.fromfile. También vea this answer.

Esto es lo que hice:

def interpret_wav(raw_bytes, n_frames, n_channels, sample_width, interleaved = True): 

    if sample_width == 1: 
     dtype = np.uint8 # unsigned char 
    elif sample_width == 2: 
     dtype = np.int16 # signed 2-byte short 
    else: 
     raise ValueError("Only supports 8 and 16 bit audio formats.") 

    channels = np.fromstring(raw_bytes, dtype=dtype) 

    if interleaved: 
     # channels are interleaved, i.e. sample N of channel M follows sample N of channel M-1 in raw data 
     channels.shape = (n_frames, n_channels) 
     channels = channels.T 
    else: 
     # channels are not interleaved. All samples from channel M occur before all samples from channel M-1 
     channels.shape = (n_channels, n_frames) 

    return channels 

Asignar un nuevo valor para dar forma generará un error si se requiere que los datos se van a copiar en la memoria.Esto es algo bueno, ya que desea utilizar los datos en su lugar (utilizando menos tiempo y memoria en general). La función ndarray.T tampoco copia (es decir, devuelve una vista) si es posible, pero no estoy seguro de cómo garantiza que no se copia.

lectura directamente desde el archivo con np.fromfile será aún mejor, pero que tendría que saltar la cabecera utilizando un dtype personalizado. No he intentado esto todavía.

Cuestiones relacionadas