GUI für SOX

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
snakeseven
User
Beiträge: 405
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Mittwoch 2. Mai 2007, 13:43

Hallöchen,

es interessierte mich, was SOX aus Audiosignalen so macht und was genau die einzelnen Parameter bewirken. Mit tkSnack zur Visualisierung und ein bischen Tkinter drum rum ist eine GUI für SOX entstanden, die gerne erweitert und verbessert werden darf. Freue mich auf Anregungen! Hier der Quelltext.

Gruss, Seven
abgdf

Samstag 5. Mai 2007, 00:00

Was ich sehe (die Übertragung auf Linux und meine Soundkarte ist wohl nicht so ganz leicht) gefällt mir sehr.

Ebenso der strukturierte Programmierstil (ich steh eigentlich nicht so auf OOP) :D.

Wäre eigentlich eine sehr gute Ergänzung zu

http://www.python-forum.de/topic-8111.html

Viele Grüße
BlackJack

Samstag 5. Mai 2007, 07:43

Wo siehst Du da bitte strukturierten Programmierstil? Es werden ja nicht einmal Funktionen richtig verwendet, die sind einfach nur ein Ersatz für Zeilennummern in alten BASIC-Programmen. Alle Daten werden über globale Variablen ausgetauscht. :shock:

Das viele "copy'n'paste" ist auch sehr unschön.
snakeseven
User
Beiträge: 405
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Mittwoch 9. Mai 2007, 17:25

BlackJack hat geschrieben:Wo siehst Du da bitte strukturierten Programmierstil? Es werden ja nicht einmal Funktionen richtig verwendet, die sind einfach nur ein Ersatz für Zeilennummern in alten BASIC-Programmen. Alle Daten werden über globale Variablen ausgetauscht. :shock:

Das viele "copy'n'paste" ist auch sehr unschön.
Hi Black-Jack,
ich bin hier nicht angetreten, einen beispielhaften Programmierstil zu präsentieren, sondern eine einfache, visuelle Schnittstelle zu Sox herzustellen, auch für Nichtprogrammierer. Natürlich kann man die globalen Variablen auch über eine Klasse "Globelvars" oder so realisieren, aber macht es das bischen Code übersichtlicher, wenn jeder Variablen noch ein Klassenname vorangestellt wird ? Außerdem sehe ich OOP in dieser Anwendung sowieso nicht. Es gibt keine Funktion, die universell ist und z.B. in einer Library seinen Platz finden sollte.
Wer sich daraus eine optimierte Applikation basteln will, kann das ja machen. Mir geht es darum, die sehr undurchsichtige und sehr schlecht dokumentierte Funktionsweise von Sox zu entschlüsseln. Der Kompressor von Sox z.B. funktioniert gänzlich anders, als alle mir bekannten Kompressoren und ich kenne ziemlich viele.

Copy and Paste ist zugegeben unschön, aber spart Zeit. Zum Ausprobieren von Sox reicht es jedenfalls allemal und nicht jeder Sound-Engineer oder Musiker ist passionierter OOP-Programmierer. Aber wie ich schon sagte, wer es verbessern will, darf sich frei bedienen und ich persönlich freue mich über jede Anregung oder Kritik, so auch über deine.

Für alle Sox-Fans: Sox 1.3 ist draußen, das hat jetzt auch einen EQ. Da spart man sich den umständlichen Weg über den Multibandkompressor.

Gruss, Seven
snakeseven
User
Beiträge: 405
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Mittwoch 9. Mai 2007, 17:30

abgdf hat geschrieben:
Wäre eigentlich eine sehr gute Ergänzung zu

http://www.python-forum.de/topic-8111.html

Viele Grüße
Hi abgdf:
Oranje kannte ich noch nicht. Danke für den Link, sieht sehr ausgereift aus. Muß ich mir gleich mal ansehen.

Gruss, Seven
BlackJack

Mittwoch 9. Mai 2007, 18:04

snakeseven hat geschrieben:ich bin hier nicht angetreten, einen beispielhaften Programmierstil zu präsentieren, sondern eine einfache, visuelle Schnittstelle zu Sox herzustellen, auch für Nichtprogrammierer. Natürlich kann man die globalen Variablen auch über eine Klasse "Globelvars" oder so realisieren, aber macht es das bischen Code übersichtlicher, wenn jeder Variablen noch ein Klassenname vorangestellt wird ?
Nein dadurch wird es selbstverständlich nicht übersichtlicher, sie wären ja immer noch global, zumindest in der Verwendung, d.h. man müsste immer noch den gesamten Quelltext durchsehen um festzustellen, wo die Variablen benutzt werden und wofür. Und umgekehrt weiss man dort wo sie benutzt werden, nicht wo sie *noch* benutzt werden. Zum Beispiel ob der Wert nach einem beliebigen Funktionsaufruf immer noch der selbe ist wie vorher.
Außerdem sehe ich OOP in dieser Anwendung sowieso nicht. Es gibt keine Funktion, die universell ist und z.B. in einer Library seinen Platz finden sollte.
Man muss keine Bibliothek schreiben wollen um Vorteile aus OOP zu ziehen. Es geht auch um das sinnvolle Strukturieren eines Programms um es leichter lesbar und leichter erweiter- oder veränderbar zu machen.

Aber selbst ohne OOP ist das ein schlechtes Programm. Keine der Funktionen nimmt Argumente entgegen oder gibt einen Wert zurück. Damit sind das einfach nur verkleidete Zeilennummern und die Aufrufe GOTO's. Das ist tiefstes Mittelalter.
Copy and Paste ist zugegeben unschön, aber spart Zeit.
Copy'n'Paste spart im Endeffekt keine Zeit, ausser man weiss, dass man das Programm wirklich nur einmal kurz braucht und nie anpassen oder erweitern muss. Dann wird es nämlich unangenehm und kostet richtig Zeit.
snakeseven
User
Beiträge: 405
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Mittwoch 9. Mai 2007, 18:20

Hi,
Ich verstehe voll und ganz, was du meinst, aber du hast da auch andere, professionellere Beurteilungskriterien. Ich schätze mal 60% der Sox-Anwender sind Programmierleien oder Gelegenheitsprogrammierer wie ich, die einfach nur schnell und unkomplliziert ihr Lieblingstool um eine optische Schnittstelle erweitern wollen. Dafür ist dieser klassische "Mittelalterstil" meiner Meinung nach geeigneter, als komplizierte OOP-Programme mit unzähligen "selfs" und kryptischen Parameterübergaben. Will Peter Meier das Programm z.B. um das Feature Delay erweitern, kopiert er sich die entsprechenden Zeilen einer der anderen Effekte und paßt die Sox-Parameter an. So soll es jedenfalls gedacht sein. Ein Hilfswerkzeug fürs Studio und keine Grundlage für einen professionellen Audioeditor.
Wobei es mich schon interessieren würde, wie es als OOP-Programm aussehen würde. Sicherlich etliche Zeilen weniger, aber leserlicher ?

Gruss, Seven
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 9. Mai 2007, 18:50

snakeseven hat geschrieben:Ich verstehe voll und ganz, was du meinst, aber du hast da auch andere, professionellere Beurteilungskriterien.
Können Programme von Hobbyprogrammierern nicht strukturiert sein?
snakeseven hat geschrieben:Ich schätze mal 60% der Sox-Anwender sind Programmierleien oder Gelegenheitsprogrammierer wie ich, die einfach nur schnell und unkomplliziert ihr Lieblingstool um eine optische Schnittstelle erweitern wollen. Dafür ist dieser klassische "Mittelalterstil" meiner Meinung nach geeigneter, als komplizierte OOP-Programme mit unzähligen "selfs" und kryptischen Parameterübergaben.
Komisch, ich finde dieses unfasssbar umständliche und unnütze, unstrukturierte OOP aber irgendwie lesbarer und einleuchtender. Ist meine Wahrnehmung gestört?
Was mich als jemand der das programm erweitern will viel mehr stört, ist der eklatante Mangel brauchbarer Kommentare. ``peWIN``, anyone?
Außerdem setzt du die Variable ``args`` selbst zusammen, was erstens unschön gelöst ist und zweitens vollständig unnötig, weil ``subprocess.Popen()`` das selbst kann.
snakeseven hat geschrieben:Will Peter Meier das Programm z.B. um das Feature Delay erweitern, kopiert er sich die entsprechenden Zeilen einer der anderen Effekte und paßt die Sox-Parameter an.
Und mit OOP ist das nicht mehr Möglich? Ich sehe da keinerlei Zusammenhang.
snakeseven hat geschrieben:Wobei es mich schon interessieren würde, wie es als OOP-Programm aussehen würde. Sicherlich etliche Zeilen weniger, aber leserlicher ?
Womöglich einige Zeilen länger und sicherlich verständlicher.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Mittwoch 9. Mai 2007, 19:33

@snakeseven: Ob es strukturierter programmiert kürzer wird weiss ich nicht. Aber länger heisst nicht unbedingt unverständlicher weil Funktionen und Klassen Funktionalität kapseln sollen. Viele kleine Funktionen, die eine Sache gut und übersichlich lösen, brauchen oft mehr Zeilen als eine "Monsterfunktion" die alles auf einmal macht, durch die man aber nur mit Mühe durchsteigt.

Aber wie schon gesagt: Selbst ohne OOP ist der Quelltext nicht schön. Temporäre Dateien kann man zum Beispiel mit dem `tempfile`-Modul anlegen. Das "denkt" sich einen passenden eindeutigen Dateinamen aus, der im systemweiten temporären Ordner liegt. Um diese simple Änderung durchzuführen muss man wegen dem vielen copy'n'paste ganz viele Stellen ändern. Mit der Gefahr, dass man eine vergisst oder einen Fehler an einer Stelle einbaut.

Viele der Effektfunktionen haben einen identischen Aufbau, der sich ganz einfach in eine eigene Funktion herausziehen lässt. Exemplarisch (und ungetestet) für die ersten drei Funktionen:

Code: Alles auswählen

def call_sox(command, *args):
    source = path_wav + ' '
    dest = last_visit + 'temp.wav '
    sox_command = '%s -q %s %stemp.wav %s ' % (sox_path,
                                               path_wav,
                                               last_visit,
                                               command)
    sox_command += ' '.join(map(str, args))
    proz = subprocess.Popen(sox_command, shell=True)
    proz.wait()
    pos = string.find(args, command)
    lb1["text"] = sox_command[pos:]


def deesser():
    call_sox('mcompand',
             '"0.001,0.1 0,0"',
             dfreq,
             '"0.001,0.1%s,-30 0 0 0"' % dthresh)


def compressor():
    call_sox('compand',
             '%s,%s' % (cattack, cdecay),
             '%s,%s' % (cthresh, cgain),
             '0 0 0')


def highpass():
    call_sox('highpass', hpf, 'vol', hpv, 'dB')
Das Erweitern um einen zusätzlichen Effekt sollte jetzt ein klein wenig einfacher und übersichtlicher sein.

Wobei es natürlich immer noch zu komplex und fehleranfällig ist. Man muss erst einmal neue globale Namen für die Argumente des Effekts finden, die sich nicht mit bereits verwendeten Namen überschneiden dürfen. Dann muss man eine vorhandene Funktion kopieren und anpassen. Und den GUI-Teil dazu schreiben. Je mehr Effekte hinzu kommen um so unübersichtlicher wird das Ganze.

Wenn es wirklich einfach für Endanwender sein soll, dann müsste man so einen Effekt deklarativ beschreiben können. Der Anwender müsste den Namen des Effekts, die Namen der Argumente, deren Typ, Voreinstellung und Wertebereich angeben. Und vielleicht noch ein "Template" für die Befehlszeile. Der Rest, inklusive der GUI-Aufbau, sollte automatisch passieren.
snakeseven
User
Beiträge: 405
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Mittwoch 9. Mai 2007, 19:35

Hi,
@Leonidas: Kommentare sollten in der Tat nicht fehlen ! Werde ich ergänzen. Subprocess.Popen baut sich den Pfad selbst zusammen ? Woher weiss es die Parameter, kannst du mir ein Beispiel geben, wie das geht ?

@Black Jack: danke für das Beispiel !

Ich kann OOP halt nicht so gut lesen, wie viele andere hier. Beschäftige mich damit allerdings auch nur rudimentär. Aber zurück zum eigentlichen Thema, um hier nicht völlig offtopic zu werden:

Ich würde mich freuen, wenn es im Forum Soxuser gibt, die Lust haben, den Code um neue Effekte zu erweitern. Ich denke, die hervorragende Audioqualität der Soxalgorythmen ist es wert. Und wenn sich einer dann noch die Mühe macht, Struktur in den Programm-Code zu bringen, dann sind alle happy (inklusive mir!).

Gruss, Seven
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 9. Mai 2007, 20:36

snakeseven hat geschrieben:@Leonidas: Kommentare sollten in der Tat nicht fehlen ! Werde ich ergänzen. Subprocess.Popen baut sich den Pfad selbst zusammen ? Woher weiss es die Parameter, kannst du mir ein Beispiel geben, wie das geht ?
Lies dir am besten den [wiki=Neue Features#Subprocess]Abschnitt aus dem Wiki[/wiki] durch.
Zuletzt geändert von Leonidas am Mittwoch 9. Mai 2007, 20:40, insgesamt 1-mal geändert.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Mittwoch 9. Mai 2007, 20:38

Es gibt anscheinend schon ein Tcl/Tk-Frontend: http://studio.sourceforge.net/

Ansonsten wäre es vielleicht nicht schlecht ein Modul zu erstellen, das Sox für Python zur Verfügung stellt. Also eine Sammlung von Funktionen, oder Objekten die den Aufruf von Sox kapseln. Darauf kann man dann verschiedene GUIs aufsetzen.

Da man Sox prima in einer Pipe verwenden kann, könnte man die API so gestalten, dass man verschiedene Aufrufe verketten kann ohne das immer temporäre Dateien bei jedem Schritt erzeugt werden müssen.
snakeseven
User
Beiträge: 405
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Donnerstag 10. Mai 2007, 02:06

BlackJack hat geschrieben:Es gibt anscheinend schon ein Tcl/Tk-Frontend: http://studio.sourceforge.net/

Da man Sox prima in einer Pipe verwenden kann, könnte man die API so gestalten, dass man verschiedene Aufrufe verketten kann ohne das immer temporäre Dateien bei jedem Schritt erzeugt werden müssen.
Ja, das Front-End kenne ich. Beschränkt sich leider nur auf wenige Standard-Effekte und mit Tcl/Tk kenne ich mich nicht aus.
Das Pipen von Sox zu Sox klappt gut, aber leider von TkSnack nach Sox nicht, oder ich habs noch nicht rausgefunden !?

Habe derweil eine OOP-Version von der GUI erstellt, die noch kommentiert werden muss. 384 statt 514 Zeilen ist schon Einiges weniger. Poste ich, sobald die Comments fertig sind.

Nächtle, Seven
snakeseven
User
Beiträge: 405
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Donnerstag 10. Mai 2007, 10:43

Moin,
Neue Version.
Gestandene OOPler können das sicherlich besser, aber immerhin gibt es keine globalen Variablen mehr. 442 Zeilen sinds dann doch geworden. Ich finds auch nicht wirklich leserlicher, aber das kann auch mit meinem Programmierstil in Sachen OOP zu tun haben. Immerhin sind jetzt auch Komentare drin. Freue mich wie immer über Verbesserungsvorschläge !

Gruss, Seven
BlackJack

Donnerstag 10. Mai 2007, 12:58

Es ist noch nicht so viel leserlicher weil nicht wirklich alles ordentlich "entkoppelt" ist. Man muss, wenn man einen neuen Effekt hinzufügen will, immer noch Änderungen über das gesamte Programm verteilt vornehmen und die Namen für die Argumente der einzelnen Effekte liegen auch immer noch alle in einem einzigen Namensraum.

Und die vielen ``if``/``elif``-Kaskaden über den Effektnamen sind ein gutes Zeichen dafür, dass man Code, der eigentlich zusammengehört, nämlich zu *einem* Effekt, über das gesamte Programm verstreut hat. Das ist ein Ansatzpunkt für einen sinnvollen Einsatz von Objekten. Statt eine ``if``-Abfrage pro Effekt könnte da *ein* Methodenaufruf auf einem Effekt-Objekt stehen. Vereinfacht sieht die Situation ungefähr so aus:

Code: Alles auswählen

creature = None

def speak():
    if creature == 'bird':
        print 'Piep'
    elif creature == 'dog':
        print 'Wau'
    elif creature == 'snake':
        print 'Ssschhhhh'


def move():
    if creature == 'bird':
        print 'flatter'
    elif creature == 'dog':
        print 'renn'
    elif creature == 'snake':
        print 'kriech'


def main():
    global creature
    for creature in ('bird', 'dog', 'snake'):
        speak()
        move()
Das würde in OOP so aussehen:

Code: Alles auswählen

class Bird(object):
    def speak(self):
        print 'Piep'
    
    def move(self):
        print 'flatter'


class Dog(object):
    def speak(self):
        print 'Wau'
    
    def move(self):
        print 'renn'


class Snake(object):
    def speak(self):
        print 'Ssschhhhh'
    
    def move(self):
        print 'kriech'


def main():
    for creature in (Bird(), Dog(), Snake()):
        creature.speak()
        creature.move()
Die OOP-Variante ist etwas länger, aber man kann jetzt jede Kreatur für sich allein betrachten und wenn man eine neue hinzufügen möchte, braucht man nicht mehr das ganze Programm abzusuchen und an den entsprechenden Stellen die ``if``-Abfragen erweitern, sondern braucht nur eine neue Klasse zu schreiben.

Die meisten Funktionen im `string`-Modul ist übrigens "deprecated" und sollten nicht mehr verwendet werden. `join()` gibt's als Methode auf Objekten. Und manuell Leerzeichen in die Liste einzufügen um dann mit der leeren Zeichenkette zu "joinen" stellt den Zweck der Methode ein wenig in Frage.
Antworten