I'm working on a kivy app which is intended to parametrically produce ear training exercises on the spot and play them. The music is described using the mingus module, and played via its fluidsynth implementation. I have an exercise playing function, which works as intended when normally called, but since with that method everything else hangs while the drill is running (on an infinite while loop waiting to be manually stopped), that does not result in acceptable behaviour. I assigned the function to its own process using Process()
, and based on the the output to the terminal it is looping as intended, but there's no sound. Another point worthy of note is that multiple presses to the start button results in multiple processes running in parallel, judging by the rhythms of the terminal activity. Here's the code of the python side of the interface:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.recycleview import RecycleView
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.config import Config
from classes import *
from multiprocessing import Process
import yaml
Config.set('graphics', 'width', '400')
Config.set('graphics', 'height', '700')
class Welcome(Screen):
pass
class Builtin(Screen):
pass
class DrillScreen(Screen):
def __init__(self, **kwargs):
super(DrillScreen, self).__init__(**kwargs)
self.options = kwargs['options']
self.desc = self.options.des
self.thedrill = drill(self.options)
desc = Label(
text=self.options.des,
size_hint_x=0.9,
size_hint_y=1)
button = Button(
text = 'Start',
size_hint=[0.4,0.1])
button.bind(on_release=self.startdrill())
self.add_widget(desc)
self.add_widget(button)
def startdrill(self):
def starter(*args):
proc = Process(target=self.thedrill.run)
proc.start()
return starter
class BuiltinView(RecycleView):
def __init__(self, **kwargs):
super(BuiltinView, self).__init__(**kwargs)
with open('builtin.yaml', 'r') as builtin:
self.drills = yaml.load(builtin)
self.data = [ {'text': self.drills[i]['name'],
'on_release': self.startermaker(i,self.drills[i])}
for i in sorted(self.drills.keys()) ]
def startermaker(self,num,options):
def startdrill():
options = drilloptions(self.drills[num])
drillscreen = DrillScreen(name='drill', options=options)
app = App.get_running_app()
app.root.add_widget(drillscreen)
app.root.current = 'drill'
#drillscreen.thedrill.run()
return startdrill
class Manager(ScreenManager):
pass
class TestingApp(App):
def build(self):
return Manager()
TestingApp().run()
The drill
class holds some parameters in its attributes and enters a loop to endlessly generate exercises within those parameters when its .run()
method is called. In the button.bind()
statement of the DrillScreen
class, if I directly put on_release=self.thedrill.run , I get the function working no problem. I don't know what I'm missing here. I can post code from other components of the project if needed. Thank you.