Skip to content

Peak meters calibrated pull #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: master
Choose a base branch
from

Conversation

brummbrum
Copy link
Contributor

@brummbrum brummbrum commented May 20, 2019

This pull request implements the Peak Level Meters on the Komplete Kontrol Keyboard. It is based on previous pull requests #7 and #9. It thus shows more changes relative to the current master which has not yet pulled #7 and #9 .

Notes:

  • The meters shown on the displays of S-Series Mk2 show a dB scale. Contrarily to Reaper, this scale is not evenly spaced, i.e. the number of pixels between e.g. the 0dB mark and the -12dB mark differs from the number of pixels between the -12dB mark and the -24dB mark and so on. Above -48dB it is logarithmic. Reaper reports peak values and shows these values on an evenly spaced scale in Reaper's on screen meters. In order to match the reading between Reaper meters on the computer screen and the keyboard's display the non-linearity of the keyboard's display scale is taken into account.
  • The above will also be relevant when sending Reaper's track fader (volume) positions in upcoming feature additions (aka "volume text").
  • As a future code optimization maybe I will substitute the currently used pow() function to transform the meter values by exp() which should be computationally more efficient

Leonard de Ruijter and others added 30 commits April 24, 2019 07:06
Direct track selection in Mixer view w top row buttons
Mixer Mode Track Navigation
Comments for future changes. Branch from here as this modifies architecture an multiple areas
Direct API calls for track selection rather than Reaper actions to overcome 99 track limit
Track selection working
Non existing tracks in last bank are now properly marked as not available
VU meter data format ok, but:
- Need a better hook (update frequency)
- VU meter updates not working properly. CMD_SEL_TRACK_PARAMS_CHANGED not fully understood yet
VU:
- functionality is there!
- some minor tweaks like scaling still open
- code cleanup required
native conversion taken from Reaper SDK
- Calibration also valid for other keyboards than S Mk2?
-Meters working
-Precise, non linear calibration for KK Mk2 Display Meters
- Stub to isolate this pull request from fork master
efficiency improvement
@brummbrum
Copy link
Contributor Author

well, the pow() vs exp() efficiency bugged me a little - improved this straight away while at it (not that it really matters.... :-)

- Use direct linear logarithmic conversion specifc to NI keyboard meter scaling rather than concatenating a calibration frunction after calling Reaper API standard conversions
- Speed improvement
- Further meter precision improvement
@brummbrum
Copy link
Contributor Author

Final code optimizations. The conversion from peak values to MIDI values is now implemented as a direct linear logarithmic transformation without any detour via Reaper API conversions. This delivers the highest precision at lowest CPU costs.

@brummbrum
Copy link
Contributor Author

Requires a fix. The fix will be introduced together with mute and solo implementation.
Current behavior:

  • meters not active when track muted
    Fixed behavior:
  • meters not active when (track muted) AND (not soloed)

@brummbrum
Copy link
Contributor Author

Actually Reaper API Track_GetPeakInfo() seems to be buggy, will raise as a separate issue

@brummbrum
Copy link
Contributor Author

Solved in pull request #18 => issue #17 closed.

Copy link
Owner

@jcsteh jcsteh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

I appreciate these being submitted as separate pull requests. However, because they're on top of other work, it's still difficult to review and merge them in isolation. If possible, please branch from master for each piece of work. That's tricky for a couple of these, since they depend on earlier code, but several of them are largely unrelated (including this one) and could be done in separate branches off master.

A few comments below.

@@ -0,0 +1,17 @@
#ifndef _WDL_DB2VAL_H_
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this file isn't needed any more?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct. can be kicked out.

@@ -1,69 +1,22 @@
# ReaKontrol

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file shouldn't be included in this PR/branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I was surprised it got in there. don't even know how to exclude it ;-) such a rookie I am with git. need to study the documentation better.
... don't be shocked ... the code itself is (despite of style issues) not as terrible

// A value of 0 will result in stopping to refresh meters further to right.
// The array needs one additional char at peakBank[16] set to 0 as a "end of string" marker.
char peakBank[(BANK_NUM_TRACKS * 2) + 1] = { 0 };
int j = 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a better name for this variable? outPos might work.

if (*(bool*)GetSetMediaTrackInfo(track, "B_MUTE", nullptr)) {
peakBank[j] = 1;
peakBank[j+1] = 1;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd prefer } else { on same line, rather than separated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, better readability. will consider in future edits.

}
else {
peakValue = Track_GetPeakInfo(track, 0); // left channel
if (peakValue < 0.0000000298023223876953125) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Please use a named constant for this value. I assume it's the float representation of -150dB?
  2. I wonder if it makes sense to move this check into peakToChar?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup. I did exactly that in later rework of the code (see later pull requests). And yes, sorry for making you read through these ventures with the incremental modifications style....

//-----------------------------------------------------------------------------------------------------------------------

static unsigned char peakToChar_KkMk2(double peak)
{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd prefer { on the same line as the function definition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree!

double a = -3.2391538612390192E+01;
double b = 3.0673618643561021E+01;
double c = 8.6720798984917224E+01;
double d = 4.4920143012996103E+00;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do these magic numbers represent? Please use named constants.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they are the result of curve fitting, i.e. reverse engineering to fit Reaper's meters exactly to what is shown on the KK display. The KK display scale is a fixed pixel image. The function calculates the MIDI values that are required to show the bar at exactly the correct height to coincide with the dB value that Reaper reports. I.e. midi = a + b * ln(c * volume +d).
With these parameters the maximum error is 0.3% between Reaper values and display reading at the curve fitting points noted in the comments, i.e. far less then the quantization due to the pixel nature of the display.
volToChar_kkMk2_FUNCTION

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should add that this is the most CPU friendly function I found.

@@ -145,6 +145,7 @@ BaseSurface::~BaseSurface() {
}

void BaseSurface::Run() {
this->_peakMixerUpdate(); // ToDo: Maybe update only every 2nd call to save CPU?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than putting this in BaseSurface, you could just override Run() in NiMidiSurface and call the superclass: BaseSurface::Run()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that would look cleaner and is also more logical (I don't even know if Mk1 has meters - do you?)

@brummbrum
Copy link
Contributor Author

Thanks!

I appreciate these being submitted as separate pull requests. However, because they're on top of other work, it's still difficult to review and merge them in isolation. If possible, please branch from master for each piece of work. That's tricky for a couple of these, since they depend on earlier code, but several of them are largely unrelated (including this one) and could be done in separate branches off master.

A few comments below.

You are very right about this - sorry for making your merging efforts harder than maybe needed. Originally I had planned to work in this fashion (separating parallel branches from a base commit) but abandoned it when I came to realize that there were more inter-dependencies than I had anticipated. This is also owed to the fact that for me it is like "double reverse engineering": the NI API is not documented at all and Reaper's API is also not documented that extensively... As a result I ventured back and forth with some approaches as you can easily see when you look at the individual pull request.
As it turned out, the meters have a lot of of inter-dependencies. They are linked to mute, solo, muted by solo, volume markers,...
I finally decided that - considering the relative small size of the code - it could be acceptable to work in this incremental fashion and at least splitting up the branches. You can still diff between the different pull requests.
PS: I'm in my second week of working with git... don't be surprised by my clunky way of using it

@brummbrum
Copy link
Contributor Author

PPS: "offline" for the next couple of days, hence I won't be able to change anything for a week or so

jcsteh pushed a commit that referenced this pull request Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants