Some basic questions
-
agggr, I can't get it....
I have pretty simple on my taste task - take the attack sample (~0.7 sec), and sustain momentary, but sustain at -120dB then on last 0.3 sec of attack fade sus to 0dB. But it seems to me that callbacks on one event are executed consecutive, including to onNoteOff my wait function from onNoteOo, which using the timer callback.
I feel that it's not working like kontakt, and there should be way to implement such a thing, but any other thoughts bring me to the table envelopes with per-note changing the attack time and moving points (for avoide stretch of the fade area itself withtin changing attack time), that seems to me too complicated and unrelieble (more than, I can't get how to edit points on the specific attack table) :)
I feel myself so stupid.... -
function onNoteOn() { note = Message.getNoteNumber(); velocity = Message.getVelocity(); //if (lastnote = 0){ //Globals.attack = 1; //Globals.sus = 1; //}else { //}; Message.ignoreEvent(true); wait.start = 1; wait.ms = 10; Synth.startTimer(0.004); } function onTimer() { if (wait.ms != 0){ if (wait.start == 1){ wait.start = 0; } if (wait.ms == 1){ Synth.playNote(note, velocity); } wait.ms -= 1; }; };
P.S. It's just debugging code for understanding how things are working, but even here I'm confused)))
P.P.S.
take the attack sample (~0.7 sec), and sustain momentary
Why this way? From my experience momentary taking two samples produces less bugs and less code, than moving sustain noteOn in time
-
Well, Now I'm almost sure about logic and syntax, but while loop terminates.
var wait = 0; const var timer = Engine.createTimerObject(); timer.callback = function() { wait = wait - 1; if (wait == 0){ timer.stopTimer; } }; function onNoteOn() { note = Message.getNoteNumber(); velocity = Message.getVelocity(); Message.ignoreEvent(true); wait = 2; timer.startTimer(150); // in milliseconds while (wait > 0){ } Synth.playNote(note, velocity); }
-
I'm still not really sure what the purpose of this is but this should help:
<?xml version="1.0" encoding="UTF-8"?> <Processor Type="SynthChain" ID="Master Chain" Bypassed="0" Gain="1" Balance="0" VoiceLimit="128" KillFadeTime="20" IconColour="0" packageName="" views="32.rk1bzA.....B.........LUYtQFL..+O..........." currentView="-1"> <EditorStates BodyShown="0" Visible="1" Solo="0" Folded="0"/> <ChildProcessors> <Processor Type="MidiProcessorChain" ID="Midi Processor" Bypassed="0"> <EditorStates BodyShown="1" Visible="0" Solo="0" Folded="1"/> <ChildProcessors/> </Processor> <Processor Type="ModulatorChain" ID="GainModulation" Bypassed="0" Intensity="1"> <EditorStates BodyShown="1" Visible="0" Solo="0" Folded="1"/> <ChildProcessors/> </Processor> <Processor Type="ModulatorChain" ID="PitchModulation" Bypassed="1" Intensity="0"> <EditorStates BodyShown="1" Visible="0" Solo="0" Folded="1"/> <ChildProcessors/> </Processor> <Processor Type="EffectChain" ID="FX" Bypassed="0"> <EditorStates BodyShown="1" Visible="0" Solo="0" Folded="1"/> <ChildProcessors/> </Processor> <Processor Type="SineSynth" ID="Sine Wave Generator" Bypassed="0" Gain="0.25" Balance="0" VoiceLimit="128" KillFadeTime="20" IconColour="0" OctaveTranspose="0" SemiTones="0" UseFreqRatio="0" CoarseFreqRatio="1" FineFreqRatio="0" SaturationAmount="0"> <EditorStates BodyShown="1" Visible="1" Solo="0" GainModulationShown="1"/> <ChildProcessors> <Processor Type="MidiProcessorChain" ID="Midi Processor" Bypassed="0"> <EditorStates BodyShown="1" Visible="1" Solo="0" Folded="0"/> <ChildProcessors> <Processor Type="ScriptProcessor" ID="Time Delay" Bypassed="0" Script="reg id; reg note; reg velo; reg waitTime = 0.5; //ms reg timePassed;function onNoteOn() { 	Message.ignoreEvent(true); 	 	note = Message.getNoteNumber(); 	velo = Message.getVelocity(); 	 	timePassed = 0; 	Synth.startTimer(0.05); } function onNoteOff() { 	Synth.noteOffByEventId(id); } function onController() { 	 } function onTimer() { 	timePassed = timePassed + 0.05; 	 	if (timePassed >= waitTime) 	{ 		id = Synth.playNote(note, velo); 		Synth.stopTimer(); 	}	 } function onControl(number, value) { 	 } "> <EditorStates BodyShown="1" Visible="1" Solo="0" contentShown="1" onInitOpen="0" onNoteOnOpen="0" onNoteOffOpen="0" onControllerOpen="0" onTimerOpen="1" onControlOpen="0"/> <ChildProcessors/> <Content/> </Processor> </ChildProcessors> </Processor> <Processor Type="ModulatorChain" ID="GainModulation" Bypassed="0" Intensity="1"> <EditorStates BodyShown="1" Visible="0" Solo="0"/> <ChildProcessors> <Processor Type="SimpleEnvelope" ID="DefaultEnvelope" Bypassed="0" Intensity="1" Attack="5" Release="10" LinearMode="1"> <EditorStates BodyShown="1" Visible="1" Solo="0"/> <ChildProcessors> <Processor Type="ModulatorChain" ID="Attack Time Modulation" Bypassed="0" Intensity="1"> <EditorStates BodyShown="1" Visible="0" Solo="0" Folded="1"/> <ChildProcessors/> </Processor> </ChildProcessors> </Processor> </ChildProcessors> </Processor> <Processor Type="ModulatorChain" ID="PitchModulation" Bypassed="0" Intensity="0"> <EditorStates BodyShown="1" Visible="0" Solo="0" Folded="1"/> <ChildProcessors/> </Processor> <Processor Type="EffectChain" ID="FX" Bypassed="0"> <EditorStates BodyShown="1" Visible="0" Solo="0" Folded="1"/> <ChildProcessors/> </Processor> </ChildProcessors> <RoutingMatrix NumSourceChannels="2" Channel0="0" Send0="-1" Channel1="1" Send1="-1"/> </Processor> </ChildProcessors> <RoutingMatrix NumSourceChannels="2" Channel0="0" Send0="-1" Channel1="1" Send1="-1"/> <macro_controls> <macro name="Macro 1" value="0" midi_cc="-1"/> <macro name="Macro 2" value="0" midi_cc="-1"/> <macro name="Macro 3" value="0" midi_cc="-1"/> <macro name="Macro 4" value="0" midi_cc="-1"/> <macro name="Macro 5" value="0" midi_cc="-1"/> <macro name="Macro 6" value="0" midi_cc="-1"/> <macro name="Macro 7" value="0" midi_cc="-1"/> <macro name="Macro 8" value="0" midi_cc="-1"/> </macro_controls> <MidiAutomation/> </Processor>
-
Thank You! I assume this code, thank God, something like this have worked, but are you using timer for stopping callback for a while?
This is the main purpose of wait))
For continue executing callback after "wait" function. Many of concepts in my head are still connected with time -
The timer goes around and around once started, I'm just counting how much time has passed and performing an action after a time limit has reached, once that happens I'm stopping the timer. Can't you use an envelope for playing attack samples?
-
Can't you use an envelope for playing attack samples?
Afraid, not. Or i have to have 3 envelopes, 0.7 sec for mixing with attack, 0,5 with gliss, 0.3 with leg
And Every time i want to change the main mixing properties should be edited three times...
Or i have poor logic)in KSP I would make something like this:
on init declare constant $attack_time := 700000 declare constant $leg_time := 300000 declare constant $gliss_time := 500000 declare constant $fade_time := 100000 end on on note if (<first note trigger>) <attack groups allowing> $attack_id := play_note () <sus groups allowing> $new_id := play_note() change_vol($new_id,0) {if i not mistake} wait ($attack_time - $fade_time) change_vol ($new_id, <0dB lvl>) fade_out ($attack_id,$fade_time,1) fade_in ($new_id,$fade_time) end if {+some other stuff is not included The same with leg and gliss} end on
-
I think you could do it with a table envelope. Or use 3 samplers
-
Or use 3 samplers
for sustain? The better to ave 3 envelopes, i think, but the problem of wasting time is here...
-
It really depends on how you're laying out other things like RRs and Dynamics but I see no reason why you could have 4 samplers (3 was a typo), one for attacks, one for sustains, one for legatos, and one for gliss. They could each have their own envelopes. Or you can one sampler with 3 envelopes and change the attack/release time on the fly.
-
I have dedicated samplers for every phase. But The point is I need different attack delay (not attack time) on sustain depends on attack, leg, or gliss triggering.
And it's quite simple example... May be i'm trying to make things too complicated... -
What do you mean by attack delay? - I think I'm not understanding correctly
-
look. If I use delay event function with 200 ms delay, and take a note shorter than 200 ms, i'll get stucking note, because note off came earlier than note has started.
Even this code doesn't works in this casevar exit = 0; function onNoteOn() { exit = 0; if (exit == 0){ Message.delayEvent(Engine.getSamplesForMilliSeconds(200)); } } function onNoteOff() { exit = 1; }
And such problems will be worse with midi-routing instead of global events. So the better practise on my taste is take everything we need at one moment, just "mute" some things for a while. Than fade in. But if these notes are off yet they would not fade in because of they are not already exists) Simple, transparent logic. But in this case on every mixing event we need fade_in delay. It can be produced by the table envelope. But for several different mixing types we need different delay with the same fade_in (attack) time.
So just one envelope with changing attack time will not work both for 300ms and for 700ms, attack (fade_in) time will be very different in this case.
And it's just note events. More complicated logic - more request for exact timing... -
well. lets try to understand how the timer works.
There's audio thread,which is executed one time per sample, timer function (callback) gets worldclock, or samples from start and is called every amount of samples. If i not mistake...
I don't think KSP behind logic works different. Just need to understand how does it came back to the callback.
I was thinking of null while loop, but it's terminated by too many iterations, i think...
Maybe there's a little bit more elegant solution? I really afraid of making garbage from the timer callback... especcially if some unpredictable usage will be produced -
AAAA) getUptime!
I was confused by the "seconds" word in the API, but it uses ms -
Yeah that confused me too :)
-
emmm.... The same problem with while loop. Even don't know who could expect)))
Well, it seems, the unique timer is the best solution at the moment) -
A key difference to KSP is that there is no wait() instruction. Instead you delay events using
Message.delayEvent()
. The problem with stuck notes can be solved by delaying the note off command with the same amount (it's hardly noticeable on note off commands).-
Don't use the
Engine.createTimerObject()
for audio stuff. This is running in the GUI thread and has absolutely no predictability or accuracy. -
There are scripting callbacks for adding volume fades. Check out
Synth.addVolumeFade()
. -
the
onTimer
callback runs in the audio thread and has sample accuracy.
Thanks for the hint, I'll fix the
getUptime
doc in the API... -
-
Ok, I think, the last question in this direction))
How about JUCE API? Can it work inside the script processor? -
can't find are reg global, and if not, 32 per plugin or 32 per script?