Noob question: Counting k-rate cycles per quarter note


#1

I'm trying to count how many k-rate ticks/cycles go in a quarter note. For the quarter note I'm using 24ppqn from MIDI, I'm using the MIDI code from the midi/in/clock object:

if (status == MIDI_TIMING_CLOCK) {
  _pos_shadow++;
  _pos = _pos_shadow;
} else if (status == MIDI_START) {
  _active = 1;
  _pos = 0;
  _pos_shadow = -1;
} else if (status == MIDI_STOP) {
  _active = 0;
  _pos = -1;
} else if (status == MIDI_CONTINUE) {
  _active = 1;
} else if (status == MIDI_SONG_POSITION) {
  _pos_shadow = 6*((data2<<7)+data1)-1;
}

Now for every increment of 24 for the _pos variable I want to know how many k-rate cycles have happened, so I used the following as my k-rate code, which as far as I can tell should work, but doesn't:

if (_pos % 24 == 0) {
  outlet_kcpqn = _count;
  _count = 0;
}
outlet_count = _count;
outlet_pos = _pos;
_count += 1;

Everything else seems to be working fine, the count outlet is showing an ever increasing integer, same for the pos outlet (at a slower rate), but the kcpqn outlet is just showing 1 all the time and I don't see why.
Is my code wrong/am I missing something obvious?
I hope someone has an idea why this isn't working :slight_smile:


#2

Btw. in https://sebiik.github.io/community.axoloti.com.backup/t/coding-axoloti-objects/2606 it says:

You can access inlets, outlets, parameters and displays in init code, k-rate code°, s-rate code, and midi code.

But I'm unable to access outlets using outlet_<outletname> from the MIDI code, I get the following error when compiling

/home/simon/axoloti/build/xpatch.cpp: In member function 'void rootc::instanceclock__2::MidiInHandler(midi_device_t, uint8_t, uint8_t, uint8_t, uint8_t)':
/home/simon/axoloti/build/xpatch.cpp:257:3: error: 'outlet_kcpqn' was not declared in this scope

So I guess either the docs are wrong or the variable is called differently in the MIDI code?


#3

the docs wrong - inlet and outlets can only be accessed in k-rate/s-rate

code, hard to tell without running, looks ok, assuming your not getting song_position (which would then depend on what data was sent to you)

id try outputting pos_shadow and seeing what values your getting there, as id guess thats where the issue is. (as you already know count, and outletcount are working)


#4

I added some logging to the k-rate code

LogTextMessage("count %d _pos %d", _count, _pos);

Which resulted in the following:

...
count 1365 _pos 22
count 1366 _pos 23
count 1367 _pos 23
count 1368 _pos 23
count 1369 _pos 23
count 1370 _pos 23
count 1371 _pos 23
count 1372 _pos 23
count 1373 _pos 23
count 1374 _pos 23
count 1375 _pos 23
count 1376 _pos 23
count 1377 _pos 23
count 1378 _pos 23
count 1379 _pos 23
count 1380 _pos 23
count 1381 _pos 23
count 1382 _pos 23
count 1383 _pos 23
count 1384 _pos 23
count 1385 _pos 23
count 1386 _pos 23
count 1387 _pos 23
count 1388 _pos 23
count 1389 _pos 23
count 1390 _pos 23
count 1391 _pos 23
count 1392 _pos 23
count 1393 _pos 23
count 1394 _pos 23
count 1395 _pos 23
count 1396 _pos 23
count 1397 _pos 23
count 1398 _pos 23
count 1399 _pos 23
count 1400 _pos 23
count 1401 _pos 23
count 1402 _pos 23
count 1403 _pos 23
count 1404 _pos 23
count 1405 _pos 23
count 1406 _pos 23
count 1407 _pos 23
count 1408 _pos 23
count 1409 _pos 23
count 1410 _pos 23
count 1411 _pos 23
count 1412 _pos 23
count 1413 _pos 23
count 1414 _pos 23
count 1415 _pos 23
count 1416 _pos 23
count 1417 _pos 23
count 1418 _pos 23
count 1419 _pos 23
count 1420 _pos 23
count 1421 _pos 23
count 1422 _pos 23
count 1423 _pos 23
count 1424 _pos 23
count 1425 _pos 23
count 1426 _pos 23
count 1427 _pos 23
count 1428 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 24
count 1 _pos 25
...

In other words it seems the MIDI code is being executed at lower rate than the k-rate code (seems to be 64 times lower rate).
Since it's not possible to write to outlets directly from the MIDI code I now set a variable in the MIDI code and assign that variable to the outlet in the k-rate code.

MIDI code:

if (status == MIDI_TIMING_CLOCK) {
  _pos_shadow++;
  _pos = _pos_shadow;
  if (_pos % 24 == 0) {
    count = _count;
    _count = 0;
  }
} else if (status == MIDI_START) {
  _active = 1;
  _pos = 0;
  _pos_shadow = -1;
} else if (status == MIDI_STOP) {
  _active = 0;
  _pos = -1;
} else if (status == MIDI_CONTINUE) {
  _active = 1;
} else if (status == MIDI_SONG_POSITION) {
  _pos_shadow = 6*((data2<<7)+data1)-1;
}

k-rate code

outlet_kcpqn = count;
outlet_pos = _pos;
_count += 1;

This seems to produce the result I was looking for:

(my sequencer is set to 120 BPM = 2 Hz, so I'd expect to see 1/2 * 3000 (k-rate) = 1500 and that's what it's showing :slight_smile: )

Is this the correct way of doing this? Seems a bit heavy-handed to do the outlet assignment every k-rate cycle when it would be enough to do it every MIDI-rate cycle.


Delay time units
#5

Don’t have time to read / process at the moment.
But no, midi handler is not processed at krate in the current version it’s called as the data arrives on another lower priority ‘thread’

Iirc this is changing in the next release, as there are potential issues in the current approach.
(Potential = we have not seen it, so it’s more a theoretical tidy up)


#6

OK, good to know. I'll keep an eye out for the next release and the changelog :slight_smile:
Thx!


#7

It makes sense that the MIDI code is only executed when there are MIDI events to process.

As for the often unnecessary assignment of output variables in k-rate code, this really goes for all objects where nothing much normally happens during a k-rate cycle, e.g. an object debouncing button presses. It's could be seen as a drawback or by-product of the design where k-rate code is run for all objects at the k-rate, whatever there is to do. However, compared to modules like oscillators and filters which do some heavy lifting during a k-rate cycle, the overhead for simple modules like the kcpqn calculator object described in the thread is still pretty small.


#8

yes, but there are threading/timing implications, which will be addressed in the next release.
(ideally they would also be timestamped, but I don't think this is currently there, but we are talking small time differentials here)