* pyalsa: synchronizing queue with MIDI clock events
@ 2009-07-17 12:54 Christopher Arndt
2009-07-20 12:31 ` Christopher Arndt
2009-07-21 13:32 ` Clemens Ladisch
0 siblings, 2 replies; 13+ messages in thread
From: Christopher Arndt @ 2009-07-17 12:54 UTC (permalink / raw)
To: alsa-devel
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)
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: pyalsa: synchronizing queue with MIDI clock events
2009-07-17 12:54 pyalsa: synchronizing queue with MIDI clock events Christopher Arndt
@ 2009-07-20 12:31 ` Christopher Arndt
2009-07-21 13:32 ` Clemens Ladisch
1 sibling, 0 replies; 13+ messages in thread
From: Christopher Arndt @ 2009-07-20 12:31 UTC (permalink / raw)
To: alsa-devel
No pyalsa or MIDI experts here?
Chris
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: pyalsa: synchronizing queue with MIDI clock events
2009-07-17 12:54 pyalsa: synchronizing queue with MIDI clock events Christopher Arndt
2009-07-20 12:31 ` Christopher Arndt
@ 2009-07-21 13:32 ` Clemens Ladisch
2009-07-21 16:20 ` Christopher Arndt
1 sibling, 1 reply; 13+ messages in thread
From: Clemens Ladisch @ 2009-07-21 13:32 UTC (permalink / raw)
To: Christopher Arndt; +Cc: alsa-devel
Christopher Arndt wrote:
> 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?
Large enough that you get a stable average, but small enough that you
can detect actual changes.
> Should I use another reference timer than Python's time.time() function?
That timer probably has a high enough resolution, but you measure the
time when your code is executed, which may be later then when the
event was actually received.
You can tell ALSA to timestamp all events that are received; just call
the snd_seq_port_info_set_timestamping() function and set a queue that
is running, then you'll get the queue's current time in each event.
This isn't implemented in pyalsa, but you can set this for a specific
connection with the queue, time_update, and time_real parameters of the
connect_ports function.
> Is pyalsa generally suitable for this kind of application even on
> older/weaker hardware (e.g. a NSLU2)?
The biggest problem is probably scheduling delays, so I guess using
Python instead of C should not add any noticeable delay.
Best regards,
Clemens
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: pyalsa: synchronizing queue with MIDI clock events
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
0 siblings, 1 reply; 13+ messages in thread
From: Christopher Arndt @ 2009-07-21 16:20 UTC (permalink / raw)
To: alsa-devel
Clemens Ladisch schrieb:
> Christopher Arndt wrote:
>> What is a sensible number of ticks to take
>> into account for measurement?
>
> Large enough that you get a stable average, but small enough that you
> can detect actual changes.
I figured out that much on my own :) I was just wondering if anybody had
already experimented with this...
> You can tell ALSA to timestamp all events that are received; just call
> the snd_seq_port_info_set_timestamping() function and set a queue that
> is running, then you'll get the queue's current time in each event.
> This isn't implemented in pyalsa, but you can set this for a specific
> connection with the queue, time_update, and time_real parameters of the
> connect_ports function.
I'll look into this.
Many thanks for your comments!
Chris
^ permalink raw reply [flat|nested] 13+ messages in thread
* pyalsa: SeqEvent.time strangeness (Was: synchronizing queue with MIDI clock events)
2009-07-21 16:20 ` Christopher Arndt
@ 2009-07-31 18:26 ` Christopher Arndt
2009-08-02 15:42 ` Christopher Arndt
2009-08-03 11:55 ` Clemens Ladisch
0 siblings, 2 replies; 13+ messages in thread
From: Christopher Arndt @ 2009-07-31 18:26 UTC (permalink / raw)
To: alsa-devel
Christopher Arndt schrieb:
>> You can tell ALSA to timestamp all events that are received; just call
>> the snd_seq_port_info_set_timestamping() function and set a queue that
>> is running, then you'll get the queue's current time in each event.
>> This isn't implemented in pyalsa, but you can set this for a specific
>> connection with the queue, time_update, and time_real parameters of the
>> connect_ports function.
I've tested this now and encountered a very strange bevahior of the
event time set by the queue:
a) SeqEvent.time seems to be in milliseconds instead of seconds as would
be expected by the ALSA documentation and looking at the source of
pyalsa.alsaseq.
5) Consecutive timestamp go up to ~1000,00 and then seem to wrap around
and start from zereo again.
I have created a small test program, which demonstrates this:
http://paste.chrisarndt.de/paste/fa8ca7201bc7419f9e001315ca02b1ef
It outputs the time of each MIDI clock signal it receives and whether it
is in tick or real time and whether it's absolute (= from the start of
the queue) or relative (to the preceding event). Here's some output from
the script:
MIDI CLOCK 0.0 ABS REAL
MIDI CLOCK 23.697488 ABS REAL
MIDI CLOCK 48.701538 ABS REAL
MIDI CLOCK 73.70515 ABS REAL
MIDI CLOCK 98.705762 ABS REAL
MIDI CLOCK 123.709812 ABS REAL
MIDI CLOCK 148.702424 ABS REAL
MIDI CLOCK 173.707474 ABS REAL
MIDI CLOCK 198.711086 ABS REAL
[...]
MIDI CLOCK 898.73904 ABS REAL
MIDI CLOCK 923.74909 ABS REAL
MIDI CLOCK 948.744702 ABS REAL
MIDI CLOCK 973.742314 ABS REAL
MIDI CLOCK 998.749364 ABS REAL
MIDI CLOCK 24.738976 ABS REAL
MIDI CLOCK 49.741026 ABS REAL
MIDI CLOCK 74.743638 ABS REAL
MIDI CLOCK 99.74725 ABS REAL
As you can see, once the time would exceed 1000.0 it seems to start from
zero again. This happens only when the queue sets the event times to
REAL. When ticks are used, the increase infinitely, as expected.
I fail to understand why this is and what I am doing wrong. I would
expect SeqEvent.time to be in seconds and always ascending until I stop
the queue. Please, somebody enlighten me!
Chris
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: pyalsa: SeqEvent.time strangeness (Was: synchronizing queue with MIDI clock events)
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
1 sibling, 0 replies; 13+ messages in thread
From: Christopher Arndt @ 2009-08-02 15:42 UTC (permalink / raw)
To: alsa-devel
Christopher Arndt schrieb:
> I've tested this now and encountered a very strange bevahior of the
> event time set by the queue:
> [...]
Should I report this as a bug then? Is there a special category or
convention for filing pyalsa issues at https://bugtrack.alsa-project.org/ ?
Chris
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: pyalsa: SeqEvent.time strangeness (Was: synchronizing queue with MIDI clock events)
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
1 sibling, 1 reply; 13+ messages in thread
From: Clemens Ladisch @ 2009-08-03 11:55 UTC (permalink / raw)
To: Christopher Arndt; +Cc: alsa-devel
Christopher Arndt wrote:
> I've tested this now and encountered a very strange bevahior of the
> event time set by the queue:
>
> a) SeqEvent.time seems to be in milliseconds instead of seconds as would
> be expected by the ALSA documentation and looking at the source of
> pyalsa.alsaseq.
>
> 5) Consecutive timestamp go up to ~1000,00 and then seem to wrap around
> and start from zereo again.
Apparently, you are the first one who tried to use this. Fixed now:
http://git.alsa-project.org/?p=alsa-python.git;a=commitdiff;h=9a7dea33dddeb2d9d7693257323d43ccffbffed2
HTH
Clemens
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: pyalsa: SeqEvent.time strangeness
2009-08-03 11:55 ` Clemens Ladisch
@ 2009-08-03 12:21 ` Christopher Arndt
2009-08-04 9:45 ` Clemens Ladisch
0 siblings, 1 reply; 13+ messages in thread
From: Christopher Arndt @ 2009-08-03 12:21 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1: Type: text/plain, Size: 655 bytes --]
Clemens Ladisch schrieb:
> Christopher Arndt wrote:
>> I've tested this now and encountered a very strange bevahior of the
>> event time set by the queue:
>
> Apparently, you are the first one who tried to use this. Fixed now:
> http://git.alsa-project.org/?p=alsa-python.git;a=commitdiff;h=9a7dea33dddeb2d9d7693257323d43ccffbffed2
Excelllent! The test script now produces correct results.
Thanks for the fix!
Might I suggest another patch to pyalsa? This would allow to use
developers to use "python setup.py develop" to install their git version
as a Python egg-link and makes it much easier to use pyalasa with
virtual Python environments.
Chris
[-- Attachment #2: setuptools.diff --]
[-- Type: text/plain, Size: 323 bytes --]
diff --git a/setup.py b/setup.py
index fa7f2d6..c2b6389 100755
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,10 @@
import os
import sys
-from distutils.core import setup, Extension
+try:
+ from setuptools import setup, Extension
+except ImportError:
+ from distutils.core import setup, Extension
VERSION='1.0.20'
[-- Attachment #3: Type: text/plain, Size: 160 bytes --]
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply related [flat|nested] 13+ messages in thread
end of thread, other threads:[~2009-08-05 13:30 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-17 12:54 pyalsa: synchronizing queue with MIDI clock events Christopher Arndt
2009-07-20 12:31 ` 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
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.