Overview
This script is an advanced evolution of the standard MIDI Transpose module. While it retains the core functionality of pitch shifting, it introduces an intelligent Auto-Wrap system. This feature ensures that transposed notes stay within a specific musical range (octave), effectively creating automatic inversions and smoother voice leading for generative patches and chords.
Core Functionalities
Standard Transposition: Functions exactly like the original script, shifting incoming MIDI notes by a user-defined interval (+/- 24 semitones).
Polyphonic Support: Handles multiple MIDI messages (chords) simultaneously, maintaining the integrity of Note-On, Note-Off, and Velocity data.
New Advanced Features
Dynamic Root Control: A new Root Note input allows you to define the start of your "active window." All harmonized notes will be mathematically forced to stay relative to this reference.
Intelligent Auto-Wrap: When active, the script monitors the output pitch. If a transposed note exceeds the Root + 12 boundary, it is automatically shifted down by octaves until it fits the window. Conversely, if it falls below the Root, it is shifted up.
Switchable Inversions: A dedicated Wrap Active switch allows you to toggle between "Block Chords" (standard parallel movement) and "Smart Voicing" (inversions within a single octave).
//////////////////////////
// transpose midi with optional auto-wrap
// Window defined by Root and Root+12
/////////////////////////
var input : Tparameter;
var output : Tparameter;
var transpo : TParameter;
var active : TParameter;
var root : TParameter;
procedure init;
begin
Input := CreateParam('midi in', ptMidi, pioInput);
Output := CreateParam('midi out', ptMidi, pioOutput);
transpo := CreateParam('transpo', ptDataFader, pioInput);
transpo.Format('%.0f');
transpo.Min(-24);
transpo.Max(24);
root := CreateParam('root note', ptDataFader, pioInput);
root.Format('%.0f');
root.Min(0);
root.Max(115);
// On ne met pas de .Value() ici pour éviter l'erreur
active := CreateParam('wrap active', ptSwitch, pioInput);
SetModuleColor($FF3298DB);
end;
procedure Process;
var i : integer;
var nbOfMidi : integer;
var ReceivedMidi : TMidi;
var TranspoVal : integer;
var RootVal : integer;
var HighLimit : integer;
begin
nbOfMidi := input.Length;
output.length(nbOfMidi);
if (nbOfMidi > 0) then
begin
TranspoVal := transpo.asInteger;
RootVal := root.asInteger;
HighLimit := RootVal + 12;
for i := 0 to nbOfMidi-1 do
begin
ReceivedMidi := input.asMidi(i);
ReceivedMidi.data1 := ReceivedMidi.data1 + TranspoVal;
if (active.asInteger > 0) then
begin
while (ReceivedMidi.data1 > HighLimit) do
begin
ReceivedMidi.data1 := ReceivedMidi.data1 - 12;
end;
while (ReceivedMidi.data1 < RootVal) do
begin
ReceivedMidi.data1 := ReceivedMidi.data1 + 12;
end;
end;
output.asMidi(i, ReceivedMidi);
end;
end;
end;
