From: Christopher Arndt <chris.arndt@web.de>
To: alsa-devel@alsa-project.org
Subject: pyalsa: synchronizing queue with MIDI clock events
Date: Fri, 17 Jul 2009 14:54:00 +0200 [thread overview]
Message-ID: <4A607468.7010300@web.de> (raw)
Hi everybody,
this is my first post on this list, so please excuse me, should it not
be the right place to post this.
I started exploring programming the ALSA sequencer via the pyalsa Python
interface, i.e the alsaseq module. I wrote a small utility that reads
MIDI events from one port, filters/processes them and writes it to
another. This allows for routing by channel, note range, controller
number etc. and to filter out, replace or add MIDI events.
Now to synchronize the queue tempo to incoming MIDI clock events, to be
able implement synchronized delays or arpeggiators, I use the method in
the code shown below. This works ok, but I notice that the measured BPM
oscillates +-1 BPM around the value displayed by the clock source (my
synth's sequencer) if I measure/average only a few (~10) ticks or do not
round the result to an integer value.
Is this the right approach? What is a sensible number of ticks to take
into account for measurement? Should I use another reference timer than
Python's time.time() function? Is pyalsa generally suitable for this
kind of application even on older/weaker hardware (e.g. a NSLU2)?
Any comments or suggestions for improvement would be very much appreciated!
Chris
class MidiProcessor(object):
def run(self):
# This is simplified to only show the general logic
while True:
events = self.sequencer.receive_events(
timeout=RECEIVE_TIMEOUT, maxevents=1)
for event in events:
if event.type == SEQ_EVENT_CLOCK:
self.sync_queue(event)
else:
# do other MIDI processing / routing
def sync_queue(self, event):
"""Sync queue tempo to incoming MIDI clock events."""
# list to collect the timestamps of the last few ticks
lt = self._last_ticks
lt.append(time.time())
ltlen = len(lt)
if ltlen > 1:
# calculate & set bpm: calculate difference between
# the times the last few ticks were received and average
# all results
avg_delta = sum(
[y-x for x,y in zip(lt, lt[1:])]) / (ltlen-1)
# tick length is a 24th of a quarter note
bpm = round(60 / avg_delta / 24)
if bpm != self.bpm:
self.bpm = bpm
self.sequencer.queue_tempo(self.queue,
tempo=int(6e7 / self.bpm), ppq=self.ppq)
# only remember last 24 received ticks
# (length of a quarter note)
if ltlen > 24:
lt.pop(0)
next reply other threads:[~2009-07-17 12:54 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-07-17 12:54 Christopher Arndt [this message]
2009-07-20 12:31 ` pyalsa: synchronizing queue with MIDI clock events Christopher Arndt
2009-07-21 13:32 ` Clemens Ladisch
2009-07-21 16:20 ` Christopher Arndt
2009-07-31 18:26 ` pyalsa: SeqEvent.time strangeness (Was: synchronizing queue with MIDI clock events) Christopher Arndt
2009-08-02 15:42 ` Christopher Arndt
2009-08-03 11:55 ` Clemens Ladisch
2009-08-03 12:21 ` pyalsa: SeqEvent.time strangeness Christopher Arndt
2009-08-04 9:45 ` Clemens Ladisch
2009-08-04 11:10 ` Christopher Arndt
2009-08-04 13:03 ` Clemens Ladisch
2009-08-05 13:18 ` [PATCH] alsa-python: Add support for setuptools Christopher Arndt
2009-08-05 13:30 ` Clemens Ladisch
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4A607468.7010300@web.de \
--to=chris.arndt@web.de \
--cc=alsa-devel@alsa-project.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.