1 题: 使用Python 3捕获192 kHz音频

在...创建的问题 Wed, Oct 30, 2013 12:00 AM

我需要使用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捕获声音的频谱图

拍摄声音的频谱图使用Audacity

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

    
12
  1. 不幸的是我没有遇到过这样的问题,而且目前没有设备可以做任何测试。但我要尝试的一件事是检查您正在使用的录音设备是否被PyAudio ”支持“采样率。
    2013-10-30 19:38:58Z
  2. 支持似乎存在一些问题。 p.get_device_info_by_index(2)告诉我defaultSampleRate是44100,而maxInputChannels是0.当我尝试p.is_format_supported时它会返回一个错误(但不是当我检查内置声卡时)。
    2013-10-30 20:03:57Z
  3. 您的代码中的
    @ user2936487看起来您在打开流时没有指定设备索引。我会尝试p.open(..., input_device_index=dev_idx),你确保使用正确的,或循环遍历它们全部尝试。收集设备信息也一样。
    2013-10-30 20:35:06Z
  4. 当我用p.open(..., input_device_index=dev_idx)打开时,我得到以下错误OSError: [Errno Invalid number of channels] -9998,类似于我在尝试p.is_format_supported(...)ValueError: ('Invalid number of channels', -9998)时得到的结果。
    2013-10-30 20:40:46Z
  5. 我在尝试让PyAudio刚刚在OS X上运行时也得到了这个。那,和[Errno Input overflowed] -9981。我设法通过循环各种采样率,通道号和设备索引来探测正确的配置(让它立即工作)。我会尝试稍微提高代码并提出一个“答案”,也许这对你有所帮助。
    2013-10-30 20:55:39Z
  6. 醇>
    1答案                              1 跨度>                         

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

    当尝试在OS X上使用PyAudio重现您的问题时,我总是遇到[Errno Input overflowed] -9981(如几个其他,它似乎)。 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'
    
        
    5
    2017-05-23 11:53:57Z
    1. 我试过你脚本w一些小修改(添加11到DEVICES)。 pa.get_device_info_by_index(11)今天看起来更好(部分输出):... 'defaultSampleRate': 192000.0, 'hostApi': 2, 'index': 11, 'maxInputChannels': 2, 'maxOutputChannels': 1,...pa.get_host_api_info_by_index(2)给出了这个:{'defaultInputDevice': 11, 'defaultOutputDevice': 11, 'deviceCount': 1, 'index': 2, 'name': 'JACK Audio Connection Kit', 'structVersion': 1, 'type': 12}
      2013-10-31 17:06:50Z
    2. 我甚至可以打开一个流:stream = pa.open(input_device_index=11,rate=192000,format=4,channels=1,frames_per_buffer=2048,input=True),偶尔读取一个块:stream.read(1024),但大多数时候它崩溃了python:python3: malloc.c:2369: sysmalloc: ... Aborted (core dumped)
      2013-10-31 17:18:55Z
    3. 为了打开一个流,似乎我只需要找到正确的input_device_index(可以改变),然后将参数值与启动JACK时返回的值匹配( rate = 192000,format = paInt24)。但是,阅读大块的崩溃让我放弃了。我可能会用Audacity录制。非常感谢Lukas的帮助。
      2013-10-31 17:24:10Z
    4. @ user2936487欢迎您,感谢您的反馈!
      2013-10-31 21:25:43Z
    5. 醇>
来源放置 这里