![]() |
Help with Optimization of Python software: real-time audio controller
I've been working on a Python-based music training application for a
few months, and have recently run into what I believe are some basic limitations (or at least constraints) of Python with regards to timing. I'll try and give a decently thorough description, and hopefully some of you can process this with your knowledge and help steer me in the right direction. As mentioned above, my application deals with music training. I have a Tkinter GUI, which communicates via pyserial with an external device I built myself. The code reads in a MIDI file and converts the song to "output data " for the external device and the GUI, all adjusted to the user-selected tempo. While the MIDI file is playing, there are 4 main actions the code must take: 1) Send "output data" signals out to the external hardware. 2) Poll the input from the external hardware device for incoming keypresses. If detected, then the play the sound corresponding to that key. 3) Start and keep a metronome running for the durations of the song. 4) Update GUI I'm able to get all the above "accomplished" through the use of threads and a top-level loop (for updating the Tkinter GUI - if you've worked with threads and Tkinter, then you know that you can't update a Tkinter GUI from a thread, but instead have to do it on the top level loop). While running, I have the following threads implemented : 1) song processing thread - this thread steps incrementally through a data matrix (the "output data"), and updates two variables: GUI_vars and Device_vars 2) metronome thread - this thread starts at the same time as thread #1, and outputs a "beep" to the audio chain 3) poll input thread - this thread loops continually, looking for data on the serial Input. When data is found, it starts playing the sound corresponding to that key until a "note off" signal is received 4) top-level recursive loop (technically not a thread) for updating GUI and calling Serial Write subfunction. This loop monitors GUI_vars and Device_vars, updating the GUI and writing out to the device when either variable has changed Currently, I have all of the above "working", although I'm running into some serious timing issues. When I run the program, I get irregular timing for my metronome (if it sounds at all), as well as irregular timing in writing to the external device. It's extremely crucial that threads #1 & #2 are executed as close to real-time as possible, as they form the "core" of the song, and their elements can't be delayed without "messing" the song up considerably. I've read up quite a bit on different optimization methods in Python, but am not sure which direction to head. I've checked out profile, Psyco, Pyrex, as well as just porting everything over to C. Since I'm on a Mac (Power PC), I can't use Psyco. And doing any of the others seemed like a big enough project that I should really ask someone else before I embark. So, for a music-based application where it's crucial to have real-time execution of serial writeouts and audio, as well as keeping a continual poll on the input from the same port....can this be done successfully in Python? Does using Tkinter have anything to do with my timing issues? Would it benefit me to move over to wxPython (something I've been considering doing)? As for the metronome, should I incorporate the metronome thread into the "song processing" thread, since both are dealing with events whose timing is crucial? I'm a relative newbie (this is my first Python project) to Python, so any help is GREATLY appreciated! Also, just for reference, here's a list of the modules I'm using and my system info: Audio: SndObj Ser com: pyserial GUI: Tkinter System: Apple PowerBook G4 (PowerPC), Mac OS 10.4, Python 2.4.4 Thanks, Craig Lewiston |
Re: Help with Optimization of Python software: real-time audio controller
Perhaps boosting priorities for time critical threads will help.
I don't know about MacOS but for Win32 something like that helps: thread = win32api.GetCurrentThread() win32process.SetThreadPriority(thread, win32process.THREAD_PRIORITY_TIME_CRITICAL) current_process = win32process.GetCurrentProcess() win32process.SetPriorityClass(current_process, win32process.REALTIME_PRIORITY_CLASS) |
Re: Help with Optimization of Python software: real-time audio controller
craiglewiston@gmail.com writes:
> So, for a music-based application where it's crucial to have real-time > execution of serial writeouts and audio, as well as keeping a > continual poll on the input from the same port....can this be done > successfully in Python? Does using Tkinter have anything to do with > my timing issues? Would it benefit me to move over to wxPython > (something I've been considering doing)? As for the metronome, should > I incorporate the metronome thread into the "song processing" thread, > since both are dealing with events whose timing is crucial? I think you can't really do that, not just because of Python but also as a result of using a multitasking OS that's not especially designed for real time. You have to rely on some buffering in the audio hardware, so you don't have to be sample-accurate with the timings. |
Re: Help with Optimization of Python software: real-time audio controller
Paul Rubin wrote: > I think you can't really do that, not just because of Python but also > as a result of using a multitasking OS that's not especially designed > for real time. You have to rely on some buffering in the audio > hardware, so you don't have to be sample-accurate with the timings. For his application you don't need "sample-accurate" timings. Between MIDI and synthesizer latency a few milliseconds of delay are inherent in what he's trying to do, regardless of operatings system, and a latency of 20 milliseconds or more is probably acceptable. Assuming he's not trying to write his own synthesizer, he might just be able to write his application in Python under Mac OS X. Ross Ridge |
Re: Help with Optimization of Python software: real-time audio controller
craiglewiston@gmail.com a écrit :
> As mentioned above, my application deals with music training. I have a > Tkinter GUI, which communicates via pyserial with an external device I > built myself. The code reads in a MIDI file and converts the song to > "output data " for the external device and the GUI, all adjusted to > the user-selected tempo. While the MIDI file is playing, there are 4 > main actions the code must take: > 1) Send "output data" signals out to the external hardware. > 2) Poll the input from the external hardware device for incoming > keypresses. If detected, then the play the sound corresponding to > that key. > 3) Start and keep a metronome running for the durations of the song. > 4) Update GUI > > I'm able to get all the above "accomplished" through the use of > threads and a top-level loop (for updating the Tkinter GUI - if > you've worked with threads and Tkinter, then you know that you can't > update a Tkinter GUI from a thread, but instead have to do it on the > top level loop). <zip> > Also, just for reference, here's a list of the modules I'm using and > my system info: > Audio: SndObj > Ser com: pyserial > GUI: Tkinter > System: Apple PowerBook G4 (PowerPC), Mac OS 10.4, Python 2.4.4 > > Thanks, > Craig Lewiston > You may take a look at PureData, interface is in TCL/Tk, but realtime sound management layers are in compiled C. "just" copy it using Python as high level language... I dont think Python itself just using scripting can achieve needed performance for *realtime* (like) audio. http://www.puredata.info/ http://www-crca.ucsd.edu/~msp/ |
Re: Help with Optimization of Python software: real-time audio controller
On Feb 11, 6:40 pm, craiglewis...@gmail.com wrote:
> Currently, I have all of the above "working", although I'm running > into some serious timing issues. When I run the program, I get > irregular timing for my metronome (if it sounds at all), as well as > irregular timing in writing to the external device. It's extremely > crucial that threads #1 & #2 are executed as close to real-time as > possible, as they form the "core" of the song, and their elements > can't be delayed without "messing" the song up considerably. > > I've read up quite a bit on different optimization methods in Python, > but am not sure which direction to head. I've checked out profile, > Psyco, Pyrex, as well as just porting everything over to C. Since I'm > on a Mac (Power PC), I can't use Psyco. And doing any of the others > seemed like a big enough project that I should really ask someone else > before I embark. Your problems do not necessarily stem from slow code. Python only performs thread context switches every 100 øpcodes, and the switch might not arrive at the right time. You can lower this value (sys.setcheckinterval). Your computationally- intensive threads may effectively lower their priority by calling time.sleep(.00001) every so often. Ultimately, maintaining explicity control over the scheduling of events is probably the way to go. Pyrex is my preferred optimization method, but it can take some knowledge of what's going on to get the most out of it. numpy is another option. -Mike |
| All times are GMT. The time now is 06:19 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.