37

Pythonでリアルタイムのプロットサウンドを作ろうとしています。マイクからチャンクを取得する必要があります。

PyAudioを使用して、使用してみてください

import pyaudio
import wave
import sys

chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"

p = pyaudio.PyAudio()

stream = p.open(format = FORMAT,
                channels = CHANNELS,
                rate = RATE,
                input = True,
                frames_per_buffer = chunk)

print "* recording"
all = []
for i in range(0, RATE / chunk * RECORD_SECONDS):
    data = stream.read(chunk)
    all.append(data)
print "* done recording"

stream.close()
p.terminate()

その後、次のエラーが表示されます。

* recording
Traceback (most recent call last):
  File "gg.py", line 23, in <module>
    data = stream.read(chunk)
  File "/usr/lib64/python2.7/site-packages/pyaudio.py", line 564, in read
    return pa.read_stream(self._stream, num_frames)
IOError: [Errno Input overflowed] -9981

このバッファが理解できません。ブロッキング IO モードを使用したいので、チャンクが利用できない場合は、それらのチャンクを待ちたいと思います。しかし、try except segment または sleep(0.1) を作成すると、クリック音が聞こえるので、これは私が望むものではありません。

私の問題に最適な解決策を提案してください。

4

9 に答える 9

32

pyaudio.Stream.read()にキーワード parameter がある場合はexception_on_overflow、これを False に設定します。

サンプルコードは次のようになります。

import pyaudio
import wave
import sys

chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"

p = pyaudio.PyAudio()

stream = p.open(format = FORMAT,
                channels = CHANNELS,
                rate = RATE,
                input = True,
                frames_per_buffer = chunk)

print "* recording"
all = []
for i in range(0, RATE / chunk * RECORD_SECONDS):
    data = stream.read(chunk, exception_on_overflow = False)
    all.append(data)
print "* done recording"

stream.close()
p.terminate()

詳細については、PyAudio のドキュメントを参照してください。

于 2016-02-16T20:38:55.417 に答える
14

多くの人がこの問題に遭遇しているようです。少し調べてみたところ、前回の呼び出しstream.read()と現在の呼び出しの間に、ストリームからのデータが失われた (つまり、クリアしたよりも早くバッファーがいっぱいになった) ことを意味していると思います。

(最終的に呼び出しを終了するPa_ReadStream()PortAudio 関数)のドキュメントから:stream.read()

@return On success PaNoError will be returned, or PaInputOverflowed if
input data was discarded by PortAudio after the previous call and
before this call.

(PaInputOverflowedその後IOError、pyaudio ラッパーで が発生します)。

すべてのフレームをキャプチャしなくても問題ない場合は、このエラーを無視してかまいません。すべてのフレームを取得することが絶対に重要な場合は、アプリケーションの優先順位を上げる方法を見つける必要があります。これを行うための Pythonic な方法を知るほど Python に精通していませんが、単純なniceコマンドを試すか、スケジューリング ポリシーを SCHED_DEADLINE に変更する価値があります。

編集:

現在の 1 つの問題は、IOError がスローされると、その呼び出しで収集されたすべてのフレームが失われることです。代わりにオーバーフローを無視して、私たちが持っているものだけを返すには、以下のパッチを適用できます。これにより、stream.read() は PortAudio からの出力アンダーランと入力オーバーフロー エラーを無視します (ただし、別のエラーが発生した場合は何かをスローします)。より良い方法は、ニーズに応じてこの動作 (スローする/スローしない) をカスタマイズ可能にすることです。

diff --git a/src/_portaudiomodule.c b/src/_portaudiomodule.c
index a8f053d..0878e74 100644
--- a/src/_portaudiomodule.c
+++ b/src/_portaudiomodule.c
@@ -2484,15 +2484,15 @@ pa_read_stream(PyObject *self, PyObject *args)
     } else {
       /* clean up */
       _cleanup_Stream_object(streamObject);
+
+      /* free the string buffer */
+      Py_XDECREF(rv);
+
+      PyErr_SetObject(PyExc_IOError,
+                       Py_BuildValue("(s,i)",
+                                     Pa_GetErrorText(err), err));
+      return NULL;
     }
-
-    /* free the string buffer */
-    Py_XDECREF(rv);
-
-    PyErr_SetObject(PyExc_IOError,
-                   Py_BuildValue("(s,i)",
-                                 Pa_GetErrorText(err), err));
-    return NULL;
   }

   return rv;
于 2015-02-18T01:41:31.557 に答える
11

コードを実行したときに同じエラーが発生しました。デフォルトのオーディオデバイスであるMacBookの内蔵マイクのデフォルトのサンプルレートを調べたところ、44100Hzではなく48000Hzでした。

p.get_device_info_by_index(0)['defaultSampleRate']
Out[12]: 48000.0

RATEをこの値に変更すると、機能しました。

于 2012-12-08T05:10:12.750 に答える
7

私はこれをOS X 10.10で作業しました。SYBA USBカード(Cメディアチップセット)のマイクからオーディオを取得しようとしているときに同じエラーが発生し、fftなどでリアルタイムで処理しました:

IOError: [Errno Input overflowed] -9981

libbkmz によって書かれたように、ブロッキング モードの代わりにコールバック モードを使用すると、オーバーフローは完全に解決されました。 ( https://www.python.org/dev/peps/pep-0263/ )

それに基づいて、作業コードのビットは次のようになりました。

"""
Creating the audio stream from our mic
"""
rate=48000
self.chunk=2**12
width = 2

p = pyaudio.PyAudio()

# callback function to stream audio, another thread.
def callback(in_data,frame_count, time_info, status):
    self.audio = numpy.fromstring(in_data,dtype=numpy.int16)
    return (self.audio, pyaudio.paContinue)

#create a pyaudio object
self.inStream = p.open(format = p.get_format_from_width(width, unsigned=False),
                       channels=1,
                       rate=rate,
                       input=True,
                       frames_per_buffer=self.chunk,
                       stream_callback = callback)

"""
Setting up the array that will handle the timeseries of audio data from our input
"""
self.audio = numpy.empty((self.buffersize),dtype="int16")

    self.inStream.start_stream()

while True:
  try:
    self.ANY_FUNCTION() #any function to run parallel to the audio thread, running forever, until ctrl+C is pressed. 

  except KeyboardInterrupt:

    self.inStream.stop_stream()
    self.inStream.close()
    p.terminate()
    print("* Killed Process")
    quit()

このコードは、コールバック関数を作成し、次にストリーム オブジェクトを作成して開始し、任意の関数でループします。別のスレッドがオーディオをストリーミングし、メイン ループが停止するとそのストリームは閉じられます。self.audio は任意の関数で使用されます。また、終了しないとスレッドが永久に実行されるという問題もありました。

Pyaudio はこのストリームを別のスレッドで実行し、これによりオーディオ ストリームが安定したため、スクリプト内の残りのプロセスの速度またはタイミングによっては、ブロッキング モードが飽和していた可能性があります。

チャンク サイズは 2^12 ですが、それより小さいチャンクでも同様に機能することに注意してください。私が検討し、それらがすべて意味を成していることを確認するために試してみた他のパラメーターがあります。

  • チャンクサイズの増減 (影響なし)
  • バッファー内のワードのビット数とフォーマット。この場合は符号付き 16 ビットです。
  • 変数の符号性 (unsigned と得られた飽和パターンで試した)
  • マイク入力の性質、およびシステムでのデフォルトとしての選択、ゲインなど。

それが誰かのために働くことを願っています!

于 2015-10-02T05:59:20.647 に答える
3
FORMAT = pyaudio.paInt16

正しいフォーマットを設定してください。私の内蔵マイクは 24 ビットに設定されていました (Audio-Midi-Setup アプリケーションを参照)。

于 2013-01-15T15:48:02.580 に答える
2

本当に遅いラズベリーパイでも同じ問題がありましたが、データを保存するためのより高速なモジュールを使用することで(ほとんどの場合)解決できました。array

import array
import pyaudio 

FORMAT = pyaudio.paInt16
CHANNELS = 1
INPUT_CHANNEL=2
RATE = 48000
CHUNK = 512

p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
                channels=CHANNELS,
                rate=RATE,
                input=INPUT_CHANNEL,
                frames_per_buffer =CHUNK)

print("* recording")


try:
    data = array.array('h')
    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
        data.fromstring(stream.read(CHUNK))
finally:
    stream.stop_stream()
    stream.close()
    p.terminate()

print("* done recording")

その後の内容dataはかなりバイナリです。numpy.array(data, dtype='i')ただし、整数のnumpy配列を取得するために使用できます。

于 2016-01-14T12:13:51.913 に答える