Go Back   Cockos Incorporated Forums > REAPER Forums > ReaScript, JSFX, REAPER Plug-in Extensions, Developer Forum

Reply
 
Thread Tools Display Modes
Old 05-21-2023, 06:33 PM   #1
BryanChi
Human being with feelings
 
Join Date: Jan 2019
Location: Taiwan
Posts: 315
Default a simple question about building a step sequencer with JSFX

I'm having difficulty with letting the JSFX know the current position within the sequencer's length.
I've figured out how to know the current playhead position in a measure with this simple equation:

MeasureNum= floor(beat_position/ts_denom);
BeatPos= beat_position - ts_denom* (MeasureNum);

but what happens when you want to make the sequencer longer than a measure?
Thank you!
BryanChi is offline   Reply With Quote
Old 05-22-2023, 02:04 AM   #2
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,834
Default

You'd use something along the lines of...

Code:
current_pos = beat_position % sequence_length;
... then go from there.
IXix is offline   Reply With Quote
Old 05-22-2023, 02:27 AM   #3
TonE
Human being with feelings
 
Join Date: Feb 2009
Location: Reaper HAS send control via midi !!!
Posts: 3,885
Default

Wo ai Taiwan, greetings to Taiwan.
TonE is offline   Reply With Quote
Old 05-22-2023, 03:15 AM   #4
souk21
Human being with feelings
 
souk21's Avatar
 
Join Date: Mar 2021
Posts: 301
Default

Quote:
Originally Posted by IXix View Post
Code:
current_pos = beat_position % sequence_length;
This, but keep in mind % returns an integer. If you want a fractional position you need to use fmod

Code:
function fmod (n, k) (
  n - k * floor(n/k);
);
current_pos = fmod(beat_position, sequence_length);
If you want the sequencer to go along but not be tied to the arrangement specific position you can use something along the lines of

Code:
@block
beat_per_spl = tempo / (srate * 60);
beat_per_block = beat_per_spl * samplesblock;
//This replaces beat_position
bp += beat_per_block;
//Fractional position
current_pos = fmod(bp, sequence_length);
//Integer position
current_beat = floor(current_pos);
This will play even if transport is stopped, so if it's not desirable you've got to check play_state.

Then you can
Code:
@block
beat_per_spl = tempo / (srate * 60);
beat_per_block = beat_per_spl * samplesblock;
bp += beat_per_block;
current_pos = fmod(bp, sequence_length);
next_block_pos = fmod(bp + beat_per_block, sequence_length);

//Next block is going to start during next beat
floor(current_pos) != floor(next_block_pos) ? (
    //How far is next beat
    beat_offset = ceil(cur_position) - cur_position;
    spl_offset = beat_offset / beat_per_block * samplesblock;
    midisend(spl_offset, [...]);
);
The advantage being that you can do stuff like
Code:
beat_per_block = beat_per_spl * samplesblock;
beat_per_block *= speed;
And if you need it to be sync with transport you can do
Code:
@init
is_init = 0;

@block
//beat_position is not available in @init so you need to set it here
!is_init ? (
    is_init = 1;
    bp = beat_position;
);

Last edited by souk21; 05-22-2023 at 05:55 AM.
souk21 is offline   Reply With Quote
Old 05-22-2023, 05:07 AM   #5
BryanChi
Human being with feelings
 
Join Date: Jan 2019
Location: Taiwan
Posts: 315
Default

@souk21 oh wow that is so comprehensive, thank you very much, you're a saint!

@IXix Thank you, I will try a bit and see how it goes!

@TonE hahaha Taiwan loves you too
BryanChi is offline   Reply With Quote
Old 05-22-2023, 05:45 AM   #6
souk21
Human being with feelings
 
souk21's Avatar
 
Join Date: Mar 2021
Posts: 301
Default

You're welcome

Just noticed this part should be:
Code:
    //How far is next beat
    beat_offset = next_block_pos - floor(next_block_pos);
    spl_offset = (1 - beat_offset / beat_per_block) * samplesblock;
    midisend(spl_offset, [...]);
I edited my previous post to correct this
souk21 is offline   Reply With Quote
Old 05-22-2023, 05:55 AM   #7
souk21
Human being with feelings
 
souk21's Avatar
 
Join Date: Mar 2021
Posts: 301
Default

Or even clearer
Code:
//How far is next beat
beat_offset = ceil(cur_position) - cur_position;
spl_offset = beat_offset / beat_per_block * samplesblock;
souk21 is offline   Reply With Quote
Old 05-25-2023, 10:49 PM   #8
BryanChi
Human being with feelings
 
Join Date: Jan 2019
Location: Taiwan
Posts: 315
Default

Thank you souk21!
I used just the first bit of your code and have already achieved most of what I need. I'll look deeper into it when I need more advanced functionalities.

Can you please explain to me what this means?

Quote:
Originally Posted by souk21 View Post

The advantage being that you can do stuff like
Code:
beat_per_block = beat_per_spl * samplesblock;
beat_per_block *= speed;
BryanChi is offline   Reply With Quote
Old 05-26-2023, 06:03 AM   #9
souk21
Human being with feelings
 
souk21's Avatar
 
Join Date: Mar 2021
Posts: 301
Default

The advantage is that if you use the "simple" version
Code:
current_pos = fmod(beat_position, sequence_length);
If you want to change the speed, you can use the following code:
Code:
current_pos = fmod(beat_position * speed, sequence_length);
That works but current_pos will jump all over the place if you change speed while playing.

Code:
//e.g beat_position is 2 and speed is 1
current_pos = fmod(2 * 1, sequence_length);

//you change speed to 2
current_pos = fmod(2 * 2, sequence_length);

//current_pos has jumped from 2 to 4
Whereas with
Code:
beat_per_block = beat_per_spl * samplesblock;
beat_per_block *= speed;
next_block_pos = fmod(bp + beat_per_block, sequence_length);
You won't have this problem

Code:
//e.g bp is 2 and speed is 1
next_block_pos = fmod(2 + beat_per_block * 1, sequence_length);

//you change speed to 2
next_block_pos = fmod(2 + beat_per_block * 2, sequence_length);

//next_block_pos has only gone up beat_per_block*2 which is what we want
souk21 is offline   Reply With Quote
Old 05-26-2023, 06:12 AM   #10
souk21
Human being with feelings
 
souk21's Avatar
 
Join Date: Mar 2021
Posts: 301
Default

And this part

Code:
//How far is next beat
beat_offset = ceil(cur_position) - cur_position;
spl_offset = beat_offset / beat_per_block * samplesblock;
Is useful if you want to trigger your sound/midi on the beat with sample accuracy.
A block will never start at the beginning of a beat, so you need to know when in the buffer the beat is.

If you want to trigger audio you can do it like this:
Code:
@buffer
[...]
//Next block is going to start during next beat
floor(current_pos) != floor(next_block_pos) ? (
    //How far is next beat
    beat_offset = ceil(cur_position) - cur_position;
    spl_offset = floor(beat_offset / beat_per_block * samplesblock);
);
@sample
spl_offset == 0 ? (
  //Beat starts at this sample, e.g start playing buffer
);
spl_offset -= 1;
and if you want to trigger midi
Code:
//Next block is going to start during next beat
floor(current_pos) != floor(next_block_pos) ? (
    //How far is next beat
    beat_offset = ceil(cur_position) - cur_position;
    spl_offset = beat_offset / beat_per_block * samplesblock;
    midisend(spl_offset, [...]);
);
souk21 is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 03:29 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2023, vBulletin Solutions Inc.