Jump to content

SCRIPT: Event Counter


Dewdman42

Recommended Posts

EventCounter

EventCounter.pst.zip

eventcounter.jpg.209a489db5a4b083329e6be726b6f2f4.jpg

Here is a Utility script which can be used to measure the midi traffic being funneled through any single instrument channel. LogicPro has midi buffer limitations which limit the number of midi events that can be sent to any given instrument channel during any one single Process Block. The time period of a process block is generally related to the audio buffer size. This script will display on the GUI a numeric value showing the maximum number of midi events that were processed within any one given Process Block during the current or most recent transport play.

 

There is also an option for logging to the Scripter window how many events occurred in each Process Block, and optionally displaying all the empty Process Blocks too. Process block start and end times are identified by BEAT:TICK

 

START:  1:0           END:  1:22    -   1 Events
START:  1:468         END:  1:490   -   5 Events
START:  1:959         END:  2:21    -   5 Events
START:  2:467         END:  2:489   -   2 Events
START:  2:957         END:  3:19    -   2 Events
START:  3:465         END:  3:487   -   2 Events
START:  3:956         END:  4:18    -   5 Events
START:  4:464         END:  4:486   -   4 Events
START:  4:954         END:  5:16    -  10 Events
START:  5:462         END:  5:484   -  10 Events

 

Usage

  1. Place an instance of Scripter, with this script loaded, on each instrument channel that you want to monitor.
    channelstrip.jpg.b894414f85e0296d26fb547f0f007820.jpg
  2. Open the Scripter gui and configure whether you want logging of process Blocks or just observe the MaxEvents slider value on the GUI, which will be updated as the transport plays.
    eventcounter.jpg.209a489db5a4b083329e6be726b6f2f4.jpg
  3. When using the logging options, you can copy and paste the data into a spreadsheet to see interesting statistics, the Show Empty Blocks option will show all Process Blocks, even the ones with no midi events. This would be most suitable, for example, to plot a graph in a spreadsheet; however be advised it will generate a lot of lines of output in the Scripter window and may take a while to flush it all after hitting stop.

 

Here is the actual Script.

 

//
// Channel Event Counter v1.0
//
// The purpose of this script will be to display the max number
// of midi events that have passed through the channel within a 
// single process block.  Logging options are availble which
// appear in the bottom of the Script Editor window when enabled.
//
//=============================================================

//===== Customization Options =====

var midiBufferSize = 512;
var maxFlush = 20;

//========================
// variable inits
//========================

var NeedsTimingInfo = true;

var maxEvents =  0;
var current = 0;
var currentEnd = 0;
var currentStart = 0;
var updateFlg = false;


//==================
// callbacks
//==================

function HandleMIDI(event) {
   event.send(); // send midi thru
   doStats(1);
}

function ProcessMIDI() {
  doStats(0);
}

function Idle() {
   // flush log
   var i=0;
   while(queue.length > 0 && i < maxFlush) {
       Trace(queue.shift());
       i++;
   }

   // Possibly update the gui
   if(updateFlg) {
       updateFlg = false;
       SetParameter(0,maxEvents);

   }
}

function ParameterChanged(id,val) {
   PluginParameters[id].data = val;
}

function Reset() {
   maxEvents = 0;
   current = 0;
   currentEnd = 0;
   currentStart = 0;
   updateFlag=true;
   SetParameter(0,0);
}

//========================
// Support functions
//========================

function doStats(add) {

   var trans = GetTimingInfo();
   
   // if transport not playing, don't count
   if(!trans.playing) {
       return;
   }
   
   // If still in the same process block, increment counter
   if(trans.blockEndBeat == currentEnd) {
       current+=add;
       return;
   }
   
   // Otherwise new process block has been started, so 
   // count it up and maybe log it.
    
   if(showBlocks()) {
       if(currentEnd > 0) {
           if (current > 0 || showEmptyBlocks()) {
               logCount(currentStart,currentEnd,current);
           }
       }
   }

   if(current > maxEvents) {
       maxEvents = current;
       updateFlg = true;
   }
   
   current=add;
   currentEnd = trans.blockEndBeat;
   currentStart = trans.blockStartBeat;
}    
   
   
   
// Buffered logging of event counts per process block 
// (ignores empty process blocks)
var queue = [];
var PPQN = 960;

function logCount(start,end,count) {

   // convert beatPos to midi ticks or perhaps ms?
   var totalStartTicks = Math.round(start * PPQN);
   var baseStartBeat = Math.floor(totalStartTicks/PPQN);
   var ticksStart = totalStartTicks % PPQN;
   var totalEndTicks = Math.round(end * PPQN);
   var baseEndBeat = Math.floor(totalEndTicks/PPQN);
   var ticksEnd = totalEndTicks % PPQN;
   
   queue.push("START:"+(baseStartBeat.toString().padStart(3))+
              ":"+(ticksStart.toString().padEnd(3))+
              "         END:"+(baseEndBeat.toString().padStart(3))+
              ":"+(ticksEnd.toString().padEnd(3))+
              "   - "+count.toString().padStart(3)+" Events"
   );
}

//===========
// GUI
//===========

var PluginParameters = []

PluginParameters.push({
   name: "MaxEvents/ProcessBlock",
   type: "lin",
   minValue: 0,
   maxValue: midiBufferSize,
   numberOfSteps: midiBufferSize,
   defaultValue: 0,
   data: 0,
   disableAutomation: true,
   hidden: false
});

PluginParameters.push({
   name: "Log Blocks",
   type: "checkbox",
   defaultValue: 0,
   data: 0,
   disableAutomation: true,
   hidden: false
});

PluginParameters.push({
   name: "Show Empty Blocks",
   type: "checkbox",
   defaultValue: 0,
   data: 0,
   disableAutomation: true,
   hidden: false
});

function showBlocks() {
   if( PluginParameters[1].data == 1) return true;
   else return false;
}

function showEmptyBlocks() {
   if( PluginParameters[2].data == 1) return true;
   else return false;
}

 

Future

 

  • Detect duplicate NoteOff events
  • Detect hung notes and show where in time they originated from
  • Ignore All Notes Off, both as CC123, but also detect when 128 NoteOff messages are sent in succession, which is likely all notes off.
  • When starting playback, including from in the middle of the sequence; ignore the first beat (optional), of playback in order to ignore various chasing activity that happens.
  • Options to select which midi events types should be counted(noteOn, NoteOff, CC, PB, PC, aftertouch, all notes off what else?

Edited by Dewdman42
Link to comment
Share on other sites

It would be to store it in the script between events. I made a voice leading script last week and know that I can store values that will be read on the next midi event but I was wondering if you had ideas on how to store note values and pitches that would conform to user defined sets of notes and rhythms. In use it would cycle through note values lets say quarter/half/quarter but I would also want to be able to have more than 3 notes, like 5 or some other user defined number. Would 2 arrays, one of note value and one of pitch, be the best way to cycle those materials? Also, how would I keep track of which array index I am at over longer periods of time?
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...