[script] data delays
-
woodslanding
- Member
- Posts: 1327
- Contact:
Somewhere in my old setup I was using a data delay. i sure as heck didn't write it as it's all greek to me.
Just wondering what it entails to delay some data with the new script. I don't need precision.... well, here's what I need:
I use mr ray22 which is an excellent rhodes emulation. Problem is, when you change patches, you get nasty clicks on every note until all 24 have been played at least once. The easy way to do this is to lay your arm on the keyboard with the volume down. Now it plays pretty!
So I created in V4 a 'virtual arm' that, when it sees a patch change, sends out a 0 to control the volume, spits out 24 different note ons, spits out another 24 about 200 ms. later, and then about 500 ms after that (so the sound can decay) sends a 1 on the volume out.
Works great, but I used three data delay modules, and three midi scripts. Now I think I could do it all with one script pretty easily if I understood delays better.
Obviously, I'd also like to make it as efficient as possible--shouldn't use any cpu except when it sees a program change.
Thoughts??
Thanks in advance!
-e
Just wondering what it entails to delay some data with the new script. I don't need precision.... well, here's what I need:
I use mr ray22 which is an excellent rhodes emulation. Problem is, when you change patches, you get nasty clicks on every note until all 24 have been played at least once. The easy way to do this is to lay your arm on the keyboard with the volume down. Now it plays pretty!
So I created in V4 a 'virtual arm' that, when it sees a patch change, sends out a 0 to control the volume, spits out 24 different note ons, spits out another 24 about 200 ms. later, and then about 500 ms after that (so the sound can decay) sends a 1 on the volume out.
Works great, but I used three data delay modules, and three midi scripts. Now I think I could do it all with one script pretty easily if I understood delays better.
Obviously, I'd also like to make it as efficient as possible--shouldn't use any cpu except when it sees a program change.
Thoughts??
Thanks in advance!
-e
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
Something like this?
Just a tiny bit of CPU to check the doChange variable in Process.
I can't think of any way of doing something like this where somethings are going to happen after the initial trigger event that wouldn't use any CPU to check whatever needs checking (in this case the elapsed). Well, you could always put the script inside a separate (sub-)patch and turn activation on and off with some similar to keep track of the proceedings, but as long as you can use something as simple as a boolean, I doubt you'll gain anything. For all that I know, the patching needed could even use a bit more CPU.
Code: Select all
var onPM : tParameter;
var startTime : Single;
var doChange, noteOffsSent : Boolean;
...
PROCEDURE Callback (n : Integer);
begin
startTime := TimeMs;
doChange := TRUE;
noteOffsSent := FALSE;
SendVol0AndNoteOns;
end;
PROCEDURE Process;
BEGIN
IF (doChange) THEN BEGIN
IF ((TimeMs - startTime) >= 700.0) THEN BEGIN
doChange := FALSE;
SendVol1;
END
ELSE IF (((TimeMs - startTime) >= 200.0) AND (NOT noteOffsSent)) THEN BEGIN
SendNoteOffs;
noteOffsSent := TRUE;
END;
END;
END;I can't think of any way of doing something like this where somethings are going to happen after the initial trigger event that wouldn't use any CPU to check whatever needs checking (in this case the elapsed). Well, you could always put the script inside a separate (sub-)patch and turn activation on and off with some similar to keep track of the proceedings, but as long as you can use something as simple as a boolean, I doubt you'll gain anything. For all that I know, the patching needed could even use a bit more CPU.
Bjørn S
-
woodslanding
- Member
- Posts: 1327
- Contact:
Thanks, Bsork!! I will start with this, should be easy!
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
-
woodslanding
- Member
- Posts: 1327
- Contact:
BTW, Bsork, I'm digging your variable naming.
The code reads like butter!
I've realized it's not so easy in Delphi when you don't have capitalization to set things apart.....
The code reads like butter!
I've realized it's not so easy in Delphi when you don't have capitalization to set things apart.....
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
-
woodslanding
- Member
- Posts: 1327
- Contact:
So, I'm wondering if I shouldn't call sendnoteons from the process thread, as it creates midi?? Still a little fuzzy on this.
I'll try it both ways and see what works.....
I'll try it both ways and see what works.....
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
-
woodslanding
- Member
- Posts: 1327
- Contact:
well, here's my first attempt. This sends out noteONs constantly, and never sends a noteOff. Not sure what I'm doing wrong....
I'm not sure why you are checking whether noteoffs are sent. I'll look into that.
EDIT: Actually this version sends one noteOFF, but if I move the noteON method to process, I lose even that one.
I'm not sure why you are checking whether noteoffs are sent. I'll look into that.
EDIT: Actually this version sends one noteOFF, but if I move the noteON method to process, I lose even that one.
Code: Select all
// resets Mr ray's oscillators on a patch change
var startTime : Single;
var doChange, noteOffsSent : Boolean;
var i : integer;
var noteOn : TMidi;
var noteOff : TMidi;
var output : Tparameter;
var volOut : Tparameter;
var trigger : Tparameter;
// initialisation : create parameters
procedure init;
begin
Output := CreateParam('Midi Out',ptMidi); SetIsInput(Output,false);
VolOut := CreateParam('Vol Out',ptDataField); SetIsInput(volOut,false);
trigger := CreateParam('trig',ptDataField); SetIsOutput(Trigger,false);
end;
Procedure SendNoteOns;
begin
SetLength(outPut,24); // set the number of output codes
for i := 1 to 24 // loop for all input codes, for polyphonic data (chords)
do begin
noteOn.data1 := i + 12;
noteOn.data2 := 1;
noteOn.msg := 144;
noteOn.channel := 1;
SetMidiArrayValue(output,i,noteOn); // set output value
end
end;
Procedure SendNoteOffs;
begin
SetLength(outPut,24); // set the number of output codes
for i := 1 to 24 do begin
noteOff.data1 := i - 12;
noteOff.data2 := 0;
noteOff.msg := 128;
noteOff.channel := 1;
SetMidiArrayValue(output,i,noteOff); // set output value
end;
end;
PROCEDURE Callback (n : Integer); // only 1 input, trigger....
begin
if n = trigger then begin
startTime := TimeMs;
doChange := TRUE;
noteOffsSent := FALSE;
SetValue(volOut, 0);
SendNoteOns;
end;
end;
PROCEDURE Process;
BEGIN
IF (doChange) THEN BEGIN
IF ((TimeMs - startTime) >= 7000.0) THEN BEGIN
doChange := FALSE;
SetValue(volOut, 1);
END
ELSE IF (((TimeMs - startTime) >= 200.0) AND (NOT noteOffsSent)) THEN BEGIN
SendNoteOffs;
noteOffsSent := TRUE;
END;
END;
END;Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
-
woodslanding
- Member
- Posts: 1327
- Contact:
okay, this sends note ons and note offs, but still does it constantly....
Code: Select all
// resets Mr ray's oscillators on a patch change
var startTime : Single;
var doChange, noteOffsSent : Boolean;
var i : integer;
var noteOn : TMidi;
var noteOff : TMidi;
var output : Tparameter;
var volOut : Tparameter;
var trigger : Tparameter;
// initialisation : create parameters
procedure init;
begin
Output := CreateParam('Midi Out',ptMidi); SetIsInput(Output,false);
VolOut := CreateParam('Vol Out',ptDataField); SetIsInput(volOut,false);
trigger := CreateParam('trig',ptDataField); SetIsOutput(Trigger,false);
end;
Procedure SendNoteOns;
begin
SetLength(outPut,48); // set the number of output codes
for i := 0 to 23 // loop for all input codes, for polyphonic data (chords)
do begin
noteOn.data1 := i + 12;
noteOn.data2 := 1;
noteOn.msg := 144;
noteOn.channel := 1;
SetMidiArrayValue(output,i,noteOn); // set output value
end
end;
Procedure SendNoteOffs;
begin
//SetLength(outPut,24); // set the number of output codes
for i := 24 to 47 do begin
noteOff.data1 := i - 12;
noteOff.data2 := 0;
noteOff.msg := 128;
noteOff.channel := 1;
SetMidiArrayValue(output,i,noteOff); // set output value
end;
end;
PROCEDURE Callback (n : Integer); // only 1 input, trigger....
begin
if n = trigger then begin
startTime := TimeMs;
doChange := TRUE;
noteOffsSent := FALSE;
SetValue(volOut, 0);
SendNoteOns;
end;
end;
PROCEDURE Process;
BEGIN
IF (doChange) THEN BEGIN
IF ((TimeMs - startTime) >= 7000.0) THEN BEGIN
doChange := FALSE;
SetValue(volOut, 1);
END
ELSE IF (((TimeMs - startTime) >= 200.0) AND (NOT noteOffsSent)) THEN BEGIN
SendNoteOffs;
noteOffsSent := TRUE;
END;
END;
END;Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
-
woodslanding
- Member
- Posts: 1327
- Contact:
I want to try making this contingent on the value of trigger, but I cannot test for
getValue(trigger) = 1
without getting a compile error. What am I doing wrong? Doesn't getValue() return a SINGLE??
getValue(trigger) = 1
without getting a compile error. What am I doing wrong? Doesn't getValue() return a SINGLE??
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
-
martignasse
- Site Admin
- Posts: 611
- Location: Lyon, FRANCE
- Contact:
hi woodlanding,
because you are comparing a single against an integer.
hope it help
trywoodslanding wrote:I want to try making this contingent on the value of trigger, but I cannot test for
getValue(trigger) = 1
without getting a compile error. What am I doing wrong? Doesn't getValue() return a SINGLE??
Code: Select all
round(getValue(trigger)) = 1;hope it help
Martin FLEURENT - Usine Developer - SDK maintainer
-
martignasse
- Site Admin
- Posts: 611
- Location: Lyon, FRANCE
- Contact:
and for your problem of notes constantly sent,
i believe you have to set the length of outpout parameter to 0 at the end of the IF (doChange) block, or the midi message is fired each time Process is executed.
i believe you have to set the length of outpout parameter to 0 at the end of the IF (doChange) block, or the midi message is fired each time Process is executed.
Code: Select all
BEGIN
IF (doChange) THEN BEGIN
IF ((TimeMs - startTime) >= 7000.0) THEN BEGIN
doChange := FALSE;
SetValue(volOut, 1);
END
ELSE IF (((TimeMs - startTime) >= 200.0) AND (NOT noteOffsSent)) THEN BEGIN
SendNoteOffs;
noteOffsSent := TRUE;
END;
SetLength(outPut,48);
END;
END;Martin FLEURENT - Usine Developer - SDK maintainer
Sorry, I (once again) forgot to take into account that the midi output has to zeroed or else it just keeps getting sent. My bad 
It's getting late, so this is probably not the most elegant code, but it works:
Doesn't ray22 recognize the lowest octave, or why else do you start at NoteNo 12? If that's the case, you can use the loop construction 0..23 with 12 added to data1 for both Ons and Offs.There's no need to "keep counting" from where you left off.
It's getting late, so this is probably not the most elegant code, but it works:
Code: Select all
// resets Mr ray's oscillators on a patch change
var startTime : Single;
var doChange, noteOnsSent, setZeroLength, noteOffsSent : Boolean;
var i : integer;
var noteOn : TMidi;
var noteOff : TMidi;
var output : Tparameter;
var volOut : Tparameter;
var trigger : Tparameter;
// initialisation : create parameters
procedure init;
begin
Output := CreateParam('Midi Out',ptMidi); SetIsInput(Output,false);
VolOut := CreateParam('Vol Out',ptDataField); SetIsInput(volOut,false);
trigger := CreateParam('trig',ptButton); SetIsOutput(Trigger,false);
end;
Procedure SendNoteOns;
begin
SetLength(outPut,24); // set the number of output codes
for i := 0 to 23 // loop for all input codes, for polyphonic data (chords)
do begin
noteOn.data1 := i;
noteOn.data2 := 1;
noteOn.msg := 144;
noteOn.channel := 1;
SetMidiArrayValue(output,i,noteOn); // set output value
end
end;
Procedure SendNoteOffs;
begin
SetLength(outPut,24); // set the number of output codes
for i := 0 to 23 do begin
noteOff.data1 := i;
noteOff.data2 := 0;
noteOff.msg := 128;
noteOff.channel := 1;
SetMidiArrayValue(output,i,noteOff); // set output value
end;
end;
PROCEDURE Callback (n : Integer); // only 1 input, trigger....
begin
if n = trigger then begin
startTime := TimeMs;
doChange := TRUE;
noteOffsSent := FALSE;
SetValue(volOut, 0);
SendNoteOns;
noteOnsSent := TRUE;
setZeroLength := FALSE;
end;
end;
PROCEDURE Process;
BEGIN
IF (doChange) THEN BEGIN
IF ((TimeMs - startTime) >= 700.0) THEN BEGIN
doChange := FALSE;
SetValue(volOut, 1);
END
ELSE IF (((TimeMs - startTime) >= 200.0) AND (NOT noteOffsSent)) THEN BEGIN
SendNoteOffs;
noteOffsSent := TRUE;
END
ELSE IF (noteOnsSent AND NOT setZeroLength) THEN BEGIN
setZeroLength := TRUE;
END
ELSE IF (setZeroLength) THEN BEGIN
SetLength(outPut, 0);
END;
END;
END;Bjørn S
Some comments about Callback and Process:
Callback is called once for each updated input parameter in a execution before Process is called. Setting the length or value of a parameter can be done from either procedure, but any assignments done in Process will override anything called from Callback.
BTW, I really welcome the new structure: It makes for much cleaner coding. For a small script like yours, there's not much too gain, but with a lot parameters things get a lot simpler when one can fetch all or most of the data in one place, for instance:
Callback is called once for each updated input parameter in a execution before Process is called. Setting the length or value of a parameter can be done from either procedure, but any assignments done in Process will override anything called from Callback.
BTW, I really welcome the new structure: It makes for much cleaner coding. For a small script like yours, there's not much too gain, but with a lot parameters things get a lot simpler when one can fetch all or most of the data in one place, for instance:
Code: Select all
VAR pMidiIn, pMidiOut, pSwitch, pButton : tParameter;
VAR numIn : Integer;
VAR switchOn : Boolean;
...
PROCEDURE Init;
BEGIN
pMidiIn := CreateParam('midi in', ptMidi); SetIsOutput(pMidiIn, FALSE);
pMidiOut := CreateParam('midi out', ptMidi); SetIsInput(pMidiIn, FALSE);
pSwitch := CreateParam('switch', ptSwitch); SetIsOutput(pSwitch, FALSE);
pButton := CreateParam('switch', ptButton); SetIsOutput(pButton, FALSE);
...
END;
...
PROCEDURE Callback(n : Integer);
BEGIN
CASE n OF
pMidiIn : numIn := trunc(GetValue(n));
pSwitch : switchOn := (GetValue(n) > 0.0);
pButton : DoSomeThing;
...
END;
END;
PROCEDURE Process;
VAR i : Integer;
VAR m : tMidi;
BEGIN
IF (switchOn) THEN
...
FOR i := 0 TO (numIn - 1) THEN DO
GetMidiArrayValue(pMidiIn, i, m);
...
END;Bjørn S
-
woodslanding
- Member
- Posts: 1327
- Contact:
I guess I figured it might not see notes below the range of the piano. But the lower the note the longer the release, so I might want to add 60 to everything, just so there's a clean volume release.
I'll study this. I see there is a litte trickery to get the output length set to zero at the beginning....
I'll study this. I see there is a litte trickery to get the output length set to zero at the beginning....
Custom Ryzen 5900x MATX build, Win10, Fireface UFX, touchscreen
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
Custom 2 manual midi keyboard
Usine, Kontakt, Reaktor, Synthmaster, Byome, Arturia, Soundtoys, Unify
Who is online
Users browsing this forum: No registered users and 31 guests
