irmen / pyminiaudio

python interface to the miniaudio audio playback, recording, decoding and conversion library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

add the possibility to read aac encoded audio file

azhenone opened this issue · comments

Hi everyone,

I am stuck with an issue, I have many audio files which are in mp4 format with the codec MPEG-4 HE AAC. They are quite a long files so I use the function stream_file(...) to read chunks but I get the error ('failed to init decoder', -1).

A little investigation shows that it comes from this section of the code

if result != lib.MA_SUCCESS:

My understanding is that lib.ma_decoder_init_file(...) is not able to decode the file. I am not very familiar with audio files codecs so I am not even sure if what I am requesting actually makes sense.

All I know is that I am just too lazy to convert them to mp3 with ffmpeg and that they seem to take less disk space in their current format

I see in this tutorial that there is a way around to use ffmpeg to read a format that is not natively supported.

import subprocess
import miniaudio

channels = 2
sample_rate = 44100
sample_width = 2  # 16 bit pcm
filename = "samples/music.m4a"  # AAC encoded audio file

def stream_pcm(source):
    required_frames = yield b""  # generator initialization
    while True:
        required_bytes = required_frames * channels * sample_width
        sample_data = source.read(required_bytes)
        if not sample_data:
            break
        print(".", end="", flush=True)
        required_frames = yield sample_data

with miniaudio.PlaybackDevice(output_format=miniaudio.SampleFormat.SIGNED16,
                              nchannels=channels, sample_rate=sample_rate) as device:
    ffmpeg = subprocess.Popen(["ffmpeg", "-v", "fatal", "-hide_banner", "-nostdin",
                               "-i", filename, "-f", "s16le", "-acodec", "pcm_s16le",
                               "-ac", str(channels), "-ar", str(sample_rate), "-"],
                              stdin=None, stdout=subprocess.PIPE)
    stream = stream_pcm(ffmpeg.stdout)
    next(stream)  # start the generator
    device.start(stream)
    input("Audio file playing in the background. Enter to stop playback: ")
    ffmpeg.terminate()

I imagine that this strategy could be used. In my case I want 15s long chunks but I am not sure how to make that to work...
I get an error while trying to iterate over the stream object

    required_bytes = required_frames * channels * sample_width
TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'

In general: builtin AAC decoding is never going to be available unless it will be in the miniaudio C library, which is highly unlikely. So yes as you discovered, use an external decoder to use this audio file format.

  1. can you post the entire stack trace of that last error? I don't know where it's coming from. In any case, one of those three variables is unknown somehow.

  2. "i want 15 seconds chunks" this sounds like a file conversion issue rather than playback. While miniaudio contains some rudimentary support for conversion of audio files, I suggest to simply use ffmpeg only to do this task

closing this now.