TeamPyOgg / PyOgg

Simple OGG Vorbis, Opus and FLAC bindings for Python
The Unlicense
63 stars 27 forks source link

Playing a file with PyAudio #87

Closed DieTapete closed 3 years ago

DieTapete commented 3 years ago

Hi there, I am having trouble getting this library to work with pyaudio. I just want to decode an opus file and play it back but no combination of options seems to work. Could you provide an example?

mattgwwalker commented 3 years ago

Hi,

Thanks for your interest in PyOgg. There are a fair few examples in the library already (although they don’t use PyAudio). Have you tried those examples yet? We’re you able to get any audio to play?

Cheers,

Matthew

On Sun, 18 Jul 2021 at 11:01, DieTapete @.***> wrote:

Hi there, I am having trouble getting this library to work with pyaudio. I just want to decode an opus file and play it back but no combination of options seems to work. Could you provide an example?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/TeamPyOgg/PyOgg/issues/87, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA653XAV62YHHFKDWFOIA4LTYIDVTANCNFSM5ARQCETQ .

DieTapete commented 3 years ago

Yes, I tried those examples and managed to succeed to play a sound file. However none of the examples actually use streaming to play a file..

DieTapete commented 3 years ago

I managed to get it kind of working but it sounds weird (a bit too fast and like with a phaser effect):

import pyaudio
from pyogg import OpusFile, OpusFileStream

def play(filename: str):
    p = pyaudio.PyAudio()
    stream = OpusFileStream(filename)
    out_stream = p.open(format=p.get_format_from_width(width=2),
                         channels=stream.channels,
                         rate=stream.frequency,
                         output=True,
                         output_device_index=1)

    print("stream.bytes_per_sample {} channels: {}, frequency:{}".format(stream.bytes_per_sample, stream.channels, stream.frequency))

    while True:
        # Read the next part of the stream
        buf = stream.get_buffer_as_array()        
        # Check if we've reached the end of the stream
        if buf is None:
            break
        out_stream.write(buf)

    out_stream.stop_stream()
    out_stream.close()
    p.terminate()
Zuzu-Typ commented 3 years ago

Hey there,

well, you've basically already found the solution yourself. The only thing you need to change is how you pass on the buffer.

out_stream.write() seems to be expecting 8-bit unsigned integer values (i.e. bytes) by default and thus, when you pass the audio data array containing 16-bit signed integers, it tries to interpret those as 8-bit, resulting in double speed and clipping.

There's two ways of changing this. Either you use the get_buffer() function instead of the get_buffer_as_array() function (which is called internally anyways, so it's not like you'd lose anything), or you add another argument to the out_stream.write:

out_stream.write(buf, len(buf))

Both seem to work.

By the way, you can use stream.bytes_per_sample instead of the constant width of 2 in the get_format_from_width() function.

Cheers --Zuzu_Typ--

DieTapete commented 3 years ago

Thank you for that quick reply @ZuZu-Typ! I got it working now. :)

DieTapete commented 3 years ago

BTW: I still get a cracking sound in the beginning of the file. I avoid it for now by just skipping the first buffer.. is that the right way to go?

Zuzu-Typ commented 3 years ago

Thank you for that quick reply @Zuzu-Typ! I got it working now. :)

You're welcome (:

BTW: I still get a cracking sound in the beginning of the file. I avoid it for now by just skipping the first buffer.. is that the right way to go?

Hm.. I've tried two different files, but didn't get any cracking, at least I didn't notice any. Could you please try using a different file to check if it's doing the same thing? This is one of the two files I've tested: https://github.com/TeamPyOgg/PyOgg/blob/master/examples/left-right-demo-5s.opus

DieTapete commented 3 years ago

Right, sorry that was just that one file i used for testing.. i thought it was similar to some issue that i had beforehand when it tried to "play" the header of the wave file. So everything is fine. Closing this issue now.