Text values for output bus, effects or gain reduction - use label, paintRoutine or animated strip?

  • @andioak Hi man and as you suffered from crashes about all this stuff(Value meters with Labels) i suffered also...(i had come to a point that i was pressing save in every additional step i was doing in order not to loose the new step)...the difficult thing was that i had/have to use in my project the Level Meters and the Labels showing the peak values for my hole mixer (16 tracks + a Mastertrack and if Hise let me work till the end of my Drumming Library i will need about 50 more for the internal mic mixers)...i tried many different senarios to avoid crashes (by the way now i don't have crashes or if i have its happening very rarely in a point that i don't know if it is caused anymore by the labels and level meters or from anything else...the whole project became very hudge and rather heavy...anyway coming again to the point)

    I tested your project and it behaves exactly as it was happening to me...the only difference between our approach is that you use the labels to show the values until the values go down to -100 and i from the other side use them to show the peak values...so if a hit is louder it pushes the label to a greater value and stays there until it will be kicked by an even louder hit again...as it happens in all DAWS (Cubase, Logic etc)...of course if the user press the mouse on that value(label) it clears the value to -100 ...see example below


    I am using a different panel for the level meters and a different panel for the labels and also use the internal timers of these panels and not the Engine timer object (Maybe it is not the case but it worked for me)

    Anyway i made for you this modification to your project and i send it so you can test and see if it fixed (maybe not)

    The snippet is

    HiseSnippet 2507.3oc4Z8taaiiDWJIZ2F2lCsE8.1ORTrevYQZhsaZRKB1stwNYubqUigb1tWOr.oJRz17prnfDc9yUTf9vbOH8K26w8Hz6I3tgT+iRV1QwHo21aSAZhHmY3LC+weCIk55SsvAATeE0kO5BOrh5cz5cgKaXqglDWkCZqndWsN3SwN5XF1+Hb.SY2K7LCBv1JppK9iboTWdIEwOe546Z5X5ZgSaRQ4UThEtCYDgk1Z2l+DwwYeSa7QjQRRuYyCrntsnNzwfGsnVMEOSq2ZN.+RStXKnon9U6YSXT+dLSFNPQcoco1WzaH8L2P4eEIfbhCl+PckdfgBadepiM2i4spzZHwwtabjGnnnp0MMOrXXd3AZ5DaRR6x4CdGnTMjyGpKLK2qtr6Uq7tmpj6sTn6cOsdV9DOVZObe61ZG3BSS8Mgo.Y2JTVkE9m2WqEEjvks9Hy2h22GdHQipaUq1ZnmTq1p6rRkUprwFGMDi5Z5hcPvjBCh+.DCZR.GPB7P.xz0VzHHmK1ekJfjALzol9nTTSnM9dT7PO.yZQG4QcgGp9vbx8vKazMOA6DHOPc66L6QHVfHSWjK1oDtWGg9EosQIz1XpZ2gZ81xL7fXIIGT.fo.63LFCyAAnyvNNqgNkXhb34GzYD1PzYCoNXDAL6.rOx9jH4WOiavE+Xw.7JduS2QxIH3JHvO3SIdXy2hn8E+c.CvTC.ZBj0PNjvYczrFti6T5A73Ix+4Evn71xHJSFkMejzOYgH.vY53JS2IfT8Hi7bvbZw5fdBpTtV60uO1BTQp6j4x1XKyKPF.ggrgZuWqW75iMdwQ6A1o15O6wQR2ZruOL5HQb.qC3xZM1WfS5HDs1NYa0nvV0SZUrXCng8QsLcbNAHb4sj5ILPx8bGPbwqa4iA2TH7gm723QDOH1XC15AXln4XSTs+XWKFg5Vc0UpjaI9rE9cbCJRbIwHJcECODkRhhYjvLhn6p0AXIJiFFWhFB5NtNarQWNPVdnSMEGim3.5lvr5HyyqF1xZQtl7PmHuwDxaDIuQ7.mSCcyym5XXDCZ9IBPZzA2mE54O557mPehzGUUJp+gTT1p7tQn2E9KTF3WpF6D1864+BXrwSUou66k.6oZkDkFjACuYBSTAQpgTjZLsH0PNRMJYjZLsHMzOhhV9rufPsO0GMh5RQzwLD72RD6ijkYRF2OSYJtmllqzmVtRWNWA5Txrk9zwEgYKf1jvyH.27ovNQ.1iaFLBe7Rf2Q7f.GRzvGrO0myqruoErsupoqQ1QRSiqfl4XEjXDJqEzSIz5gYRLYWy4lXhBosnvY1EiW0BxBgaCJmHP3h3youOjXahJELS+vZEUebs3R1argndd7VP6wF2ue1hiEVcLzEi2kSAUDE92kzud19WoR7lKuzhZHX6RR9Q1I3LtVB0+rKzs1kTHLDFjszRwiS99VaBuZ0choo3+eVZ.Ia9CEkrWMdocxZbzTlSJxl6DqTDQYJkQQjFRlqH5iDqLAxM1EJ8hr74lI2tJGQT8gL74rGtVjYsoigS+cDsGym3Nnf7d3rVdvhwjfEiqDXo1k.VpMUvhwL.KFS.VLJEXwnPvhQ4.KFECVLJDrTF3hwb.WLlK3hwrfKFWE3hQAvEcXuBShSzuVIUlNNQeF3D8IvI5kBmnWHNQub3D8hwI5yMNQeNvI5yENQeF3jqBJQOCJg6aQUYSqYkVd8I0BKVm9u35WHp6KoL7gPgrJuqxxUdeET9t52uv93Ga1m53.luntCG3YnXU2wiNA6uV3EWjHnh5RYukMsoeKaxWBnU3o3kDj5dfKgcnG1cZ28lRzQ+UTT+5HuBDkItCt+Pzcv0ygXi8UH1JpqHcYocTDtc5sa95OpbEMgw7YB4qrkesQ4sxmddYrhlF.RxqZTFQV0UhTU.UEZdes7v1XybKsGUuFr0oxXkGnMYM0qI6XLoc94CZaxL4W1ZzLNfB7v9LBGfo1FeJwBGd0qKq0FG7VF0SQcgjaCRQsR1wWr.SL92SK2tZUNWNedg7CmLH9xuqnUeqs2d6F0ehBggGIem3oO2HrgyH1rgIl4SdMGh4mYNoEzIM4LFw13NZ0q8jsd1VatUssg0RRwv8KIvVJ.Z2TJ.91l8INifSjR7NXj4.vTHs2003v+7dsN538OrS68LdepcV2ycfBrDmSb4EjXkO9WalMfTta9.5Muo4H4W7vq+HTwI8wuoY.C60i72yf4CfiIPNmiqQ16pLhXa6f6RCHbNGoWAwGsw8MG6DdHE4gfekqGAowcomGl1GQsifCBJcEt.Bs5R8FCniuRieAMJdl7BnRY4IADJx8VRlAo38OkcNnDYuqmoo7If+2LmHmx+ZMwsEcUy4KWdpzzP5C6Nan+2NibJ2TSIuBYkbSfMJXB7JFf29RX4kln9U4npUSu3hgGHPfR6NjmjMGwGOdWKqE+t+lEJ30QXlvQcZy2JW04uox8VQKduNSizE3Fylt+vulOc27maNe7x4HcebsmtUiFOcSfzcwImaJUYTofXGo4oOnmOHZmOHT1TTCPpjGF1CkYxKirOT0qG6BGwBZC7fwNl9Rkiti1lM19o0eVsZOs1jyNRoYkxDYEVZWJ1dfLF76xSn05xiso33EFjYyC2DwlLY8GN32nw1jui46poSsAyvx95u4K9i5fupU98LyeWxtvp4KjYytQdm3k0cumVWByZXw96BE3uvN.uo82nuvfUzBeqfoN6RZ6+W9L+4Dbqju5iDhcgqjkoeJexGu4e38uedariYl72ujEQ+5lE7Qgb.+N6Yco.FMe1ewrg7hk6rcEDlKUZHBOjPew.ouulHk+kjCKfDe43v2ku6jeC3tFzwLh6.cSXGh7MI+RXyh.wuEtU3a5ie0GpKvqZD9bM9ybGpG10V7v+A9Ipy57mUi5rdbmxojGDlRts1uXdJV7ZvEYi+n349T+QneD6h844p5WGeEXdk9q.6PKF3BG4a5F3QCv0ksbt9ZH2WaLaraVwCaJiT7vaeH7jj6VMiargbi.rHiwfmyXIchzlX9WOeOWds2dXHZrOLvBBVdtSNS0crS.Vr5ntrhoM2Pt47biKUNtwun+3297sujEKm6dIETWN1GCqetGTnygBsDybKNGabqYWFwuAeugTWhkLlx.Cq9GL.mA2TX.8BFyDNgpztnMvNXy.r7oT6Pbwl95gmbedxE0KetXVyWeiVn6h3q8Q++w9IW72k6mr7qPA5wemTU8ywXLxzxmdrU38eyW5cKQKPb6J9ZoWVSm+Lpd7kcqowO93Hf.+XKKN53QP9oXcZLG5734PmMmCcdxbnyVygNaOG57zYpCu14KFyniBw+PCc2S7VGTUC2pfXofx+EHNYGrD

    and i hope it will work for you!!!...check it and tell me about!

  • What would be the best timer approach ?

    • Engine timer for all meters
    • One panel timer for all meters
    • Or one panel timer per meter

    Also I am not sure using a timer is the best approach to detect the peaks, especially for high transient content like percussion. In 30ms you have the time to miss the real transient...

  • @ustk I wonder about the best timer approach also... I feel (it doesn't mean that i for sure know) that using Engine timer for all meters value labels and animations is probably leading to more crashes because i faced that option in my project...
    Maybe it should be a good option to use one panel per meter but then if someone have to use a lot of meters and value labels its getting dangerous(i remember i read somewhere in another topic where @Christoph-Hart told that you are ok with about 100 different timers) but this number is not so big as it sounds...(imagine a drumming instrument with every kit element independent on the mixer and 2 meters for each track (left, right)...so for a 17 track mixer you have already 34 timers...if you use value labels that they also need a timer we go to 68...and if you go further to create independent microphone mixers for each drum element (because for example a snare recording and the final sound contains usually these different mic sources: top, bottom, oh, room, the bleed to the other mics, and the compressed signal...so a mic mixer for the snare should use 6 tracks...so 6 timers for meters and 6 more for value labels)...so in this option it is not that difficult to pass the 100 timers...

    Thats why i thing that maybe the best approach is to divide logicaly all your stuff to different categories and put them in different panels(Maybe about 10-20) and use the timer of every different panel

    Anyway from the moment that i followed this option i dont have any crashes or i have very rarely a crash that is probably not happened for sure from timers (it could happen from any other cause...)

    My big question in all the subject was...is...and probably will be...Should we somehow stop the timers?...Because i dont feel safe when i thing that the timers are running endless...that "smells" a possible crash to me...but how to stop that kind of timer?...
    In different senarios when we need a timer for an animation things are more controllable...we simply stop the timer when the animation finishes (or when we like to stop) and we coding to begin the timer again when for example we press a certain button
    But with level meters it is not possible using this way...For a moment i thought that i found the solution to stop timers and fire them again in the "on note" callback when a key is pressed...and it was a logical thought but i had a lot of crashes...
    Maybe a logical contition should be:
    "if all values of a panel == -100...stop the timer"
    else start the timer...
    For sure i have to test it

    The funny thing is that i have read so many times in different posts about timers but till now i didn't have a clear opinion about stopping or not timers

  • Just throwing out a wild idea, but this might do something. If you don't need precision in your Synth timer (note: this is different from the Engine timers you created), you can call Synth.deferCallbacks(true); which will defer the callbacks to the message thread instead of the audio thread. More on that functionality here.

    You could try updating all of your panels in the onTimer() callback with the setting above and see how it runs. Or you could even just try setting that to true first and see if it helps 🤔

  • @Lunacy-Audio Hi my friend...I have already called Synth.deferCallbacks(true); and maybe it is one of the reasons that i dont have any crashes now...although i can not be sure because i had tried many different options...Sorry that i forgot to mention that...

    Another cure that i probably suspect is the fact that i changed the declaration for the values of the labels...
    In my early attempts i declared them as reg values (and i think that they were more accurate) and at some point i changed them to var...
    Things are now complicated enough to my project so i am really not sure what was the cure... and because i have a long way to go till the end (i say again "if Hise allow me to go till there") i just continue having in my mind that using different panels with their timers instead of the Engine timer...calling Synth.deferCallbacks(true); and using var instead of reg for my value labels is ok for now

    Maybe the easiest test would be to call Synth.deferCallbacks(false); and if i will have crashes means that this was maybe the cure

  • @Lunacy-Audio said in Text values for output bus, effects or gain reduction - use label, paintRoutine or animated strip?:

    Just throwing out a wild idea, but this might do something. If you don't need precision in your Synth timer (note: this is different from the Engine timers you created), you can call Synth.deferCallbacks(true); which will defer the callbacks to the message thread instead of the audio thread. More on that functionality here.

    After some more reading it´s clear that the audio thread should be kept as clean as can be. Instead I would probably use a timer on the audio-thread that simply probes all values into an array, that is then processed on the message thread with another timer that has the "option", NOT a requirement, to process and view information. This is my theory:

    1. on audio thread: use a timer to probe all channels and store values in 5ms intervalls. But with an option to fail and move to the next channel, in a for-loop style manner, like:
    const var allChannels = [channel1, channel2, channel3, channel4]; // fill with your desired channels.
    const var currentMixerValues = []; // latest value array that we will fill with latest values from mixer gain-probe.
    	// the currentMixerValues array can also house 10 or more previous values (using a multi-dimensional array/sub-arrays), for use with RMS or loudness-values.
    const var t = Engine.createTimerObject();
    	for (i in allChannels) {
    		local level = allChannels[i].getCurrentLevel(1);
    		if (level) {
    			// if level returns true, aka not undefined, store the result in...
    			currentMixerValues[i] = Engine.getDecibelsForGainFactor(level);
        ClipIndicator.setValue(LevelMax > 0); // boolean, 1 is red, slider second state.
    t.startTimer(5); // start audio level probe timer for all of the mixer values. 

    1. Use the Message thread to probe the values from the previous fast timer on the audio thread. This one updates message-thread, a.k.a. "user interface thread", instead, with new values, but only every 50 ms. This way we get smooth values, and we could additionally get Loudness or RMS values as well from previous probe saves, if we save it to a multi-dimensional array, like currentValues[i][j] = value;, or anything alike.
    const var view = Engine.createTimerObject();
    const var previousVal = [];
    	for (i in allChannels) {
    		local level = allChannels[i].getCurrentLevel(1); // for the Left Channel only here, or mono, if you got that.
    		if (level != undefined) {
    			if (level > -99) {
    				// if level returns true, aka not undefined, store the result in...
    				outputValue = currentMixerValues[i];
    			} else {
    				outputValue = -100;
    			previousVal[i] = value; // also, store values in an array for next time a value prove fails:
    		} else {
    			outputValue = previousVal[i]; // for all undefined, use the last probe value. 
    	// then print it to your mixer-part or output panel...
    view.startTimer(50); // start message thread timer at 50ms intervals. 

    @Lunacy-Audio How would I use the different audio / message threads for this? The manual gives us:

    But be aware that you can't defer only selected callbacks of a script (there's a "all or none"-policy for deferring)...

  • So I think if you set deferCallbacks to true, it will affect the MIDI callbacks only. The Synth timer is different than the Engine timers you create with Engine.createTimerObject(). You'd use this call instead Synth.startTimer(double seconds) and put your logic in the onTimer callback of your MIDI processor. I believe other timers are on the message thread already? I'm not totally sure, but worth experimenting.

  • @DimitrisSP Yeah, you should always use var for all graphics-related stuff. You only get 32 reg variables per namespace, so that might have been creating issues.

  • @Lunacy-Audio said:

    So I think if you set deferCallbacks to true, it will affect the MIDI callbacks only.

    Guessing you mean Synth.deferCallbacks(true); here, and in that case the manual says that :

    ... the other callbacks ( onNoteOn , onNoteOff , onController , onTimer ) live in the audio-thread.

    Which means they live in the audio thread and get deferred to the message thread.

    This deferring from one thread to another, it seems to be a per-node/processor basis. As in "ScriptNode". So perhaps only info true for the ScriptNode branch?

    So if my main interface.js is running in "normal mode", with no deferring - i could then use another script processor in another part of the instrument structure to be deferring it´s internal callbacks to the message thread, thus saving the audio thread from excessive work ?? @Christoph-Hart

    On another note, there must surely be a list of all the values already in hise, running and ready to be read, with all values currently active, right?

    Otherwise, perhaps a internal structure that updates a list of values upon a certain percentage of changes would be in order. Like a "ping" whenever a value changes like 0.4db or something. I think that´s already in JUCE, if it´s as good as they say 🙂

  • @DimitrisSP said in Text values for output bus, effects or gain reduction - use label, paintRoutine or animated strip?:

    Maybe a logical contition should be:
    "if all values of a panel == -100...stop the timer"
    else start the timer...

    Yes, we want to stop anything at times we don´t need it. But on the other hand it will have to be started again once a sample reaches a certain value. Which cannot be known unless we probe the values in a timer. Catch 22. 😕

    So at the time we got sound to process (using cpu) we also have to start the timer. And when it´s off ... well no stress, I guess... 🙂

    If we got x amount of channels, we have to always probe x amount of channels. That´s almost all we would need to do at a very fast rate. Except for transforming the values into gainFactors. Which is a calculation. So the calculation could be set to only have to be made if we have a value change. Or if it´s above -100. But that requires all x channels to be probed first.

    Anyway I understand your fear of "infinite timers", I definitely share your concern there 😕

Log in to reply