pyAudiere problem

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Also mit GTK kann man über den Befehl `main_iteration` die GUI-Events ablaufen lassen. In Kombination mit subprocess hab ich das mit einer while Schleife folgendermaßen gelöst.

Code: Alles auswählen

proc = Popen(...)
while proc.poll() is None:
    gtk.main_iteration()
Damit wird auf den Prozess gewartet und gleichzeitig ist noch die GUI aktiv (bei mir in Form einer Progressbar).

Vielleicht kann man das mit wx ähnlich lösen.
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

ms4py hat geschrieben:Also mit GTK kann man über den Befehl `main_iteration` die GUI-Events ablaufen lassen. In Kombination mit subprocess hab ich das mit einer while Schleife folgendermaßen gelöst.

Code: Alles auswählen

proc = Popen(...)
while proc.poll() is None:
    gtk.main_iteration()
Damit wird auf den Prozess gewartet und gleichzeitig ist noch die GUI aktiv (bei mir in Form einer Progressbar).

Vielleicht kann man das mit wx ähnlich lösen.
Es klappt! Sort of... ;) Es gibt tatsaechlich einen Befehl in wxPython genannt "wx.EnableTopLevelWindows()", der durch einen boolean definiert ist (True fuer an und False fuer aus, is klar). Das sieht dann bei mir im GUI so aus als function:

Code: Alles auswählen

def onPlay(self, event):
       
    d = audiere.open_device()

    f = d.open_file('my/audio/file', -1) # -1 equals 'streaming', 0 is load fully into RAM prior to use
    f.play()
        
    while f.playing:
        wx.EnableTopLevelWindows()
Leider spuckt das noch einen Fehler aus, aber ansonsten klappt's. Der Fehler ist komisch weil in der documentation ist der default value auf True gesetzt und wenn ich True explizit angebe, stuerzt das programm ab...

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Dokumente und Einstellungen\Nebelhom\workspace\DSAMusic\src\DSAMusicGUI.py", line 159, in onPlay
    wx.EnableTopLevelWindows()
  File "C:\Python26\lib\site-packages\wx-2.8-msw-unicode\wx\_misc.py", line 382, in EnableTopLevelWindows
    return _misc_.EnableTopLevelWindows(*args, **kwargs)
TypeError: Required argument 'enable' (pos 1) not found
Ich bedanke mich zweitausend mal fuer diesen hilfreichen tipp!!! <insert smiley fuer fuesse kuess> ;)

Alles andere wird jetzt wohl ein Problem mit wxPython sein und das werde ich in einem separaten thread auffuehren, falls es denn notwendig ist.
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

Kurzes add-on. Ich habe es jetzt ungewollt geschafft mein problem mit dem eingefrorenen GUI zu beheben, indem ich die audio datei abspiel und stop funktion in eine andere klasse verschoben habe. Ich war etwas ueberrascht, dass das ging, weil ich eigentlich nur dabei war herauszufinden, wie ich die audiere library fuer meine zwecke benutzen kann (problem war: wie stoppe ich die datei wenn ich sie erst innerhalb der funktion play definiere, oeffne und abspiele)

unten angehaengt der sample code und mein frage:

War das zu erwarten, dass ich das gui einfrieren loese indem ich die logik in eine andere klasse versetze? (denn ich bin davon wirklich ueberrascht)

Ausserdem, da ich mit OOP noch nicht besonders gut bin. ist es clever, dieses outsourcing der logik auf andere klassen?

Ich war der meinung "Ja", aufgrund der pythonic code reusability predigt, aber bitte belehrt mich, falls ich das falsch verstanden habe.

Code: Alles auswählen

class Audiofile:
    
    # Amazingly, this works without locking up the GUI!!!
    
    def __init__(self, path):
        
        self.path = path
        self.file = audiere.open_device()
        self.song = self.file.open_file(path, -1) # -1 stands for streaming, tested with .mp3, .wav, .ogg
    
    def player(self):    
        self.song.play()
        
    def stopper(self):
        self.song.stop()

# Excerpt from gui functions bound to buttons in wxpython

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):

# constructor stuffs
   
   ...

   wx.EVT_BUTTON (self, ID_PLAY, self.onPlay)       
   wx.EVT_BUTTON (self, ID_STOP, self.onStop)
   
   ...
   self.audio = Audiofile('an/audio/file')

   def onPlay(self, event):
        self.audio.player()
        
    def onStop(self, event):
        self.audio.stopper()
BlackJack

@Nebelhom: Dass das reine verschieben sollte das Problem eigentlich nicht gelöst haben. Bist Du sicher, dass Du nicht noch etwas anderes an der Programmlogik verändert hast?

Wieso nennts Du das Device-Objekt `file`? Das finde ich ein wenig verwirrend.

Der Kommentar bezüglich der -1 und dem Streaming ist falsch. Als zweites Argument wird dort ein Wahrheiswert erwartet und -1 ist zufällig "wahr". Genauso wie -2 oder 42 oder die Zeichenkette "spam". Man sollte dort aber trotzdem `True` übergeben um es dem Leser deutlicher zu machen.

`player()` und `stopper()` sollten wohl eher `play()` und `stop()` heissen.
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

hi blackjack, danke fuers feedback. es kommt also nicht nur mir etwas komisch vor, dass das jetzt so uuuurploetzlich toll funktioniert.

zu deinen kommentaren:

1) soweit ich das verstehe, habe ich nur das button binding, dass ich innerhalb der "myframe" class angegeben habe, in die class audiofile verschoben. Der grosse unterschied, glaube ich, war diesmal, dass ich den "while playing"-loop weglassen konnte und die datei wurde immernoch abgespielt (weil die gui einen endlos-loop gibt). Warum ich den diesmal weglassen konnte ist mir jedoch ein absolutes raetsel.

als vergleich, frueher gab es die audiofile class nicht und dafuer hatte ich die funktion folgendermassen definiert innerhalb von myframe (bitte keine groesseren kommentare zu der funktion, dass hab ich nur so da rein geschrieben, um zu sehen ob es geht und sofort gesehen, dass das gui einfriert):

Code: Alles auswählen

    def onPlay(self, event, path='my/audio/file'):

        d = audiere.open_device() #defined without self
        f = d.open_file(path)
        f.play()
        
        while f.playing: # leaving it out causes the audiofile not to play
            time.sleep(.01)
2) ja namensgebung. es erschien mir gestern, um 2 uhr morgens sehr clever meine "datei" mit self.file zu benennen. ich werde es mal umbenennen in etwas besseres. aber bei namensgebung von variablen bin ich ziemlich schlecht

3) Streaming: Nach nochmaligen nachschauen, frage ich mich wirklich, woher ich das -1 habe.... weil selbst im example code steht nur eine "1" da... notiert. danke fuer die bemerkung. da habe ich einfach geschlafen.

4) player() und stopper(): da die methoden bei audiere play() und stop() jeweils hiessen, dachte ich es hlft gegen die verwirrung, wenn ich meine funktionen anders nenne, falls ein fehler auftritt, damit ich weiss wo der fehler ist. in meinem code selbst oder in der art wie ich versuche die audiere library zu benutzen. Ist das falsch... nein nicht falsch... programmiererisch ungeschlacht? ;)

danke fuer die kommentare. wieder ein paar sachen mehr auf die ich aufmerksam sein muss :) schade, dass du auch nicht weisst, warum sich mein problem geloest hat. ich mag es nicht, wenn sich etwas verbessert, ich aber nicht verstehe, warum (und dann daraus etwas lerne).

thanks again
BlackJack

@Nebelhom: Das die GUI bei der ``while``-Schleife blockiert sollte eigentlich klar sein. Solange die läuft wird die Kontrolle ja nicht mehr an die GUI-Bibliothek zurückgegeben, die in ihrer Hauptschleife für die Aktualisierung der GUI sorgt.

Ad 4: Die Benennung ist ungünstig. Funktionen und Methoden sollten mit Worten benannt werden, die Tätigkeiten entsprechen. Wenn ein Fehler auftritt zeigt der Stapelabzug ja welche Zeile(n) im Programm aktuell aktiv waren, inklusive Zeilennummer. Da kann man dann auch leicht gleichnamige Funktionen und Methoden auseinanderhalten.
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

hmmm... ja das war schon klar mit dem einfrieren des GUIs.

Was fuer mich nicht klar war, warum ich im ersten fall den while loop drinnen lassen musste, damit die datei ueberhaupt abspielt und in zweiterem fall eben nicht. weshalb kann ich beim zweiten, den Mainloop die arbeiten machen lassen? da ist bei mir der knick in der birne.
Antworten