1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161 |
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" parlatype-example.py demonstrates libparlatype.
Change testfile to an existing file! """
import gi
from gi.repository import Parlatype as Pt
from gi.repository import Gtk
from gi.repository import GObject # for GObject.timeout
gi.require_version('Gtk', '3.0')
testfile = "file:///home/user/example.mp3"
def error_message(message, parent):
msg = Gtk.MessageDialog(parent=parent,
flags=Gtk.DialogFlags.MODAL,
type=Gtk.MessageType.ERROR,
buttons=Gtk.ButtonsType.OK,
message_format=message)
msg.run()
msg.destroy()
""" PtPlayer's error signal.
It's a severe error and the PtPlayer is reset. There is not much we can
do about it, here we simply quit. """
def player_error(player, error):
error_message(error.args[0], win)
Gtk.main_quit
""" PtPlayer's end-of-stream signal.
Player is at the end and changes to paused state. Note that stream means
any playable source like files, too.
We set our buttons according to the state. """
def player_end_of_stream(player):
button.set_active(False)
""" The two main functions are Pt.Player.play() and Pt.Player.pause().
PtWaveviewer scrolls to cursor (follow-cursor) by default but if the user
has scrolled manually follow-cursor is set to False. Here we assume that on
play the user wants to follow cursor again. """
def button_toggled(button):
if button.get_active():
viewer.set_property("follow-cursor", True)
player.play()
else:
player.pause()
""" In this timeout callback we update cursor position and time label. """
def update_cursor():
viewer.set_property("playback-cursor", player.get_position())
text = player.get_current_time_string(Pt.PrecisionType.SECOND_10TH)
# Sometimes the position can't be retrieved and None is returned.
if (text):
label.set_text(text)
# Continue updating
return True
""" PtWaveviewer's cursor-changed signal.
This means the user clicked on the widget to change cursor position.
We have to inform the PtPlayer. We set the follow-cursor property, too. """
def cursor_changed(viewer, position):
player.jump_to_position(position)
viewer.set_property("follow-cursor", True)
""" Player's open async callback.
Destroy progress dialog and get result. On success get wave data and pass
it to the PtWaveviewer. Add a timeout of 10 ms to update cursor position
and time label. """
def open_callback(player, result):
progress.destroy()
try:
player.open_uri_finish(result)
# Get data at a resolution of 100 px per second
data = player.get_data(100)
viewer.set_wave(data)
GObject.timeout_add(10, update_cursor)
except Exception as err:
error_message(err.args[0], win)
""" Pass PtPlayer's emitted progress signal to the PtProgressDialog. """
def progress_update_callback(player, value, dialog):
dialog.set_progress(value)
""" PtPlayer's async open function can be cancelled.
This emits an error message for the open callback. """
def progress_response_callback(progress, response):
if response == Gtk.ResponseType.CANCEL:
player.cancel()
if testfile == "file:///home/user/example.mp3":
error_message("Please change 'file:///home/user/example.mp3' in source "
"to an existing test file.", None)
exit()
# PtPlayer has a failable constructor, if GStreamer can't be initted.
try:
player = Pt.Player.new()
except Exception as err:
error_message(err.args[0], None)
exit()
player.connect("error", player_error)
player.connect("end-of-stream", player_end_of_stream)
# For the PtProgressDialog we have to use the async opening function
player.open_uri_async(testfile, open_callback)
# Now create the window with play button, PtWaveviewer and time label.
win = Gtk.Window()
win.set_border_width(12)
win.set_default_size(500, 80)
win.connect("delete-event", Gtk.main_quit)
viewer = Pt.Waveviewer.new()
viewer.connect("cursor-changed", cursor_changed)
button = Gtk.ToggleButton.new_with_label("Play")
button.connect("toggled", button_toggled)
label = Gtk.Label("0:00.0")
hbox = Gtk.Box(spacing=6)
hbox.pack_start(button, False, False, 0)
hbox.pack_start(viewer, True, True, 0)
hbox.pack_start(label, False, False, 0)
win.add(hbox)
win.show_all()
# PtProgressDialog, connect signals and show only, do not progress.run()
progress = Pt.ProgressDialog.new(win)
progress.connect("response", progress_response_callback)
player.connect("load-progress", progress_update_callback, progress)
progress.show_all()
Gtk.main() |