GNMIDI script examples

GNMIDI Professional can modify one or more MIDI files according to a script program.
This page shows some examples that can be used with GNMIDI Professional 3.46 or higher.

Examples

copy measures within a MIDI song

// (c) Günter Nagler 2025 GNMIDI script
// 
// this script contains functions for copying a part of a midi file to an other position
// do not use it for copying setup measure at beginning of song (this part should only be once in a midi file)
// do not copy to a position before setup measure (near begin of song) if it contains MIDI reset initialisations
// call function copyunits instead if you want to copy an units range part

function copyunits(fromunit, tillunit, insertatunit)
{
   if (tillunit <= fromunit)
      throwexception("error: tillunit must be greater than fromunit");
   var copiedunits = tillunit - fromunit;
   var moverangelistunits = insertatunit - fromunit;
   var movelaterunits = +copiedunits; 
   
   var rangelist = song.collectevents("startunit", ">=", fromunit, "startunit", "<", tillunit);
   var laterlist = song.collectevents("startunit", ">=", tillunit);
   foreach (var ev in laterlist)
   {
      if (ev.type == EVENTTYPE_HEADER)
         continue;
         if (ev.hasend)
             ev.setnoteunits(ev.startunit + movelaterunits, ev.endunit + movelaterunits);
         else
             ev.startunit += movelaterunits;
   }
   var duplicatelist;
   foreach (var ev in rangelist)
   {
       if (ev.type == EVENTTYPE_HEADER)
          continue;
      if (ev.type == EVENTTYPE_TEXT)       println("orig: ",ev.event2string());
       var dupev = ev.copyevent(song, song.events.size());
       if (dupev.hasend)
          dupev.setnoteunits(ev.startunit+moverangelistunits, ev.endunit + moverangelistunits);
       else
          dupev.startunit += moverangelistunits;
       if (dupev.type == EVENTTYPE_TEXT)       println("new: ",dupev.event2string());
       dupev.copyevent(song,song.events.size());
       
   }
}

function copymeasures(fromnr, count, insertbeforenr) // do not use fromnr value 1 
{
   if (count <= 0)
      throwexception("error: invalid measure count used");
   if (fromnr <= 0)
      throwexception("error: invalid fromnr (used must be 1 or higher)");
   if (insertbeforenr <= 0)
      throwexception("error: invalid insertbeforenr (used must be 1 or higher)");
   var fromunit = song.unitatmeasure(fromnr);
   var tillunit = song.unitatmeasure(fromnr + count);
   var insertatunit = song.unitatmeasure(insertbeforenr);
   copyunits(fromunit, tillunit, insertatunit);
}

var copyfrommeasurenr = 9; // change this to a value greater than 1
var copymeasurecount = 3;  // change this to a value greater than 0
var copytobeforemeasurenr = 12; // change this to a value greater than 1
copymeasures(copyfrommeasurenr, copymeasurecount, copytobeforemeasurenr);

find MIDI songs longer than 3 minutes

// (c) Günter Nagler 2025 GNMIDI script
// the script calculates song duration and writes file name and duration into GNMIDI logfile if duration is longer than value of longerthanseconds variable 
// it does not produce a midi file output

var longerthanseconds = 3 * 60;  // replace 3 against a minutes number or 3 * 60 against a seconds number

var durms = song.timeat(song.lastunit());

if (durms > longerthanseconds*1000)
    logmessage(input, " is longer: ", time2shorttext(seconds2time(durms/1000))); // result is in GNMIDI log file

lasttoolstate = "IGNORE";// do not produce output files

interpolate tempo within a MIDI song (fade tempo)

// (c) Günter Nagler 2025 GNMIDI script
//
// change tempo within a given range dynamically between firstbpm and lastbpm
// inserts tempo changes every stepunit (default: measure) if necessary

var firstunit = 0;
var lastunit = song.lastunit();

var firstbpm = 120;
var lastbpm = 40;
var stepunit = song.getresolution() * 4;

// bpm values must be in a correct range
if (firstbpm < 40)
  firstbpm = 40;
if (firstbpm > 300)
  firstbpm = 300;
if (lastbpm < 40)
  lastbpm = 40;
if (lastbpm > 300)
  lastbpm = 300;

var oldtempoevents = song.collectevents("type", "=", EVENTTYPE_TEMPO);
foreach (var ev in oldtempoevents)
{
   song.deleteevent(ev);
}
var bpmatunit;
var curbpm = -1;
for (var unit = 0; unit < lastunit; unit+= stepunit)
{
    // interpolate tempo 
   //(bpmatunit - firstbpm) / (lastbpm - firstbpm) = unit / lastunit;
   bpmatunit  = round(((lastbpm - firstbpm) * unit) / lastunit) + firstbpm;
   if (curbpm == bpmatunit)
     continue; // do not insert twice
   
   song.inserttempo(1,unit,bpm2microsecperbeat(bpmatunit));
   curbpm = bpmatunit;
}