beep auf Ubuntu mit Python aufrufen / Beispiel Morsen

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.
orpidor
User
Beiträge: 7
Registriert: Mittwoch 23. März 2016, 00:18

[Codebox=text file=Unbenannt.txt]
Ich bin Neuling und lerne gerade Python auf Ubuntu und bin stolzer Besitzer eines Tuxedo Notebooks.
Ich habe Python 3.4.3+ auf meinem Rechner und bin gerade dabei ein Morse-Listing zu bearbeiten, welches in einem Lern-Beispiel mit winsound arbeitet, was mir aber nichts nutzt.(Ich lerne Python gerade mit dem BUch "Python für Einsteiger von Thomas Theis.
Nun habe ich bereits im Internet gelesen, dass man mit os.system("beep") Piepsignale aufrufen kann. Ich habe beep bereits installiert, aber leider funktioniert es nicht. Über das Internet habe ich gelesen, dass es vielleicht am BIOS liegen kann (Beep beim Start ein-bzw. ausschalten.)
Aber auch das hat mich nicht weitergebracht.
Vielleicht kann mir jemand helfen, wie ich da jetzt weiterkomme?
Wie kann ich Beep durch Python aufrufen oder an welcher Einstellung und/oder Konfigurationsdatei könnte es vielleicht liegen, dass es bei mir nicht funktioniert?
Danke schon mal für eine Antwort...
:)
[/Codebox]

Code: Alles auswählen

import sys, morsen, time, os

# im Listing: import winsound

# Beispieltext codieren
def tonCode(text,code):
    # Zeitschema, Dauer eines Signals in msec.
    signalDauer = {".":200, "-":600}

    # Zeitschema, Dauer einer Pause in sec.
    signalPause = 0.2
    zeichenPause = 0.6
    wortPause = 1.4

    # Text in Worte zerlegen
    alleWorte = text.split()

    # Jedes Wort im Text
    for w in range(len(alleWorte)):
        # Übernahme eines Worts
        wort = alleWorte[w]
        # Jedes Zeichen im Wort
        for z in range(len(wort)):
            # Übernahme eines Zeichens
            zeichen = wort[z]
            # Kontrollausgabe des Zeichens
            print(zeichen, end="")
            # Versuch ein Zeichen auszugeben
            try:
                # Übernahme des Morsezeichens für das Zeichen
                # Falls kein Eintrag im Dictionary: KeyError
                alleSignale =code[zeichen]
                # Jedes Signal des Morsezeichens
                for s in range (len(alleSignale)):
                    # Übernahme eines Symbols
                    signal = alleSignale[s]
                    # Ausgabe des Symbols, kurz oder lang
                    os.system("beep -f 800 -l signalDauer[signal]")
                    
                    # original: winsound.Beep(800, signalDauer[signal])

                    # Nach jedem Signal eine Signalpause
                    # ausser nach dem letzten Signal
                    if s < len(alleSignale)-1:
                        time.sleep(signalPause)
                # Nach jedem Zeichen eine Signalpause,
                # ausser nach dem letzten Zeichen
                if z < len(wort)-1:
                    time.sleep(zeichenPause)
            # Falls kein Eintrag im Dictionary: ignorieren
            except KeyError:
                pass
        # Nach jedem Wort eine Wortpause,
        # ausser nach dem letzten Wort
        if w < len(alleWorte)-1:
            print(" ", end = "")
            time.sleep(wortPause)

# Lesefunktion aufrufen
code = morsen.leseCode()
# Schreibfunktion aufrufen
tonCode("Hallo Welt", code)
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

os.system("xxx ...") führt den Befehl "xxx ..." aus. Öffne ein Terminal-Fenster und führe

Code: Alles auswählen

beep -f 165.4064 -l 1000
aus. Das sollte einen Ton ergeben, der eine Sekunde anhält.
Nun öffne die Python-Shell und versuche aus dieser den Ton zu erzeugen. Ich würde folgendes bekommen, wenn ich beep installiert hätte.

Code: Alles auswählen

$ python
Python 2.4.3 (#1, Feb 24 2012, 13:04:26)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-50)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system("beep -f 165.4064 -l 1000")
0
>>>
Und ein Ton würde erklingen. 0 ist der Rückgabewert von os.system und der ist immer 0 wenn das Kommando erfolgreich ausgeführt wurde.
Ich habe aber Beep nicht installiert (und auch kein Ubuntu). Darum schaut es bei mir so aus:

Code: Alles auswählen

[oracle@upx1media01 trash]$ python
Python 2.4.3 (#1, Feb 24 2012, 13:04:26)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-50)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system("beep -f 165.4064 -l 1000")
sh: beep: command not found
32512
>>>
Wie schaut das bei dir aus?

Ich habe deinen Code nur überflogen: er kann nicht funktionieren. Führe im Terminal-Fenster

Code: Alles auswählen

beep -f 800 -l signalDauer[signal]
Das wird natürlich einen Fehler ergeben, da beep nichts mit der Zeichenkette 'signalDauer[signal]' anfangen kann. Aber genau so rufst du beep aus Python auf. Wenn du wills, das beep aus Python mit dem Wert von signalDauer[signal] aufgerufen wird, musst du die entsprechende Befehlszeichenkette erzeugen, zum Beispiel so

Code: Alles auswählen

os.system("beep -f 800 -l "+str(signalDauer[signal]))
Mehr über Zeichenketten erfährst du im Tutorial: https://docs.python.org/3/tutorial/intr ... ml#strings

Die töne so zu erzeugen ist etwas ineffizient, da für jeden Piepser ein eigener beep-Prozess erzeugt wird. Und möglicherweise auch ein eigenes Terminal-Fenster, falls du python nicht aus so einem startes. Aber voerst kannst du es ja so versuchen. Danach könntest du versuchen, für einen Text beep nur einmal aufzurufen.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@orpidor: Der Fehler liegt im Aufruf von beep.

Für jedes Modul solltest Du eine eigene import-Zeile schreiben. Namen sind wichtige Informationsträger. Funktionen sollten nach Tätigkeiten benannt sein, was soll ich mir also unter einer Funktion vorstellen, die tonCode heißt? morse_text ist z.B. viel aussagekräftiger. Das Argument code sagt mir gar nichts und ich mußte erst den ganzen Code lesen, um zu verstehen, dass code ein Wörterbuch ist, das Zeichen in Morsesequenzen mappt, der Name char2morsesequenze wäre damit passender. `for w in range(len(xy)):` ist in Python ein Antipattern, weil Du auch direkt über die Liste iterieren kannst: `for wort in alleWorte:` bzw. `for zeichen in wort:`.
os.system solltest Du nicht verwenden, und statt dessen subprocess.call. In Python werden nicht auf magische Weise Variablen in Strings ersetzt, das mußt Du explizit angeben:

Code: Alles auswählen

subprocess.call(['beep', '-f', '800', '-l', str(signalDauer[signal])])
Kommentare sollten im Code beschreiben, warum etwas passiert und nicht was. Der Mehrwert von "Lesefunktion aufrufen" tendiert gegen minus unendlich, weil zum einen die Information fehlt, was gelesen werden soll, zum anderen in der nächsten Zeile klar ist, dass eine Funktion aufgerufen wird.

Code: Alles auswählen

import sys
import morsen
import time
import subprocess

SIGNAL_PAUSE = 0.2
ZEICHEN_PAUSE = 0.6
WORT_PAUSE = 1.4
SIGNAL_DAUER = {".":200, "-":600}
FREQUENZ = 800

def morse_text(text, char2morsesequenz):
    pause = 0
    for wort in text.split():
        for zeichen in wort:
            print(zeichen, end="")
            try:
                morsesequenz = char2morsesequenz[zeichen]
            except KeyError:
                pass
            else:
                for signal in morsesequenz:
                    time.sleep(pause)
                    subprocess.call(['beep', '-f', str(FREQUENZ)), '-l', str(SIGNAL_DAUER[signal])])
                    pause = SIGNAL_PAUSE
                pause = ZEICHEN_PAUSE
        print(" ", end = "")
        pause = WORT_PAUSE

char2morsesequenz = morsen.leseCode()
morse_text("Hallo Welt", char2morsesequenz)
BlackJack

Zum ``beep``-Problem: Das benutzt den eingebauten PC-Lautsprecher den es nicht mehr in allen Geräten gibt. Wobei im Laptop verbaute Lautsprecher nicht zwangsläufig als „PC speaker“ angesprochen werden können, denn das sind ja echte Lautsprecher im Gegensatz zu dem ”Piepsdings” was früher in jedem PC eingebaut war. Es kann also durchaus sein, dass es letztendlich auf ein Hardwareproblem hinausläuft.

Edit: Hab's bei mir gerade mit ``sudo modprobe pcspkr`` zum ``beep``\en bekommen. Der Kerneltreiber für den „PC speaker“ war also nicht geladen. Und zwar weil der bei mir in ``/etc/modprobe.d/blacklist.conf`` auf der schwarzen Liste steht:

Code: Alles auswählen

# ugly and loud noise, getting on everyone's nerves; this should be done by a
# nice pulseaudio bing (Ubuntu: #77010)
blacklist pcspkr
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

Also deshalb wie beschrieben zuerst einmal mit

Code: Alles auswählen

beep -f 165.4064 -l 1000
ausprobieren, ob das überhaupt funktioniert. Bevor beep so nicht funktioniert brauchst du es auch in Python mit beep nicht versuchen.
Zusätzlich solltest du beim Aufruf von beep gleich den Pfad mit angeben. Das garantiert nicht nur, das das Programm beep gefunden wird, es verhindert auch, dass dir irgendwer ein anderes, bösartiges beep in einem anderen Pfad unterjubeln kann. In Python sollte der Pfad in einer Variablen gespreicher sein, das erleichtert die Anpassung and andere Systeme.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@orpidor
Ich würde ganz auf den Gebrauch von `beep` verzichten und mir statt dessen einen 'beep-sound' besorgen, diesen evtl. noch vorne und hinten kürzen und dann mit aplay, das von den meisten Distris bereits vorinstalliert ist aufrufen oder ein Python Paket zur Audioausgabe nutzen.
Wie BlackJack bereits schreibt stammt `beep` noch aus Zeiten, in denen ein PC diese fürchterlich nervtötenden Piepser eingebaut hatte.
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

mutetella hat geschrieben:@orpidor
Ich würde ganz auf den Gebrauch von `beep` verzichten und mir statt dessen (...)
Wenn er jetzt schon beep installiert hat und das ohne größeren Aufwand zum laufen bringt, wir das wohl ausreichen. Es geht vermutlich mehr um das Programmieren und um Python als um das Morsen. Der prakische Einsatz des fertigen Programms wird sich in grenzen halten.


Was das Programmieren betrifft möchte ich noch feststellen, dass bei Verwendung von os.system(), was ja laut Sirius3 eigentlich vermieden werden sollte, noch eine Fehlerbehandlung eingebaut werden muss. Also so ähnlich wie

Code: Alles auswählen

result=os.system("beep ...")
if result:
    raise RuntimeError("beep-errors %d" % result)
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@miracle173: jetzt sag mir nur noch, welchen Exitcode beep haben soll? Die Dokumentation schweigt sich dazu aus. subprocess liefert das, was Du da von Hand zusammenbaust, schon mit: check_call.
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

Sirius3 hat geschrieben:@miracle173: jetzt sag mir nur noch, welchen Exitcode beep haben soll? Die Dokumentation schweigt sich dazu aus. subprocess liefert das, was Du da von Hand zusammenbaust, schon mit: check_call.
Sie schweigt sich eigentlich nicht darüber aus:

On Unix, the return value is the exit status of the process encoded in the format specified for wait().

und für wait gilt
a 16-bit number, whose low byte is the signal number that killed the process, and whose high byte is the exit status (if the signal number is zero); the high bit of the low byte is set if a core file was produced.
also nimm das Hi-Byte.

der Vollständigkeit halber
On Windows, the return value is that returned by the system shell after running command.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@miracle173: was ein Exitcode ist, ist mir klar. Was es für Exitcodes bei beep gibt aber nicht.
Benutzeravatar
noisefloor
User
Beiträge: 4253
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

das Dekodieren von Morse-Code muss du auch nicht selber machen. Dafür gibt's fertige Module. Einfach mal nach "morse" bei PyPi suchen.
Wobei ich persönlich ja [url]https://pypi.python.org/pypi/pyMorseCode[/ulr] gut finde :-)

Gruß, noisefloor
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

@Sirius3: Mir ist eigentlich nicht ganz klar, was du jetzt eigentlich wissen willst bzw. worauf du hinaus willst.
Sirius3 hat geschrieben: (...)
jetzt sag mir nur noch, welchen Exitcode beep haben soll?
(...)
Haben soll es natürlich 0, weil das bedeutet, dass der Befehl erfolgreich ausgeführt wurde.
Sirius3 hat geschrieben: (...)
was ein Exitcode ist, ist mir klar. Was es für Exitcodes bei beep gibt aber nicht.
(...)
Mir ist auch nicht klar, was für Exitcodes es bei beep gibt. Allerdings ist mir das auch ziemlich egal. Die brauch ich eigentlich nicht, um das Morseprogramm zu schreiben. Ich würde da eigentlich nicht auf irgendwelche Fehlercodes eingehen.
Sirius3 hat geschrieben: (...)
subprocess liefert das, was Du da von Hand zusammenbaust, schon mit: check_call
(...)
Das spricht zwar für subprocess, aber nicht dagegen, dass man, wenn man os.system() verwendet, eine geeignete Fehlerbehandlung einbaut.
Benutzeravatar
noisefloor
User
Beiträge: 4253
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Das spricht zwar für subprocess, aber nicht dagegen, dass man, wenn man os.system() verwendet
Eigentlich spricht alles dagegen, dass man `os.system()` verwendet. Seit es das `subprocess` Modul gibt, gibt es sehr wenig Gründe, noch `os.system()` zu nutzen. Die offizielle Pyhton-Doku rät ja auch dazu, `subprocess` zu verwenden.

Gruß, noisefloor
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

noisefloor hat geschrieben:Hallo,
Das spricht zwar für subprocess, aber nicht dagegen, dass man, wenn man os.system() verwendet
Eigentlich spricht alles dagegen, dass man `os.system()` verwendet.
(...)
Hallo
Auch ich sehe keine Grund os.system() zu verwenden, aber viele Gründe subprocess zu verwenden. Ich habe aber auch nie für os.system() geworben. Auch mein von dir zitierte Satz tut das in keiner Weise.
Benutzeravatar
noisefloor
User
Beiträge: 4253
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Auch mein von dir zitierte Satz tut das in keiner Weise.
Nee, du rätst aber auch nicht von der Nutzung explizit ab. Aber explizit ist besser als implizit, kennste ja ;-)

Gruß, noisefloor
orpidor
User
Beiträge: 7
Registriert: Mittwoch 23. März 2016, 00:18

miracle173 hat geschrieben:os.system("xxx ...") führt den Befehl "xxx ..." aus. Öffne ein Terminal-Fenster und führe

Code: Alles auswählen

beep -f 165.4064 -l 1000
aus. Das sollte einen Ton ergeben, der eine Sekunde anhält.
Nun öffne die Python-Shell und versuche aus dieser den Ton zu erzeugen. Ich würde folgendes bekommen, wenn ich beep installiert hätte.

Code: Alles auswählen

$ python
Python 2.4.3 (#1, Feb 24 2012, 13:04:26)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-50)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system("beep -f 165.4064 -l 1000")
0
>>>
[/code]
Wie schaut das bei dir aus?

Danke für die tollen Hinweise.
Ich erhalte ebenfalls den Rückgabewert 0, also scheint alles ok zu sein, aber der Piepton ist nicht zu hören.



Ich habe deinen Code nur überflogen: er kann nicht funktionieren. Führe im Terminal-Fenster

Code: Alles auswählen

beep -f 800 -l signalDauer[signal]
Das wird natürlich einen Fehler ergeben, da beep nichts mit der Zeichenkette 'signalDauer[signal]' anfangen kann. Aber genau so rufst du beep aus Python auf. Wenn du wills, das beep aus Python mit dem Wert von signalDauer[signal] aufgerufen wird, musst du die entsprechende Befehlszeichenkette erzeugen, zum Beispiel so

Code: Alles auswählen

os.system("beep -f 800 -l "+str(signalDauer[signal]))
Das stimmt, da habe ich den Code zu schnell übermittelt, bevor ich es nochmals überprüft habe. Danke.
Mehr über Zeichenketten erfährst du im Tutorial: https://docs.python.org/3/tutorial/intr ... ml#strings

Die töne so zu erzeugen ist etwas ineffizient, da für jeden Piepser ein eigener beep-Prozess erzeugt wird. Und möglicherweise auch ein eigenes Terminal-Fenster, falls du python nicht aus so einem startes. Aber voerst kannst du es ja so versuchen. Danach könntest du versuchen, für einen Text beep nur einmal aufzurufen.
Ja, Danke. Ich stehe noch am Anfang meiner Python-Programmier-Karriere, bin aber schon jetzt begeistert, was ich hier im Forum für tolle Tipps und Hinweise bekomme. Echt Klasse. Ich lerne hier eine Menge.
orpidor
User
Beiträge: 7
Registriert: Mittwoch 23. März 2016, 00:18

[quote="Sirius3"]@orpidor: Der Fehler liegt im Aufruf von beep.
... In Python werden nicht auf magische Weise Variablen in Strings ersetzt, das mußt Du explizit angeben:

Code: Alles auswählen

subprocess.call(['beep', '-f', '800', '-l', str(signalDauer[signal])])
Kommentare sollten im Code beschreiben, warum etwas passiert und nicht was. Der Mehrwert von "Lesefunktion aufrufen" tendiert gegen minus unendlich, weil zum einen die Information fehlt, was gelesen werden soll, zum anderen in der nächsten Zeile klar ist, dass eine Funktion aufgerufen wird
.
Vielen Dank auch Dir für die vielen Hinweise und Tipps. Gerade mit der Beschreibung im Listing und der Nameswahl hast Du natürlich recht. Ich stehe ganz am Anfang und bringe mir gerade Python bei und werde darauf in Zukunft stärker achten.
orpidor
User
Beiträge: 7
Registriert: Mittwoch 23. März 2016, 00:18

BlackJack hat geschrieben:Zum ``beep``-Problem: Das benutzt den eingebauten PC-Lautsprecher den es nicht mehr in allen Geräten gibt. Wobei im Laptop verbaute Lautsprecher nicht zwangsläufig als „PC speaker“ angesprochen werden können, denn das sind ja echte Lautsprecher im Gegensatz zu dem ”Piepsdings” was früher in jedem PC eingebaut war. Es kann also durchaus sein, dass es letztendlich auf ein Hardwareproblem hinausläuft.

Edit: Hab's bei mir gerade mit ``sudo modprobe pcspkr`` zum ``beep``\en bekommen. Der Kerneltreiber für den „PC speaker“ war also nicht geladen. Und zwar weil der bei mir in ``/etc/modprobe.d/blacklist.conf`` auf der schwarzen Liste steht:

Code: Alles auswählen

# ugly and loud noise, getting on everyone's nerves; this should be done by a
# nice pulseaudio bing (Ubuntu: #77010)
blacklist pcspkr
Danke für Deine Hilfe. Ich habe inzwischen die gleiche Erfahrung gemacht und etliches gelesen und ausprobiert. Ich freue mich, dass es bei mir wahrscheinlich tatsächlich ein Hardware-Problem ist. :)
orpidor
User
Beiträge: 7
Registriert: Mittwoch 23. März 2016, 00:18

miracle173 hat geschrieben:Also deshalb wie beschrieben zuerst einmal mit

Code: Alles auswählen

beep -f 165.4064 -l 1000
ausprobieren, ob das überhaupt funktioniert. Bevor beep so nicht funktioniert brauchst du es auch in Python mit beep nicht versuchen.
Zusätzlich solltest du beim Aufruf von beep gleich den Pfad mit angeben. Das garantiert nicht nur, das das Programm beep gefunden wird, es verhindert auch, dass dir irgendwer ein anderes, bösartiges beep in einem anderen Pfad unterjubeln kann. In Python sollte der Pfad in einer Variablen gespreicher sein, das erleichtert die Anpassung and andere Systeme.
habe es ausprobiert und der Computer sagt mir, dass alles ok ist (Rückgabewert 0), aber kein Gepiepe. Ich gehe inzwischen davon aus, dass es nicht funktioniert, weil es wohl eine "Hardware-Sache" ist. Danke für die Hilfe.
orpidor
User
Beiträge: 7
Registriert: Mittwoch 23. März 2016, 00:18

mutetella hat geschrieben:@orpidor
Ich würde ganz auf den Gebrauch von `beep` verzichten und mir statt dessen einen 'beep-sound' besorgen, diesen evtl. noch vorne und hinten kürzen und dann mit aplay, das von den meisten Distris bereits vorinstalliert ist aufrufen oder ein Python Paket zur Audioausgabe nutzen.
Wie BlackJack bereits schreibt stammt `beep` noch aus Zeiten, in denen ein PC diese fürchterlich nervtötenden Piepser eingebaut hatte.
@mutetella:
Danke, ich werde mir die Sache mit aplay in Kürze ansehen. Übrigens Klasse Zitat! :lol:
Antworten