Hi, I´ve 2 basic coding questions:
A) What is the difference between << and <<= as used in beat16?
B) The accum88 datatype is basically a uint16_t. It represents with 8 bit the integer part and with 8 bit the fraction. How do I set only the fractional part? I´m asking because it would be handy to have 256 values between 0 and 1 bpm for beatsin16.
<< does not modify it’s argument; <<= does:
(foo << 4) does not alter the value of foo.
(foo <<= 4) does alter the value of foo.
As for super-slow beatsin16 - that’s a great idea. Right now if you pass in an accum88 with the high eight bits zero (e.g., 0x003C == decimal 60) , it assumes that you meant 60 beats per minute, and auto-scales it up (to 0x3C00). There should be a better way to specify low-BPM cycles, and there isn’t right now. Let me think on it a bit.
Thank you, Mark!
Ok, I’ve got an idea here; it will be in the category of “make the easy things easy, and make the hard things possible”. Stay tuned.
Just by the way, I slightly modified beatsin16 in order to shift the wave by a given phase:
// for a 90 degree shift use phase = 63
uint16_t beatsin(accum88 beats_per_minute, uint16_t lowest = 0, uint16_t highest = 65535, uint8_t phase = 0)
{
uint16_t beat = beat16( beats_per_minute);
uint16_t beatsin = (sin16( beat + ( phase << 8 )) + 32768);
uint16_t rangewidth = highest - lowest;
uint16_t scaledbeat = scale16( beatsin, rangewidth);
uint16_t result = lowest + scaledbeat;
return result;
}
I believe that the latest beatsin functions in github take both a timebase offset and a phase offset, like what you’ve done here. Both default to zero. Went it about two weeks ago; sorry I didn’t announce that change.
What’s coming is a way of specifying BPM values between 0 and 1. (accum88 values 0x0001 … 0x00FF, which presently cannot be expressed, because they’re automatically scaled up to 0x0100…0xFF00, to make it more convenient to say “120 BPM” instead of having to always write “(120*256) beats per 256th of a minute”.)
I have it working one way already, but maybe I have a better way. I’ll commit the new API today either way.
What about 2 differnt functions like “classic” beatsin16 and beatsin16precise?
Well the existing one already lets you do fractional BPM, so it’s not a precision issue exactly.
But yeah, I may decide to go with two APIs.
Just added in github on the v3.1 branch: beatsin88.
beatsin88 is just like beatsin16, except that the BPM value MUST be specified in Q8.8 format. Meaning that if you want “120 BPM”, you have to explicitly pass in 120 * 256. Passing in just “120” would result in 120/256 BPM, or one beat every 28.125 seconds. That’s the bad/annoying news.
The good news is that you can specify fractional BPM values, down to 1/256th BPM, which works out to one full beat cycle every four minutes sixteen seconds. Should be good for some nice slow oscillators.
I did decide to go with a separate API call. Let me know how it works for you.
Awesome! Thanks, Mark - it works very well!
Just a short story about iterative construction: Within the last days I thought about implementing a master speed controller for FunkyNoise. It seemed hard for the coordinates - because I was gridlocked to the relative calculation of the values for the next step. Not trivial with permanently changing fps. I ended up with a big array of timestamps (when was every parameter changed the last time), had ugly math going on like how much time passed since the last call, that relative to the change per second I want, based on that the calculation how much I have to add now, to maintain my desired speed of change… Until I finally asked myself, why it is so complex to get a simple linear ramp. Then I looked at the beatsin functions again and slowly the insight came: Don´t care about the relative steps - just calculate the absolute value NOW.
So back to the coordinates:
x = millis() * individual_ratio * speed does now everything I need. 