PyAudio - How mix wave file into a continuous stream

穿精又带淫゛_ 提交于 2019-12-11 14:22:26

问题


I want to write a very basic application that passes audio from microphone to speakers. This is very simple with pyaudio as described on https://people.csail.mit.edu/hubert/pyaudio/ .

def passthrough():
    WIDTH = 2
    CHANNELS = 1
    RATE = 44100

    p = pyaudio.PyAudio()

    def callback(in_data, frame_count, time_info, status):

        return (in_data, pyaudio.paContinue)

    stream = p.open(format=p.get_format_from_width(WIDTH),
                    channels=CHANNELS,
                    rate=RATE,
                    input=True,
                    output=True,
                    stream_callback=callback)

    stream.start_stream()

    while stream.is_active():
        time.sleep(0.1)

    stream.stop_stream()
    stream.close()

    p.terminate()

But now I try to mix a wave file into this stream, when an event occurs. And that's where I am stuck right now. Playing a wave file seems to be easy, too.

def play_wave(wav_file):
    wf = wave.open(wav_file, 'rb')

    sample_width=wf.getsampwidth()
    channels=wf.getnchannels()
    rate=wf.getframerate()
    second=sample_width*channels*rate

    def callback(in_data, frame_count, time_info, status):
        data = wf.readframes(frame_count)
        return (data, pyaudio.paContinue)

    p = pyaudio.PyAudio()

    stream = p.open(format=p.get_format_from_width(sample_width),
                channels=channels,
                rate=int(rate),
                output=True,
                stream_callback=callback)
    stream.start_stream()

    while stream.is_active():
        time.sleep(0.1)

    stream.stop_stream()
    stream.close()
    wf.close()

    p.terminate()

At this time, I have two problems.

  1. How do I mix the wave output into the continuous stream
  2. How can I trigger 1. on an event basis

Hope someone can light up the dark basement I am in right now.

EDIT: Assume the wave file to have same number of channels and same rate, so no conversion necessary.


回答1:


After moving the throughput() function into a thread it works like desired. When I tried this yesterday, I just fucked up the thread start (called throughput from init instead in run() method).

So here the complete, working code.

import pyaudio
import wave
import threading
import time

class AudioPass(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        self.passthrough()
    def passthrough(self):
        WIDTH = 2
        CHANNELS = 1
        RATE = 44100

        p = pyaudio.PyAudio()

        def callback(in_data, frame_count, time_info, status):

            return (in_data, pyaudio.paContinue)

        stream = p.open(format=p.get_format_from_width(WIDTH),
                        channels=CHANNELS,
                        rate=RATE,
                        input=True,
                        output=True,
                        stream_callback=callback)

        stream.start_stream()

        while stream.is_active():
            time.sleep(0.1)

        stream.stop_stream()
        stream.close()

        p.terminate()


def play_wave(wav_file):
    wf = wave.open(wav_file, 'rb')

    sample_width=wf.getsampwidth()
    channels=wf.getnchannels()
    rate=wf.getframerate()
    second=sample_width*channels*rate

    def callback(in_data, frame_count, time_info, status):
        data = wf.readframes(frame_count)
        return (data, pyaudio.paContinue)

    p = pyaudio.PyAudio()

    stream = p.open(format=p.get_format_from_width(sample_width),
                channels=channels,
                rate=int(rate),
                output=True,
                stream_callback=callback)
    stream.start_stream()

    while stream.is_active():
        time.sleep(0.1)

    stream.stop_stream()
    stream.close()
    wf.close()

    p.terminate()

thread = AudioPass()
thread.start()
play_wave('C:/bell.wav')

Later I will also try another way a colleauge suggested today and if it does well too, I will put it here as an alternative, too. Using the threaded way is nice because I can use different rates for the stream and the wav file.




回答2:


A colleague provided the below solution, which is a very raw approach, but it works and is good for understanding how this pyaudio stuff works.

import time
import pyaudio
import numpy
WIDTH = 2
CHANNELS = 1
RATE = 44100
p = pyaudio.PyAudio()
SINE_WAVE_FREQUENCY = 440.0 # In Hz
SINE_WAVE_DURATION = 5.0 # In seconds
SINE_WAVE_VOLUME = 0.5
SINE_WAVE = (numpy.sin(2 * numpy.pi * numpy.arange(RATE * SINE_WAVE_DURATION) * SINE_WAVE_FREQUENCY / RATE)).astype(numpy.float32) * SINE_WAVE_VOLUME
def loopback(in_data, frame_count, time_info, status):
        return (in_data, pyaudio.paContinue)
stream = p.open(format=p.get_format_from_width(WIDTH), channels=CHANNELS, rate=RATE, input=True, output=True, stream_callback=loopback)
stream.start_stream()
def playsine():
        sinestream = p.open(format=pyaudio.paFloat32, channels=1, rate=RATE, output=True)
        sinestream.write(SINE_WAVE)
        sinestream.stop_stream()
        sinestream.close()
while True:
        input("Press enter to play a sine wave")
        playsine()


来源:https://stackoverflow.com/questions/45700970/pyaudio-how-mix-wave-file-into-a-continuous-stream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!