Reason Document - Song Position

Have an urge to learn, or a calling to teach? Want to share some useful Youtube videos? Do it here!
User avatar
Raveshaper
Posts: 1089
Joined: 16 Jan 2015

Post 17 May 2015

I wanted to share an explanation of the Song Position remotable item that can be found in the master list, linked here.
But, after checking my work I found that my math was incredibly off.

The song positions in the sequencer are roughly as follows:

Minimum value 0 = song position 1. 1. 1. 0 (.0000)
Maximum value 2147483646 = song position 9999. 4. 4 .239 (.9375)

I say that the above numbers are "roughly" those values because I have tried numerous times to get an accurate measurement of subticks but have not succeeded.

According to this article, each beat (or quarter note if you prefer) has a subtick resolution of 15360.
Since a sixteenth note is one fourth of a quarter note and each sixteenth note has a length of 240 ticks, we can solve for the smallest possible increment in the sequencer using the following simple formula:
x = 15360 / 4 / 240
x = 16
To get an accurate measurement of subticks, we must convert this value by diving 1 by 16, resulting in 0.0625 ticks.
Therefor, the smallest increment that is possible in Reason's sequencer must be 0.0625 ticks or 62.5 subticks (assuming a subtick is 1/1000 of a tick).

Going back to the value of a quarter note, a bar written in 4/4 tempo should be equal to 4 * 15360, or 61440 subticks.
If we calculate all of the major subdivisions of time that are used to display a position within the sequencer, we get the following table:
61440 subticks = 1 bar
15360 subticks = 1/4 note
3840 subticks = 1/16 note
16 subticks = 1 tick
This should mean that we can now perform the following calculation to get the maximum value for Song Position (2147483646 subticks):
v = 16 subticks * 240 ticks * 4 16th notes * 4 beats * 4 bars * 9999
But, I always return the following result:
v = 2457354240
A big number, but...
2457354240 != 2147483646, solution does not check
I'm probably missing something here, but I'm not being hard on myself for having goofed when I first posted this.
The subdivisions of time are; from smallest to biggest; 1/16, 1/240, 1/4, 1/4, 1/1.
With no clear order to the quantities being generated by those fractions, it's easy to get confused. I've calculated the subtick resolution and I'm still confused.

So, somehow it is possible to multiply the maximum number of bars (9999) by the number of beats (4) by the number of subticks in each beat (15360) by the number of 1/16th notes in each beat (4) by the number of subticks in each 1/16th note (3840) by the number of subticks in each tick (16), and then finally add 239 * 16 + 15 to the result and get the maximum value of 2147483646. I have no idea how to get this, even after trying to use whole numbers and subtract one to account for zero as the starting value.

I believe the problem is not knowing the value of the subticks, but 0.0625 should be correct because it takes 16 subticks to equal 1 tick (and 1/16=0.0625).
Perhaps someone with more mathematical skill than me can figure this out?
:reason: :ignition: :re: :refillpacker: Enhanced by DataBridge v5

User avatar
Pepin
Posts: 285
Joined: 16 Jan 2015

Post 08 Jun 2015

You have an extra *4 in your calculation (9999 already accounts for all the "bars").

So the maximum song position would at first appear to be:

Code: Select all

subticks  16ths    bars
 |         |        |
16 * 240 * 4 * 4 * 9999 = [b]614338560 subticks[/b]
      |        |
     ticks    beats
But I tested this a bit, and while Reason's UI enforces that limit while typing in positions, it's possible to drag clips and loop/end markers significantly further than that.

Image 

As the screenshot above shows, I managed to position the playhead as far as 34953.3.1.127*.

That's equal to about...

Code: Select all

(16 * 240 * 4 * 4 * 34952) + (16 * 128 * 1 * 3) = [b]2147457024 subticks[/b].
...which is just a couple bars short of the number in the list you posted. That could be for any number of reasons (maybe something to do with count-in, or maybe the UI just doesn't let you nudge the playhead quite that far?).

Hopefully I didn't get any of that wrong  :crazy: .
You do not have the required permissions to view the files attached to this post.

User avatar
Raveshaper
Posts: 1089
Joined: 16 Jan 2015

Post 08 Jun 2015

Thanks Pepin,

That number is crazy huge so I don't blame you for feeling confused.
The motivation behind understanding correct division of time using this remotable is that I am working on a rather ambitious project that transforms a Reason Document into a variant on the same idea as Traktor.

It started as a drum pad expander using a stepped jog wheel to access different "layers" for the pads, but exploded into a quasi-Traktor emulation as well.

I'm building in a way for a song project to use EMI loopback to access a second document that contains the Traktor style emulation. This means timeline based riffs of triggered audio can be tracked as an instrument using a multi channel audio interface.

In theory, it's been a beast just figuring this one out.
:reason: :ignition: :re: :refillpacker: Enhanced by DataBridge v5

User avatar
ScuzzyEye
Moderator
Posts: 1385
Joined: 15 Jan 2015

Post 08 Jun 2015

Pepin wrote:That's equal to about...

Code: Select all

(16 * 240 * 4 * 4 * 34952) + (16 * 128 * 1 * 3) = [b]2147457024 subticks[/b].
...which is just a couple bars short of the number in the list you posted. That could be for any number of reasons (maybe something to do with count-in, or maybe the UI just doesn't let you nudge the playhead quite that far?).

Hopefully I didn't get any of that wrong  :crazy: .
I'm guessing the limit is because of the 240 ticks. That's not a nice "computer" (2^y) number. It's probably stored internally as 2^8 = 256. So you end up losing 15 or 16 ticks for each bar.

User avatar
Raveshaper
Posts: 1089
Joined: 16 Jan 2015

Post 08 Jun 2015

ScuzzyEye wrote:I'm guessing the limit is because of the 240 ticks. That's not a nice "computer" (2^y) number. It's probably stored internally as 2^8 = 256. So you end up losing 15 or 16 ticks for each bar.
Precisely my fear, because without knowing how that fall off is carried out, measurements of time in terms of subticks would become more inaccurate the further you go along the timeline.
:reason: :ignition: :re: :refillpacker: Enhanced by DataBridge v5

User avatar
ScuzzyEye
Moderator
Posts: 1385
Joined: 15 Jan 2015

Post 08 Jun 2015

ScuzzyEye wrote:I'm guessing the limit is because of the 240 ticks. That's not a nice "computer" (2^y) number. It's probably stored internally as 2^8 = 256. So you end up losing 15 or 16 ticks for each bar.
QwaizanG wrote: Precisely my fear, because without knowing how that fall off is carried out, measurements of time in terms of subticks would become more inaccurate the further you go along the timeline.
What happens when you try to jump to simply, the 250 subtick mark?

I have a feeling that even though it's stored as an 8-bit value, Reason does more behind the scenes to round invalid values up. But that means you need to take that into account when trying to convert between subticks and location. That is, you need to apply the same conversion Reason uses.

User avatar
Raveshaper
Posts: 1089
Joined: 16 Jan 2015

Post 08 Jun 2015

That's the problem. As far as I know, you can't actually read the subtick position, only ticks. So knowing the precise location is quite hard.
:reason: :ignition: :re: :refillpacker: Enhanced by DataBridge v5

User avatar
ScuzzyEye
Moderator
Posts: 1385
Joined: 15 Jan 2015

Post 08 Jun 2015

I see what you mean. I was meaning ticks, but that doesn't matter...

How about this. When you're right on a tick, there's no * in the location display. So try setting different position values, and see how they round off. There should be some some values that don't seem like they should be even ticks, but don't show an asterisk.

I've got too much other stuff in my head right now, to work out the math. But if you don't make any progress, I'll come back to it in a few days.

User avatar
Raveshaper
Posts: 1089
Joined: 16 Jan 2015

Post 16 Jun 2015

Ok, more confused than ever.

Still can't get that 2147483646 value according to the values involved. Last attempt was over 168 million too large in value.
:reason: :ignition: :re: :refillpacker: Enhanced by DataBridge v5

User avatar
Pepin
Posts: 285
Joined: 16 Jan 2015

Post 16 Jun 2015

You might find this useful:

When fully zoomed horiztonally, it seems the playhead can only be placed at subtick positions.

You can verify this by creating an audio track, fully zooming horizontally, and turning off snap. If you try nudging the playhead as little as possible, you'll find there are exactly 15 possible positions between tick marks and they line up with the subtick audio offsets.



I'm not sure if it's possible to place the playhead between subticks by turning snap off at a lower zoom setting, but I suspect it's not.

User avatar
Raveshaper
Posts: 1089
Joined: 16 Jan 2015

Post 17 Jun 2015

What I know so far:
  • The subticks range from 0 to 15.
  • The ticks are every 16th subtick.
  • Each 1/16th note contains 240 ticks, or [(16^2)*15] (3840 subticks).
  • Each 1/4th note or "beat" in 4/4 timing contains 4 * [(16^2) * 15] (960 ticks, 15360 subticks).
  • Each bar contains [(16^3) * 15] (3840 ticks, 61440 subticks).
  • The maximum song position converts to the hexadecimal string "7FFFFFFE".
From here, my eyes cross and I start drooling.

What I don't understand is how the values are being parsed. Try as I might, I can't get the known data to yield the maximum value as described previously in this thread. It always adds up to more or less than the amount I anticipate. I must be messing up on something really simple and just not catching it. But over and over?

I think the proper way to extract bar position, etc. is to do bitwise shifts according to 16 raised to a power between 1 and 6. I could be wrong.
In my head this seems like a simple bit of math, similar to an odometer. Each time the rightmost chunk reaches 16, it increments the next chunk to the left, etc all the way until the far left side.
Something so easy shouldn't be this hard to figure out. Maybe my brain is just mush.
:reason: :ignition: :re: :refillpacker: Enhanced by DataBridge v5

User avatar
ScuzzyEye
Moderator
Posts: 1385
Joined: 15 Jan 2015

Post 17 Jun 2015

I'd say the binary storage probably looks like this:

Code: Select all

-BBBBBBBBBBBBBBBbbbbTTTTTTTTssss

- = sign bit
B = bar
b = beat
T = tick
s = subtick
So it does work like an odometer, with each field incrementing the one to its left. Except for ticks. They don't go all the way to 255. When ticks are greater than 239, 240 is subtracted from the total, and beat is increased.

User avatar
Raveshaper
Posts: 1089
Joined: 16 Jan 2015

Post 17 Jun 2015

So then the answer would be to convert the song position to a binary string and split that string into segments that each define a given piece of song position data.

I hadn't thought of that. Once I write that and study it, I'll be able to convert it into something more useful for my purposes.
:reason: :ignition: :re: :refillpacker: Enhanced by DataBridge v5

User avatar
ScuzzyEye
Moderator
Posts: 1385
Joined: 15 Jan 2015

Post 17 Jun 2015

Yeah, your idea about bit shifts would work to do the splitting, but you probably want to mask it first.

Code: Select all

position & 00000000000000000000000000001111 = subticks
position & 00000000000000000000111111110000 >> 4 = ticks
position & 00000000000000001111000000000000 >> 12 = beats
position & 01111111111111110000000000000000 >> 16 = bars

User avatar
avasopht
Posts: 2931
Joined: 16 Jan 2015

Post 17 Jun 2015

15 bar bits only allows for up to 32765 bars, but Pepin got the playhead up to bar 34952.

Right, so anyways the calculated position of 2147483646 is 34953.3.1.127(.14) since you can only fit 34952 bars into 2147483646 (and bars/beats/16ths start from 1, so add 1). Keep performing this conversion with beats, 16ths and ticks, and you end up with that position.
---

User avatar
ScuzzyEye
Moderator
Posts: 1385
Joined: 15 Jan 2015

Post 17 Jun 2015

You're right. I just went back and looked at that again. I was thinking the value he has was lower than 32765.

That means the song position is stored purely in subticks.

So to extract any of the other higher measurements you'd have to take a modulus of the smaller fields multiplied together, and then find subtract that out.

Code: Select all

position % 16 = subticks
(position - subticks) % 3840 = ticks
(position - subticks - ticks) % 15360 = beats
(position - subticks - ticks - beats) % 61400 = bars

User avatar
avasopht
Posts: 2931
Joined: 16 Jan 2015

Post 17 Jun 2015

ScuzzyEye wrote:That means the song position is stored purely in subticks.

So to extract any of the other higher measurements you'd have to take a modulus of the smaller fields multiplied together, and then find subtract that out.

Code: Select all

position % 16 = subticks (position - subticks) % 3840 = ticks (position - subticks - ticks) % 15360 = beats (position - subticks - ticks - beats) % 61400 = bars
We need to use division for this conversion to work. This is how I did it.

Code: Select all

int position = 2147483646
int bars = position / SUBTICKS_IN_BAR;
position %= SUBTICKS_IN_BAR;
int beats = position / SUBTICKS_IN_BEAT;
position %= SUBTICKS_IN_BEAT;
int v16ths = position / SUBTICKS_IN_16TH;
position %= SUBTICKS_IN_16TH;
int ticks = position / SUBTICKS_IN_TICK;
position %= SUBTICKS_IN_TICKS;
int subticks = position;
---

User avatar
ScuzzyEye
Moderator
Posts: 1385
Joined: 15 Jan 2015

Post 17 Jun 2015

avasopht wrote:We need to use division for this conversion to work.
Discarding the fractional part after division is the same thing as subtracting the modulus. So yeah, it just depends on which end you approach the problem from.

User avatar
avasopht
Posts: 2931
Joined: 16 Jan 2015

Post 17 Jun 2015

Yes but that calculation only gives you the number of subticks, .. Just tested it too.

Much cleaner code than my approach though
---

User avatar
Djstarski
Posts: 358
Joined: 20 Jan 2015

Post 17 Jun 2015

i wonder if the producers that have made hit records and the engineers that have mixed and mastered these hit records , use this information to do their job . i hope not . i`ll have to learn this also to get the job done .

User avatar
Raveshaper
Posts: 1089
Joined: 16 Jan 2015

Post 17 Jun 2015

Are you getting any inaccuracy from using 61400 for bars? My evaluation for that subtick count was 61440.
:reason: :ignition: :re: :refillpacker: Enhanced by DataBridge v5

User avatar
avasopht
Posts: 2931
Joined: 16 Jan 2015

Post 17 Jun 2015

QwaizanG wrote:Are you getting any inaccuracy from using 61400 for bars? My evaluation for that subtick count was 61440
I used 61440 and tested the calculation in pen and paper (was on a train journey at the time).

Code: Select all

BAR_SUBTICKS = 61440
BEAT_SUBTICKS = 15360
N_16THS_SUBTICKS = 3840
TICK_SUBTICKS = 16
function subticks_to_timecode (position)
  local subticks = position % TICK_SUBTICKS
  local ticks = (position - subticks) % N_16THS_SUBTICKS
  local n_16ths = (position - subticks - ticks) % BEAT_SUBTICKS
  local beats = (position - subticks - ticks - n_16ths) % BAR_SUBTICKS
  local bars = (position - subticks - ticks - n_16ths - beats)
  return {
    bars = (bars // BAR_SUBTICKS) + 1,
    beats = (beats // BEAT_SUBTICKS) + 1,
    n_16ths = (n_16ths // N_16THS_SUBTICKS) + 1,
    ticks = ticks // TICK_SUBTICKS,
    subticks = subticks,
  }
end
timecode = subticks_to_timecode(2147483646)
print(timecode.bars .. "." .. timecode.beats .. "." .. timecode.n_16ths .. "." .. timecode.ticks .. "." .. timecode.subticks)

--> Outputs "34953.3.1.127.14"

Djstarski wrote:i wonder if the producers that have made hit records and the engineers that have mixed and mastered these hit records , use this information to do their job . i hope not . i`ll have to learn this also to get the job done .

This is how all the tools, technology and software that producers and engineers use get created. Did you not see that QwaizanG is creating a production tool?
---

User avatar
Raveshaper
Posts: 1089
Joined: 16 Jan 2015

Post 18 Jun 2015


Do you have a PayPal, avasopht? Because that bit of crisp, clean logic up there is worth a donation.
avasopht wrote:Did you not see that QwaizanG is creating a production tool?
Yes, I should explain what I'm putting together. This was the last piece I needed to fully wrap my head around it.

Traktor has something called "cue points" that allow you to specify a position along the timeline of an audio track that can be bound to a button or other midi input. This allows the user to trigger that specific point in the audio the moment that input is received. If you expand on that and map multiple cue points to different midi inputs, such as drum pads, you can "play" the audio track like a massive storage capacity sampler.

Mad Zach has done numerous demos of this for Native-Instruments and DJTechTools if you want to take a look at that in action.
Here's an example:



This type of thing falls under the category of "yeah, Reason can do that too, but you have to work really hard to make it happen."
It hasn't made the rounds because nobody has yet put in some rather long hours to emulate that (and I don't blame anyone for that, it's hard as nails).

If you're still following along, what I have done is create a sort of "all in one" surface that can be used to play Reason live or during a production session.
In its default behavior, it nests 8 layers of memory inside of each drum pad, effectively expanding most 4 x 4 drum pad controllers from a max sample trigger count of 128 all the way up to 1024 (2048 if it has 16 pages/scenes/banks).
In its alternate behavior, it nests 16 slices inside of each memory slot that is nested inside of each pad. This makes it possible to define up to 16384 slices per drum pad controller (32768 if it has 16 pages/scenes/banks). A programming mode is being written that will allow the user to scrub through the audio and record each audio slice as they choose.
In a variant mode of its alternate behavior, the surface can be controlled via MIDI notes instead of CC numbers via loopback so that the document containing the audio track and cue points can function like an external plugin whose output can then be put to use as long as the user has a multi-channel audio interface.

The major difference between cue points and the slice method I'm building is that you can create asynchronous "loops" made up of snippets along the timeline that can be out of order in terms of their original continuity. I wanted to be able to throttle the dimensions of slices to nearest values based on accurate subdivisions of beats, bars, 16ths, etc. Or at the very least, figure out a pseudo quantize ability.

This all-in-one could be dismantled into smaller and more manageable pieces. Maybe it should and I can do that after the big version is done.
But the logic that avasopht just provided here is highly valuable.

It is now possible to use this knowledge to generate accurate rolls with 1/128th note timing, even 1/256th note timing.
Something I have wanted to build is a variable note repeat with precise timing that can smoothly transition from one subdivision of time to another.
Now, anybody can. And that's awesome.

Does any of this make sense?
I promise it's going to be good. The only challenge is making it user friendly.
:reason: :ignition: :re: :refillpacker: Enhanced by DataBridge v5

User avatar
avasopht
Posts: 2931
Joined: 16 Jan 2015

Post 18 Jun 2015

To me this was very much a group effort, .. Many heads working towards one outcome.

Looking forward to seeing this in action.
---

User avatar
Raveshaper
Posts: 1089
Joined: 16 Jan 2015

Post 18 Jun 2015

Why don't some of us form programming collabs to make surfaces for enhancing production?
:reason: :ignition: :re: :refillpacker: Enhanced by DataBridge v5

  • Information
  • Who is online

    Users browsing this forum: CommonCrawl [Bot] and 2 guests