首页 > 解决方案 > 绑定滑块以适应音频位置而不会导致性能下降

问题描述

我有一个用python 和 kivy制作的 mp3 播放器应用程序,我想创建一个滑块,使其值适应歌曲位置。

我已经有了一些解决方案,但所有解决方案的问题在于它们使音频播放变得不愉快和故障。

目前我使用Clock每隔一秒运行一次功能,但正如我之前提到的,它使音频非常滞后且无法收听。

我的代码:

import os
os.environ["KIVY_AUDIO"] = "ffpyplayer"
from kivy.lang import Builder
from kivy.core.audio import SoundLoader
from kivy.app import App


class MainApp(App):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.path = "C:/Users/Family/Downloads/10_poker_face.mp3"
        self.song = SoundLoader.load(self.path)
        self.kv = Builder.load_string('''
#:kivy 2.0.0
#:import Clock kivy.clock.Clock
BoxLayout:
    orientation: "vertical"
    Label:
        text: app.path
        font_size: 32
    Slider:
        id: song_slider
        min: 0
        max: app.song.length
        on_value: app.song.seek(self.value)
    Button:
        text: "Play"
        font_size: 32
        on_release:
            Clock.schedule_interval(app.update_slider, 1)
            app.song.play()
''')

    def build(self):
        return self.kv

    def update_slider(self, dt):
        self.kv.ids.song_slider.value = self.song.get_pos()


if __name__ == "__main__":
    MainApp().run()

我什至尝试了一个线程替代方案,但这比时钟方法更糟糕:

import os
os.environ["KIVY_AUDIO"] = "ffpyplayer"
from threading import Thread
from time import time
from kivy.lang import Builder
from kivy.core.audio import SoundLoader
from kivy.app import App


class MainApp(App):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.path = "C:/Users/Family/Downloads/10_poker_face.mp3"
        self.song = SoundLoader.load(self.path)
        self.start_time = None
        self.kv = Builder.load_string('''
#:kivy 2.0.0
BoxLayout:
    orientation: "vertical"
    Label:
        text: app.path
        font_size: 32
    Slider:
        id: song_slider
        min: 0
        max: app.song.length
        on_value: app.song.seek(self.value)
    Button:
        text: "Play"
        font_size: 32
        on_release: app.start_song()
''')

    def build(self):
        return self.kv

    def start_song(self):
        self.start_time = time()
        Thread(target=self.update_slider, daemon=True).start()
        self.song.play()

    def update_slider(self):
        while True:
            now = time()
            if now - self.start_time >= 1:
                self.start_time = now
                self.kv.ids.song_slider.value = self.song.get_pos()


if __name__ == "__main__":
    MainApp().run()

如何绑定滑块以适应歌曲的音频位置而不会导致性能问题?

标签: pythonpython-3.xkivykivy-language

解决方案


我可以提供这样的解决方案,它独立于KIVY_AUDIO论点起作用。

import os
os.environ["KIVY_AUDIO"] = "ffpyplayer"
from kivy.lang import Builder
from kivy.core.audio import SoundLoader
from kivy.clock import Clock
from kivy.app import App

KV = '''
BoxLayout:
    padding: 10
    orientation: 'vertical'
    
    Label:
        text: app.path
        halign: 'center'
        font_size: sp(32)
        text_size: self.width, None
        size_hint: 1, None
        height: self.texture_size[1]

    Slider:
        id: song_slider
        min: 0
        max: 100
        
    Button:
        id: btn
        text: 'Play'
        font_size: sp(32)
        on_release: app.start_song()
'''


class MainApp(App):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.path = 'music.mp3'

        self.song = SoundLoader.load(self.path)
        self.clock_event = None
        self.kv = Builder.load_string(KV)

    def build(self):
        return self.kv

    def start_song(self):
        if self.song.state == 'stop':
            self.song.play()
            self.clock_event = Clock.schedule_interval(self.update_slider, self.song.length / 60)
            self.kv.ids.btn.text = 'Stop'
        else:
            self.clock_event.cancel()
            self.song.stop()
            self.kv.ids.song_slider.value = 0
            self.kv.ids.btn.text = 'Play'

    def update_slider(self, *args):
        if self.kv.ids.song_slider.value < 100:
            self.kv.ids.song_slider.value += 1


if __name__ == '__main__':
    MainApp().run()

推荐阅读