array.array -> numpy, pyaudio oder andere

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Benutzeravatar
lightos
User
Beiträge: 39
Registriert: Montag 12. Dezember 2011, 19:39
Wohnort: Raum Bruchsal
Kontaktdaten:

Aktuell habe ich folgendes Problem beim Bearbeiten von PCM-Audio Files:

Lesen, Schreiben mit wave klappt gut.
Ich möchte aber nun möglichst schnell und effektiv z.B. Stereo nach Mono Demuxen und dann alle Mono-Spuren auf 7.1 (also 8 Mono-Kanäle) abspielen.
Hierzu verwende ich aktuell nur wave und array in python3.

Offline klappt das ohne Probleme, da es keine Timing-Probleme gibt.
Online leider nicht: Stereo Wave-read in chunks von z.B. 8k und demux nach 2x Mono klappt noch, aber diese Daten in 5.1 oder 7.1 hoch zu multiplexen gelingt nicht.

Ich denke nun, dass numpy das evtl. schneller hinbekommt, habe aber hier noch keine Erfahrung. Gibt's aber evtl. auch Alternativen aus Media-Extensions?

Eine Empfehlung der Möglichkeiten wäre sinnvoll.

Danke,
lightos
Benutzeravatar
lightos
User
Beiträge: 39
Registriert: Montag 12. Dezember 2011, 19:39
Wohnort: Raum Bruchsal
Kontaktdaten:

Das Ganze hat sich zum Teil schon erledigt:

Bei der Verwendung von PTVS läuft das weit unter der normalen Performance!!!

Innerhalb von PTVS läuft nicht mal ein Stereo-Encoding, wobei das identische Script mit Python3 in der Shell 8 Kanäle encodiert (7.1 16-bit).

Source-Extrakt: Python Script unter Verwendung wave, audioop

Im Beispiel wird eine Stereo-Source demuxed auf die 2 Mono und diese auf 8 Kanäle vervielfacht. Im Beispiel Left/Right wieder 0/1 und der Rest der erster Mono-Kanal.
Mein i7/2.8 Ghz kann das mit Verwendung von array gerade so. USB-Buffer 8k, was bei 7.1/16-bit 48 kHz gerade mal 10 ms sind.
Morgen dann der Test mit dem neuen Raspberry Pi Quad.

Falls hier jemand Interesse hat, oder das auch gerne mal mit numpy optimieren möchte, einfach hier melden.

Code: Alles auswählen

dev = usbiopi_api.open(DevDesc, 0)
if dev == None:
    print('Open USB failed!!!')
    sys.exit()

outPipe1 = usbiopi_api.open_out_pipe(dev, 0x01, 8, TxBufferSize, 0)
if outPipe1 == None:
    usbiopi_api.close(dev)
    print('Open Pipe failed!!!')
    sys.exit()

print('Device opened: {0}  Pipe: {1}'.format(dev, outPipe1))

fileName = os.path.join(audioPath, AudioFiles[0])
print('FileName: {0}'.format(fileName))
if os.path.exists(fileName):
    wavIn = wave.open(fileName, 'r')
    print('WAV: NumChannels: {0} SampleRate:{1} Width(Bytes):{2}'.format(wavIn.getnchannels(), wavIn.getframerate(), wavIn.getsampwidth()))
    bytesPerSample = wavIn.getnchannels() * wavIn.getsampwidth()
else:
    sys.exit(-1)

#skip first silence
while 1:
    dataRead = wavIn.readframes(500)
    if dataRead[0] != 0:
        break


pool = MuxPool()
for j in range(8):
    mux = MuxDataBufferU16(NumTxChannels, NumTxBuffers, BlockSize)

    dataRead = wavIn.readframes(mux.numSamplesPerBuffer * mux.numBuffers)
    bytesSwapped = audioop.byteswap(dataRead, 2)    # network stream has to M
        
    demuxU16.fill_buffer_from_stream(bytesSwapped)
    mux.fill_byte_stream(0, 0, demuxU16.demux_stream(0))
    mux.fill_byte_stream(1, 0, demuxU16.demux_stream(0))
    #mux.fill_byte_stream(2, 0, demuxU16.demux_stream(0))
    #mux.fill_byte_stream(3, 0, demuxU16.demux_stream(0))
    #mux.fill_byte_stream(4, 0, demuxU16.demux_stream(0))
    #mux.fill_byte_stream(5, 0, demuxU16.demux_stream(0))
    #mux.fill_byte_stream(6, 0, demuxU16.demux_stream(0))
    #mux.fill_byte_stream(7, 0, demuxU16.demux_stream(0))

    pool.add(mux)

# fill-up all USB buffers
pool.restart()

for j in range(8):
    mux = pool.get_next()
    res = usbiopi_api.write_pipe(outPipe1, mux.get_byte_stream(), 0)

pool.restart()
mux = pool.get_next()        
try:
    while 1:
        dataRead = wavIn.readframes(mux.numSamplesPerBuffer * mux.numBuffers)
        if len(dataRead) > 0:
            bytesSwapped = audioop.byteswap(dataRead, 2)    # network stream has to MSB
        
            demuxU16.fill_buffer_from_stream(bytesSwapped)
            mux.fill_byte_stream(0, 0, demuxU16.demux_stream(0))
            mux.fill_byte_stream(1, 0, demuxU16.demux_stream(1))
            mux.fill_byte_stream(2, 0, demuxU16.demux_stream(0))
            mux.fill_byte_stream(3, 0, demuxU16.demux_stream(0))
            mux.fill_byte_stream(4, 0, demuxU16.demux_stream(0))
            mux.fill_byte_stream(5, 0, demuxU16.demux_stream(0))
            mux.fill_byte_stream(6, 0, demuxU16.demux_stream(0))
            mux.fill_byte_stream(7, 0, demuxU16.demux_stream(0))
            
            res = usbiopi_api.write_pipe(outPipe1, mux.get_byte_stream(), 100)

            if res == TxBufferSize:
                print_same_line('Send Buffer OK: {0}'.format(res))
            else:
                pass
            # end of-file, close and reopen to start from beginning
        else:
            wavIn.rewind()

        mux = pool.get_next()


except KeyboardInterrupt:
    wavIn.close()
    clear = b'\x00' * (NumTxBuffers * BlockSize)
    mux.fill_buffer_from_stream(clear, 0)
    for j in range(10):
        res = usbiopi_api.write_pipe(outPipe1, mux.get_byte_stream(), 10)

    usbiopi_api.close_pipe(outPipe1)
    usbiopi_api.close(dev)
    usbiopi_api.unregister_device_change_callback(notifyHandle)

 
Benutzeravatar
lightos
User
Beiträge: 39
Registriert: Montag 12. Dezember 2011, 19:39
Wohnort: Raum Bruchsal
Kontaktdaten:

Habe leider noch kein Feedback hierzu, aber inzwischen mehr Details:

Auf dem RaspI-Linux hat auddioop keine swapbytes() Methode.
Habe das nun auf der Standard-Methode von array umgebaut (ist so besser und generischer).

Der Raspi (neues Modell mit Quad-Core) schafft damit leider nicht mal Stereo.
Einzig was klappt, ist ein wav zu öffnen, mit array.swapbytes() zu drehen und auf den USB-Port zu streamen.

Gibt es hierzu jemanden, der mir sagen kann, ob das mit numpy evtl. gehen könnte.
Alternative wäre dann wohl eine Dll/so, aber dann wird der Aufwand größer und die Portierung auf neue Targets umständlicher.
Antworten