使用Python 3捕获192 kHz音频

时间:2013-10-30 19:20:53

标签: python audio python-3.x pyaudio jack

我需要使用Python 3捕获192 kHz音频以进行一些生物声学实验。 我有硬件,声音设备USBPre 2声卡,麦克风具有高达100 kHz的良好频率响应曲线,我已经启用了我的操作系统(ubuntu 13.04)以192 kHz的频率从该卡中采样。

我尝试用PyAudio录音。它似乎工作,并将给我一个采样率为192 kHz的wav文件。然而,当我观察光谱时,没有超过24 kHz的功率,这表明PyAudio不是真正捕获192 kHz,而是48 kHz。但是,当我使用Audacity录制来自JACK的输入时,我得到了一个很好的录音,功率高达96kHz。所以,我的印象是PyAudio实际上并没有以192 kHz采样声音,即使它应该能够。 如何解决这个问题?

我没有错误地启动JACK:

/usr/bin/jackd -R -dalsa -Chw:1,0 -n3 -o1 -p2048 -r192000

jackd 0.122.0
Copyright 2001-2009 Paul Davis, Stephane Letz, Jack O'Quinn, Torben Hohn and others.
jackd comes with ABSOLUTELY NO WARRANTY
This is free software, and you are welcome to redistribute it
under certain conditions; see the file COPYING for details

JACK compiled with System V SHM support.
loading driver ..
apparent rate = 192000
creating alsa driver ... -|hw:1,0|2048|3|192000|0|1|nomon|swmeter|-|32bit
control device hw:0
configuring for 192000Hz, period = 2048 frames (10.7 ms), buffer = 3 periods
ALSA: final selected sample format for capture: 24bit little-endian
ALSA: use 3 periods for capture

初始化PyAudio(没有任何实际错误(据我所知)):

p = pyaudio.PyAudio()
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
bt_audio_service_open: connect() failed: Connection refused (111)
bt_audio_service_open: connect() failed: Connection refused (111)
bt_audio_service_open: connect() failed: Connection refused (111)
bt_audio_service_open: connect() failed: Connection refused (111)
ALSA lib pcm_dmix.c:957:(snd_pcm_dmix_open) The dmix plugin supports only playback stream

打开PyAudio流:

stream = p.open(format=pyaudio.paInt32,
                channels=1,rate=192000,
                input=True,
                frames_per_buffer=2048)

我有光谱图的图像,如果有人想验证我的解释,PyAudio不能以192 kHz捕获(但Audacity确实如此):

使用PyAudio捕获声音的频谱图 Spectrogram of sound captured usig PyAudio

拍摄声音的频谱图使用Audacity Spectrogram of sound captured usig Audacity

如何使用PyAudio以192 000样本/秒的速度录制声音? 我们也欢迎使用Python 3捕获声音的其他方法的建议。

1 个答案:

答案 0 :(得分:5)

这并不是一个确凿的答案,而是试图帮助您自己追踪问题。

当尝试在OS X上使用PyAudio重现您的问题时,我总是遇到[Errno Input overflowed] -9981(例如several其他peopleseems)。 p.is_format_supported()报告为OK的配置也会导致这些错误。所以我制作了一个脚本,试图记录录制设置的所有可能的排列。

此脚本会探测设备采样率格式频道列表的所有排列防御方式,并将结果保存到根据录制设置命名的文件。

import os
import pyaudio
import sys

# === These parameters will be permuted ===========
DEVICES = [0, 1, 2]
RATES = [44100, 48000, 192000]
FORMATS = ['Float32', 'Int32', 'Int24', 'Int16', 'Int8', 'UInt8']
CHANNELS = [1, 2]
# =================================================

CHUNK = 1024
COLUMNS = (('filename', 30),
           ('result', 9),
           ('dev', 5),
           ('rate', 8),
           ('format', 9),
           ('channels', 10),
           ('chunk', 7),
           ('reason', 0))
STATUS_MSG = "Recording... "

pa = pyaudio.PyAudio()


def get_format(format):
    fmt = getattr(pyaudio, 'pa%s' % format)
    return fmt


def record(filename=None,
           duration=5,
           dev=0,
           rate=44100,
           format='Float32',
           channels=2,
           chunk=1024,):
    """Record `duration` seconds of audio from the device with index `dev`.
    Store the result in a file named according to recording settings.
    """
    if filename is None:
        filename = "dev{dev}-{rate}-{format}-{channels}ch.raw".format(**locals())
    result = 'FAILURE'
    reason = ''

    outfile = open(filename, 'w')
    print STATUS_MSG,
    sys.stdout.flush()

    try:
        stream = pa.open(input_device_index=dev,
                         rate=rate,
                         format=get_format(format),
                         channels=channels,
                         frames_per_buffer=chunk,
                         input=True,
                         )

        try:
            for i in range(0, rate / (chunk) * duration):
                a = stream.read(chunk)
                outfile.write(a)
            result = 'SUCCESS'
        # Catch exceptions when trying to read from stream
        except Exception, e:
            reason = "'%s'" % e
    # Catch exceptions when trying to even open the stream
    except Exception, e:
        reason = "'%s'" % e

    outfile.close()

    # Don't leave files behind for unsuccessful attempts
    if result == 'FAILURE':
        os.remove(filename)
        filename = ''

    info = {}
    for col_name, width in COLUMNS:
        info[col_name] = str(locals()[col_name]).ljust(width)

    msg = "{filename}{result}{dev}{rate}{format}{channels}{chunk}{reason}"
    print msg.format(**info)

def main():
    # Build the header line
    header = 'STATUS'.ljust(len(STATUS_MSG) + 1)
    for col_name, width in COLUMNS:
        header += col_name.upper().ljust(width)
    print header
    print "=" * len(header)

    # Record samples for all permutations of our parameter lists
    for dev in DEVICES:
        for rate in RATES:
            for format in FORMATS:
                for channels in CHANNELS:
                    record(duration=2,
                           dev=dev,
                           rate=rate,
                           format=format,
                           channels=channels,
                           chunk=CHUNK)

if __name__ == '__main__':
    main()

示例输出(简化):

STATUS        FILENAME                      RESULT   DEV  RATE    FORMAT   CHANNELS  CHUNK  REASON
==================================================================================================
Recording...  dev0-44100-Float32-1ch.raw    SUCCESS  0    44100   Float32  1         1024
Recording...  dev0-44100-Float32-2ch.raw    SUCCESS  0    44100   Float32  2         1024
Recording...  dev0-44100-Int16-1ch.raw      SUCCESS  0    44100   Int16    1         1024
Recording...  dev0-44100-Int16-2ch.raw      SUCCESS  0    44100   Int16    2         1024
Recording...                                FAILURE  0    192000  Float32  1         1024   '[Errno Input overflowed] -9981'
Recording...                                FAILURE  0    192000  Float32  2         1024   '[Errno Input overflowed] -9981'
Recording...                                FAILURE  0    192000  Int16    1         1024   '[Errno Input overflowed] -9981'
Recording...                                FAILURE  0    192000  Int16    2         1024   '[Errno Input overflowed] -9981'
Recording...  dev1-44100-Float32-1ch.raw    SUCCESS  1    44100   Float32  1         1024
Recording...  dev1-44100-Float32-2ch.raw    SUCCESS  1    44100   Float32  2         1024
Recording...  dev1-44100-Int16-1ch.raw      SUCCESS  1    44100   Int16    1         1024
Recording...  dev1-44100-Int16-2ch.raw      SUCCESS  1    44100   Int16    2         1024
Recording...                                FAILURE  1    192000  Float32  1         1024   '[Errno Input overflowed] -9981'
Recording...                                FAILURE  1    192000  Float32  2         1024   '[Errno Input overflowed] -9981'
Recording...                                FAILURE  1    192000  Int16    1         1024   '[Errno Input overflowed] -9981'
Recording...                                FAILURE  1    192000  Int16    2         1024   '[Errno Input overflowed] -9981'
Recording...                                FAILURE  2    44100   Float32  1         1024   '[Errno Invalid number of channels] -9998'
Recording...                                FAILURE  2    44100   Float32  2         1024   '[Errno Invalid number of channels] -9998'
Recording...                                FAILURE  2    44100   Int16    1         1024   '[Errno Invalid number of channels] -9998'
Recording...                                FAILURE  2    44100   Int16    2         1024   '[Errno Invalid number of channels] -9998'
Recording...                                FAILURE  2    192000  Float32  1         1024   '[Errno Invalid number of channels] -9998'
Recording...                                FAILURE  2    192000  Float32  2         1024   '[Errno Invalid number of channels] -9998'
Recording...                                FAILURE  2    192000  Int16    1         1024   '[Errno Invalid number of channels] -9998'
Recording...                                FAILURE  2    192000  Int16    2         1024   '[Errno Invalid number of channels] -9998'