Change panorama position of a noteOn Message
-
Can we have a function like change_pan() (known from K Script)?
Coming from Kontakt, I used to give my instruments a SPREAD knob. In the noteOn callback I would use the function
change_pan($EVENT_ID, ($EVENT_NOTE) * $spread, 0)
The noteNumber of a message gets multiplied by the value of my SPREAD knob. This way, each higher note will move its panorama position a little more away from the lower.
-
-
This post is deleted! -
@d-healey said in Change panorama position of a noteOn Message:
https://forum.hise.audio/topic/2315/change-specific-samples-pan?_=1678119958650
yeah thats about modulating the output of the sampler with a random value - this thread seems to me to be more about assigning specific notes to specific positions...unless I'm misunderstanding this.
-
@Lindon Yes, you understood correctly.
-
Yeah I think this would be a useful addition as well.
-
This would be really cool! I'm looking forward to develop a keyboard mapped synthetic tom that I made in Kontakt. And I found this feature by accident but it turned out to be a very crucial parameter of this instrument.
-
@Frankbeat if you are using a sampler, you can do this but it's not recommended to do it in the NoteOn callback, but you could make a function to spread the pan for each sample in the sampler and save this in the sample map.
Or you could connect the function to a "spread" knob and set it but not while playing.I use this script for one of my sampled instruments, it's only 16 notes and each note has it's own pan knob, but you could modify this script to your likings of course
// Pan -------------------------------------- inline function onPanKnbsControl(component, value) { // Selects all samples Sampler1.selectSounds(""); // get number of samples selected local NUMSelected = Sampler1.getNumSelectedSounds(); // lookup array (note numbers) local indexList = ["48", "50", "52", "53", "55", "57", "59", "60", "62", "64", "65", "67", "69", "71", "72"]; for (i = 0; i < NUMSelected; i++) { local index = PanKnbs.indexOf(component); local root = Sampler1.getSoundProperty(Sampler1.Root, i); Console.print(root); if (root == indexList[index]) { Sampler1.setSoundProperty(i, Sampler1.Pan, PanKnbs[index].getValue()); } } } for (p in PanKnbs) { p.setControlCallback(onPanKnbsControl); }
-
@ulrik Wow… thank you! I will have to investigate this but no, I'm not dependent on using the onNoteOn callback for making it happen… Only purpose is to be able to set the stereo width across the keyboard. So, your example reads very promising on first glance. I'll report!
-
@Lindon said in Change panorama position of a noteOn Message:
@d-healey said in Change panorama position of a noteOn Message:
https://forum.hise.audio/topic/2315/change-specific-samples-pan?_=1678119958650
yeah thats about modulating the output of the sampler with a random value - this thread seems to me to be more about assigning specific notes to specific positions...unless I'm misunderstanding this.
If I remember correctly you can use a simple gain module and change the balance knob per note.
-
@Frankbeat I would do it something like this
-
@ulrik said in Change panorama position of a noteOn Message:
@Frankbeat I would do it something like this
Thank you very much!
What is that Timer Object for? Is it a workaround to omit a call from onNoteOn? -
You need a stereo fx with a scripted voice start modulator.
-
@Frankbeat you don't need the timer, it's just there for the visual meters in this example.
-
@ulrik If I want to apply the same panorama settings to a Sampler2, would this be a more complex operation?
I have tried to just duplicate the setSoundProperty call like:Sampler1.setSoundProperty(i, Sampler1.Pan, pan); Sampler2.setSoundProperty(i, Sampler2.Pan, pan);
But that doesn't work. It makes the knob have no effect anymore.
-
@Frankbeat with the same knob?
Can I see your code? -
@ulrik Yes, both with the same knob. Here is the function (script references for Sampler1 and Sampler2 are given, but not shown here):
const spreadKnb=Content.getComponent('spread'); inline function onSpreadKnb(component, value) { Sampler1.selectSounds(''); local NumSelected = Sampler1.getNumSelectedSounds(); local sampleRoots = []; for (r = 0; r < NumSelected; r++) sampleRoots.push(Sampler1.getSoundProperty(Sampler1.Root, r)); sampleRoots.sort(); local lowestNote = sampleRoots[0]; local highestNote = sampleRoots[sampleRoots.length - 1]; local range = highestNote - lowestNote; local centerNote = lowestNote + range/2; local step = 150 / range; // Note numbers of both maps are: // 45,46,47,48,49,50,51, 52, 53,54,55,56,57,58,59]; // Spread from the center and out for (i = 0; i < 59; i++) { pan = (-(52-sampleRoots[i])) * value; Sampler1.setSoundProperty(i, Sampler1.Pan, pan); Sampler2.setSoundProperty(i, Sampler2.Pan, pan); } }; spreadKnb.setControlCallback(onSpreadKnb);
-
@Frankbeat You can't have the same variables for both samplers, you have to duplicate them and also have a separate for-loop for the Sampler2 samples
also Sampler2.selectSounds(''); -
@ulrik Alright, now it works… Thank you very much, again!
-
Changing the sample properties like this might lead to a few edge case issues (eg. if you load a sample map in a preset and then change the pan it might cause order-of-initialization issues), also it's a very heavyweight operation so you can't automate it.
The stereo FX with scripted voice start modulator solution looks like this:
HiseSnippet 1431.3oc2X0saSbDEd1jLoXCkBnnpJ0aFg5ENTvX2BoUBghyeFYAArxF9oWglr6wwixtyrc1wgXPU8l97zWgxiPeDZeC3Mn8Lyt1dcvJXaU.Q8EIdNybly2424bbasJ.RSUZhWo86m.DuKP86KMc2pKWHIs1l3cQ5t7TCnYYj1reBOMEBIddKdOKAuRKQbedy5axi3x.XDIB4IJQ.7.QrvLhZ6F2WDE0jGB6KhKb5a0nUfRtkJR0CwyhzZjDdvQ7CgGxsGaAJwa4cBEFk12vMPJdlMUg886pdgL67OQjJNHBrKpS7wKJiLYqthnv1Cz0TBwi1djluXlluBcWQnXH8QVfK41fMhih1.uENKHUeFfjWAHsTFjtL0OPKRLi1whmySaIQGRGNZpKBkryR7dMcKEd.ooZL+HnoFWLjgJqUq10Y3eV8Nc5ICLBkjojOTYfGIqrZ4WUtT4eoL6za0oyD2yJFsJJBzSbaq2UeVLVQ1K9.Pec1w7ndvvChp+31zkmNaZPlVW3fJYKov7nDHecSUTn0VY+9a6AH4lMquHGg3QMNOwEy8D9QhPPSD3k7Yz6KUGTm3.ewXdxiasM2vGbM3MhRIAzFgUY71FNFyIxbvknaCoGYTItyFmnjV46c92oPOYj.EM5ObwqOrQpou0zrr6fjXQXXDzVkJrl9QL8Wq2QDEmZvquULlhQ7tB8wo.KD5v6EYXoGgA+QB4QP39JWtmANAQ14n9IZfGRRFX3Zgn5Knt77rsPjlv0XJKFxY2bHKj2N.GSsTg8h3lwy2rEVx2vh5hA41HYIpM8KV3YFRBqclIgSKDuLssvDzcxXbgIfQLX38AFyKc84zc5zABLi.3RzlOadqSM8h+hYh+7TegDbua3D9W5VydJ+XfcOPBZqwq9Y7zweNsOcjL0Oc7n.CJ980bYZhJcrK1GhE6iYZoEIhA+M0vOum0aVj9VJtdha8l0ahJ4D4wma5ocgEaDq5IMiEFr339gkltZaimQT37S3gjk9H711+MoUeDy7G642RCvnuHNIB1QdLDgUvcX7JXIaWMxATGOvdWkTkzUIEAE856AXk1CODzEw9DUnMLFromQTVowdPDvKFA+MMd.F4w0ncBlSawr2JxD8WeEMCtLa1H6S2J1K9+5J1i4NoYxuL0GedFTnLsB+B4KYMe13gys4EJS+SMdpHDqwWfvG9XtKQQLw93WiX4LL9048nk0.jgqMCwrCtmt0n2IZ2Tjnh3ZaeD4Mzuvut.EecK0f8IqYY2js4N1cYCZzmG5nT4pY6d0qyvt7wd7KWtPW2ifXkiseskLDNw008MuIqIfYGLSWfIwN9YI4cLxpXIsKpyXShrfHD6rWfOAy5hsRy3LMzAiavWtYFEycQCuBjYSWN1JoUhPnaCmbWkwkgrz.dDvDFKi2nNqZ0pr5kKEoPxH+5XrmUTAqjK5pGBF6nHOzMwPkUY2fs1spVaU1Mc++N3jCVguQRRTemjRcFhxkFbUW6tErb1a6I111qr5.Ns7LzVIAHL0BLMfujKQ8LdX7V1vJrC.yK.Pxp4Tl542AptNqyA.iiPQfpMOk4bdboSUcXKKWanMV0YjwoZ4R4Bsx.n+sr5VM8ZrZUu8cN0jT49TUxocoy1nZy3.YycV9LNh0vQGdOLi0Ed2REGxh5YEV+AeY5Ft5M+A5gS7EuzA4Wsxueu+9k+15wE63kPh4mTLsOsWmNhSbSZMqSlQ1S0yHjGtKGYxhYLIwGaDN.vplRIDkZg+BVqe15ZCTGePF5V7O3m7MqaW6kuY8Aa9AQFw7.s54AYwE15smyQAiPjteAnRzcsqYCm4lRqUsl0MHddPf8IzaTmPlLOe2bvy2OG7bq4fmaOG7r1bvyOLG77imIO1gG1nmQEm8TLRn8Nt7ROucjbrjf6cNx+xakGYp
relevant code (you might need to scale the range according to what you want):
function onVoiceStart(voiceIndex) { // Fetch the note position (the Message class will hold a reference to // the note on that started the voice) and scale it to -1 ... 1 local normPos = (Message.getNoteNumber() - 64.0) / 64.0; // Apply the spread normPos *= SpreadKnob.getValue(); // the function needs to return a modulation value between 0 and 1 // that will be applied as constant to the stereo position of the voice. return (normPos + 1.0) * 0.5; }