I need to capture 192 kHz audio for some bioacoustics experiments using Python 3. I have the hardware, a Sound Devices USBPre 2 sound card, a microphone with good frequency response curve up to 100 kHz, and I have enabled my os (ubuntu 13.04) to sample from this card at 192 kHz.
I have tried recording with PyAudio. It appears to work, and will give me a wav file with a sampling rate of 192 kHz. However, when I look at the spectra there is no power above 24 kHz, suggesting that PyAudio doesn't really capture at 192 kHz, but rather at 48 kHz. However, when I record using Audacity with input from JACK, I get a nice recording with power up to 96kHz. So, I have the impression that PyAudio doesn't actually sample the sound at 192 kHz even though it should be able to. How to fix this?
I start JACK without errors:
/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
Initialize PyAudio (without any real errors (as far as I can tell)):
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
Open a PyAudio stream:
stream = p.open(format=pyaudio.paInt32,
channels=1,rate=192000,
input=True,
frames_per_buffer=2048)
I have images of the spectrograms, in case someone wants to verify my interpretation that PyAudio doesn't capture at 192 kHz (but Audacity does):
Spectrogram of sound captured usig PyAudio
Spectrogram of sound captured usig Audacity
How can I record sound at 192 000 samples/s using PyAudio? Suggestions of other ways to capture sound using Python 3 are also welcome.
Recording AudioThe python-sounddevice and pyaudio libraries provide ways to record audio with Python. python-sounddevice records to NumPy arrays and pyaudio records to bytes objects. Both of these can be stored as WAV files using the scipy and wave libraries, respectively.
To use PyAudio, first instantiate PyAudio using pyaudio. PyAudio() (1), which sets up the portaudio system. To record or play audio, open a stream on the desired device with the desired audio parameters using pyaudio.
Play sound on Python is easy. There are several modules that can play a sound file (. wav). These solutions are cross platform (Windows, Mac, Linux).
This is not meant to be a conclusive answer, but rather an attempt to help you maybe track down the issue yourself.
When trying to reproduce your issue with PyAudio on OS X, I always kept running into [Errno Input overflowed] -9981
(like several other people, it seems).
Also configurations that p.is_format_supported()
reported as OK caused these errors. So I whipped up a script that just tries to record with all the possible permutations of the recording settings.
This script probes all permutations of lists of devices, sample rates, formats and channels, in a defensive way, and saves the results to files named according to the recording settings.
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()
Sample output (simplified):
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'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With