Sounddateien in Schleife abspielen

  • Hallo, sorry ich bin wieder zurück.

    Vorweg einmal ein riesiges Dankeschön an die tolle Unterstützung. Ich habe nicht erwartet, das ihr mich bei dem Projekt so intensiv begleitet und unterstützt. Vor allem Franky07, hyle, Fred0815, und Dennis89. Danke.

    Es ist ja schon fast geschafft und ich hoffe, das wir das gemeinsam fertig kriegen.

    Es wäre toll, wenn es ab jetzt wieder ein bisschen übersichtlicher ablaufen könnte. Ich habe die Basissachen bisher eingerichtet, dann den RFID-Scanner angeschlossen. Der müsste jetzt eingerichtet werden und dann die Soundkarte. Vielleicht könnt ihr mir Schritt für Schritt vorgeben was ich jetzt machen muss? Als eine Liste oder so, die alle kommentieren können bis sie steht und dann poste ich schritt für Schritt wie ich es umsetze und die Testergebnisse usw.

    Liebe Grüße

    FrauBerry

  • Raspi OS auf die Karte,

    Dann noch die Soundkarte einrichten und probieren ob das Script rfid_scanner3.py läuft.

    Wenn ja, dann gucken wir nochmal nach dem Autostart.

  • Ich habe mir mal die letzte Version des Quelltextes angeschaut, die hier gezeigt wurde, und auch schon das mit dem `read_id` korrigiert, aber da ist dann immer noch `multiprocessing` undbekannt, dass noch importiert werden muss.

    Dafür werden `sys` und `getopt` importiert aber nirgends verwendet.

    Der Kommentar ``# Hinzugefügt`` ist unsinnig. Irgendwann wurde jede Zeile mal hinzugefügt. So etwas sieht man in der Versionsverwaltung im Diff, das schreibt man nicht willkürlich zu Zeilen als Kommentar.

    ``from os import path as os_path`` statt nur ``import os`` um dann ``os_path`` statt ``os.path`` zu schreiben ist ein bisschen fragwürdig.

    Statt ``filename.split(".")[-1]`` sollte man `os.splitext()` verwenden, oder gleich die entsprechende Funktionalität aus dem `pathlib`-Modul anstelle der Funktionen aus `os.path`.

    Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

    Dann fällt auf, dass `read_card_id()` auf `reader` zugreift obwohl es das gar nicht geben dürfte. Alles was eine Funktion oder Methode ausser Konstanten benötigt, wird als Argument(e) übergeben.

    Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

    Grunddatentypen haben nichts in Namen verloren. Den Typen ändert man gar nicht so selten mal während der Programmentwicklung und dann muss man überall im Programm die betroffenen Namen ändern, oder man hat falsche, irreführende Namen im Quelltext.

    Konstanten gehören an den Anfang des Moduls, hinter die Importe. Dann braucht man auch nicht an irgendwelche Variableninitialisierungen den Kommentar ``# Finger weg`` schreiben.

    Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht. Einen Kommentar ``# Titelliste`` vor der Definition einer Variablen `Title_List` oder ``# Init RFID Reader`` vor dem erstellen eines `SimpleMFRC522`-Objekts braucht kein Mensch.

    Der Kommentar ``# Read data from stdin`` ist gänzlich falsch.

    Bei `Title_List` ist es auch ein bisschen verwirrend, das es sich gar nicht um eine Liste sondern ein Wörterbuch handelt. Die werden oft nach dem Muster <key>_to_<value> benannt wobei <key> ein passender Name für einen Schlüssel und <value> ein Passender Name für einen Wert aus dem Wörterbuch ist. Hier also beispielsweise `rfid_to_filename`.

    Variablen werden nicht en block am Anfang definiert sondern erst dann wenn man sie braucht.

    `Stopp_ID` würde ich `SHUTDOWN_ID` nennen, denn „Stopp“ klingt für herunterfahren IMHO ein bisschen zu harmlos.

    `check_file()` prüft gar nicht *eine* Datei, sondern alle aus `file_table`, sollte also `check_files()` heissen — Mehrzahl.

    Bei `file_table` wird über die Schlüssel iteriert, um dann über den Schlüssel auf den Dateinamen zuzugreifen, um dann nur mit *dem* tatsächlich etwas zu machen. Da hätte man gleich über `file_table.values()` iterieren können. Und da man die Schlüssel gar nicht benötigt, sollte man vielleicht besser auch nur die Werte übergeben und die Funktion damit etwas allgemeiner machen.

    Von `exit()`/`sys.exit()` sollte man die Finger lassen wenn man nicht mindestens potentiell einen anderen Rückgabecode als 0 an den Aufrufer übermitteln will. Was man hier auch tatsächlich machen könnte, weil das sinnvoll wäre.

    `Running` ist überflüssig. Einfach eine ”Endlosschleife” und an entsprechender Stelle ein Abbruch mit ``break``.

    `playit` kann man sich sparen wenn man dafür `play_thread` entweder an `None` oder ein `Process`-Objekt bindet.

    `old_id` wird nicht wirklich benutzt. Das sollte komplett raus, denn wenn man diese Funktionalität implementieren würde, dann sicher nicht so komisch unübersichtlich über den Code verteilt. Damit ist `read_card_id()` überflüssig weil die nicht mehr wirklich etwas sinnvolles tut.

    Wenn man die Zufallstitel-Karte dazu programmiert, wird auffallen, das viel aus dem Zweig wo eine Karte für einen Titel behandelt wird, auch dort gebraucht wird. Also sollte man in der Kartenverarbeitung nur den zu spielenden Titel ermitteln und den gemeinsamen Code danach, *einmal* hinschreiben.

    `device` im Hauptprogramm wird immer an den gleichen Wert gebunden, also ist das eigentlich eine Konstante.

    Es macht nicht wirklich Sinn `play()` das `Wave`-Objekt zu übergeben und sich um das öffnen und schliessen immer ausserhalb der Funktion zu kümmern. Das gehört *in* die Funktion.

    Der Code für das eventuelle beenden eines `play_thread` existiert zweimal — das sollte man in eine Funktion auslagern.

    Das `PCM`-Objekt sollte man auch wieder schliessen.

    Ungetestet:

    Das mit dem `player` würde man eigentlich in einer Klasse kapseln, und ich sehe auch nicht warum das ein Prozess sein muss und nicht auch per Thread im gleichen Prozess funktionieren sollte.

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

  • Dennis89 Ich übergebe da immer Listen. Scheiss drauf das die Doku Tupel will, bei jeder API die mich zwingt potentiell einelementige Tupel zu schreiben, bekomme ich Lust den Autor davon zu steinigen.

    Tatsächlich muss es bei `Process` nicht einmal eine Sequenz sein, ja Listen gehen, es gehen sogar beliebige iterierbare Objekte. *Da* würde ich mich dann aber nicht drauf verlassen und das als Implementierungsdetail ansehen.

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

  • Moinsen

    Ich habe mir mal die letzte Version

    Du kannst hier an irgendwelchen Codes herumkritisieren was du willst Es ist Wursch um nicht zu sagen Wurschtegal.
    Die Geräte - ja mehrere - sind fertig, die Kunstausstellung wofür sie erdacht waren ist erfolgreich eröffnet worden.
    Laßt das Thema ruhen, es war sicherlich nicht aus jeder Sicht eine Stern-Stunde für dieses Forum. Die Beteiligung war überragend, nur gab es zu viele Akteure die immer wieder nur "reingequatscht" haben.

    Wenn man auf diese Projekt zurück blickt, und weiß das FrauBerry hier mit einer Hardware-Ausstattung nach einem Tutorial angetreten ist. Zudem erkennen konnte das die Auswahl eines RasPi Zero in Verbindung mit einem USB !? (noch mit OTG-Adapter) RFID Reader und einem Soundausgabe-Modul welches mit dem dazugehörigen Python-Code nur *.Wav Dateien wiedergeben kann, hat eigentlich erkennen müssen, dass das Tutorial aus den Kindertagen des RasPi stammt.
    Wenn man feststellt, dass der aus dem Tutorial übernommene Python-Code auf dem aktuellen RasbianOS "Bullseye" nicht mehr wirklich performt, zudem es zu ganzen Systemabstürzen gekommen ist, und somit FrauBerry wirklich nur Anfänger-Erfahrungen besaß, was auch die Kommentare meinerseits begründet, sollte sich überlegen, ob er Wochen später an irgend etwas herumkritisiert.
    Ob FrauBerry sich hier nochmal melden wird, wage ich fast zu bezweifeln, nachdem man auf ihre Ausführungen nicht wirklich eingegangen ist, und sie immer wieder mit neuen Programmbeispielen zugedröhnt hatte, die in dieser und auch nach der Konfigurationsänderung während des Projektes trotzdem nicht performant lauffähig waren.

    Du kannst gerne eine andere Schreibweise bevorzugen, überhaupt kein Problem, doch wenn ein Programm aus Stücken und Codeschnipseln hier auch über das Forum fast nach dem C&P Prinzip zusammengestückelt wurde, muss man den Anfänger der einen Großteil des gesamten Python Codes nicht wirklich versteht, irgendwie mitteilen, dass er an einigen Einstellungen nichts ändern darf. Wie man das nun gestaltet ist doch eigentlich auch Wurscht egal, Hauptsache durch die vielen Fehlversuche entstandene Zeit-Kanppheit hatte sie erst einmal ein funktionierendes System in der Hand.

    Franky

    Franky

  • Hallo,

    ich bin großer Befürworter dieser Art von Kritik/Code-Review.

    Es spielt meiner Meinung nach absolut gar keine Rolle, ob das Projekt schon "fertig" ist oder unter welchen Rahmenbedingungen es entstanden ist.

    Morgen kommt jemand anderes mit einem ähnlichen Problem, sieht einen zusammen gestückelten Code und das ganze geht von vorne los, weil wieder irgendwas nicht richtig funktioniert und keiner so wirklich durchblickt, was da eigentlich genau vor sich ging. Man muss bedenken, dass die Infos aus Themen nicht nur für den TE relevant sind.

    Zu dem tut es dem Internet sehr gut, wenn auch mal Programmierer, die ihr Handwerk wirklich von Grund auf gelernt haben und verstehen, ihre professionelle Meinung abgeben und dann sogar noch mit Codebeispielen! Dieses Wissen das da weiter gegeben wird sollte geschätzt und von jedem, der sich in diese Richtung weiterbilden will, aufgesaugt werden.

    Alle anderen können diese Beiträge ja einfach überlesen.

    Bitte keine weiteren Argumentationen darüber, wie der Code entstanden ist und auf welchem Stand der TE ist/war. Mein Post (bzw. meine Meinung dazu) ist allgemeingültig und auf jedes Thema anwendbar, dass mit solch einem Code-Review beglückt wird ;)

    Grüße

    Dennis

    🎧 With the music execution and the talk of revolution, it bleeds in me and it goes 🎧

  • Dennis89 Ich übergebe da immer Listen. Scheiss drauf das die Doku Tupel will, bei jeder API die mich zwingt potentiell einelementige Tupel zu schreiben, bekomme ich Lust den Autor davon zu steinigen.

    Anfänger machen aufgrund der Vorgabe öfter Fehler, weil sie bei einer Tuple mit nur einem Element das Komma vergessen. Das ist ja der Vorteil von Python. Beide Objekte sind iterierbar und die Vorgabe ist kein Zwang, dennoch wäre eine Änderung der Doku ein Vorteil für Anfänger.


    Code
    thread = Thread(target=..., args=(1,))
    
    # besser lesbar
    thread = Thread(target=..., args=[1])

    Das Gleiche bei Process.

    In seltenen Fällen ist es notwendig, den erwarteten Datentyp zu übergeben.

    Bei isinstance muss für den Typen ein Typ oder eine Tuple mit Typen oder ein Union (ab Python 3.10) mit Typen übergeben werden:

    Code
    isinstance("Hello", str)
    isinstance("Hello", (str, bytes))
    isinstance("Hello", str | bytes)
    isinstance("Fehler", [str, bytes])
  • Moinsen __blackjack__

    es ist toll, was du als Code- Review hier aufgearbeitet hast. Für diese Zusammenfassungen :danke_ATDE:
    Aber dabei sollte man es auch belassen, bzw dem Code den du als Re-Make veröffentlicht hast mit dem Kommentar versehen, das dieser Code auf einem Single-Core RasPi nicht lauffähig ist !
    Wenn du dein Augenmerk mal wohlwollend auf den gesamten Thread richten würdest und #70 von fred0815 gelesen hättest, würde dir auffallen, das diese MFRC522.read_id() Funktion diese Single Core CPU Last des RasPi Zero ( Version 1 ) fast auf 100% hoch treibt.
    Da du in deinem Code weder die Hardware angeben hast, noch dieses Programm mit der Hardware der TO FrauBerry getestet hast, => Raspberry Zero , der Soundkarte, sowie dem RFID-Reader halte ich diese Abschlußaussage für verfehlt.
    Ich habe auf meinem Zero mit Bullseye 32 Bit, 3.92 Python, 0.9.2 pyalsaaudio sowie diesem GitHub RFID Python- Code versucht deinen Code auszuführen. Genauso wie der Hardware Aufbau bei FrauBerry war.
    Mit dem Ergebnis dein Code funktioniert nicht, bzw führt zu Abstürzen, oder sagen wir ganz einfach der Code hängt fest. Nach nicht einmal 3 Sek. Play einer Monospur Wave-Datei tritt das unvermeidliche ein -> die CPU keult am Anschlag und die Audiowiedergabe bricht ab. Auf einem 3er PI mit ausreichend CPU Reserven funktioniert der von dir überarbeitet Code zweifelsfrei.

    Franky

    Franky

  • Franky07 Was lief denn dann bei ihr? Das war ja der Code den sie laut eigener Aussage laufen lassen hat. Unter anderem auch mit der Begründung dass das Abspielen per Prozess und `alsaaudio` das einzige war, was sie zum laufen bekommen hat. Und ich denke nicht, das der Code durch meine Überarbeitung signifikant unperformanter geworden ist. Ist vielleicht auch eine Frage der Abspielhardware und das man der was liefert was nicht noch grossartig in Software resampled/konvertiert werden muss.

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

  • Moinsen __blackjack__,

    ich gehe mal davon aus das du den Code aus #69 als Basis für deine Überarbeitung genommen hast !?
    Aber bevor ich dir hier weitere Frage beantworten werde, bist du mir noch die Antwort schuldig, mit welcher Hardware-Konfiguration du diesen Code getestet hast ?
    Vollständige HW Auflistung und alle SW Stände !

    Franky

    PS: Ich empfinde es der vielen Nachtschichten die hier nur Ich, sonder wie FrauBerry schon in ihrem Post #221schon aufgeführt hat, sich Wochen im nachhinein hinzustellen, und hier den großen Erklärbär spielen zu wollen ganz schön dreist.
    Zumindest hätte man, was auch jeder mitbekommen haben dürfte, dass FrauBerry hier abrupt die Weiterbeteiligung eingestellt hat, mal nachfragen können, was der Abschlußstand war. Das ist jetzt nicht gegen deine Fähigkeiten als Programmierer oder wohlwollender Unterstützer anzusehen, eher an die Art des Vortrag. Es ist ein Code-Review / Re-Make was in der schon genannten modifizierten Basiskonfiguration nicht lauffähig ist !

    Franky

  • Franky07 Ich habe den letzten Stand den FrauBerry selbst gepostet hat genommen, wo es in ihren Beiträgen nicht mehr darum ging *ob* das läuft, sondern wie sie das jetzt automatisch gestartet bekommt. Für den Code gab es eine Rückmeldung von jemand anderem weil da eine Zeile kaputt gegangen war beim Übertragen ins Forum, und nach der Korrektur ging es dann wohl auch bei demjenigen.

    Wozu brauchst Du meine Hardware-Information um zu sagen was bei FrauBerry gelaufen ist?

    Der Code ist/war offenbar bei mehreren Leuten lauffähig, und ich habe den überarbeitet, damit andere einen besseren Code verwenden können. Auf welcher Hardware ist doch egal. Insbesondere wenn FrauBerry sich sowieso aus der Diskussion zurückgezogen hat, spielt diese Anforderung das auf der schlechtesten Hardware unter den widrigsten Umständen benutzen zu können, überhaupt gar keine Rolle mehr. Und was haben Deine Nachtschichten zu dem Thema damit zu tun? Hast Du irgendwie ein Monopol hier zu antworten, oder zu entscheiden was für Antworten — die *Dich* eigentlich gar nicht betreffen — erlaubt sind und welche nicht? Worin genau besteht die ”Dreistigkeit”?

    Wie Dennis89 schon schrob ist es üblich, dass sich Anfänger irgendwelche Code-Stücke aus dem Netz nehmen, die halbwegs zu ihrem Problem passen. Dabei ist oft weniger schöner Code dabei, der nicht selten seinerseits schon aus Versatzstücken unterschiedlicher Qualität besteht. Da finde ich es sinnvoll solchen Code zu überarbeiten und etwas besseren Code für nachfolgende Anfänger mit ähnlichen Problemstellungen zum kopieren und anpassen zu hinterlassen. Egal ab welcher Hardware das läuft, wie viel Zeit die beteiligten da rein gesteckt haben, und wie lange das her sein mag — ich finde das sinnvoll Code der öffentlich wo rum steht, zu kommentieren und zu überarbeiten.

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

  • Moinsen __blackjack__

    Ich gehe mal davon aus das du den Code aus #97 ? Aber schön das man sich für eine Antwort alles selber zusammensuchen darf !
    Und hier bist du über die 68 gestolpert. Denn wenn du bemerkt hättest, was auch von FrauBerry so gesagt und wiedergegeben wurde, funktioniert das Programm auf dem Zero nur, wenn dieser Parameter auf False gesetzt bleibt und somit der Playcocde nur über die Zeilen 107 -110 ausgeführt wird.
    Sobald hier in den Beispiel multiprocessing.Process ist Spiel kommt schafft es das Zero nicht mehr !
    Somit hätte man bemerken können das dieser import multiprocessing gar nicht mehr vorhanden ist, und damit der Code falls der Parameter dennoch auf True gesetzt worden wäre gar nicht mehr lauffähig gewesen wäre. Somit sind die Zeilen ab 98 bis 104 und 117 gar nicht mehr ausführbar gewesen.

    Das ist einfach nur ein unkorrigiertes Überbleibsel aus den vielen Annäherungsversuchen die zuvor stattgefunden haben.

    Und ich habe definitiv nicht das alleinige Anrecht hier etwas zu sagen oder zu schreiben. Aber wenn man sich dann Wochen später hinstellt und so tut, als wäre man der Große Guru, dann habe ich sehr wohl ein Problem damit, weil deine Code in dieser dem eigentlichen beinhalteten Hardware Konfiguration nicht funktioniert.

    Ich bin hier raus, mir egal. Soll der Nächste sich dann an dem Code die Zähne ausbeißen, wenn er mit der selben Konfiguration sich an deinem Tutorial Code abackert.

    Franky

    Franky

  • Franky07 Ich hatte mir den letzten Code rausgesucht der gepostet wurde und mir natürlich nicht gemerkt in welchem Beitrag der stand. Warum sollte ich den denn erneut suchen wenn Du wissen willst aus welchem Beitrag und das genau so gut selbst machen kannst? Wenn Dir das zu viel Arbeit ist mal in einem Thema zurück zu blättern um was nachzulesen, dann musst Du das ja nicht tun. ?‍♂️

    Ich *habe* bemerkt das `multiprocessing` nicht mehr importiert wurde, aber es wurde im Code referenziert. Mir ist schon öfter untergekommen, dass Funktionalität aus Code entfernt wurde und vergessen wurde dazugehörige Importe mit zu entfernen. Das jemand auf die Idee kommen könnte Funktionalität zu entfernen in dem einfach ein dafür wichtiger Import entfernt, der ganze Code aber drin gelassen wird, wäre mir echt nicht im Traum eingefallen. Zumal der Code der das benutzt durch die Konfiguration über eine Konstante ja auch immer noch deaktiviert ist wenn `multiprocessing` importiert wird. Die eine Import-Zeile hin zu schreiben ändert nichts am Laufzeitverhalten des Programms, repariert es aber im Sinne von a) es gibt keine Meldung von der IDE mehr, dass da unbekannte Namen im Code verwendet werden, und b) kann man das mit der Konstanten einfach wieder aktivieren wenn man möchte. Also war das für mich der logische Schritt.

    Wenn mein Code nicht funktioniert, dann tut es der den ich überarbeitet habe auch nicht. Du sagst jetzt aber selber das der für FrauBerry tut/tat wenn man den so benutzt wie er dort steht.

    Wärst Du glücklicher wenn ich statt den Import wieder hinzuzufügen, den Code der den direkt und indirekt benutzt entfernt hätte? Warum? Für den Raspi Zero ändert das ja nichts, warum sollte das also stören? Und bei leistungsstärkeren Modellen — wahrscheinlich sogar schon beim Raspi Zero 2 — könnte man die Konfiguration an einer Stelle ändern und hätte Abspielen und Karten erkennen nebenläufig. Was ist da jetzt so schlimm dran? Oder dreist? Ich verstehe immer noch nicht warum/worüber Du Dich so dermassen aufregst. Ich habe Code überarbeitet. Inhaltlich begründet/begründbar. Da bist Du nicht wirklich drauf eingegangen, Dir scheint es aus irgendeinem Grund quer zu sitzen das ich es überhaupt gewagt habe hier etwas zu schreiben.

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

  • Es gibt meiner Meinung nach keinen Grund sich zu rechtfertigen, vorhandenen Code zu verbessern. Wir wünschen uns hier grundsätzlich die Lösung eines Threads zu sehen. Es geht dabei nicht um die beteiligten User und gleich garnicht darum wer mit seiner Antwort recht hatte, sondern um die *Nachwelt*, die schon erwähnt wurde.

    Wenn der TO wie so oft dem nicht nachkommt, weil dieser eine möglichen Lösung verwendet, sich aber dann nicht mehr meldet, ist es IMHO umso besser Code zu optimieren oder zumindest den gängigen Konventionen anzupassen.

    Ich mache hier zu, denn eine weitere Diskussion bringt nichts.

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!