![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
scott wrote:
>> Also, they are both equally perplexed by missing / additional beat
>> signals, so I need to go figure that out...
>
> With your array of times-between-beats, calculate the mean and sd of the
> whole array, then remove any entries that are outside of the mean +/-
> N*sd before you do your BPM calculation. You can choose N based on the
> results, but I guess around 1 should work.
Yes, that's more or less my plan. I just haven't coded it yet.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
I had expected the taps to be approximately correct, but jittered either
side of the correct points by a roughly normal distribution. However,
this is not what I observe.
Take a look at the first attachment. There's an obvious U-shapred trend
in the error graph, and I have no idea why. It appears very, very
frequently though. But aside from that, the errors look much more like a
random walk than a normal distrubition. The timing error in each tap
appears to be highly correlated with its neighbors.
The second attachment shows a similar pattern (although the U-shapred
trend is now inverted). Note the difference in tempo between the two
examples.
I hypothesize that what actually happens is that my tapping is actually
running off an internal mental clock, which is being adjusted by a
feedback loop that keeps it reasonably in-phase with the actual
drumbeat. Hence the random-walk variations.
Of course, it's possible that the music I'm tapping to actually contains
subtle tempo variations. Or that some of these patterns are prediction
errors. I think what I need to do is perform a tapping experiment with a
timing source of known tempo, so I can get genuine error measurements.
(Currently it's tricky to reperate human tapping errors from computer
prediction errors.)
Post a reply to this message
Attachments:
Download 'bpm1.png' (14 KB)
Download 'bpm2.png' (16 KB)
Preview of image 'bpm1.png'
![bpm1.png](/povray.off-topic/attachment/%3C4c0f6a79%40news.povray.org%3E/bpm1.png?preview=1)
Preview of image 'bpm2.png'
![bpm2.png](/povray.off-topic/attachment/%3C4c0f6a79%40news.povray.org%3E/bpm2.png?preview=1)
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Invisible wrote:
> I think what I need to do is perform a tapping experiment with a
> timing source of known tempo, so I can get genuine error measurements.
Heh, this is more difficult than you'd imagine.
I wrote a small program that basically does
Get wall time.
Save wall time to file.
Print something to stdout.
Wait X seconds.
Repeat.
The amount of time is computed from the requested BPM. Only trouble is,
when I analysed the resulting data, I discovered that the program is
ticking too slowly. (E.g., I request 135 BPM, but I get 128 BPM.)
So then I tried having a thread that just does
Send signal.
Wait X seconds.
Repeat.
and another thread that waits to receive a signal, and then does all the
other stuff. But noooo, the timing accuracy has increased, but it's
still ticking too slowly.
Thing is, what I want to do isn't "wait until X seconds from now", it's
"wait until time X". But there isn't a function to do that. If there
was, I could take the wall time now, compute the correct time for all
future clock ticks, and schedule the thread to run at those times. But
there isn't.
So I started digging through the library source code. Oh, this is fun:
Internally the "wait X seconds" function is implemented using a "wait
until time X" function. But it's private, so I can't call it. Thanks,
guys...
Next plan: Write out a WAV file containing sonic pulses with the correct
timing. Because, let's face it, there isn't much that can go wrong here.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 6/9/2010 5:18 AM, Invisible wrote:
> I hypothesize that what actually happens is that my tapping is actually
> running off an internal mental clock, which is being adjusted by a
> feedback loop that keeps it reasonably in-phase with the actual
> drumbeat. Hence the random-walk variations.
Am I the only one who thought PLL when I read this?
--
~Mike
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
>> I hypothesize that what actually happens is that my tapping is actually
>> running off an internal mental clock, which is being adjusted by a
>> feedback loop that keeps it reasonably in-phase with the actual
>> drumbeat. Hence the random-walk variations.
>
> Am I the only one who thought PLL when I read this?
No, that's pretty much what I was thinking when I wrote it...
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
> and another thread that waits to receive a signal, and then does all the
> other stuff. But noooo, the timing accuracy has increased, but it's still
> ticking too slowly.
If you can call API functions, call QueryPerformanceCounter from
Kernel32.dll. It is pretty much the ultimate in terms of useful timing
accuracy and resolution under windows. It only takes one parameter (a
pointer to a 64-bit signed integer) so should be easy to set up if you don't
have the header.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
>>> I hypothesize that what actually happens is that my tapping is actually
>>> running off an internal mental clock, which is being adjusted by a
>>> feedback loop that keeps it reasonably in-phase with the actual
>>> drumbeat. Hence the random-walk variations.
>>
>> Am I the only one who thought PLL when I read this?
>
> No, that's pretty much what I was thinking when I wrote it...
I also thought about it when I suggested to write code to find the BPM
automatically.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
scott wrote:
>> and another thread that waits to receive a signal, and then does all
>> the other stuff. But noooo, the timing accuracy has increased, but
>> it's still ticking too slowly.
>
> If you can call API functions, call QueryPerformanceCounter from
> Kernel32.dll. It is pretty much the ultimate in terms of useful timing
> accuracy and resolution under windows. It only takes one parameter (a
> pointer to a 64-bit signed integer) so should be easy to set up if you
> don't have the header.
http://msdn.microsoft.com/en-us/library/ms644904%28VS.85%29.aspx
"Retrieves the current value of the high-resolution performance counter."
From what little documentation there is, it seems this allows me to
measure wall-time, really accurately. Which isn't the problem - the
problem is scheduling a thread to run when I actually want it to run.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Mike Raiford wrote:
> Ludicrously difficult is programming in machine code for a processor
> that doesn't yet exist's micro-ops. ;)
If it makes you feel any better...
http://en.wikipedia.org/wiki/6502#Bugs_and_quirks
Note also that the 6502 doesn't have any microcode. It just uses a PLA
as the control matrix - much like the processor that I'm designing. ;-)
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
>> Ludicrously difficult is programming in machine code for a processor that
>> doesn't yet exist's micro-ops. ;)
>
> If it makes you feel any better...
>
> http://en.wikipedia.org/wiki/6502#Bugs_and_quirks
>
> Note also that the 6502 doesn't have any microcode. It just uses a PLA as
> the control matrix - much like the processor that I'm designing. ;-)
FWIW when Acorn designed the original ARM processor, one person designed and
simulated it on a 6502 before starting actual hardware design. IIRC it only
took a very small number of people in total (like 5 or 6) to design the
hardware implementation.
According to wikipedia over 10 billion ARM cores have been built, I bet they
never imagined that when they were sat at their 6502's designing it back in
the 80s :-)
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |