Skip to content

Instantly share code, notes, and snippets.

@jampola
Last active May 12, 2021 14:10
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jampola/ad3995e227dc46cfe069 to your computer and use it in GitHub Desktop.
Save jampola/ad3995e227dc46cfe069 to your computer and use it in GitHub Desktop.
Fully functioning mp3/wav/ogg playing Alarm Clock (PyGTK and Gst)
#!/usr/bin/python
'''
jamesbos [at] gmail [dot] com - originally shared at https://gist.github.com/jampola/ad3995e227dc46cfe069
Fully functioning alarm clock. Very primitive I know but this shows how basic events and
"threading" within pygtk[1] and media playback in gst[2] works. The main reason for sharing this on gist.github.org is so
it is searchable via google.
Include a an mp3 file called "alarm.mp3" in the same directory as this file OR supply the
/path/to/whatever.mp3/wav/ogg that you wish to play.
note: For the sake of your own ability, read and really understand what everything here does.
[1] http://python-gtk-3-tutorial.readthedocs.org/en/latest/
[2] http://blogs.gnome.org/uraeus/2011/10/04/tutorial-for-python-gstreamer-and-gtk-3/
license: are you kidding? :)
'''
from gi.repository import Gtk, GObject, Pango, Gst
import pygst
from datetime import datetime
import os
Gst.init(None)
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Alarm Clock")
self.alarm_state = False
self.table = Gtk.Table(5,4,False)
self.add(self.table)
# # GST
self.player = Gst.ElementFactory.make("playbin", "player")
self.player.set_property('uri','file://'+os.path.abspath('alarm.mp3'))
# # Clock label
self.labelClock = Gtk.Label()
self.labelClock.modify_font(Pango.FontDescription("sans 14"))
self.table.attach(self.labelClock,0, 6, 0, 1)
# initially set time to clock label otherwise there is a delay
# when displaying the clock when app is first run
self.labelClock.set_label(str(datetime.now()))
# # alarm switch
self.alarmSwitch = Gtk.Switch()
self.table.attach(self.alarmSwitch,0,6,1,2)
# # alarm label
self.labelSetAlarm = Gtk.Label("No Alarm Set")
self.table.attach(self.labelSetAlarm,0, 6, 2, 3)
# # time labels
self.time_hr_label = Gtk.Label("Hour")
self.table.attach(self.time_hr_label,0,1, 3,4)
self.time_min_label = Gtk.Label("Min")
self.table.attach(self.time_min_label,2,3, 3,4)
self.time_sec_label = Gtk.Label("Sec")
self.table.attach(self.time_sec_label,4,5, 3,4)
# # hours
self.hr_adj = Gtk.Adjustment(value = 1, lower=0, upper=23, step_incr=1)
self.time_hr_spinner = Gtk.SpinButton()
self.time_hr_spinner.set_adjustment(self.hr_adj)
self.table.attach(self.time_hr_spinner,0,1, 4,5)
# # mins
self.min_adj = Gtk.Adjustment(value = 1, lower=0, upper=59, step_incr=1)
self.time_min_spinner = Gtk.SpinButton()
self.time_min_spinner.set_adjustment(self.min_adj)
self.table.attach(self.time_min_spinner,2,3, 4,5)
# # seconds
self.sec_adj = Gtk.Adjustment(value = 1, lower=0, upper=59, step_incr=1)
self.time_sec_spinner = Gtk.SpinButton()
self.time_sec_spinner.set_adjustment(self.sec_adj)
self.table.attach(self.time_sec_spinner,4,5, 4,5)
# # alarm media file
self.fileEntryLabel = Gtk.Label("/path/to/file.mp3")
self.table.attach(self.fileEntryLabel,0,6, 5,6)
self.fileEntry = Gtk.Entry()
self.table.attach(self.fileEntry,0,6, 6,7)
# # connect methods
self.alarmSwitch.connect("notify::active", self.alarm_trigger)
self.alarmSwitch.set_active(False)
# # format time to str for comparison
def format_time(self,time):
rounded = int(round(time))
if len(str(rounded)) == 1:
formatted = "{}{}".format("0",rounded)
return formatted
else:
return rounded
# # main alarm function
def set_alarm(self):
# get current time for compatison to alarm time
timenow = str(datetime.now())[11:19]
# get values from our time spinners
hour = self.time_hr_spinner.get_value()
minute = self.time_min_spinner.get_value()
seconds = self.time_sec_spinner.get_value()
# format our time for comparison against timenow
alarm_formated = "{}:{}:{}".format(self.format_time(hour),self.format_time(minute),self.format_time(seconds))
# if the alarm state is true, wait for the alarm time to equal current time then trigger alarm
if self.alarm_state:
if timenow == alarm_formated:
# if no file is supplied to be played, play the default alarm.mp3 in CWD
if self.fileEntry.get_text() == "":
self.player.set_property('uri','file://'+os.path.abspath('alarm.mp3'))
print "beep beep beep"
# as above except file is supplied so lets play that one instead!
else:
alarmFile = 'file://'+self.fileEntry.get_text()
self.player.set_property('uri',alarmFile)
print "beep beep beep"
# set gst to start playing whatever file
self.player.set_state(Gst.State.PLAYING)
self.alarm_state = False
self.labelSetAlarm.set_label("Alarm OFF!")
else:
self.labelSetAlarm.set_label("No Alarm Set")
# return tree true to ensure timeout_add continues
return True
# this is called from our "alarmSwitch" button and will set our alarm state to True
def alarm_trigger(self,switch,gparam):
if self.alarmSwitch.get_active():
self.alarm_state = True
self.labelSetAlarm.set_label("Alarm ON!")
else:
self.alarm_state = True
self.labelSetAlarm.set_label("Alarm OFF!")
self.player.set_state(Gst.State.NULL)
# # run clock
def displayclock(self,state):
# putting our datetime into a var and setting our label to the result.
# we need to return "True" to ensure the timer continues to run, otherwise it will only run once.
datetimenow = str(datetime.now())[11:19]
self.labelClock.set_label(datetimenow)
return state
# Initialize Timer
def startclocktimer(self):
# this takes 2 args: (how often to update in millisec, the method to run)
GObject.timeout_add(100, self.displayclock, True)
GObject.timeout_add(1000, self.set_alarm)
win = MainWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
win.startclocktimer()
Gtk.main()
@jampola
Copy link
Author

jampola commented Oct 10, 2014

This is expanded upon my original clock app (posted here: https://gist.github.com/jampola/473e963cff3d4ae96707) -- Yes, it's super primitive but it does again go over some of the semantics surrounding timeout_add and also some new toys such as GST.

If you see any ways this could be improved upon (in terms of code efficiency, not so much practicability) please leave it in the comments! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment