Welcome to %s forums

BrainModular Users Forum

Login Register

Midi Harmonizer

I need help on a Patch
Post Reply
Fléau
Member
Posts: 99
Contact:

Unread post by Fléau » 11 Jun 2012, 15:39

Hello usiners,
let's talk about a project that started in the french forum:
http://www.sensomusic.com/forums/viewtopic.php?id=3402.

actually there are 3 goal for this patch:
1- rescale a midi note to chosen scale (major,minor etc)
2- detect a played chord (ex major,major7,minor,diminished...)
3- play arpegio according to goal 1&2

Goal 1 is done:
download: midi note scaler

Image

Goal 2:
-chord database is built
-chord isolator & comparator are near to be finished

Goal 3:
waiting for goal 2 finished,
but, same as in the french forum, i'm waiting suggestions to make this arpegiator sexy!

Will give you news when the chord detector will be patched.

Now i need help from someone who script, to make it lighter and simpler.
Here is a function that is used a lot there:
remove zeros from an array and resize it.

Image

If someone could help me there it would be great.

Fléau.

caco
Member
Posts: 306
Contact:

Unread post by caco » 11 Jun 2012, 17:19

Fléau I really like the use of the dec2bin module, that is an ingenious way of storing the scale patterns :)

If nobody else has time for your script I will have a go for you tomorrow, I am learning Usine's script language at the moment so it will be good practice for me ;)

Fléau
Member
Posts: 99
Contact:

Unread post by Fléau » 11 Jun 2012, 17:53

Yes, efficient way.
I remember that module is yours, it was me and my sister (berenice) who asked for it.
That's a great module!

seamus
Member
Posts: 484
Contact:

Unread post by seamus » 12 Jun 2012, 07:03

Is it possible to have this work with chordal input? I was using the moody note scaler with chords being input into it and it constrained the notes to scale. This note scaler seems to only work on monophonic input. I would love to use yours as the scale and key options are fantastic!


seamus
Member
Posts: 484
Contact:

Unread post by seamus » 12 Jun 2012, 07:35

one interesting function that maybe could be added which i used to have on an old digitech dhp-33 harmonizer was the ability to have non-scale tones treated in different ways. I like having my lead voice be chromatic and the harmonized voices forced to scale. Non chord tones could be treated with another scaler so that for example if you were harmonizing in f dominant but you played an F# then the harmonized notes would harmonize to say a diminished scale. Im not sure how to add this feature quite yet. Still a newbie!

Fléau
Member
Posts: 99
Contact:

Unread post by Fléau » 12 Jun 2012, 07:48

It is monophonic just for the test, when scale and a key are selected you can only play degree I II III IV V VI VII,
When the chord detector will be patched you'll be able to link the tonic key to the root key, and it'll be polyphonic.

Not sure to understand, but it may be possible with a dual chord detector,
actually i didn't found a way to detect if you play a triad or a 13th so i may add a fader to limit input note number,
so you'll be able to use one seventh chord detector where you input your chord, and a 13th one
where you input your chord + additionals tones to detect the closest limited chord/scale.

Edit: midi make monophonic script is here just for my test, you can remove it, polyphony works here.

seamus
Member
Posts: 484
Contact:

Unread post by seamus » 12 Jun 2012, 08:33

http://www.sensomusic.com/forums/upload ... scaler.pat


here i added a harmonizer in front. Multiple scalers but all sharing the same presets.

Brilliant Fleau thanks for your great work!

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

Unread post by bsork » 12 Jun 2012, 09:20

caco wrote:Fléau I really like the use of the dec2bin module, that is an ingenious way of storing the scale patterns :)
Agreed! The only problem is the behaviour of the list/combo boxes when using text/value pairs, as it will jump to the first item with the chosen value when the value is repeated. Confusing, but in this case educational, as you learn that scales with different names are in fact alike.
caco wrote:If nobody else has time for your script I will have a go for you tomorrow, I am learning Usine's script language at the moment so it will be good practice for me ;)
If you don't find the time Caco, I think I can do it tonight. It shouldn't take many lines of code.
Bjørn S

Fléau
Member
Posts: 99
Contact:

Unread post by Fléau » 12 Jun 2012, 10:26

bsork wrote:The only problem is the behaviour of the list/combo boxes when using text/value pairs, as it will jump to the first item with the chosen value when the value is repeated..
agreed
bsork wrote:Confusing, but in this case educational, as you learn that scales with different names are in fact alike..
That's why i didn't removed duplicates.
I could patch an 'educational button' to switch between two list.
Here are the duplicates:
duplicate.txt
What are the ones i should keep?

Thanks for the support.

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

Unread post by bsork » 12 Jun 2012, 11:01

I'm not the right person to ask - my knowledge in this area is rather limited. Actually, the only scales I remember the names of, are standard major and minor, which makes this patch al the more interesting for me.
Bjørn S

caco
Member
Posts: 306
Contact:

Unread post by caco » 12 Jun 2012, 11:07

Here is my first version of the script to removes zero values from an array. Only had a quick test so far but it seemed to work okay so let me know what bugs you spot. Bsork feel free post a better version :)

Code: Select all

///////////////////////////////////////////////////////////////////////////////
// Function: Removes any zero values from an array 
// Version : 1.0
// Date : 12 June 2012
//////////////////////////////////////////////////////////////////////////////
// variables declaration
Var ArrayIn, ArrayOut : tparameter;
Var non_zero, i, j : integer;
// initialisation : create parameters
procedure init;
begin  
	ArrayIn:= createParam('Array in', PtArray); 
	SetIsOutput(ArrayIn,false);
	ArrayOut:= createParam('Array out', PtArray);         
	SetIsInput(ArrayOut,false);
end;

// Callback procedure
Procedure Callback(N:integer); 
begin
	if (N=ArrayIn)  then begin
		non_zero := 0;
		i := 0;
		j := 0;
		//count non-zero elements
		for i:= 0 to GetLength(ArrayIn)-1 do begin
			If  GetDataArrayValue&#40;ArrayIn, i&#41;  <> 0  then begin
				non_zero &#58;= non_zero + 1;
			 end;
		end;	
		//set output array to size of non zero elements
		SetLength&#40;ArrayOut, non_zero&#41;;
		//copy only non_zero elements to output
		for i&#58;= 0 to GetLength&#40;ArrayIn&#41;-1  do begin
			If  GetDataArrayValue&#40;ArrayIn, i&#41;  <> 0  then begin
				SetDataArrayValue&#40;ArrayOut, j, GetDataArrayValue&#40;ArrayIn, i&#41;&#41;; 
				j &#58;= j + 1;
			end;
		end;	
	end;
end;
//////////////////////////////
// main proc
//////////////////////////////
Procedure Process;
begin

end;

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

Unread post by bsork » 12 Jun 2012, 12:17

Had to take the challenge... :)

Your script works just fine, but could be a bit more efficient:

Code: Select all

Var ArrayIn, ArrayOut &#58; tparameter;
// initialisation &#58; create parameters
procedure init;
begin  
    ArrayIn&#58;= createParam&#40;'Array in', PtArray&#41;; 
    SetIsOutput&#40;ArrayIn,false&#41;;
    ArrayOut&#58;= createParam&#40;'Array out', PtArray&#41;;         
    SetIsInput&#40;ArrayOut,false&#41;;
end;

// Callback procedure
Procedure Callback&#40;N&#58;integer&#41;; 
  Var i, j &#58; Integer;
begin
    if &#40;N=ArrayIn&#41;  then begin
        j &#58;= 0;
        for i&#58;= 0 to GetLength&#40;ArrayIn&#41;-1 do begin
            If &#40;GetDataArrayValue&#40;ArrayIn, i&#41;  <> 0&#41; then begin
               SetDataArrayValue&#40;ArrayOut, j, GetDataArrayValue&#40;ArrayIn, i&#41;&#41;;
               j &#58;= j + 1;
            end;
        end;    
        SetLength&#40;ArrayOut, j&#41;;
    end;
end;
You can set the length after filling in the values, even if the new length is longer than the previous. AFAIK there shouldn't be any problems with that. I haven't done it much (if ever) with data arrays, but a lot of times with Midi arrays.

Besides, if you don't need Process - skip it. I don't know if it really matters and it's being called the engine when the procedure is empty, but in this case there's no need for it. I think you can do that with all the standard procedures: Init, Destroy, Callback and Process when they're not needed.
Bjørn S

caco
Member
Posts: 306
Contact:

Unread post by caco » 12 Jun 2012, 12:58

Thanks for the feedback bsork. Not too bad for my first proper script, after many years using C++ and R the Pascal syntax feels unnatural to me with all its begins and ends, I miss my curly braces... :)

I do like the scripts though, it was very quick to create I can see myself starting to use them now in some cases instead of SDK to save time. I have been avoiding them so far but the language is pretty easy to pick up.

I didn't realize you could write to data arrays prior to resizing them, that makes things easier. In the SDK you can set DontProcess==TRUE if you do not need the audio processing to be called, maybe scripts have something similar?

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

Unread post by bsork » 12 Jun 2012, 14:20

Not bad indeed for a first try!

...and your post reminds me that it's about time I got into the SDK. Long time since I've done much with curly braces, though, and I've never used C++, which I must admit I find quite confusing. I'm not much of an OO programmer...

Regarding DontProcess or similar, I can't recall anything like that. I've just taken it for granted that if Process isn't declared, nothing happens. Well, maybe a couple of CPU cycles to find that there's nothing to do, but not much more. Any comments from the boss?
Bjørn S

Fléau
Member
Posts: 99
Contact:

Unread post by Fléau » 12 Jun 2012, 18:45

Ok it works,
my patch was taking 0.04% cpu
caco script 0.03%
bsork script 0.02%
need to repace them all, and then 'chord detector' will be finished (it works yet)
many thanks!

need your advice:
should i make restricted scale list or should i patch a switch to chose between restricted/educational?

tanabarbier
Member
Posts: 159
Location: Mexico D.F.
Contact:

Unread post by tanabarbier » 12 Jun 2012, 19:53

Maybe I don't get the recurency problem, but I propose only one list with all the names of the same scale for each scale, both educational and practical?
like "pentatonic major / chinese mongolian"=661
etc ?
Anyway thanks a lot for this work, it's gonna be a HIT among the growing Usine community!

Fléau
Member
Posts: 99
Contact:

Unread post by Fléau » 13 Jun 2012, 15:56

@bsork:
I've found a better solution to compare chords, using your 'array find' script,
but it don't work with my array and i can't find why.
here is the workspace:
http://www.sensomusic.com/forums/upload ... %20bug.wkp

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

Unread post by bsork » 14 Jun 2012, 00:19

I'm looking into it. There's a bug when there are repeated values in the array. Probably just something really stupid, but I just can't see where the problem lies tonight... :/

If anyone else feels compelled to have a go at it - please do!
Bjørn S

Fléau
Member
Posts: 99
Contact:

Unread post by Fléau » 14 Jun 2012, 10:19

Got it!:)
BEGIN
r := -1;
IF (((lenA - startA) >= lenB) AND (lenB > 0)) THEN BEGIN
b := 0;
// bx := GetDataArrayValue(pArrB, b); THIS LINE (42 i think)
FOR a := startA TO (lenA - 1) DO BEGIN
ax := GetDataArrayValue(pArrA, a);
bx := GetDataArrayValue(pArrB, b); HAD TO BE PLACED HERE
IF (ax = bx) THEN BEGIN
IF (b = 0) THEN r := a;
b := b + 1;
IF (b = lenB) THEN BREAK;
bx := GetDataArrayValue(pArrB, b);
END
ELSE BEGIN
b := 0;
r := -1;
END;
IF ((lenA - a - 1) < (lenB - b)) THEN BEGIN
r := -1;
BREAK;
END
END;
END;
SetValue(pResult, r);
doFind := FALSE;
END; // Find
Need to learn scripting,
what is the used language?

caco
Member
Posts: 306
Contact:

Unread post by caco » 14 Jun 2012, 11:21

Was just about to post the same thing, bx does not get updated in the FOR loop.

@Fléau - The scripting language used is based on Delphi.

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

Unread post by bsork » 14 Jun 2012, 11:40

Great that you've found a solution!

I think, however, that I can make the script somewhat more efficient by doing things in another order. Will probably do it tonight.
Bjørn S

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

Unread post by bsork » 14 Jun 2012, 23:23

I've tried the suggestion, but It didn't do help anything. I've rewritten the script, and as far as I can tell, it should work now, also where there are equal values after another. It's maybe not (noticably) more efficient than the old one, but it's a little bit more compact, and I managed to avoid BREAKs, which I'm no fan of. :)

Here it is:

Code: Select all

////////////////////////////////////////////////////////////////////////////////
// ArrayFind.script
// Returns the array index where array B is first found in array A, with an
// optional start index for array A. If no matches, the result is -1.
//
// The returned index in A is the "real" index; the start offset is not 
// subtracted from the result.
//
// bSork, V2 June 2012
////////////////////////////////////////////////////////////////////////////////

VAR pArrA, pStartA, pArrB, pResult &#58; tParameter;

PROCEDURE Init;
BEGIN
   pArrA &#58;= CreateParam&#40;'array A', ptArray&#41;; SetIsOutput&#40;pArrA, FALSE&#41;;
   SetMin&#40;pArrA, -1000000000&#41;;    SetMax&#40;pArrA, +1000000000&#41;;

   pStartA &#58;= CreateParam&#40;'start index A', ptDataFader&#41;; SetIsOutput&#40;pStartA, FALSE&#41;;
   SetMin&#40;pStartA, 0&#41;; SetMax&#40;pStartA, 8191&#41;; SetFormat&#40;pStartA, '%.0f'&#41;;
   SetDefaultValue&#40;pStartA, 0&#41;;

   pArrB &#58;= CreateParam&#40;'array B', ptArray&#41;; SetIsOutput&#40;pArrB, FALSE&#41;;
   SetMin&#40;pArrB, -1000000000&#41;;    SetMax&#40;pArrB, +1000000000&#41;;

   pResult &#58;= CreateParam&#40;'result', ptDataField&#41;; SetIsInput&#40;pResult, FALSE&#41;;
   SetMin&#40;pResult, -1&#41;; SetMax&#40;pResult, 8191&#41;; SetFormat&#40;pResult, '%.0f'&#41;;
   SetValue&#40;pResult, 0&#41;;
END; // Init

PROCEDURE Find;
   VAR lenA, lenB &#58; Integer;
   VAR r, a, a2, b &#58; Integer;
   VAR bx &#58; Single;
   VAR found &#58; Boolean;
BEGIN
   r &#58;= -1;
   lenB &#58;= GetLength&#40;pArrB&#41;;
   IF &#40;lenB > 0&#41; THEN BEGIN
      b &#58;= 0;
      bx &#58;= GetDataArrayValue&#40;pArrB, b&#41;;
      a &#58;= round&#40;GetValue&#40;pStartA&#41;&#41;;
      lenA &#58;= GetLength&#40;pArrA&#41;;
      WHILE &#40;&#40;r = -1&#41; AND &#40;&#40;lenA - a&#41; >= lenB&#41;&#41; DO BEGIN
         found &#58;= &#40;bx = GetDataArrayValue&#40;pArrA, a&#41;&#41;;
         IF &#40;found&#41; THEN BEGIN
            a2 &#58;= a + 1;
            b &#58;= 1;
         END;
         WHILE &#40;found AND &#40;b < lenB&#41;&#41; DO BEGIN
            found &#58;= &#40;GetDataArrayValue&#40;pArrA, a2&#41; = GetDataArrayValue&#40;pArrB, b&#41;&#41;;
            a2 &#58;= a2 + 1;
            b &#58;= b + 1;
         END;
         IF &#40;found AND &#40;b = lenB&#41;&#41; THEN
            r &#58;= a
         ELSE
            b &#58;= 0;
         a &#58;= a + 1;
      END;
   END;
   SetValue&#40;pResult, r&#41;;
END; // Find

PROCEDURE Callback&#40;n &#58; Integer&#41;;
BEGIN
   IF &#40;n <= pArrB&#41; THEN
      Find;
END; // Callback
Hope it works for you!

I'll replace the old one in the add-ons as well.
Bjørn S

caco
Member
Posts: 306
Contact:

Unread post by caco » 15 Jun 2012, 12:06

A nice elegant solution bsork :)

Fléau
Member
Posts: 99
Contact:

Unread post by Fléau » 15 Jun 2012, 14:50

I'm about post the latest version but scripting make me sick

Code: Select all

var input   &#58; Tparameter;
var output  &#58; Tparameter;
var transpo &#58; TParameter;
var voices  &#58; TParameter;

procedure init;
begin  
 Input &#58;= CreateParam&#40;'In',ptMidi&#41;;
 Output &#58;= CreateParam&#40;'Out',ptMidi&#41;;
 transpo &#58;= CreateParam&#40;'transpo',ptDataFader&#41;;
 voices &#58;= CreateParam&#40;'voices',ptDatafield&#41;;

 SetIsInput&#40;Output,false&#41;;
 SetIsOutPut&#40;Input,false&#41;;
 SetIsOutPut&#40;transpo,false&#41;;
 SetFormat&#40;transpo,'%.0f'&#41;;
 SetIsInput&#40;voices,false&#41;;
 SetMin&#40;transpo,-24&#41;;
 SetMax&#40;transpo,24&#41;;

end;

var i            &#58; integer;
var nbOfMidi     &#58; integer;
var ReceivedMidi &#58; TMidi;
var TranspoVal   &#58; single;

//////////////////////////////
// main proc
//////////////////////////////
procedure Process;
begin
 nbOfMidi &#58;= GetLength&#40;input&#41;;  // get the number of incoming midi codes 
 if nbOfMidi > 0 
 then begin
    SetLength&#40;outPut,nbOfMidi&#41;;      // set the number of output codes
    transpoVal &#58;= getValue&#40;transpo&#41;; // get the transpo value
    for i &#58;= 0 to nbOfMidi-1         // loop for all input codes, for polyphonic data &#40;chords&#41;
    do begin
      GetMidiArrayValue&#40;input,i,ReceivedMidi&#41;; // get each code
      ReceivedMidi.data1 &#58;= ReceivedMidi.data1+trunc&#40;transpoVal&#41;; // calculate transpo
      SetMidiArrayValue&#40;output,i,ReceivedMidi&#41;; // set output value     
    end;
 end 
 else SetLength&#40;outPut,0&#41;; // nothing received, set out length to 0
end;
I added:
var voices : TParameter;
voices := CreateParam('voices',ptDatafield);
SetIsInput(voices,false);

i'd like to get
voices := nbOfMidi; (number of note on)
tried to place this line everywhere in the process but nothing happen,
what i'm doing wrong?

caco
Member
Posts: 306
Contact:

Unread post by caco » 15 Jun 2012, 15:12

I suspect the line you are looking for is

Code: Select all

SetValue&#40;voices, nbOfMidi &#41;;
This will assign the value of nbOfMidi to the parameter called voices

I do not think this will not work as you hope though as nbOfMidi will only be greater than zero for the actual BLOC (e.g 64, 128 samples etc) that you receive the MIDI messages in. After that it will go back to zero. It will not give you the number of actual MIDI messages currently switched on.

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

Unread post by bsork » 15 Jun 2012, 23:57

Counting the number of sounding notes could be done with not too many modules, but I thought that what you were after was a subset of the Transpose script in the Midi Utility pack, so I dug it up, removed most of the code and added an extra output with the number of notes:

Code: Select all

CONST BUFFER_SIZE = 128;

// MIDI channel messages
CONST NOTEOFF = Byte&#40;128&#41;;
CONST NOTEON  = Byte&#40;144&#41;;

TYPE tMidiArr = ARRAY OF tMidi;

TYPE tNoteOns = RECORD
        origChannel &#58; Byte;
        origNoteNo  &#58; Byte;
        outChannel  &#58; Byte;
        outNoteNo   &#58; Byte;
     END;

VAR pMidiIn, pMidiOut1 &#58; tParameter;
VAR pTranspose, pNumNotes &#58; tParameter;

VAR sentNoteOns &#58; ARRAY OF tNoteOns;
VAR numIn, numSentNoteOns, numOut1 &#58; Integer;
VAR transpose &#58; Integer;

PROCEDURE Init;
   VAR i &#58; Integer;
BEGIN
   pMidiIn &#58;= CreateParam&#40;'midi in', ptMidi&#41;; SetIsOutput&#40;pMidiIn, FALSE&#41;;
   pMidiOut1 &#58;= CreateParam&#40;'midi out', ptMidi&#41;; SetIsInput&#40;pMidiOut1, FALSE&#41;;

   pTranspose &#58;= CreateParam&#40;'transpose', ptDataFader&#41;; SetIsOutput&#40;pTranspose, FALSE&#41;;
   SetMin&#40;pTranspose, -48&#41;; SetMax&#40;pTranspose, 48&#41;;
   SetFormat&#40;pTranspose, '%.0f'&#41;; SetSymbol&#40;pTranspose, 'sm'&#41;;

   pNumNotes &#58;= CreateParam&#40;'num notes', ptDataField&#41;; SetIsInput&#40;pNumNotes, FALSE&#41;;

   SetArrayLength&#40;sentNoteOns, BUFFER_SIZE&#41;;

   numSentNoteOns &#58;= 0;
   numOut1 &#58;= 0;
END; // Init

FUNCTION IsNoteOn &#40;currMsg &#58; tMidi&#41; &#58; Boolean;
BEGIN
   IsNoteOn &#58;= &#40;&#40;currMsg.msg = NOTEON&#41; AND &#40;currMsg.data2 > 0&#41;&#41;;
END;

FUNCTION IsNoteOff &#40;currMsg &#58; tMidi&#41; &#58; Boolean;
BEGIN
   IsNoteOff &#58;= &#40;currMsg.msg = NOTEOFF&#41; OR &#40;&#40;currMsg.msg = NOTEON&#41; AND &#40;currMsg.data2 = 0&#41;&#41;;
END;

PROCEDURE CreateOut&#40;currMsg &#58; tMidi&#41;;
BEGIN
   SetMidiArrayValue&#40;pMidiOut1, numOut1, currMsg&#41;;
   numOut1 &#58;= numOut1 + 1;
END; // CreateOut

PROCEDURE CreateNoteOnOut&#40;origMsg, outMsg &#58; tMidi&#41;;
   VAR curr &#58; tNoteOns;
BEGIN
   WITH curr DO BEGIN
      origChannel &#58;= origMsg.channel;
      origNoteNo  &#58;= origMsg.data1;
      outChannel  &#58;= outMsg.channel;
      outNoteNo   &#58;= outMsg.data1;
   END;
   sentNoteOns&#91;numSentNoteOns&#93; &#58;= curr;
   numSentNoteOns &#58;= numSentNoteOns + 1;
   CreateOut&#40;outMsg&#41;;
END; // CreateNoteOnOut

PROCEDURE CheckSendNoteOff&#40;currMsg &#58; tMidi&#41;;
   VAR i, j &#58; Integer;
   VAR outMsg &#58; tMidi;
   VAR curr &#58; tNoteOns;
BEGIN
   j &#58;= 0;
   FOR i &#58;= 0 TO &#40;numSentNoteOns - 1&#41; DO BEGIN
      curr &#58;= sentNoteOns&#91;i&#93;;
      IF &#40;&#40;currMsg.channel = curr.origChannel&#41; AND &#40;currMsg.data1 = curr.origNoteNo&#41;&#41; THEN BEGIN
         outMsg.msg     &#58;= currMsg.msg;
         outMsg.channel &#58;= curr.outChannel;
         outMsg.data1   &#58;= curr.outNoteNo;
         outMsg.data2   &#58;= currMsg.data2;
         CreateOut&#40;outMsg&#41;;
         j &#58;= j + 1;
      END
      ELSE BEGIN
         sentNoteOns&#91;i - j&#93; &#58;= curr;
      END;
   END;
   numSentNoteOns &#58;= numSentNoteOns - j;
END; // CheckSendNoteOff

PROCEDURE CheckInput&#40;currMsg &#58; tMidi&#41;;
   VAR newMsg &#58; tMidi;
BEGIN
   newMsg &#58;= currMsg;
   IF &#40;IsNoteOn&#40;currMsg&#41;&#41; THEN BEGIN
      newMsg.data1 &#58;= newMsg.data1 + transpose;
      CreateNoteOnOut&#40;currMsg, newMsg&#41;;
   END
   ELSE IF &#40;IsNoteOff&#40;currMsg&#41;&#41; THEN
      CheckSendNoteOff&#40;currMsg&#41;;
   SetValue&#40;pNumNotes, numSentNoteOns&#41;;
END; // CheckInput

PROCEDURE Callback&#40;n &#58; Integer&#41;;
BEGIN
   CASE n OF
      pMidiIn    &#58; numIn     &#58;= GetLength&#40;n&#41;;
      pTranspose &#58; transpose &#58;= round&#40;GetValue&#40;n&#41;&#41;;
   END;
END; // Callback

PROCEDURE Process;
   VAR i &#58; Integer;
   VAR currMsg &#58; tMidi;
BEGIN
   FOR i &#58;= 0 TO &#40;numIn - 1&#41; DO BEGIN
      GetMidiArrayValue&#40;pMidiIn, i, currMsg&#41;;
      CheckInput&#40;currMsg&#41;;
   END;
   SetLength&#40;pMidiOut1, numOut1&#41;;
   numOut1 &#58;= 0;
END; // Process
There are still bits and pieces of the code left that could be removed.
Bjørn S

Fléau
Member
Posts: 99
Contact:

Unread post by Fléau » 17 Jun 2012, 17:57

First, a lot of thanks for those scripting help.
Here is the new version with the chord detector:

download:http://www.sensomusic.com/forums/upload ... onizer.wkp

Image

Next step is isolating chords according to a scale and play them,
vice versa, and then play arpeggio.

damstraversaz
Member
Posts: 159
Location: Chambéry
Contact:

Unread post by damstraversaz » 18 Jun 2012, 14:49

first thanks a lot for sharing.
I have an issue with the dec2bin module, which is not find by usine in the modules folder. does it need a additionnal pack ?
best,
Damien

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

Unread post by bsork » 18 Jun 2012, 15:18

You'll find it in the add-ons under data tools. It's called "Decimal To Binary"
Bjørn S

damstraversaz
Member
Posts: 159
Location: Chambéry
Contact:

Unread post by damstraversaz » 18 Jun 2012, 15:46

thanks !

Fléau
Member
Posts: 99
Contact:

Unread post by Fléau » 22 Jun 2012, 16:46

download:http://www.sensomusic.com/forums/upload ... onizer.wkp

Corrected a scale mistake in the chord database.
Added a 'key feedback' switch on the note scaler.
Added a chord player and a arppegio player with modulated speed.

I'm near to upload it in the addons, so all suggestions are welcome!

User avatar
nay-seven
Site Admin
Posts: 5684
Location: rennes France
Contact:

Unread post by nay-seven » 22 Jun 2012, 17:45

Really a good job
thanks a lot !

Post Reply

Who is online

Users browsing this forum: No registered users and 9 guests