Page 1 of 1

Posted: 19 Nov 2007, 21:49
by antwan
Hi there,

I'm taking a journey into the realms of scripting in Usine. Hands up anyone who cares to help a complete amateur!

I've spent an evening intensively looking through the forum, at script examples and the manual and I'd say I've gotten somewhere from square one but still have mileage to cover :)

I'm doing a small exercise for myself and I have a couple of questions...

First of all:
What am I trying to accomplish?
A script that takes in Midi, looks for midi notes from the range 60-71, and maps note ons and offs for each note in that range to their own little on/off switch output.

Secondly, a few questions:
1) Is this the sort of idea that is smart to carry out by scripting?
2) Could someone have a look at my code and tell me what they see... I can see it works as I intended but the script looks very long and complex to me... maybe there's something I could learn in simplifying it - and making it better coding?

Feel free to smile, as I said, I'm a first-timer!

ps. the msg, data1 & data2 outputs are there just to... you know.... monitor what's going on...

Code: Select all

//////////////////////////
// Remaps each midi note from range 60-71 to triggers
/////////////////////////
// parameters declaration

var input   : Tparameter;

var msg     : Tparameter;
var data1   : Tparameter;
var data2   : Tparameter;

var trig1   : Tparameter;
var trig2   : Tparameter;
var trig3   : Tparameter;
var trig4   : Tparameter;
var trig5   : Tparameter;
var trig6   : Tparameter;
var trig7   : Tparameter;
var trig8   : Tparameter;
var trig9   : Tparameter;
var trig10  : Tparameter;
var trig11  : Tparameter;
var trig12  : Tparameter;

// initialisation : create parameters
procedure init;
begin  
 Input := CreateParam('In',ptMidi);
 msg := CreateParam('msg', ptdataField);
 data1 := CreateParam('data1', ptdataField);
 data2 := CreateParam('msg', ptdataField);
 trig1 := CreateParam('trig1', ptSwitch);
 trig2 := CreateParam('trig2', ptSwitch);
 trig3 := CreateParam('trig3', ptSwitch);
 trig4 := CreateParam('trig4', ptSwitch);
 trig5 := CreateParam('trig5', ptSwitch);
 trig6 := CreateParam('trig6', ptSwitch);
 trig7 := CreateParam('trig7', ptSwitch);
 trig8 := CreateParam('trig8', ptSwitch);
 trig9 := CreateParam('trig9', ptSwitch);
 trig10 := CreateParam('trig10', ptSwitch);
 trig11 := CreateParam('trig11', ptSwitch);
 trig12 := CreateParam('trig12', ptSwitch);
  
 SetIsOutPut(Input,false);
 SetIsInput(msg, false);
 SetIsInput(data1, false);
 SetIsInput(data2, false);
 SetIsInput(trig1, false);
 SetIsInput(trig2, false);
 SetIsInput(trig3, false);
 SetIsInput(trig4, false);
 SetIsInput(trig5, false);
 SetIsInput(trig6, false);
 SetIsInput(trig7, false);
 SetIsInput(trig8, false);
 SetIsInput(trig9, false);
 SetIsInput(trig10, false);
 SetIsInput(trig11, false);
 SetIsInput(trig12, false);
 
end;

// Global variables

var nbOfMidi     : integer;
var Miditmp      : TMidi;
var trigger1     : integer;
var trigger2     : integer;
var trigger3     : integer;
var trigger4     : integer;
var trigger5     : integer;
var trigger6     : integer;
var trigger7     : integer;
var trigger8     : integer;
var trigger9     : integer;
var trigger10    : integer;
var trigger11    : integer;
var trigger12    : integer;

//////////////////////////////
// main proc
//////////////////////////////
begin

nbOfMidi := GetLength(input);  // get the number of incoming midi codes  
 if nbOfMidi > 0 
 then begin
    GetMidiArrayValue(input,0,Miditmp);  
    setValue(msg,MidiTmp.msg);
    setValue(data1,MidiTmp.data1);
    setValue(data2,MidiTmp.data2);

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 60)
	 then begin
	    trigger1 := 1;
	    SetValue(trig1, trigger1);
	end

	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 60)
	 then begin
	trigger1 := 0;
	SetValue(trig1, trigger1);
	end
	
	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 61)
	 then begin
	    trigger2 := 1;
	    SetValue(trig2, trigger2);
	end
	
	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 61)
	 then begin
	trigger2 := 0;
	SetValue(trig2, trigger2);
	end

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 62)
	 then begin
	    trigger3 := 1;
	    SetValue(trig3, trigger3);
	end
	
	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 62)
	 then begin
	trigger3 := 0;
	SetValue(trig3, trigger3);
	end

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 63)
	 then begin
	    trigger4 := 1;
	    SetValue(trig4, trigger4);
	end

	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 63)
	 then begin
	trigger4 := 0;
	SetValue(trig4, trigger4);
	end	

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 64)
	 then begin
	    trigger5 := 1;
	    SetValue(trig5, trigger5);
	end
	
	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 64)
	 then begin
	trigger5 := 0;
	SetValue(trig5, trigger5);
	end

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 65)
	 then begin
	    trigger6 := 1;
	    SetValue(trig6, trigger6);
	end
	
	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 65)
	 then begin
	trigger6 := 0;
	SetValue(trig6, trigger6);
	end

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 66)
	 then begin
	    trigger7 := 1;
	    SetValue(trig7, trigger7);
	end
	
	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 66)
	 then begin
	trigger7 := 0;
	SetValue(trig7, trigger7);
	end

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 67)
	 then begin
	    trigger8 := 1;
	    SetValue(trig8, trigger8);
	end
	
	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 67)
	 then begin
	trigger8 := 0;
	SetValue(trig8, trigger8);
	end

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 68)
	 then begin
	    trigger9 := 1;
	    SetValue(trig9, trigger9);
	end
	
	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 68)
	 then begin
	trigger9 := 0;
	SetValue(trig9, trigger9);
	end

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 69)
	 then begin
	    trigger10 := 1;
	    SetValue(trig10, trigger10);
	end
	
	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 69)
	 then begin
	trigger10 := 0;
	SetValue(trig10, trigger10);
	end

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 70)
	 then begin
	    trigger11 := 1;
	    SetValue(trig11, trigger11);
	end
	
	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 70)
	 then begin
	trigger11 := 0;
	SetValue(trig11, trigger11);
	end

	if (MidiTmp.msg = 144) and (MidiTmp.data1 = 71)
	 then begin
	    trigger12 := 1;
	    SetValue(trig12, trigger12);
	end
	
	if (MidiTmp.msg = 128) and (MidiTmp.data1 = 71)
	 then begin
	trigger12 := 0;
	SetValue(trig12, trigger12);	
	end

end

end.
thanks a million for your help!

/antwan

Posted: 20 Nov 2007, 09:31
by bsork
First of all, I would like to say that if this is your first attempt, it's a good one.

I haven't tried your script (sorry, at work), but it could easily be simplified a bit to at least make it more CPU-friendly. Before I get into details, I'd like to add that the simplest way of creating a note-message-to-switch functionality in Usine would be to use MIDI learn on switches, but I guess you already knew that.

Since you're creating a lot of switches, using an output array would be the most effective and the program could have been quite a bit shorter. Without changing the structure of your program, you could for instance drop the triggerX variables (unless you're planning to expand the script of course) - you might as well just enter 0 and 1 directly into the trigX outputs. Then you could also skip the BEGIN/END pairs of the IF-THEN since you're only having one statement executed.

One thing you haven't done, is to loop through the incomming MIDI messages. If you've used the unpack feature on the MidiIn module, I guess that would work ok, but if not you could get into trouble when hitting several keys simultaniously. There are numerous examples of looping through MIDI messages in the scripts you've already have had a look at.

It might not be relevant to you, but you should also have in mind that a NoteOn with velocity = 0 (msg=144, data2=0) should also be treated as a NoteOff.

---


Here's an (untested!) example that should accomplish the same as your script using an output array, which can be accessed using various Usine modules.

Code: Select all

// initialisation : create parameters
procedure init;
begin  
 Input := CreateParam('In',ptMidi);
 msg := CreateParam('msg', ptdataField);
 data1 := CreateParam('data1', ptdataField);
 data2 := CreateParam('msg', ptdataField);
 trigArr := CreateParam('triggers', ptDataArray);
 SetLength(trigArr, 12);
  
 SetIsOutPut(Input,false);
 SetIsInput(msg, false);
 SetIsInput(data1, false);
 SetIsInput(data2, false);
 SetIsInput(trigArr, false);
end;

// Global variables

var nbOfMidi     : integer;
var Miditmp      : TMidi;
var i            : integer;
var index        : integer;

//////////////////////////////
// main proc
//////////////////////////////
begin

nbOfMidi := GetLength(input);  // get the number of incoming midi codes  
 if nbOfMidi > 0 
 then begin
    for i := 0 to nbOfMidi - 1 do begin
       GetMidiArrayValue(input, i, Miditmp);  
       setValue(msg,MidiTmp.msg);
       setValue(data1,MidiTmp.data1);
       setValue(data2,MidiTmp.data2);

       if &#40;&#40;MidiTmp.msg = 144 or MidiTmp.msg = 128&#41; and MidiTmp.data1 >= 60 and MidiTmp.data1 <= 71&#41; then begin
          index &#58;= MidiTmp.data1 - 60;
          if &#40;&#40;MidiTmp.msg = 144 and MidiTmp.data2 = 0&#41; or MidiTmp.msg = 128&#41; then // NoteOff
             SetDataArrayValue&#40;trigArr, index, 0&#41;;
          else
             SetDataArrayValue&#40;trigArr, index, 1&#41;;
       end;
    end;
  end;
end.

Posted: 20 Nov 2007, 19:06
by senso
perfect script Bsork!
If you prefer standard switches as outputs, easier for patching, you can use an array of parameters:

Code: Select all

var trigs  &#58; array of Tparameter;

procedure init;
var i &#58; integer;
begin  

... // create other params here

  setarraylength&#40;trigs,12&#41;;
  for i &#58;= 0 to 11 
  do begin
     trigs&#91;i&#93; &#58;= CreateParam&#40;'trig'+inttostr&#40;i+1&#41;, ptSwitch&#41;;
     setisInput&#40;trigs&#91;i&#93;, false&#41;;
  end;
....

Posted: 20 Nov 2007, 21:18
by bsork
Ooops, I had forgotten that way of doing it! Guess I'm a bit hung up on using array modules all the time...

I also forgot to initialize the values, which Senso remembered.

Posted: 21 Nov 2007, 08:22
by antwan
hi guys,

thanks for your replies, i'm right now solving another patch but after I get it done, I'll get back to learning scripting and have a good look at your tips. When I do, I will probably have more questions about your codes. Till then! Thanks,

antwan

Posted: 21 Nov 2007, 18:59
by antwan
Hello,

okay so I tried to follow both of your advice, but apparently did something wrong > it's giving a type mismatch. here's what i ended up with:

Code: Select all

//////////////////////////
// Remaps each midi note from range 60-71 to triggers
/////////////////////////
// parameters declaration

var input   &#58; Tparameter;

var msg     &#58; Tparameter;
var data1   &#58; Tparameter;
var data2   &#58; Tparameter;

var trigs  &#58; array of Tparameter;

// initialisation &#58; create parameters
procedure init;
var i &#58; integer;
begin  
 Input &#58;= CreateParam&#40;'In',ptMidi&#41;;
 msg &#58;= CreateParam&#40;'msg', ptdataField&#41;;
 data1 &#58;= CreateParam&#40;'data1', ptdataField&#41;;
 data2 &#58;= CreateParam&#40;'msg', ptdataField&#41;;
  
 SetIsOutPut&#40;Input,false&#41;;
 SetIsInput&#40;msg, false&#41;;
 SetIsInput&#40;data1, false&#41;;
 SetIsInput&#40;data2, false&#41;;

 setarraylength&#40;trigs,12&#41;;
  for i &#58;= 0 to 11 
  do begin
     trigs&#91;i&#93; &#58;= CreateParam&#40;'trig'+inttostr&#40;i+1&#41;, ptSwitch&#41;;
     setisInput&#40;trigs&#91;i&#93;, false&#41;;
  end;
end;

// Global variables

var nbOfMidi     &#58; integer;
var Miditmp      &#58; TMidi;
var i            &#58; integer;
var index        &#58; integer;

//////////////////////////////
// main proc
//////////////////////////////
begin

 nbOfMidi &#58;= GetLength&#40;input&#41;;  // get the number of incoming midi codes  
 if nbOfMidi > 0 
 then begin
    for i &#58;= 0 to nbOfMidi - 1 do begin
       GetMidiArrayValue&#40;input, i, Miditmp&#41;;  
       setValue&#40;msg,MidiTmp.msg&#41;;
       setValue&#40;data1,MidiTmp.data1&#41;;
       setValue&#40;data2,MidiTmp.data2&#41;;

       if &#40;&#40;MidiTmp.msg = 144 or MidiTmp.msg = 128&#41; and MidiTmp.data1 >= 60 and MidiTmp.data1 <= 71&#41; then begin
          index &#58;= MidiTmp.data1 - 60;
          if &#40;&#40;MidiTmp.msg = 144 and MidiTmp.data2 = 0&#41; or MidiTmp.msg = 128&#41; then // NoteOff
             SetDataArrayValue&#40;trigs, index, 0&#41;;
          else
             SetDataArrayValue&#40;trigs, index, 1&#41;;
       end;
    end;
  end;
end.
where did i go wrong?
thanks

antwan

Posted: 21 Nov 2007, 19:43
by senso
there is a couple of wrong details in the parenthesis of the IF condition.

Also, dont forget that 128 = NOTE OFF
and 144 with velocity = 0 gives also a NOTE OFF

Code: Select all

//////////////////////////////
// main proc
//////////////////////////////
begin

 nbOfMidi &#58;= GetLength&#40;input&#41;;  // get the number of incoming midi codes  
 if nbOfMidi > 0 
 then begin
    for i &#58;= 0 to nbOfMidi - 1 do begin
       GetMidiArrayValue&#40;input, i, Miditmp&#41;;  
       setValue&#40;msg,MidiTmp.msg&#41;;
       setValue&#40;data1,MidiTmp.data1&#41;;
       setValue&#40;data2,MidiTmp.data2&#41;;
  
       if &#40;&#40;MidiTmp.msg = 144&#41; or &#40;MidiTmp.msg = 128&#41;&#41; 
       and &#40;MidiTmp.data1 >= 60&#41; and &#40;MidiTmp.data1 <= 71&#41; 
       then begin
          index &#58;= MidiTmp.data1 - 60;
          if &#40;MidiTmp.msg = 128&#41; 
          or&#40;&#40;MidiTmp.data2 = 0&#41; and &#40;MidiTmp.msg = 144&#41;&#41;
          then // NoteOff
             SetValue&#40;trigs&#91;index&#93;, 0&#41;
          else
             SetValue&#40;trigs&#91;index&#93;, 1&#41;;
       end;
    end;
  end;
end.

Posted: 21 Nov 2007, 20:21
by moody33
Great !

I need the same script but with Midi Notes Output rather than On/Off switches...because I need the velocity output.

Anyone for scripting this? Thanks.

Posted: 21 Nov 2007, 21:02
by bsork
@Antwan: Sorry that I made a mistake with the IFs. In fact, if I had used my own programming "style", I would've used even more parantheses than Olivier....

@Moody33: Are you looking for a script that filters all MIDI messages except NoteOns and NoteOffs between Note no X and Note no Y?

Posted: 21 Nov 2007, 21:27
by senso
parenthesis often a nightmare...

@antwan: if you write

if MidiTmp.msg = 144 or MidiTmp.msg = 128

for most compiler it is ambiguous because it can interpreted as

if MidiTmp.msg = ((144 or MidiTmp.msg) = 128)

and generates a compilation error because 144 is not a boolean...
It's tricky, but for the first time, not my fault!

Posted: 22 Nov 2007, 11:07
by moody33
bsork wrote:@Moody33: Are you looking for a script that filters all MIDI messages except NoteOns and NoteOffs between Note no X and Note no Y?
Yes, absolutely. I want to filter each notes of an octave. But i 'm bad in script...

Posted: 22 Nov 2007, 14:54
by bsork
Unless someone else chimes in to help you, I will look into it. I'm a sick and want some sleep, so not now...

You could try to use modules though; filter Note messages, check note number values and use a PassEventFlow module when in the right interval. If you do, please tell whether you fixed it.

Posted: 28 Nov 2007, 21:41
by antwan
hi,

what's the proper way to script a trigger to come out of one of the ouputs?
i.e. lets say we have an output in the script module called "trigger" and under some condition I want a rapid 1 and then 0 to come out from "trigger".

thanks,

antwan

Posted: 29 Nov 2007, 08:49
by bsork
Senso might correct my on this, but what I do is to have a SetValue(trigger, 0) early in the procedure - before any statements that might call SetValue(trigger, 1).

Posted: 29 Nov 2007, 09:08
by senso
yes bsork but it can cost a lot to set all triggs to 0 all the time.
We ca use a flag 'Need_Reset : boolean'

Code: Select all

//////////////////////////////
// main proc
//////////////////////////////

//--------------------
var Need_Reset &#58; boolean;
//--------------------
begin
  if Need_Reset 
  then begin
     need_reset &#58;= false;
     for i &#58;= 0 to 11 do SetValue&#40;trigs&#91;i&#93;, 0&#41;;
  end;

 nbOfMidi &#58;= GetLength&#40;input&#41;;  // get the number of incoming midi codes  
 if nbOfMidi > 0 
 then begin
    for i &#58;= 0 to nbOfMidi - 1 do begin
       GetMidiArrayValue&#40;input, i, Miditmp&#41;;  
       setValue&#40;msg,MidiTmp.msg&#41;;
       setValue&#40;data1,MidiTmp.data1&#41;;
       setValue&#40;data2,MidiTmp.data2&#41;;
  
       if &#40;&#40;MidiTmp.msg = 144&#41; or &#40;MidiTmp.msg = 128&#41;&#41; 
       and &#40;MidiTmp.data1 >= 60&#41; and &#40;MidiTmp.data1 <= 71&#41; 
       then begin
          index &#58;= MidiTmp.data1 - 60;
          if &#40;MidiTmp.msg = 128&#41; 
          or&#40;&#40;MidiTmp.data2 = 0&#41; and &#40;MidiTmp.msg = 144&#41;&#41;
          then // NoteOff
             SetValue&#40;trigs&#91;index&#93;, 0&#41;
          else begin
             SetValue&#40;trigs&#91;index&#93;, 1&#41;;
             need_reset &#58;= true;
          end;
       end;
    end;
  end;
end.
not tested but should work!

Posted: 30 Nov 2007, 20:07
by antwan
hi,

thanks guys, worked like a charm.

antwan