Welcome to %s forums

BrainModular Users Forum

Login Register

Scripting: Newbie at work...

I need help on a Patch
Post Reply
antwan
Member
Posts: 164
Contact:

Unread post by antwan » 19 Nov 2007, 21:49

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

bsork
Site Admin
Posts: 1334
Location: Asker, Norway
Contact:

Unread post by bsork » 20 Nov 2007, 09:31

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.
Bjørn S

User avatar
senso
Site Admin
Posts: 4424
Location: France
Contact:

Unread post by senso » 20 Nov 2007, 19:06

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;
....

bsork
Site Admin
Posts: 1334
Location: Asker, Norway
Contact:

Unread post by bsork » 20 Nov 2007, 21:18

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.
Bjørn S

antwan
Member
Posts: 164
Contact:

Unread post by antwan » 21 Nov 2007, 08:22

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

antwan
Member
Posts: 164
Contact:

Unread post by antwan » 21 Nov 2007, 18:59

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

User avatar
senso
Site Admin
Posts: 4424
Location: France
Contact:

Unread post by senso » 21 Nov 2007, 19:43

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.

moody33
Member
Posts: 338
Contact:

Unread post by moody33 » 21 Nov 2007, 20:21

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.

bsork
Site Admin
Posts: 1334
Location: Asker, Norway
Contact:

Unread post by bsork » 21 Nov 2007, 21:02

@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?
Bjørn S

User avatar
senso
Site Admin
Posts: 4424
Location: France
Contact:

Unread post by senso » 21 Nov 2007, 21:27

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!

moody33
Member
Posts: 338
Contact:

Unread post by moody33 » 22 Nov 2007, 11:07

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...

bsork
Site Admin
Posts: 1334
Location: Asker, Norway
Contact:

Unread post by bsork » 22 Nov 2007, 14:54

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.
Bjørn S

antwan
Member
Posts: 164
Contact:

Unread post by antwan » 28 Nov 2007, 21:41

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

bsork
Site Admin
Posts: 1334
Location: Asker, Norway
Contact:

Unread post by bsork » 29 Nov 2007, 08:49

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).
Bjørn S

User avatar
senso
Site Admin
Posts: 4424
Location: France
Contact:

Unread post by senso » 29 Nov 2007, 09:08

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!

antwan
Member
Posts: 164
Contact:

Unread post by antwan » 30 Nov 2007, 20:07

hi,

thanks guys, worked like a charm.

antwan

Post Reply

Who is online

Users browsing this forum: No registered users and 13 guests