If someone is interested, here is a piece of code in which you can :
o by clicking on "...", navigate on your file system, select a mp3 file
and click "Ok", it should play the file, display the elapsed and remaining
time and display the name
o a click on ">||" toogle play/pause
o a click on "<<" goes to the beginning
It has been tested on :
o fedora 20 with kivy 1.8.1 dev (gstreamer1-devel must be installed as rpm
and Cython-0.20.1 must be installed manually before compiling kivy)
o android as apk using the construction with VirtualBox Image
With kivy launcher, it works but the times remains to 0.0 ...
Here is the code :
# ----------------------------------------------------------------------
# Server and client part
# Music player object
# ----------------------------------------------------------------------
from kivy.event import EventDispatcher
class MuwssysPlayer(EventDispatcher):
from kivy.properties import StringProperty
current_track_informations = StringProperty('')
from kivy.properties import NumericProperty
current_track_total_time = NumericProperty(0)
current_track_elapsed_time = NumericProperty(0)
def __init__(self):
self._single_file_player = MuwssysSingleFilePlayer()
self._single_file_player.bind(informations=self.onCurrentTrackInformationsChanged)
self._single_file_player.bind(total_time=self.onCurrentTrackTotalTimeChanged)
self._single_file_player.bind(elapsed_time=self.onCurrentTrackElapsedTimeChanged)
return
# --
# Methods to single file player
# --
def load(self, url):
# --
# Temporary : for the moment, load one file at once
# --
self._single_file_player.load(url)
return
def rewind(self):
self._single_file_player.rewind()
return
def togglePlayPause(self):
self._single_file_player.togglePlayPause()
return
# ----------------------
def getCurrentTrackInformations(self):
return self.current_track_informations
def getCurrentTrackTotalTime(self):
return self.current_track_total_time
def getCurrentTrackElapsedTime(self):
return self.current_track_elapsed_time
# -------
def onCurrentTrackInformationsChanged(self, instance, value):
self.current_track_informations = value
return
def onCurrentTrackTotalTimeChanged(self, instance, value):
self.current_track_total_time = value
return
def onCurrentTrackElapsedTimeChanged(self, instance, value):
self.current_track_elapsed_time = value
return
# -------
pass
from kivy.event import EventDispatcher
class MuwssysSingleFilePlayer(EventDispatcher):
# ------------------------------
from kivy.properties import StringProperty
informations = StringProperty('')
from kivy.properties import NumericProperty
total_time = NumericProperty(0)
elapsed_time = NumericProperty(0)
# ------------------------------
def __init__(self):
self._sound = None
self._interval = 0.5
from kivy.clock import Clock
Clock.schedule_once(self._onClock, self._interval)
return
def _onClock(self, dt, work=False):
# -----
if not work:
try:
self._onClock(dt, True)
finally:
from kivy.clock import Clock
Clock.schedule_once(self._onClock, self._interval)
pass
return
# -----
sound = self._sound
if not sound:
return
# -----
if hasattr(sound, "_paused"):
self.total_time = max(int(sound._current_length), 0)
self.elapsed_time = max(int(sound._current_pos), 0)
else:
self.total_time = max(int(sound.length), 0)
self.elapsed_time = max(int(sound.get_pos()), 0)
pass
# -----
return
# ------------------------------
def load(self, url):
if self._sound:
self._sound.unload()
self._sound = None
self.informations = ''
pass
from kivy.core.audio import SoundLoader
sound = SoundLoader.load(url)
if not sound:
return
sound.play()
# --
from os.path import basename
infos = basename(sound.source)
self.informations = infos
# --
self._sound = sound
return
def rewind(self):
sound = self._sound
if not sound:
return
sound.seek(0.0)
if hasattr(sound, "_paused"):
sound._current_pos = 0.0
pass
return
def togglePlayPause(self):
sound = self._sound
if not sound:
return
if sound.state == "play":
sound._paused = True
sound._current_length = sound.length
sound._current_pos = sound.get_pos()
sound.stop()
elif sound.state == "stop":
delattr(sound, "_paused")
sound.play()
if sound._current_length > 1.0:
while sound.length < sound._current_length/2:
pass
pass
sound.seek(sound._current_pos)
pass
return
pass
# ----------------------------------------------------------------------
# Client GUI part
# ----------------------------------------------------------------------
from kivy.uix.boxlayout import BoxLayout
class MuwssysBoxLayout(BoxLayout):
def __init__(self):
# -------
super(MuwssysBoxLayout, self).__init__()
self.player = MuwssysPlayer()
self.orientation = "vertical"
# -------
bl = self.addBoxLayoutToParent(self)
bl.size_hint_y = None
self.addButtonToParent(bl, "...", self.onChooseButtonRelease)
# -------
bl = self.addBoxLayoutToParent(self)
from kivy.uix.label import Label
bl.add_widget(Label())
label = bl.children[0]
label.text = "0:00"
self._label_time_elapsed = label
bl.add_widget(Label())
label = bl.children[0]
label.text = "0:00"
self._label_time_remaining = label
# -------
bl = self.addBoxLayoutToParent(self)
bl.size_hint_y = None
self.addButtonToParent(bl, "<<", self.onRewind)
self.addButtonToParent(bl, ">||", self.onTogglePlayPause)
# -------
bl = self.addBoxLayoutToParent(self)
from kivy.uix.label import Label
bl.add_widget(Label())
label = bl.children[0]
label.text = ""
self._label_current = label
# -----
self.player.bind(current_track_informations=self.onCurrentLabelUpdate)
self.player.bind(current_track_total_time=self.onTimeUpdate)
self.player.bind(current_track_elapsed_time=self.onTimeUpdate)
# -----
return
def addBoxLayoutToParent(self, parent):
from kivy.uix.boxlayout import BoxLayout
parent.add_widget(BoxLayout())
bl = parent.children[0]
return bl
def addButtonToParent(self, parent, text, target):
from kivy.uix.button import Button
parent.add_widget(Button())
btn = parent.children[0]
btn.size_hint_y = None
btn.text = text
btn.bind(on_release=target)
return btn
# -----------------------------
def onChooseButtonRelease(self, button):
from kivy.uix.popup import Popup
popup = Popup()
popup.title = "Choose a file"
from kivy.uix.boxlayout import BoxLayout
popup.content = BoxLayout()
# ---
boxlayout = popup.content
boxlayout.orientation = "vertical"
# ---------
from kivy.uix.filechooser import FileChooserListView
boxlayout.add_widget(FileChooserListView())
# ---------
file_chooser = boxlayout.children[0]
try:
file_chooser.path = self._previous_file_chooser_dir
except AttributeError:
from os import getcwd
file_chooser.path = getcwd()
pass
# --------
bl = self.addBoxLayoutToParent(boxlayout)
bl.size_hint_y = None
btn = self.addButtonToParent(bl, "Ok", self.onButtonOkRelease)
btn.popup = popup
btn.file_chooser = file_chooser
btn = self.addButtonToParent(bl, "Cancel", self.onButtonCancelRelease)
btn.popup = popup
# -------
popup.open()
# ----
return
def onButtonOkRelease(self, button):
fc = button.file_chooser
if fc.selection:
url = fc.selection[0]
from os.path import dirname
d = dirname(url)
self._previous_file_chooser_dir = d
self.onChooseTrack(url)
pass
button.popup.dismiss()
return
def onButtonCancelRelease(self, button):
button.popup.dismiss()
return
# ---------------------------------------------------
def onChooseTrack(self, url):
self.player.load(url)
return
def onRewind(self, button):
self.player.rewind()
return
def onTogglePlayPause(self, button):
self.player.togglePlayPause()
return
# ---------------------------------------------------
def onTimeUpdate(self, instance, value):
total = self.player.getCurrentTrackTotalTime()
elapsed = self.player.getCurrentTrackElapsedTime()
remaining = total - elapsed
self._label_time_elapsed.text = "%i:%2.2i"%(elapsed/60, elapsed%60)
self._label_time_remaining.text = "%i:%2.2i"%(remaining/60, remaining%60)
return
def onCurrentLabelUpdate(self, instance, value):
infos = self.player.getCurrentTrackInformations()
self._label_current.text = infos
return
# ---------------------------------------------------
pass
# ----
from
kivy.app import App
class MuwssysApp(App):
def build(self):
return MuwssysBoxLayout()
pass
# ----------
if __name__ == '__main__':
MuwssysApp().run()
pass