Register / Login  |  Desktop view  |  Jump to bottom of page

tcMenu Arduinio library » Logarithmic scale in AnalogItem

Author: pruttelherrie
06/04/2021 19:54:58
Is it possible to have a scaling with a logarithmic "feel" to it? I have an AnalogMenuItem for a LFO speed in Hz, in an audio application. Now I have to choose between either small steps or not enough resolution in the lower part of the range.

I assume it is possible to overload the display function for the value so I get a kind of mapping, but I have no idea where to start or where to look.

Author: davetcc
06/04/2021 20:32:57
We’ve mainly done this with dB for audio purposes so that the display scale looks linear. But beyond that I don’t think we’ve really considered anything else. Would something like that not work here? The other option would be to use a large number.

Author: pruttelherrie
06/04/2021 20:45:12
I guess that would work, but isn't that the other way around? As in: the dB scale is linear, but the amplification has to be calculated from that display value.

Is there example code for the dB menu?

Author: davetcc
07/04/2021 08:25:38
Yes, the ESPAmplifer or many of the other examples have a scale in dB. The dB scale is essentially presented completely as linear, but the calculations are done by a volume control IC, such as a PGA2310 which accurately increases volume in steps of 0.5dB. So the non-linearity of the scale is handled there (I suspect using a table in the IC).

If you needed to do the calculation yourself, would you not just do the math (or provide a table of values) to convert the display units into actual units.

Maybe I am oversimplifying here. But let us say you had 255 steps in your menu item, something like this may be the simplest approach:

const uint32_t valueToActualMap[256] = {.......}; // populated with your values, ensure it's stored in flash by using PROGMEM if needed 

void onMenuItemChanged(int /*id*/) {
   int val = menuItem.getCurrentValue(); // returns between 0 and 255
   uint32_t corrected = volumeToActualMap[val];
   // do something here with corrected
}


The other option would be to use an editable large number, which can handle values of huge range, up to 12 significant figures, with up to 9 of those being the whole part. You can read about those here: https://www.thecoderscorner.com/products/arduino-libraries/tc-menu/menu-item-types/largenum-menu-item/


Author: pruttelherrie
07/04/2021 17:03:12
Ok, clear.

But is it possible to "transform"/correct the value of an AnalogMenuItem before it gets displayed? So the internal value goes linear, but it is put through a function before being displayed.

Author: davetcc
08/04/2021 10:24:40
I think that I would do this for now with a scroll choice item. You can move them up and down in value and although it seems odd to use what's essentially a choice element for this, you could for example provide 255 choices using the custom render function option, with your own text and value for each one. Take a look at the scroll choice guide and see what you think. That would work right now, with tcMenu 1.7 out of the box.

https://www.thecoderscorner.com/products/arduino-libraries/tc-menu/menu-item-types/scrollchoice-menu-item/

EDIT: just to reiterate I'm not talking about using the memory or eeprom array option, I'm talking about using the custom function option, where you'd be called back whenever a values was needed, or when it was selected. The above guide goes through this option in the section "Custom rendering option".

Author: pruttelherrie
08/04/2021 18:25:08
Yes, works perfectly!

Now I got to find the correct function to transform 0-255 to sane values for the LFO but the interface now works as I want it to.

Weird thing though, the (Linux) Designer creates 2 callbacks in the .ino file, of which the first one is not used:

// see tcMenu list documentation on thecoderscorner.com
int CALLBACK_FUNCTION fnLFO1SpeedLogRtCall(RuntimeMenuItem* item, uint8_t row, RenderFnMode mode, char* buffer, int bufferSize) {
   switch(mode) {
    case RENDERFN_INVOKE:
        // TODO - your code to invoke goes here - row is the index of the item
        return true;
    case RENDERFN_NAME:
        // TODO - each row has it's own name - 0xff is the parent item
        ltoaClrBuff(buffer, row, 3, NOT_PADDED, bufferSize);
        return true;
    case RENDERFN_VALUE:
        // TODO - each row can has its own value - 0xff is the parent item
        buffer[0] = 'V'; buffer[1]=0;
        fastltoa(buffer, row, 3, NOT_PADDED, bufferSize);
        return true;
    case RENDERFN_EEPROM_POS: return 0xffff; // lists are generally not saved to EEPROM
    default: return false;
    }
}


// see tcMenu list documentation on thecoderscorner.com
int CALLBACK_FUNCTION fnLFO1SpeedlogRtCall(RuntimeMenuItem* item, uint8_t row, RenderFnMode mode, char* buffer, int bufferSize) {
   switch(mode) {
    case RENDERFN_INVOKE:
        // TODO - your code to invoke goes here - row is the index of the item
        return true;
    case RENDERFN_NAME:
        // TODO - each row has it's own name - 0xff is the parent item
        ltoaClrBuff(buffer, row, 3, NOT_PADDED, bufferSize);
        return true;
    case RENDERFN_VALUE:
        // TODO - each row can has its own value - 0xff is the parent item
        buffer[0] = 'V'; buffer[1]=0;
        fastltoa(buffer, row, 3, NOT_PADDED, bufferSize);
        return true;
    case RENDERFN_EEPROM_POS: return 0xffff; // lists are generally not saved to EEPROM
    default: return false;
    }
}


See the uppercase L in the first function name. I doublechecked it's not used elsewhere in the menu so I just deleted this function and it works.


Author: davetcc
08/04/2021 21:20:33
Could you send me emf file for that. Feel free to PM it to me if you wish. I’ll take a look at it on our Linux box.




Register / Login  |  Desktop view  |  Jump to top of page