Old 05-03-2008, 06:51 PM   #1
mbncp
Human being with feelings
 
Join Date: Mar 2008
Posts: 197
Default Midi Clock

I know reaper can send midi clock but not exactly my way.
This one has 2 options.

1) Start offset (see below)
Useful if you need to compensate for latency.

2) Start resolution (in beats)
If you set this slider to 4, it will wait until the beginning of the next bar before sending the start message(assuming you are in 4:4).
This gives some time to the other device to catch the proper tempo, plus it's necessary if you want a negative delay (start early).

Edit:
Changed a little the offsets, it has 3 sliders now, being summed.
You can now offset by buffer size (+/-4 audio buffers), by msec (+/-500 msec) and by beats (+/- 1 beat).
It shows also current position in beats(when stopped) and where the Start will/was sent, in beats value (divide by 4 for 4:4 measures).
Edit v1.2:
Now compensates the tempo to match reapers special loop size.
The 7th slider (Loop compensation time) let's you decide how fast the compensation is done(over 0 to 8 beats).
I still have some problems with very high buffers(4096), but looping a single measure with a 512 samples buffer at 140 bpm is good, even after 5 minutes.
Attached Files
File Type: txt MidiClock.txt (2.3 KB, 569 views)

Last edited by mbncp; 05-05-2008 at 01:40 PM. Reason: Code change
mbncp is offline   Reply With Quote
Old 05-04-2008, 11:53 AM   #2
mbncp
Human being with feelings
 
Join Date: Mar 2008
Posts: 197
Default

I have a little problem when I'm looping, my code is based on the fact that loops are beat based.

So if I set a 2 bars long loop, at some point, either the last buffer and the first one of the loop should have different sizes (split), or at least there should be an info about the loop position.

But I don't see any variable telling me the loop position and the buffer size doesn't change.

Is this a limitation of JS or is reaper taking some shortcuts with timing .. ?
mbncp is offline   Reply With Quote
Old 05-04-2008, 02:54 PM   #3
xackley
Human being with feelings
 
Join Date: Feb 2007
Posts: 1,120
Default

Is this a problem of not checking a beat_position != savedbeat_position when looping. Start position keeps shifting because the loop controls start and end?

Also the download version contains only 2 sliders.
__________________
^^^^^^^^^^
Ignore this post.
xackley is offline   Reply With Quote
Old 05-04-2008, 04:15 PM   #4
mbncp
Human being with feelings
 
Join Date: Mar 2008
Posts: 197
Default

Quote:
Originally Posted by xackley View Post
Is this a problem of not checking a beat_position != savedbeat_position when looping. Start position keeps shifting because the loop controls start and end?
With this little script, I check that the new beat_position is the correct one based on previous position + samplesblock.
The math must be ok. As long as I don't loop the values do match.

Now on a loop, I get some strange results:
my loop is between beat 4 and 8 ( 1 bar), tempo=30, buffer=4096 samples

next should be position : 8.021769 (0.021769 too long)
beat_position after the loop: 3.975329 (0.024671 too long)

Values are changing each time off course, but this means that the loop is not 4 beat long as it should be but a little longer.

So, I can compensate and send the clock at the correct time to keep the right tempo, but it will get out of sync.
A trick would be to compensate the tempo, but as we don't know in advance where the loop is, it's a bit hard to do it in a smooth way, not even speaking about my little brain :/

I'm not aware of all the issues, but wouldn't it be better that reaper splits the buffer in 2 on a loop ?
At least as an option (Accurate loop size) ?

The code I used for testing:
Code:
desc:test
slider1:0<0,0,0>Low buffer size
slider2:0<0,0,0>Hi Buffer size
slider3:0<0,0,0>init counter
slider4:0<0,0,0>Next_beat_position 
slider5:0<0,0,0>beat_position
//-------------------------
@init
slider1 = 50000;
slider2 = 0;
slider3 = slider3+1;
Next_beat_position = -1;

//-------------------------
@slider
//-------------------------
@block
samplesblock < slider1 ? slider1 = samplesblock;
samplesblock > slider2 ? slider2 = samplesblock;

play_state&1 ?
(
	beat_position != Next_beat_position ?
	(
		slider4 = Next_beat_position;
		slider5 = beat_position;
	);
	Next_beat_position = beat_position + samplesblock*tempo/(srate*60);
);
Quote:
Originally Posted by xackley View Post
Also the download version contains only 2 sliders.
It should have 6 sliders, v1.1
mbncp is offline   Reply With Quote
Old 05-05-2008, 07:04 PM   #5
xackley
Human being with feelings
 
Join Date: Feb 2007
Posts: 1,120
Default

ok, this made me curious. what I am seeing is the start of loop is exactly the .xxxxxx of the end of the loop minus the number of beats.

so a loop from bar 3 to bar 4
example:
If the loop ends on 11.994974 it will rewind to 7.994974.
If the loop ends on 11.999509 it will rewind to 7.999509.


The end of loop varies, so the beginning of loop varies too. The loop has to stop before bar 4, so the 11.994974 range of number is probably right, but the program shouldn't be doing a straight subtract of 4. The start of loop should be static. The slop at the end of the loop should not be carried over to the beginning of the loop

I think what I am seeing is a bug in how loop are handled?
__________________
^^^^^^^^^^
Ignore this post.
xackley is offline   Reply With Quote
Old 05-06-2008, 03:30 AM   #6
mbncp
Human being with feelings
 
Join Date: Mar 2008
Posts: 197
Default

As it's handled now, the loop is always 1 audio buffer larger than it should be.
Making the start of the loop a little early is maybe a way to distribute this extra buffer between the start and the end of the loop. (?)

In a vst, cycleStartPos and cycleEndPos show the "correct" values so the plug knows at least that it shouldn't fill totally the last buffer.
mbncp is offline   Reply With Quote
Old 01-14-2011, 04:52 PM   #7
Subz
Human being with feelings
 
Subz's Avatar
 
Join Date: Jun 2006
Location: UK
Posts: 2,925
Default

when looping the first 4 beats of the loop are not the same as the rest of the loop,

its like it drops to the dotted version of the tempo for the first 4 beats (only when looping)

Subz
Subz is offline   Reply With Quote
Old 01-15-2011, 05:20 AM   #8
Subz
Human being with feelings
 
Subz's Avatar
 
Join Date: Jun 2006
Location: UK
Posts: 2,925
Default

I'm using this & its close to perfect!!


Code:
desc:MidiClock (v1.2, mbncp (c) 2008)
slider1:0<-4,4,1>Start Offset(audio buffersize)
slider2:0<-500,500,1>+Start Offset(msec)
slider3:0<-1,1,.1>+Start Offset(beats)
slider4:4<0,12,1>Start Resolution(4=next measure 4:4)
slider5:0<0,0,0>Current Position (Beats, Read Only)
slider6:0<0,0,0>Start Position (Beats, Read Only)
slider7:1<0,8,1>Loop compensation time (beats)
//slider8:0<0,0,0>Current Compensation (read only) 
//-------------------------
@init
last_play_state = 0;
last_non_play_pos = -1;
//-------------------------
@slider
slider4=floor(slider4);
last_play_state = 0;
last_non_play_pos = -1;
//-------------------------
@block
last_play_state != play_state&1 ?
(
	midisend(0,$xFC,0);
	last_play_state = play_state&1;
	startposition = ((floor(beat_position / slider4)+1)*slider4)+(slider1*samplesblock*tempo/srate/60)+(slider2*tempo/60000)+slider3;
	Next_beat_position = beat_position;
	Total_beat_position = beat_position;
	clockposition = Total_beat_position;
	LoopSize = 0;
	k_24 = 1/24;
	loop_comp = 0;
);
last_play_state ?
(
	startposition >= beat_position ?
	(
		offset = floor((startposition-beat_position) / tempo * srate*60);
		offset < samplesblock? 
		(
			midisend(offset,$xFA,0);
			startposition = -1;
		);
	);
	beat_position != Next_beat_position ? // loop
	(
		LoopSize+= (Next_beat_position-beat_position);
		extra = Next_beat_position-floor(Next_beat_position) + floor(beat_position+.5)-beat_position;
		loop_comp = slider7 > 0 ? extra / (slider7*24)  : extra;
  	);
	Next_beat_position = beat_position + samplesblock*tempo/(srate*60);
	Total_beat_position = beat_position+LoopSize;
	offset = floor((clockposition-Total_beat_position) / tempo * srate*60);
	offset < samplesblock?
	(
		while
		(
			midisend(offset,$xF8,0);
			extra > 0?
			(
				extra < loop_comp? loop_comp = extra;
				extra-=loop_comp;
			): loop_comp=0;
			clockposition+=(k_24+loop_comp);
			offset = floor((clockposition-Total_beat_position) / tempo * srate*60);
			offset < samplesblock;
		);
	);
)
:
(
	last_non_play_pos != beat_position?
	(
		last_non_play_pos = beat_position;
		slider5 = beat_position;
		slider6 = ((floor(beat_position / slider4)+1)*slider4)+(slider1*samplesblock*tempo/srate/60)+(slider2*tempo/60000)+slider3;
	);
);
//slider8=extra;
the problem's i'm having are when looping the first 1/4 bar is incorrect & when i start recording the first hole bar is lose (out of time a bit)

these are the settings i use

[IMG]http://img809.**************/img809/4876/25874812.png[/IMG]

is any one else seeing this or is it maybe related to the USB drivers on my AKAI? (known to not be that stable)

Subz
Subz is offline   Reply With Quote
Old 01-15-2011, 05:57 AM   #9
Subz
Human being with feelings
 
Subz's Avatar
 
Join Date: Jun 2006
Location: UK
Posts: 2,925
Default

Just to add

i have this code that dose loop correctly

Code:
desc:simple MIDI clock generator
slider1:0<0,3,1>BEAT
slider2:0<0,1,1>RUN
slider3:24<2,24,1>DIV
slider4:0<0,100,1>time shift (ms)


@init
ext_noinit = 1;

prev_count = 24;
prev_play_state = 0;

noteOnMsg = $x90;  
noteOffMsg = $x80;

clockMsg = $xF8;
startMsg = $xFA;
stopMsg = $xFC;
contMsg = $xFB;

@slider
time_div = slider3;

pdc_delay = srate*slider4/1000;

pdc_midi = 1;

@block

(beat_position%4 == 0) ? slider1 = 0; 
(beat_position%4 == 1) ? slider1 = 1;
(beat_position%4 == 2) ? slider1 = 2;
(beat_position%4 == 3) ? slider1 = 3;
slider2 = play_state;

my_beat_position = beat_position; /* save the current beat_position so we can extrapolate it */
beats_per_sample = (tempo/60)/srate; /* get the beats per sample so we can track the beat position at a given sample */

offset = 0; /* reset offset from current block start */

@sample

(prev_count != (my_beat_position*time_div)%time_div) ? (
  midisend(offset,clockMsg,0);
  prev_count = (my_beat_position*time_div)%time_div;
);

(play_state != prev_play_state) ? (
  (play_state == 0) ?  midisend(offset,stopMsg,0);
  (play_state == 1 || play_state == 5) ? midisend(offset,startMsg,0);
  prev_play_state = play_state;
);

my_beat_position += beats_per_sample; /* advance the beat with the current known tempo so we are tracking it sample accurate */
offset += 1; /* advance offset so we send the midi notes at the correct time */
but this code goes out of sync if press record while playing (have to start from stop, & it has to be started on bar exactly) & the offset settings don't work

i really wish i understood JS code,

is there any way to merge the best of these two plugins?

Sorry for the badly explained questions & thank you to mbncp for the code!!

Subz
Subz is offline   Reply With Quote
Old 01-15-2011, 12:51 PM   #10
Subz
Human being with feelings
 
Subz's Avatar
 
Join Date: Jun 2006
Location: UK
Posts: 2,925
Default

Quote:
Originally Posted by Subz View Post
I'm using this & its close to perfect!!


Code:
desc:MidiClock (v1.2, mbncp (c) 2008)
slider1:0<-4,4,1>Start Offset(audio buffersize)
slider2:0<-500,500,1>+Start Offset(msec)
slider3:0<-1,1,.1>+Start Offset(beats)
slider4:4<0,12,1>Start Resolution(4=next measure 4:4)
slider5:0<0,0,0>Current Position (Beats, Read Only)
slider6:0<0,0,0>Start Position (Beats, Read Only)
slider7:1<0,8,1>Loop compensation time (beats)
//slider8:0<0,0,0>Current Compensation (read only) 
//-------------------------
@init
last_play_state = 0;
last_non_play_pos = -1;
//-------------------------
@slider
slider4=floor(slider4);
last_play_state = 0;
last_non_play_pos = -1;
//-------------------------
@block
last_play_state != play_state&1 ?
(
	midisend(0,$xFC,0);
	last_play_state = play_state&1;
	startposition = ((floor(beat_position / slider4)+1)*slider4)+(slider1*samplesblock*tempo/srate/60)+(slider2*tempo/60000)+slider3;
	Next_beat_position = beat_position;
	Total_beat_position = beat_position;
	clockposition = Total_beat_position;
	LoopSize = 0;
	k_24 = 1/24;
	loop_comp = 0;
);
last_play_state ?
(
	startposition >= beat_position ?
	(
		offset = floor((startposition-beat_position) / tempo * srate*60);
		offset < samplesblock? 
		(
			midisend(offset,$xFA,0);
			startposition = -1;
		);
	);
	beat_position != Next_beat_position ? // loop
	(
		LoopSize+= (Next_beat_position-beat_position);
		extra = Next_beat_position-floor(Next_beat_position) + floor(beat_position+.5)-beat_position;
		loop_comp = slider7 > 0 ? extra / (slider7*24)  : extra;
  	);
	Next_beat_position = beat_position + samplesblock*tempo/(srate*60);
	Total_beat_position = beat_position+LoopSize;
	offset = floor((clockposition-Total_beat_position) / tempo * srate*60);
	offset < samplesblock?
	(
		while
		(
			midisend(offset,$xF8,0);
			extra > 0?
			(
				extra < loop_comp? loop_comp = extra;
				extra-=loop_comp;
			): loop_comp=0;
			clockposition+=(k_24+loop_comp);
			offset = floor((clockposition-Total_beat_position) / tempo * srate*60);
			offset < samplesblock;
		);
	);
)
:
(
	last_non_play_pos != beat_position?
	(
		last_non_play_pos = beat_position;
		slider5 = beat_position;
		slider6 = ((floor(beat_position / slider4)+1)*slider4)+(slider1*samplesblock*tempo/srate/60)+(slider2*tempo/60000)+slider3;
	);
);
//slider8=extra;
the problem's i'm having are when looping the first 1/4 bar is incorrect & when i start recording the first hole bar is lose (out of time a bit)

these are the settings i use

[IMG]http://img809.**************/img809/4876/25874812.png[/IMG]

is any one else seeing this or is it maybe related to the USB drivers on my AKAI? (known to not be that stable)

Subz
if any one is interested i managed to solve the loop causing the first 4 bars to do strange stuff by removing this hole line from the middle of the code

Code:
extra = Next_beat_position-floor(Next_beat_position) + floor(beat_position+.5)-beat_position;
if i set the start resolution to 1.0 then if i start recording from stop the first 4 beats (1 Bar) are out of time, but there after is perfectly in sync for the rest of its playing duration (looped or un-looped) <unless your loop starts from 1.0.0.0 in the sequencer, then it will slowly drift out of time with each loop>

PS, only tested in V4 alpha & i don't use low latency mode on the midi out!

this is the best use i have got from my MPD26's note repeat!

so thank you very much!!

Subz
Subz is offline   Reply With Quote
Old 10-28-2011, 05:21 PM   #11
Adam Fulara
Human being with feelings
 
Adam Fulara's Avatar
 
Join Date: Jan 2011
Posts: 48
Default Full/X Midi Clock

I was upset, because Midi Clock doesn't work well in Reaper, so I made my own, using JS and examples with Midi Clock, for my Akai XR-20.

This is Midi clock with SPP, just load FX and set output to midi out connected to external device. If you need compensation, Ctrl+P, Midi devices -> Midi out ->Offset output to this device by:.... (I use -3ms).

I have got very tight timing with my drum machine (tight means less than 1 ms), and also features:
-LOOP looping XR20 the same part of beat too
-SPP in any transport situation, forward, skip, etc.
-Tempo change during playing.

For syncing purpose first note of beat is not played on XR, I will figure it out later, but it's not needed for me.

I used midi clock codes from this forum as examples.

Code:
desc:Full/X MIDI clock + SPP generator
/*************
MIDI clock + SPP generator by Adam Fulara 2011
Sends clock and SPP messages do midi out sync device
Create empty MIDI track, set IO > Output to synced MIDI out
You can change the time of clock 
Options-Preferences-MIDI devices-Your MIDI Output-
Enable output to this device + Offset output latency by ... ms
-3 ms are working fine for Akai XR-20
**************/

in_pin:none
out_pin:none
@init
prev_count = 24;
prev_play_state = 0;
clockMsg = $xF8;
startMsg = $xFA;
stopMsg = $xFC;
contMsg = $xFB;
sppMsg = $xF2; //pointer to project position
synchro=0; //synchromization state: 0- no, 2-looking for, 1-synchronized
prev_tempo=tempo; //tempo change check
prev_beat_position=0; 

@block
my_beat_position = beat_position; /* save the current beat_position so we can extrapolate it */
beats_per_sample = (tempo/60)/srate; /* get the beats per sample so we can track the beat position at a given sample */
offset = 0; /* reset offset from current block start */
//loop / tap tempo / wet off - reset clock:
play_state && (beat_position<prev_beat_position || 
  tempo!=prev_tempo || beat_position-prev_beat_position>0.2)  ?  synchro=0;  
play_state != prev_play_state ? 
(
  synchro=0;
  play_state==0 ? 
  (
   pozycja=floor(4*my_beat_position);
   poz7bit=(pozycja & 127) + (2 * (pozycja & 16256)); //8bit to 2x7bit 
   midisend(offset,stopMsg,0);
   midisend(offset,sppMsg,poz7bit);//start position = 4x beat pos.  
  );
  prev_play_state = play_state;
);
play_state==0 && (prev_beat_position!=beat_position) ? //position moved when stopped
(
   pozycja=floor(4*my_beat_position);
   poz7bit=(pozycja & 127) + (2 * (pozycja & 16256)); //8bit to 2x7bit 
   midisend(offset,sppMsg,poz7bit);//start position = 4x beat pos.  
);

play_state ? //for each sample section
( 
 loop( samplesblock,
  synchro==0 ?
  (
   teraz=my_beat_position*4;
   zaraz=teraz-floor(teraz)<0.001 ? teraz : floor(teraz)+1; 
   synchro=2;
  );
  synchro==2?
  (
   teraz2=my_beat_position*4;
   teraz2>=zaraz ? 
   (
     pozycja=floor(4*my_beat_position);
     poz7bit=(pozycja & 127) + (2 * (pozycja & 16256)); //8bit to 2x7bit 
     midisend(offset,stopMsg,0); //offset w 3 linijkach zamiast 0
     midisend(offset,sppMsg,poz7bit);//start position = 4x beat pos.  
     midisend(offset,contMsg,0); //zamiast start continue
     synchro=1; //transport_change?
    );
   ); 
   tyka = (my_beat_position * 24) % 24; 
   prev_count != tyka ? 
   (
     synchro==1 ? midisend(offset,clockMsg,0);
     prev_count = tyka;
   );
   my_beat_position += beats_per_sample; /* advance the beat with the current known tempo so we are tracking it sample accurate */
   offset += 1;
 );
);

prev_beat_position = beat_position;
prev_tempo=tempo;
__________________
http://adam.fulara.com/software
Guitar and Midi stuff

Last edited by Adam Fulara; 10-30-2011 at 06:12 AM.
Adam Fulara is offline   Reply With Quote
Old 05-16-2013, 07:18 AM   #12
TonE
Human being with feelings
 
Join Date: Feb 2009
Location: Reaper HAS send control via midi !!!
Posts: 1,288
Default

Hi Adam,

I tried your midi clock with Sequetron, somehow it does not work correctly, Reaper had 120 bpm, but Sequetron was showing only 20 bpm. I did all as described. What could be the reason for it?

Probably I should try also the above different midi clock versions?

Great jazz guitar tapping videos by the way, very cool, lots of respects!



Quote:
Originally Posted by Adam Fulara View Post
I was upset, because Midi Clock doesn't work well in Reaper, so I made my own, using JS and examples with Midi Clock, for my Akai XR-20.

Last edited by TonE; 05-23-2013 at 01:02 PM.
TonE 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 10:00 PM.


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