Anders, 39, from Malmö, Sweden. Sample lib dev, mixing engineer, aspiring Hise developer, web-ui development & design, all-round tech-tinkerer and relapse skateboarder. Unnecessary stickler for detail. :/
Best posts made by andioak
-
RE: The world of HISE
-
Tool published: SFZ to HISE samplemaps & JSON opcodes extractor
I made a tool for myself a while ago, a translator for SFZ to HISE samplemaps that worked better than the internal one in HISE did at the time. Since then @Christoph-Hart fixed the importer and it now works better. Even so, I went ahead and made it an open source web app (standard JS) that translates SFZ into HISE samplemaps.
It also does another thing I wanted at the time I started the project and that came from another thing I was doing, which is to gather up all the opcodes into an object form so I could interface and re-work it a bit and save it as data. So this app outputs a JSON object that you can copy to clipboard with a button on the app ui to raw JSON or in a variable form. So either just the object itself
{ data }
or in avar x = { data };
.The project is now on my website, KeyPleezer.com, and you can check it out and test it out and see if it works for you. It can be used for those SFZ instruments that are in structures that HISE has issues with or where settings in the SFZ to HISE converter app can help solve the issue and get you a valid samplemap.
The fact that you get an object with the opcodes makes it possible to output other formats as well, like the DecentSampler.
I will be publishing the source and a stand-alone HTML/JS app on Github soon and then post the links here.
Until then you can test it out in the published web tool:
https://keypleezer.com/sfz-to-hise-converter/
I wrote a little manual for it as well:
https://keypleezer.com/sfz-to-hise-converter/manual/
I'm sure there are bugs remaining in it so feel free to help me test it out and find them, give feedback on features etc.
-
RE: Tool published: SFZ to HISE samplemaps & JSON opcodes extractor
Added a link to the app to the SFZ format site, now the SFZ to HISE converter is linked (and thereby HISE itself :) ) from the tools section:
-
RE: Tool published: SFZ to HISE samplemaps & JSON opcodes extractor
The open source project is accessible here on GitHub:
https://github.com/anderseklov/SFZ-to-HISE-converter
I still did not add a release yet, but will soon. Then you can download a minimalistic HTML app and keep in your book marks, work with offline etc. Or just use the live web app.
-
RE: HISE Script Coding Standards
@d-healey Very nice page, will check it out in detail. But this is new to me:
const var foo = a || b; const var bar = !c;
Very efficient.
-
RE: Cant build with IPP, but I could the last 2 yrs.
@d-healey said in Cant build with IPP, but I could the last 2 yrs.:
@andioak IPP isn't included with HISE.
Dough! Haha, no it isn´t included, you're right. IPP is just implied as a somewhat good performance enhancement addition.
Okay, I found few examples of (to me less understandable) comparisons of IPP vs FFT3W, but this one of the KissFFT and FFTW3 has some single-precision bumps of around 2-7x the speed:
http://www.fftw.org/speed/CoreDuo-3.0GHz-icc64/
I just read that the GNU GPL contains some kind of linking exception. So perhaps that can apply to using the IPP with a GNU GPL plugin.
I would worry about the opposite order here, the IPP license's reservations to be delivered within the GNU GPL. But of course, GPL-v3 is nasty in its allowances of differences in open:ness, so perhaps your worry is more warranted.
Still I would avoid including any proprietary components in a free software app.
I agree entirely.
-
RE: Creating dynamic fx's with Drag and Drop functionality in javascript?
@lalalandsynth said in Creating dynamic fx's with Drag and Drop functionality in javascript?:
Ok, as for the ids , I was thinking of having say 4 fx available per slot , then just switch which one is loaded , obviously i would need to think of having the sliders and buttons
copied between them.I know this one is quite old, but still relevant! :)
Perhaps it is more efficient having an
object
store all latest values with each knob twist or button on-off action. Then loading the new set of configured plugins into place followed by initiating the values of the current states object. The states retrieved into the plugin structure will be the latest recorded for each UI elements.Not sure all plugin states or knobs can actually be stored. I mean, it can be stored ahead of time in data inside the HISE design application, the one we use to design a plugin, but to be entered into the same strings or structures in a finalized plugin? Hopefully.
Example (calling JS/HISE
object
"currentstates"):- initiate plugin,
currentstates.plugins.plugin-in-question.control-name
stores initial values if not loaded from a preset. - twisting the knob of the plugin-in-question updates the value in
currentstates.plugins.plugin-in-question.control-name
- reordering using the drag-and-drop re-initiates the reading of the object based on released state
This approach is common in web dev and the tech stack item is called Redux.
I guess that part could be seen as pretty obvious but still, if the saving of all of a plugin's states can be done easily, the approach is simple. Perhaps the even easier thing would be to run the UI elements's UI callbacks on re-initiation.
Is it possible to run a callback from script? Or is that just possible with actual user input?
(there is also a way to just run a function that does the same, extracting the actual actions from the designated callback function, which would do the same)
- initiate plugin,
-
RE: Standalone app icon
@d-healey Okay, but the icons should be a .icns file, a multi-png icon file with all resolutions. Made with this script: (
iconutil
)# shell script for creating an icon for an application from a set of input images input_filepath="icon_name_1024_x_1024.png" output_iconset_name="outputicon.iconset" mkdir $output_iconset_name sips -z 16 16 $input_filepath --out "${output_iconset_name}/icon_16x16.png" sips -z 32 32 $input_filepath --out "${output_iconset_name}/icon_16x16@2x.png" sips -z 32 32 $input_filepath --out "${output_iconset_name}/icon_32x32.png" sips -z 64 64 $input_filepath --out "${output_iconset_name}/icon_32x32@2x.png" sips -z 128 128 $input_filepath --out "${output_iconset_name}/icon_128x128.png" sips -z 256 256 $input_filepath --out "${output_iconset_name}/icon_128x128@2x.png" sips -z 256 256 $input_filepath --out "${output_iconset_name}/icon_256x256.png" sips -z 512 512 $input_filepath --out "${output_iconset_name}/icon_256x256@2x.png" sips -z 512 512 $input_filepath --out "${output_iconset_name}/icon_512x512.png" iconutil -c icns $output_iconset_name rm -R $output_iconset_name
I mean if one is to be a good boy and future-proof the icons on mac with all the resolutions (retina, 4k, 5k, 8k etc)
So can I just use a icon.icns instead?
@Christoph-HartA large png file is sometimes not that pretty once it is downsized, can be blurry.
-
RE: vuuuu meter.... vu meter? vu meter master?
@DimitrisSP @Natanr @yall
Thanks a lot @DimitrisSP for the vu-meter. I modified it a bit to make whole integers from your png of 107 strips and set it to -100 to +6 dbFS. Also added peak values in labels for both L, R and highest of the two.
Here is that project (scriptnode 2020-08-20): LevelMeterTest--andioak-peak-values.zip
@Christoph-Hart Is there a pan-law compensation built into the Simple Gain module/plugin? To compensate for the increased value from the other channel? The values I get are steep when I pan towards one way, but it might be my programming here. (and my gain is +1, but at Left 40:ish i get around 5-6 db over the center peak, that´s about what pan law should compensate for...) (and the gif below is 7fps :) )
Here it is:
Script of this thing:
Content.makeFrontInterface(600, 500); const var LevelMeterL = Content.getComponent("LevelMeterL"); const var LevelMeterR = Content.getComponent("LevelMeterR"); const var LevelMeterLock = Content.getComponent("LevelMeterLock"); // show values as well, via label with whole integer db values. const var Label_MeterValue = Content.getComponent("Label_MeterValue"); // the peak of the strongest channel. const var Label_MeterValue_L = Content.getComponent("Label_MeterValue_L"); const var Label_MeterValue_R = Content.getComponent("Label_MeterValue_R"); // ------------ const var Pan = Content.getComponent("Pan"); const var SimpleGain1 = Synth.getEffect("SimpleGain1"); //Decay Rate const var DECAY_RATE = 0.93; //Current Values var curLevelL = 0.0; var curLevelR = 0.0; var curLevelM = 0.0; //Timer Callback const var t = Engine.createTimerObject(); t.setTimerCallback(function() { //Synth Values var LevelL = SimpleGain1.getCurrentLevel(1); var LevelR = SimpleGain1.getCurrentLevel(0); //Peak Synth Values var peakLevelL = Math.max(LevelL, LevelL); var peakLevelR = Math.max(LevelR, LevelR); var peakLevelMax = Math.max(LevelL, LevelR); //Kick Left //----------------------------------------------------------------------------- if (peakLevelL > curLevelL) { curLevelL = peakLevelL; } else { curLevelL *= DECAY_RATE; } //Kick Right //----------------------------------------------------------------------------- if (peakLevelR > curLevelR) { curLevelR = peakLevelR; } else { curLevelR *= DECAY_RATE; } //Kick Max peak for mono out or label with max peak for strongest channel. //----------------------------------------------------------------------------- if (peakLevelMax > curLevelM) { curLevelM = peakLevelMax; } else { curLevelM *= DECAY_RATE; } //Decibel Conversion //----------------------------------------------------------------------------- LevelL = Engine.getDecibelsForGainFactor(curLevelL); LevelR = Engine.getDecibelsForGainFactor(curLevelR); var LevelMax = Engine.getDecibelsForGainFactor(curLevelM); //Set Values //---------------------------------------------------------------------------- LevelMeterL.setValue(LevelL); LevelMeterR.setValue(LevelR); Label_MeterValue.set("text", (LevelMax >= -99) ? Math.round(LevelMax) : -100); // use Math.round (round up) for all except minimum value, -100. Label_MeterValue_L.set("text", (LevelL >= -99) ? Math.round(LevelL) : -100); Label_MeterValue_R.set("text", (LevelR >= -99) ? Math.round(LevelR) : -100); }); t.startTimer(30);
UPDATE: this code does what it´s supposed to, but using labels to be updated by a timer seems to crash hise and the output plugins/standalone exported instruments. Read here about it.
-
RE: How can show my image on hise?
@ustk said in How can show my image on hise?:
const var p = Content.createPath();
Looord, have mercy! Thank you for that line of code there. Riiiiight before the
p.loadFromData
, it was missing from the example in the docs in LookAndFeel, so I was chasing a ghost for around 2hrs. Hahaha.Thanks. And for the SVG Path Converter to C++ info too, I thought the JS/HTML5/CSS3 paths looked a bit different :)
-
RE: Designing / changing hise output vst basic setting panels / elements?
@Lunacy-Audio
Okay, 5 mins after, I solved this haha. Here´s how:
- Remove the paint routines inside of the:
laf.registerFunction("drawToggleButton", function(g, obj) {
- then recompile all scripts / F5.
- then delete that code as well and this line: (or your equivalent)
const var laf = Engine.createGlobalScriptLookAndFeel();
- lastly recompile and save, exit HISE and start it again. Upon next start it´s gone. But that did not happen unless I did it in exactly that order.
-
RE: Switching sample maps with radio buttons.
Okay I got a little upgrade here with 6 linked buttons. It does what radio-buttons do. One turned on turns the others off. Also, no button can ever be turned off, if it is trying to set itself to 0, we simply switch it on again.
onInit callback:
- const var all elements
- set array with elements var names
- sync array with states in 0s and 1s in arr_buttons_sw.
const var Button1 = Content.getComponent("Button1"); const var Button2 = Content.getComponent("Button2"); const var Button3 = Content.getComponent("Button3"); const var Button4 = Content.getComponent("Button4"); const var Button5 = Content.getComponent("Button5"); const var Button6 = Content.getComponent("Button6"); const var arr_buttons = [Button1, Button2, Button3, Button4, Button5, Button6]; const var arr_buttons_sw = [ [1, 0, 0, 0, 0, 0], // for button 1 [0], we set all else to 0. [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1] ];
Then the onControl callback:
for (var i = 0; i < arr_buttons.length; i++) { // loop through the 6. // for any button matching one in array list. if (number == arr_buttons[i]) { if (value == 1) { var btn_nr = arr_buttons.indexOf(number); for (var j = 0; j < arr_buttons.length; j++) { // now setting the elements all in one go to their pre-set values in the arr_buttons_sw array number presets. arr_buttons[j].setValue(arr_buttons_sw[btn_nr][j]); } } else { // we dont want the value to be able to be set to 0, cause that´s not radio-style. number.setValue(1); // just set it back to one. } } }
Here´s the new project in all its might:
-
RE: Switching sample maps with radio buttons.
Hey there, I played around with it a while and found a solution. It´s not @d-healey style, like looping through everything all efficient n stuff But it gets it done.
Note: I just made the basic Samplemap loading using
Sampler.loadSamplerMap()
, but did not make any actual radio buttons in the design, but I gathered you got that covered from Healey´s video.// onInit Content.makeFrontInterface(633, 400); // store references to the samplers. const var Sampler1 = Synth.getSampler("Sampler1"); const var Sampler2 = Synth.getSampler("Sampler2"); const var Sampler3 = Synth.getSampler("Sampler3"); // UI references const var ComboBox1 = Content.getComponent("ComboBox1"); const var boxVals = ComboBox1.getAllProperties(); // just get all properties of the combobox element, for later reference. // just printing all values of the combobox´s available properties: for (var i = 0; i < boxVals.length; i++) { Console.print("ComboBox1:s element id " + i + ": " + boxVals[i]); } // get state of combobox, on init: const var cboxState = ComboBox1.getValue(); Console.print("Current choice made in combobox: " + cboxState); // onControl ui-control: function onControl(number, value) // this needs to be copied into the onControl callback. { if (number == ComboBox1) { Console.print("ComboBox1: " + value); if (value == 1) { // loading Samplemap nr 1 for all three. Sampler1.loadSampleMap("Samplemap-1-1"); Sampler2.loadSampleMap("Samplemap-1-2"); Sampler3.loadSampleMap("Samplemap-1-3"); } if (value == 2) { Sampler1.loadSampleMap("Samplemap-2-1"); Sampler2.loadSampleMap("Samplemap-2-2"); Sampler3.loadSampleMap("Samplemap-2-3"); } if (value == 3) { Sampler1.loadSampleMap("Samplemap-3-1"); Sampler2.loadSampleMap("Samplemap-3-2"); Sampler3.loadSampleMap("Samplemap-3-3"); } } }
Here´s an upload of the full project from my hise testing, so you can load it directly, with a single sample in the all the sample maps.
radio-buttons-control-samplermaps.zip
Made using Scriptnode branch (2020-08 ish), if that´s important. On macos.
-
RE: Building HISE on macOS (10.13) errors and questions about using /auto_build/ files in hise source folder
SOLVED the issue, see last part, if you have the same issues.
-
RE: xcpretty missing from macOS build of product (the export of instrument, standalone)?
@dustbro Thanks, I saw some of these, but I thought I´d add this anyway, since the issue has not made it into the documentation yet. It should be included in the documentation on the main github page since you cannot export your instruments without it.
-
RE: Time Stretching
@d-healey said in Time Stretching:
I think for now this is beyond my C++ level. I'll come back to it again at some point unless someone else implements it first (pleeeeaaaassseeee!!!) :D
Thanks for giving this a go, David! This is indeed an attractive feature for hise! Can't wait for this to work. My C++ is much worse than yours, but perhaps not this guys:
The Audio Programmer - "Implementing a TimeStretching Library (RubberBand)":
https://youtu.be/XhmM8HZj7aU?t=1721
(It's a live stream, so watch in 1.5x speed :) , not sure it gives you more insight than you got cause it's for JUCE. Perhaps the Hise part is more difficult)
-
RE: Sympathetic resonance for piano experiment
@Christoph-Hart said in Sympathetic resonance for piano experiment:
Actually you‘ll get much better results for sympathetic resonance by using a convolution reverb with an impulse response of all strings resonating than by modelling the harmonics like this.
True story, I got that in a new Kontakt instrument coming up. The LivingRoom Upright Piano uses it for both pedal action controlled string resonances and body resonances, separately controllable. Not sure if it is more efficient too cpu-wise, but definitely more realistic and easy to make custom presets with multiple IR-samples depending on your preference. Also entirely based of the actual piano acoustics.
-
RE: Text values for output bus, effects or gain reduction - use label, paintRoutine or animated strip?
@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:
- 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(); t.setTimerCallback(function() { 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.
- 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 = []; view.setTimerCallback(function() { 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... Mixer[i].setValue(outputValue); }); 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)...
-
RE: Text values for output bus, effects or gain reduction - use label, paintRoutine or animated strip?
@ustk said in Text values for output bus, effects or gain reduction - use label, paintRoutine or animated strip?:
... I simply preview my interface in an additional floating window on the second monitor and hide the main one.
It appears that the preview in the main Hise window causes crashes when drawing permanently different components, eventually via timers...Weird with crashes, but timers kind of makes sens that they crash though, would be great with a indicator output when setting things and functions inside of the timers
Hmm, how does one make a second preview window on another monitor? I´m using mac and I´ve never found that function...
@Lunacy-Audio said in Text values for output bus, effects or gain reduction - use label, paintRoutine or animated strip?:
Strange that it crashes when setting the text. Maybe setting labels in fast timers is bad? I think if you draw the text to the panel it'll be a lot cleaner.
Yes, I think the apple crash report say that
Crashed Thread: 0 JUCE Message Thread
. However, the lineTermination Reason: Namespace SIGNAL, Code 0xb
seems to indicate that the 'signal' namespace is affected and perhaps not able to handle the load or access correct info. There are 3 separate checks for current gain factors and also text set with boolean logic in the last bit. Perhaps not easy around everything else at 30ms a pop :) But then again, all applications that show sound levels use a timer...Perhaps a panel, indeed, but then it´s the paintRoutine. Not that high on that atm, but perhaps later, for now it´ll be another slider with a transparent filmstrip of 1px slides. Done deal. And not crashing nor slow.