Reputation: 171
I recently found out that you can play sounds in python. I instantly wanted to make a text to morse code program but when I try to assign winsound.Beep(600,300) to "a" and launch, it just beeps once and when i type a it does nothing.
import winsound
def dot():
winsound.Beep(600,100)
def line():
winsound.Beep(600,100)
a = dot(), line() #it doesn't work when i just do
#a = winsound.Beep(600,100) either
#and it beeps at the beginning which i don't want
can you tell me how i can assign winsound.Beep() to a varible?
Upvotes: 2
Views: 1982
Reputation: 109
Here's a small modification of thebjorn's answer with a complete alphabet and more precise timing parameters:
import winsound
import time
alphabet = {'A': '.-',
'B': '-...',
'C': '-.-.',
'D': '-..',
'E': '.',
'F': '..-.',
'G': '--.',
'H': '....',
'I': '..',
'J': '.---',
'K': '-.-',
'L': '.-..',
'M': '--',
'N': '-.',
'O': '---',
'P': '.--.',
'Q': '--.-',
'R': '.-.',
'S': '...',
'T': '-',
'U': '..-',
'V': '...-',
'W': '.--',
'X': '-..-',
'Y': '-.--',
'Z': '--..',
'1': '.----',
'2': '..---',
'3': '...--',
'4': '....-',
'5': '.....',
'6': '-....',
'7': '--...',
'8': '---..',
'9': '----.',
'0': '-----',
', ': '--..--',
'.': '.-.-.-',
'?': '..--..',
'/': '-..-.',
'-': '-....-',
'(': '-.--.',
')': '-.--.-'}
unit = 100 # ms
frequency = 3000 # Hz
def play_dot():
winsound.Beep(frequency, 1*unit)
def play_dash():
winsound.Beep(frequency, 3*unit)
def play_char(ch):
if ch == ' ':
time.sleep(7*unit/1000)
return '<space>'
morse_value = alphabet[ch]
for d in morse_value:
if d == '.':
play_dot()
else:
play_dash()
time.sleep(1*unit/1000)
return morse_value
def txt2morse(txt):
for ch in txt.upper():
print(play_char(ch))
if __name__ == "__main__":
txt2morse('SOS SOS')
txt2morse('hello world')
Upvotes: 2
Reputation: 27321
Adding a layer of indirection is often helpful. Define the character values separately from the playing, then you can loop over any text:
import winsound
import time
# define the values for the alphabet (using easy to verify strings)
alphabet = dict(
a='.-',
b='-...',
c='-.-.',
d='-..',
e='.',
h='....',
l='.-..',
o='---',
w='.--',
r='.-.',
# etc.
)
How to play (single) dots and dashes (the lines are referred to as dashes):
def play_dot():
winsound.Beep(600, 100)
def play_dash():
winsound.Beep(500, 200) # a bit lower frequency, double length
Play one character by looking up the morse value for the character in the alphabet
and then iterate over the dots/dashes:
def play_char(ch):
if ch == ' ': # space is a special case
time.sleep(0.9) # wait for 0.9 seconds before returning
return '<space>'
morseval = alphabet[ch] # morseval is now a series of dots/dashes
for d in morseval: # loop over them
if d == '.': # if it's a dot, play a dot
play_dot()
else:
play_dash()
time.sleep(0.1) # a small break (0.1 secs) makes it easier on the ears
return morseval # return the morse value so we can see what was played..
to play a text, assuming it's ascii, just iterate through the characters and play each of them in turn:
def txt2morse(txt):
for ch in txt.lower(): # convert the text to lower case, just in case..
print play_char(ch), # Python 2.7'ism to keep printing on the same line
print
then:
>>> txt2morse('hello world')
.... . .-.. .-.. --- <space> .-- --- .-. .-.. -..
Upvotes: 1
Reputation: 56654
You are mixing up "code that runs right now" with "code I want to run later".
Your line,
a = dot(), line()
runs dot()
(which beeps and returns None
) then runs line()
(which beeps and returns None
) then assigns the result (None, None)
to the variable a
.
Instead try
def a():
dot()
line()
which creates a function which you can run later by calling a()
... but it will still sound like one continuous beep, because you need to add a short pause after each tone in the definitions of dot()
and line()
. You might find time.sleep()
useful, or possibly winsound
already provides something similar.
Edit:
You can use a dispatch table (a dict that translates characters to function calls) and an input loop, like so:
MORSE_CHARS = {
"a": (dot, line),
"b": (dot, dot, line),
# define other characters and space here
}
def morse(s):
"""
Turn string s into Morse beeps
"""
for ch in s.lower():
for fn in MORSE_CHARS[ch]:
fn()
def main():
while True:
s = input("Enter text to play (or just hit Enter to quit): ")
if s:
morse(s)
else:
break
if __name__ == "__main__":
main()
Upvotes: 3
Reputation: 2243
My solution to your problem will involve passing functions as parameters to other functions. If this is unfamiliar to you, I suggest you look into functional programming with Python a little bit.
import winsound
import time
# first - create the `dot` and `line` functions
def dot():
winsound.Beep(600, 100)
time.sleep(0.1) # this is in seconds
def line():
....
def space():
....
def full_stop():
....
# now you need some way of mapping letters to sounds
mapping = {
"a": (dot, line),
"b": (line, dot, dot, dot),
....
" ": (space,), # A one-tuple is defined like this, not like `(var)`
".": (full_stop,)
}
# And as a final step you need a function to play the sounds
def play_morse(message):
for character in message:
character = character.lower()
if character in mapping:
for func in mapping[character]:
func()
else:
print("Unknown character: '{}'".format(character))
You would use the function like so:
>>> play_morse("Hello world!")
Upvotes: 1
Reputation: 6063
In python everything is an object. If you run this:
a = dot()
Execute dot() and assign the returned value to a
- in your case it's None
.
However, if you want to "assign" the function dot()
to a
and then call a
you do this:
a = dot
a()
In this case the names a
and dot
refer to the same object. a
is now a function which you call with parentheses only.
Upvotes: 0