2016-11-02 13 views
2

私は後でユーザー入力を介してサウンドをモジュレーションするために、コールバックメソッドを使用して純粋なサイントーンをストリームするためにpythonとpyaudioを使用しています。私がコードを実行すると、警告メッセージに関連したクラッキング音が1秒間に発生する以外はすべてうまくいきます。 ALSA lib pcm.c:7339:(snd_pcm_recover)アンダーランが発生しましたその後、サイントーンは正しくストリーミングされます。最初のポッピング音を取り除く方法についてのヒント? はここpyaudioのクラッキングサウンドサイントーン

import pyaudio 
import time 
import numpy as np 

CHANNELS = 1 
RATE = 44100 
freq = 600 
CHUNK = 1024 
lastchunk = 0 
def sine(current_time): 
    global freq,lastchunk 
    length = CHUNK 
    factor = float(freq)*2*np.pi/RATE 
    this_chunk = np.arange(length)+lastchunk 
    lastchunk = this_chunk[-1] 
    return np.sin(this_chunk*factor) 

def get_chunk(): 
    data = sine(time.time()) 
    return data * 0.1 


def callback(in_data, frame_count, time_info, status): 
    chunk = get_chunk() * 0.25 
    data = chunk.astype(np.float32).tostring() 
    return (data, pyaudio.paContinue) 

p = pyaudio.PyAudio() 

stream = p.open(format=pyaudio.paFloat32, 
      channels=CHANNELS, 
      rate=RATE, 
      output=True, 
      stream_callback=callback) 

stream.start_stream() 
time.sleep(1) 




stream.stop_stream() 
stream.close() 

乾杯

+0

バッファアンダースタンは、通常、コード(コールバック)が次回のDAC送信に適時にオーディオデータを提供できなかったことを意味します。あなたのコールバックには、最初の数回または最初の数回の実行に時間がかかりますか? – Linuxios

+0

もう一度見れば、 'time.sleep(1)'を取り除くとどうなりますか?これは、プログラムが1秒間応答しなくなり、コールバックが実行されなくなり、記述した問題が発生する可能性があります。 – Linuxios

+0

よく私はストリームの長さを示すためにtime.sleep(int)が必要です。 stream.stop_stream()によって直ちにストリームが終了するので、time.sleepをゼロ長のストリームで削除します。実際には、time.sleep()の長さを変更しても、異なる動作にはなりません.... –

答えて

2

PortAudio(PyAudioの背後にあるライブラリ)を使用すると、一般的にPyAudio例でCHUNKと呼ばれるブロックサイズを指定することができます1秒間の音声をストリーミングするコードです。指定しない場合、デフォルトは0です.PortAudioという用語では、ブロックサイズが自動的に選択され、コールバックからコールバックに変更されることを意味します。

これをチェックするには、コールバック内でframe_count(ブロックサイズの別名)を印刷してみてください。私はPortAudioが最初に小さすぎるブロックサイズを選択し、アンダーランが発生するとブロックサイズが増加すると思われます。私は正しい?

はこれを回避するには、使用して、最初から固定ブロックサイズを指定する必要があります。

stream = p.open(..., frames_per_buffer=CHUNK, ...) 

... frames_per_bufferはまだブロックサイズのための別の名前です。

実際のブロックサイズを知らなくても、これまでのところコード内でlength = CHUNKを使用した方が意味があります。

これでもアンダーランが発生する場合は、さらにブロックサイズを2048に増やすことができます。

最後に、自分のPortAudioラッパーであるsounddeviceモジュールのために恥知らずのプラグを作りましょう。基本的にはPyAudioと同じですが、インストールは簡単ですが、IMHOはより良いAPIを備えており、NumPyを直接サポートしています。手動変換は必要ありません。

+0

ありがとう、私の問題を解決!実際には、それを動作させるために、私はあなたの提案の両方を適用しなければなりませんでした。それは、バッファの長さをプリセットし、その長さを2048に増やすことです。 –

0

まだ受け入れられている答えは、完全なオーディオ品質を提供していません。私が聞いたこと(測定していない)から判断すると、正弦波にドロップアウトや位相のジャンプがあることがあります。 PyAudio例のコードと内容に基づいて、私は、このソリューションに来たhereを見つけることができます:

"""PyAudio Example: Play a wave file (callback version).""" 

import pyaudio 
import time 
import math 
from itertools import count 
import numpy as np 

RATE = 96000 

# More efficient calculation but period = int(framer... causes high granularity for higher frequencies (15kHz becoming 16kHz for instance) 
# def sine_wave(frequency=1000, framerate=RATE, amplitude=0.5): 
#  period = int(framerate/frequency) 
#  amplitude = max(min(amplitude, 1), 0) 
#  lookup_table = [float(amplitude) * math.sin(2.0 * math.pi * float(frequency) * 
#             (float(i % period)/float(framerate))) for i in xrange(period)] 
#  return (lookup_table[i % period] for i in count(0)) 

def sine_wave(frequency=440.0, framerate=RATE, amplitude=0.5): 
    amplitude = max(min(amplitude, 1), 0) 
    return (float(amplitude) * math.sin(2.0*math.pi*float(frequency)*(float(i)/float(framerate))) for i in count(0)) 

sine = [sine_wave(150), sine_wave(1500), sine_wave(15000)] 

# instantiate PyAudio (1) 
p = pyaudio.PyAudio() 

# define callback (2) 
def callback(in_data, frame_count, time_info, status): 
    wave = sine[0] 
    data = [wave.next()] 
    for i in range(frame_count - 1): 
     data.append(wave.next()) 
    ret_array =np.array(data).astype(np.float32).tostring() 
    return (ret_array, pyaudio.paContinue) 

# open stream using callback (3) 
stream = p.open(format=pyaudio.paFloat32, 
       channels=1, 
       rate=RATE, 
       frames_per_buffer=1024, 
       output=True, 
       stream_callback=callback) 

# start the stream (4) 
stream.start_stream() 

# Insert your own solution to end the sound 
time.sleep(3) 

# stop stream (6) 
stream.stop_stream() 
stream.close() 

# close PyAudio (7) 
p.terminate() 

これは、ハードウェアが死ぬか、次の停電までサインを再生することができるはず...しかし、唯一のI 30分テストしました;-)

関連する問題