Fragen zu Python's wave-Modul

Für Spaß, Bilder von der Kaffemaschine (oder dem Entchen ;^), abschweifende Links, Meinungen zum Wetter und anderen spannenden Sachen.
Antworten
Benutzeravatar
tmk
Beiträge: 1196
Registriert: 18.04.2007 12:18
Wohnort: Halle
Kontaktdaten:

Fragen zu Python's wave-Modul

Beitrag von tmk »

Hallo Gemeinde,

ich komme bei einem Projekt mit dem Programmieren in python3 nicht weiter und vielleicht kann mir wer von euch helfen.

Ich möchte Audiodateien zerhacken. Dabei gebe ich dem Programm eine Input.wav, diese soll in wählbar viele und wählbar lange Schnipsel zerlegt werden. Die Schnipsel werden von zufälligen Positionen aus der Input.wav heraus geholt und in einem Arbeitsordner durchnummeriert abgespeichert. In einem zweiten Schritt soll das Programm alle erstellten Schnipsel in zufälliger Reihenfolge aneinander hängen und als Output.wav abspeichern.

Soweit zur Idee. Nun komme ich an folgender Stelle nicht weiter: Ich weiß nicht, wie ich das Wave_write.writeframesraw(data) benutzen soll. Was genau ist dabei das "data"? Wie vermittle ich dem Programm, dass die Schnipseldateien sich ergeben sollen aus gewissen Frames der Input.wav? Und die zweite Frage, die sich später stellen wird, wie addiere ich die Schnippsel wieder zu einer neuen Output.wav?

Ich poste mal meinen bisherigen Fortschritt:

Code: Alles auswählen

# Mitschnitt Hakker
# Version 1
#
# Version Tmk zur Sichtung Ruben
#
# Stellen, an denen du die Ordnerstruktur fuer dich aendern musst sind markiert mit "#HIER" (4 Stellen)
#
# Aus Kompatibilitaet zu python2.6 sind hier keine Umlaute oder sz-ts drin.
#
# 2010-02-18, 2010-02-19

# Welcome
print('''''')
print('''=================''')
print('''Mitschnitt Hakker''')
print('''=================''')
print('''''')
print('''Mitschnitt Hakker zerlegt eine Wave-Audiodatei in kleine Schnippsel und frikkelt diese in zufaelliger Reihenfolge zu einer neuen Audiodatei zusammen.''')
print('''''')
print('''Die Eingabedatei kann alles sein, sie muss nur in "/home/<user>/Audio/" liegen, "Input.wav" heissen und eine Sounddatei sein. Und sie muss für das Python-Wave-Modul eine Sampling-Tiefe von 16 bit haben.''')
print('''''')

# Module laden
import os, sys, wave, random

# Datei laden
try:
    InputFile = wave.open('/home/tmk/Audio/Input.wav','r') #HIER
    print('''"Input.wav" gefunden, OK.''')
    print('''Sampling-Rate ist''',int(InputFile.getframerate()),'''Hertz.''')
    print('''Laenge der Datei ist''',int(InputFile.getnframes()) / int(InputFile.getframerate()),'''Sekunden =''',int(InputFile.getnframes()) / int(InputFile.getframerate()) / 60,'''Minuten =''',InputFile.getnframes(),'''einzelne Samples.''')
    print('''''')
except:
    print('''Erwartete "Input.wav" nicht in "/home/<user>/Audio/" gefunden.''')
    print('''Entweder der Ordner oder die Datei fehlen oder heissen falsch oder die Sampling-Tiefe ist ungleich 16 bit. Python's Wave-Modul kann nur 16 bit.''')
    print('''''')
    print('''Versuche es nochmal.''')
    print('''''')
    sys.exit()

# Auf Ordner /home/<user>/Audio/Schnippsel/ prüfen und ggfs anlegen (Arbeitsordner)
try:
    os.mkdir('/home/tmk/Audio/Schnippsel') #HIER
    print('''Lege Arbeitsordner "/home/<user>/Audio/Schnippsel/" an, OK.''')
    print('''''')
except:
    print('''Arbeitsordner "/home/<user>/Audio/Schnippsel/" gefunden, OK.''')
    print('''''')

# SchnippselLength
SchnippselLength = int(input('''Wie lang soll ein Schnippsel werden (in Sekunden)? '''))
if int(SchnippselLength) <= 0:
    print('''''')
    print('''Schnippsel koennen nicht kleiner gleich Null sein. Das geht einfach nicht. Danke fuers Probieren.''')
    print('''Versuche es nochmal.''')
    print('''''')
    sys.exit()
elif int(SchnippselLength) < int(InputFile.getnframes()) / int(InputFile.getframerate()):
    print('''''')
else:
    print('''''')
    print('''Schnippsel sollten kuerzer sein als die Eingabedatei.''')
    print('''Versuche es nochmal.''')
    print('''''')
    sys.exit()

# SchnippselAnzahl
print('''Bei richtig vielen Schnippseln, gemessen an der Laenge der Eingabedatei, werden sich die Inhalte, nicht 1 zu 1, aber doch, wiederholen.''')
SchnippselAnzahl = int(input('''Wie viele Schnippsel sollen von zufaelligen Positionen aus der Eingabedatei herausgeholt werden? '''))
print('''''')
if int(SchnippselAnzahl) <= 0:
    print('''Hole''',int(SchnippselAnzahl),'''Schnippsel.''')
    print('''OK, fertig.''')
    print('''''')
    sys.exit()
else:
    print('''Zerhacke "Input.wav" in''',int(SchnippselAnzahl),int(SchnippselLength),'''Sekunden lange Schnippsel. Bitte warten...''')
    print('''''')

# bis hier ist alles cool.
# ab hier weiß ich noch nicht so recht weiter...

# Zerhakken
i = 1 # das ist für die Dateinamenerzeugung der Schnippsel und zur Anzeige der Durchlaufsnummer. Ich liebe Konsolenoutput! :-)
while int(SchnippselAnzahl) > 0:
    r = random.randint(1,round(int(InputFile.getnframes()) - int(InputFile.getframerate()) * int(SchnippselLength))) # Erzeugt die Zufallszahl - SchnippselLength in Frames
#    InputFile.setpos(r)
#    OutputFile.setparams(2,2,int(InputFile.getframerate()),(wie viele samples))
    # Recorde von Stelle InputFile.setpos(r) + SchnippselLength in Frames nach BetweenFile --- kein plan bis jetzt wie...
    BetweenFile = wave.open('/home/tmk/Audio/Schnippsel/schnipp'+str(i)+'.wav','w') #HIER
    BetweenFile.setnchannels(2)
    BetweenFile.setframerate(int(InputFile.getframerate()))
    BetweenFile.setsampwidth(2) # 2 = 2 Byte = 16 Bit also OK
    print('''Durchgang Nummer''',int(i),'''- Extrahiere''',int(SchnippselLength),'''Sekunden ab Frame''',int(r))
    print('''''')
    SchnippselAnzahl = int(SchnippselAnzahl) - 1
    i = int(i) + 1

# Zusammensetzen
OutputFile = wave.open('/home/tmk/Audio/zerhakkt.wav','w') #HIER
OutputFile.setnchannels(2)
OutputFile.setframerate(int(InputFile.getframerate()))
OutputFile.setsampwidth(2)
# randommaessig aus den int(SchnippselAnzahl) Stuecken 1 neue wav bauen, sodass alle Schnippsel 1 mal drin vorkommen.


# Dateien schließen! jeht irgendwie nicht...
InputFile.close()
BetweenFile.close()
OutputFile.close()

# Verabschiedung
Für Hilfe und Anregung wäre ich dankbar.
SyntaxError: invalid syntax
Benutzeravatar
tox
Beiträge: 1417
Registriert: 11.08.2007 16:33
Wohnort: Halle
Kontaktdaten:

Re: Fragen zu Python's wave-Modul

Beitrag von tox »

Ich glaub du brauchst:

Code: Alles auswählen

GeleseneFrames = InputFile.readframes(Anzahl)
BetweenFile.writeframes(GeleseneFrames)
Hab ich hier gefunden: http://docs.python.org/library/wave.html
みんなはばかだ。
Mein öffentlicher Schlüssel (OpenPGP)
Mein öffentlicher Schlüssel (SSH2, kommerzielles Format)
Verwalter von 7.42, 7.43, 7.44, 9.42, 10.42, 10.43, 15.42 und 28.1.
Anschluss: T-Com Call & Surf Comfort Plus inkl. HotSpot-Flat 16/1 Mbit
Modem, Router, TK-Anlage: Speedport W 700V
FF-Router: Buffalo WHR-HP-G54, FFF-Leipzig 1.6.10-core-1-halle-3, Doppel-Biquad-Antenne
Benutzeravatar
tmk
Beiträge: 1196
Registriert: 18.04.2007 12:18
Wohnort: Halle
Kontaktdaten:

Re: Fragen zu Python's wave-Modul

Beitrag von tmk »

Hey, danke für den Hinweis mit den "readframes". Das habe ich bis jetzt übersehen, obwohl es ja ziemlich fett dasteht... Hmm, leider funktioniert es so auch noch nicht...

Code: Alles auswählen

# Ich schreibe mal mehr hin, zum nachvollziehen
>>> import wave
>>> InputFile = wave.open('/home/tmk/Audio/Input.wav','r')
>>> OutputFile = wave.open('/home/tmk/Audio/Output.wav','w')
>>> OutputFile.setnchannels(2) # 2 = Stereo
>>> OutputFile.setsampwidth(2) # 2 = 2 Bytes = 16 bit
>>> OutputFile.setframerate(InputFile.getframerate()) # kHz von Input
>>> GeleseneFrames = InputFile.readframes(100000) # In Input.wav sind 1,3 Milliarden drin, das sollte also nicht der Fehler sein...
>>> OutputFile.writeframes(GeleseneFrames)
...
struct.error: required argument is not an integer
Wenn ich ihm

Code: Alles auswählen

OutputFile.writeframes(int(GeleseneFrames))
gebe, sagt er

Code: Alles auswählen

ValueError: invalid literal for int() with base 10: ''"
Was ist da falsch?
SyntaxError: invalid syntax
Benutzeravatar
tmk
Beiträge: 1196
Registriert: 18.04.2007 12:18
Wohnort: Halle
Kontaktdaten:

Re: Fragen zu Python's wave-Modul

Beitrag von tmk »

Ich sehe gerade, der Inhalt in "GeleseneFrames" nach "GeleseneFrames = InputFile.readframes(n)" ist wirklich kein Integer, das sieht anders aus...

Code: Alles auswählen

>>> GeleseneFrames
b'\x00\x00\xfe\xff\xff\xff\x01\x00\x01\x00\xff\xff\xff\xff # usw, ewig lang
Ich muss das bestimmt erst noch in einen Integer umwandeln, das ist aber irgendwie gar nicht so einfach:

Code: Alles auswählen

i = int(GeleseneFrames)
...
ValueError: invalid literal for int() with base 10: ''
Ich geh am Stock...

edit: Wie wandle ich einen "String of Bytes" in ein "Integer"?
SyntaxError: invalid syntax
PapaBaer
Beiträge: 256
Registriert: 14.04.2008 00:19

Re: Fragen zu Python's wave-Modul

Beitrag von PapaBaer »

Hey,

du kannst nicht einfach wie wild strings und sonstwas in integer casten. Das geht nur an Stellen, wo es Sinn macht, sonst kommt da Schrott raus. (Was soll z.B. "Hallo Welt" in integer sein???)

Das Ding ist auch kein String, sondern (beim ersten Drüberfliegen) eine elendig lange Binärzahl. Du erinnerst dich, integer sind beschränkt in ihrer Größe und laufen irgendwann über.

Du musst dir noch einmal seh genau ansehen, wie diese wave-lib funktioniert und in der Doku dazu nachlesen, was genau das Ding für Werte liefert, welche es an bestimmten Funktionen verlangt und wie das alles zusammenhängt. Da einfach rumzubasteln führt zu keinem sinnvollem Ergebnis. Und es hat auch keiner überschüssige Energie, mal eben so die API durchzuforsten, was da jetzt klemmt.

Nicht falsch verstehen, is nich böse gemeint, sind nur deine Hausaufgaben. Wenn du Probleme irgendwo in Python selbst hast, immer her damit.
Benutzeravatar
tox
Beiträge: 1417
Registriert: 11.08.2007 16:33
Wohnort: Halle
Kontaktdaten:

Re: Fragen zu Python's wave-Modul

Beitrag von tox »

Mh... so aus dem Stehgreif ist der Fehler für mich auch nicht verständlich. Ich hab hier ein knappes Beispiel gefunden: http://codingmess.blogspot.com/2008/07/ ... ython.html
Im Wesentlichen unterscheidet es sich darin, dass beim Öffnen der Datei "b" für den Binärmodus mit angegeben wird und beim Initialisieren zusätzlich zu Samplegröße, Samplerate und Kanalanzahl auch die Anzahl der Frames und die Kompression angegeben wird.

@papabaer, die Doku zu der Bibliothek ist meiner Ansicht nach nicht aussagekräftig genug. Die meisten Erklärungen beschränken sich auf einen Satz und lassen ohnehin nur das verlauten, was man schon anhand des Funktionsnamens erraten konnte. Insbesondere fehlen Informationen zu den Datentypen.
みんなはばかだ。
Mein öffentlicher Schlüssel (OpenPGP)
Mein öffentlicher Schlüssel (SSH2, kommerzielles Format)
Verwalter von 7.42, 7.43, 7.44, 9.42, 10.42, 10.43, 15.42 und 28.1.
Anschluss: T-Com Call & Surf Comfort Plus inkl. HotSpot-Flat 16/1 Mbit
Modem, Router, TK-Anlage: Speedport W 700V
FF-Router: Buffalo WHR-HP-G54, FFF-Leipzig 1.6.10-core-1-halle-3, Doppel-Biquad-Antenne
Benutzeravatar
tmk
Beiträge: 1196
Registriert: 18.04.2007 12:18
Wohnort: Halle
Kontaktdaten:

Re: Fragen zu Python's wave-Modul

Beitrag von tmk »

Hallo, ich weiß, dass man nicht unbedacht Strings in Zahlen umwandelt. Seit Python3 ist int() gleich float() und ganze Zahlen sind zB round(int()). Ich habe natürlich die Hilfen zum wave Modul gelesen, Wave_read.readframes() liefert einen "String of Bytes" (Ist das nicht eine "elendig lange Binärzal"?) und Wave_write.writeframes() will "Integer". Find ich auch komisch. Im python-forum.de meinen sie, man bräuchte zum Umwandeln "struct", das liefert bei mir aber Fehler wegen meiner 64 bit Version von OS und Python. Ich muss den Code auch noch aufräumen und will euch natürlich nicht mit meinen Hausaufgaben stressen, nur wo zieht man die Grenze? Hab ja grad erst angefagen mit Python und hoffe, euch nicht zu sehr zu nerven ;-) Ich bin gerade an dem Punkt, bei dem ich erstmal in Python eine Input.wav in eine Output.wav kopieren mag, um zu verstehen, wie das geht, um später dann das Zerhacken zu programmieren. Wer über Hinweise stolpert, her damit! Keep it coming, ich bin auch nicht untätig. Danke fürdie Links, Tox. Ich meld' mich.
SyntaxError: invalid syntax
PapaBaer
Beiträge: 256
Registriert: 14.04.2008 00:19

Re: Fragen zu Python's wave-Modul

Beitrag von PapaBaer »

Erste Frage: Python3 ist ziemlich neu, ist diese wave-lib kompatibel?

Zu den Datentypen: Das das Lesen einer Wave einen binären "String" liefert klingt ja erstmal ziemlich sinnvoll. Sind ja unbegrenzt lange Folgen von Bits. Was nun mal überhaupt keinen Sinn macht ist, dass der von der Schreibfunktion verlangte Integer die zu schreibenden Daten repräsentiert. Selbst der größte denkbare Integer wäre nur ein Sekundenbruchteil Audiomaterial. Also Frage: Wofür steht der Integer und wie kommen die Audiodaten ins File? Wenn die Doku dazu nix hergibt im schlimmsten Falle direkt in den Code der Funktion sehen, ist ja OpenSource ;-)
Benutzeravatar
tmk
Beiträge: 1196
Registriert: 18.04.2007 12:18
Wohnort: Halle
Kontaktdaten:

Re: Fragen zu Python's wave-Modul

Beitrag von tmk »

Da das wave Modul in der Python 3.1 Dokumentation beschrieben ist, denke ich, dass es läuft. http://docs.python.org/3.1/library/wave ... odule-wave
Auch existiert eine Datei /usr/lib/python3.1/wave.py .

Es scheint, als müsse ich tatsächlich in das wave Modul rein gucken, um zu verstehen, was dort vor sich geht. Eigentlich dachte ich, Python einfach für meine Idee benutzen zu können, aber was solls, dümmer wird man nicht dabei... Ich befürchte aber, dass ich nicht so ohne Weiteres verstehe, was da vor sich geht und ich brauche beim Debuggen bestimmt die Hilfe des ein oder der anderen.

Code: Alles auswählen

>>> OutputFile.writeframes(Frames)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.1/wave.py", line 432, in writeframes
    self.writeframesraw(data)
  File "/usr/lib/python3.1/wave.py", line 416, in writeframesraw
    self._ensure_header_written(len(data))
  File "/usr/lib/python3.1/wave.py", line 459, in _ensure_header_written
    self._write_header(datasize)
  File "/usr/lib/python3.1/wave.py", line 472, in _write_header
    self._sampwidth * 8, 'data'))
struct.error: required argument is not an integer
SyntaxError: invalid syntax
Benutzeravatar
tox
Beiträge: 1417
Registriert: 11.08.2007 16:33
Wohnort: Halle
Kontaktdaten:

Re: Fragen zu Python's wave-Modul

Beitrag von tox »

Ok, offenbar liegt es daran, dass eine Zahl, die du irgendwann vorher angibst, float statt int ist. Du sagst zwar, dass das in Python 3 dasselbe ist, das glaube ich aber nicht so recht. Ich habe auch in einem Buch gefunden, dass da immer noch unterschieden wird. Ich nehme an, du musst irgendwie sagen, dass die Samplegröße und Kanalanzahl, die du vorher angibst, ints sind.

Die betreffende Zeile im Modul ist in der Methode _write_header(self, initlength):

Code: Alles auswählen

            self._file.write(struct.pack('<l4s4slhhllhh4s',
            36 + self._datalength, 'WAVE', 'fmt ', 16,
            WAVE_FORMAT_PCM, self._nchannels, self._framerate,
            self._nchannels * self._framerate * self._sampwidth,
            self._nchannels * self._sampwidth,
            self._sampwidth * 8, 'data'))
Dort möchte er offenbar ganz streng ints haben...
みんなはばかだ。
Mein öffentlicher Schlüssel (OpenPGP)
Mein öffentlicher Schlüssel (SSH2, kommerzielles Format)
Verwalter von 7.42, 7.43, 7.44, 9.42, 10.42, 10.43, 15.42 und 28.1.
Anschluss: T-Com Call & Surf Comfort Plus inkl. HotSpot-Flat 16/1 Mbit
Modem, Router, TK-Anlage: Speedport W 700V
FF-Router: Buffalo WHR-HP-G54, FFF-Leipzig 1.6.10-core-1-halle-3, Doppel-Biquad-Antenne
Benutzeravatar
tmk
Beiträge: 1196
Registriert: 18.04.2007 12:18
Wohnort: Halle
Kontaktdaten:

Re: Fragen zu Python's wave-Modul

Beitrag von tmk »

Es läuft! Es geht! Es zerhackt wie befohlen! :-) Das Problem war, dass es vor einem "OutputFile.writeframes()" ein "OutputFile.setnframes()" wollte. Davor schreibt es einfach nicht.

Ich poste dem interessierten Freifunker mal den Code, Pfade müssen angepasst werden darin, dann läufts. (bei # Datei laden und # OutputFile vorbereiten)

Code: Alles auswählen

# Mitschnitt Hacker, ein Beat Slicer
# Version 1
#
# Version Tmk, Ruben
#
# Ausführen mit: In Ordner wechseln, wo Script liegt, sagen "python3 <dateiname>.py"
#
# 2010-02-18, 2010-02-19, 2010-03-16
#
# noch: In- und Output selber wählen

# Welcome
print('''''')
print('''=================''')
print('''Mitschnitt Hacker''')
print('''=================''')
print('''''')
print('''Mitschnitt Hacker zerlegt eine Wave-Audiodatei in kleine Schnippsel und frikkelt diese in zufaelliger Reihenfolge zu einer neuen Audiodatei zusammen. Es ist ein Beat Slicer.''')
print('''''')
print('''Die Eingabedatei kann alles sein, sie muss nur in "/home/<user>/Audio/" liegen, "Input.wav" heissen und eine Sounddatei sein. Und sie muss für das Python-Wave-Modul eine Sampling-Tiefe von 16 bit haben.''')
print('''''')

# Module laden
import os, sys, wave, random

# Datei laden
try:
    InputFile = wave.open('/home/tmk/Audio/Input.wav','r')
    print('''"Input.wav" gefunden, OK.''')
    print('''Sampling-Rate ist''',int(InputFile.getframerate()),'''Hertz.''')
    print('''Laenge der Datei ist''',int(InputFile.getnframes()) / int(InputFile.getframerate()),'''Sekunden =''',int(InputFile.getnframes()) / int(InputFile.getframerate()) / 60,'''Minuten =''',InputFile.getnframes(),'''einzelne Samples.''')
    print('''''')
except:
    print('''Erwartete "Input.wav" nicht in "/home/<user>/Audio/" gefunden.''')
    print('''Entweder der Ordner oder die Datei fehlen oder heissen falsch oder die Sampling-Tiefe ist ungleich 16 bit. Python's Wave-Modul kann nur 16 bit.''')
    print('''''')
    print('''Versuche es nochmal.''')
    print('''''')
    sys.exit()

# SchnippselLength
SchnippselLength = int(input('''Wie lang soll ein Schnippsel werden (in Sekunden)? '''))
if int(SchnippselLength) <= 0:
    print('''''')
    print('''Schnippsel koennen nicht kleiner gleich Null sein. Das geht einfach nicht. Danke fuers Probieren.''')
    print('''Versuche es nochmal.''')
    print('''''')
    sys.exit()
elif int(SchnippselLength) < int(InputFile.getnframes()) / int(InputFile.getframerate()):
    print('''''')
else:
    print('''''')
    print('''Schnippsel sollten kuerzer sein als die Eingabedatei.''')
    print('''Versuche es nochmal.''')
    print('''''')
    sys.exit()

# SchnippselAnzahl
print('''Bei richtig vielen Schnippseln, gemessen an der Laenge der Eingabedatei, werden sich die Inhalte, nicht 1 zu 1, aber doch, wiederholen.''')
SchnippselAnzahl = int(input('''Wie viele Schnippsel sollen von zufaelligen Positionen aus der Eingabedatei herausgeholt werden? '''))
print('''''')
if int(SchnippselAnzahl) <= 0:
    print('''Hole''',int(SchnippselAnzahl),'''Schnippsel.''')
    print('''OK, fertig.''')
    print('''''')
    sys.exit()
else:
    print('''Zerhacke "Input.wav" in''',int(SchnippselAnzahl),int(SchnippselLength),'''Sekunden lange Schnippsel. Bitte warten...''')
    print('''''')

# OutputFile vorbereiten
OutputFile = wave.open('/home/tmk/Audio/Output.wav','w')
OutputFile.setsampwidth(2)
OutputFile.setnchannels(2)
OutputFile.setframerate(InputFile.getframerate())
OutputFile.setnframes(SchnippselAnzahl * int(SchnippselLength * InputFile.getframerate()))

# Zerhacken
for i in range (1, int(SchnippselAnzahl) + 1):
    r = random.randint(1,round(int(InputFile.getnframes()) - int(InputFile.getframerate()) * int(SchnippselLength)))
    InputFile.setpos(r)
    GeleseneFrames = InputFile.readframes(int(SchnippselLength * InputFile.getframerate()))
    OutputFile.writeframes(GeleseneFrames)
    print('''Durchgang Nummer''',int(i),'''- Extrahiere''',int(SchnippselLength),'''Sekunden ab Frame''',int(r))

# Dateien schließen
InputFile.close()
OutputFile.close()

# Verabschiedung
print('''''')
print('''Fertig. Viel Spaß!''')
print('''''')
Es ist (noch) auf 2.147.483.648 Frames Ausgabegröße beschränkt, das sind bei 44,1 kHz Samplingrate etwa 33,82 Stunden. Sollte reichen für den Anfang. Beispiele gibt's demnächst (muss schlafen) auf meiner Netzseite.

LG'st, bedankt für die Anregungen,
Tmk
SyntaxError: invalid syntax
Antworten