Jump to content

3-way cymbal handler / note prioritizer


Recommended Posts

Hi everybody,

 

I am not sure if the following special script could be of any interest, but nevertheless I'll give it a try.

 

I created the script for a quite special e-drum use case: most, if not all, of today's drum modules such as my old Roland TD-20X, still only offer one specialized trigger input combination for a so-called 3-way cymbal. This is an e-cymbal with 3 zones (bow, edge and bell) which is triggered by two stereo triggers (bow with edge and bow with bell). The module then internally eliminates the duplicate bow hits that occur with this combination, and also gives priority to edge and bell hits. However, this simple magic only occurs for the special "ride" inputs and cannot be dialed in for other inputs such as the various available AUX inputs. In the old days of e-drumming, this was sufficient because there were not so many 3-way cymbals available.

 

However, today this has changed and now we have also 3-way hi-hats or crashes, e.g. from ATV. But as long as the existing modules cannot handle more than one such e-cymbal, we have to live with work arounds. This script is such a work around, and of course only a very special one that lives inside LPX and is therefor only useful for those e-drummers that go for MIDI/VST instead of using the built-in sounds of a drum module.

 

So, if there is someone out there with a similar setup and "problem", this is for you...

 

Otherwise, you might either just ignore it or see the script as a "general note prioritizer", but I have no idea if such a thing could be useful.

 

Installation and usage: the script source code is attached below. Simply open the Scripter plug-in, open any of the presets in the editor and replace the contents with this script. Then choose Save-as... and save the script under any new name.

 

One last tip: you might have more than one instance of this plug-in in the same channel if you have more than one additional 3-way cymbal or other use case. However, be careful as LPX behaves a bit odd when changing and saving the source code in this case. Better always keep a working copy of the script source code outside.

 

Have fun and best regards,

edrumhead

 

//
// 3-way cymbal handler for e-drums / general note prioritizer
//
// The original intention for this script is a quite special e-drum use case:
// The script handles the required elimination of duplicate 'bow' notes if an e-cymbal with
// 3 zones (bow, edge and bell) is connected to two independent trigger inputs (e.g. Hi-hat
// and one AUX, or two AUXs) instead of the specialized "ride input" that handles this inside
// the drum module. By using this script, you may use more than one 3-way cymbal with your
// existing drum module and do the required logic afterwards here on the MIDI level.
//
// Each zone may be represented by up to 2 different notes even though this is merely an artifact
// produced by some drum modules for hi-hats to distiguish "open" and "close" states. Modern VST
// software such as SSD5 or SD3 will of course use the CC information of the hi-hat pedal to
// produce more than two different articulations/sounds depending on the opening state of the pedal.
// So, having two notes per zone is just a convenience so that you don't have to change to MIDI
// notes produced by your drum module.
//
// More generally, you may also think of this script as a note prioritizer. In this sense, it
// grants 4 notes (named 'edge 1/2' and 'bell 1/2') priority over 2 other notes (named 'bow 1/2') 
// within a definable short time frame.
//
// Technical notes: 
//
// 1. the script uses the JavaScript Date().getTime() method to measure millisecond time intervals
// between subsequent calls to HandleMIDI() and/or ProcessMIDI().
// This might or might not be a good idea, however, it seems to work quite reliably within
// LPX and I am not aware of an alternative / more official way to do this within the Scripter
// environment. Please note that this script is intended also to be used in monitoring mode, not
// only for playback or recording. Nevertheless, if you have an alternative, you might simply replace 
// the implementation of the getTimeMillis() function below.
//
// 2. in order to be able to prioritize the edge and bell hits over the bow hits irrespective of the
// order in which they arrive, the script defers the execution of all bow hits by a defineable time 
// interval (default is 3 ms). 
//

var NeedsTimingInfo = true

var minBowDist = 3
var bow1 = 46
var bow2 = 42
var edge1 = 26
var edge2 = 22
var bell1 = 9
var bell2 = 9

var lastBowOn = 0
var lastBowPitch = 0
var lastBowVelo = 0
var lastEdgeOn = 0

// Definition of the visible parameters
var PluginParameters =
[ 
{name:"Min. time between bow hits", type:"lin", unit:"ms", 
minValue:0, maxValue:10, numberOfSteps:10, defaultValue:3},
{name:"Bow note 1", type:"lin",  
minValue:0, maxValue:127, numberOfSteps:127, defaultValue:bow1},
{name:"Bow note 2", type:"lin",  
minValue:0, maxValue:127, numberOfSteps:127, defaultValue:bow2},
{name:"Edge note 1", type:"lin",  
minValue:0, maxValue:127, numberOfSteps:127, defaultValue:edge1},
{name:"Edge note 2", type:"lin",  
minValue:0, maxValue:127, numberOfSteps:127, defaultValue:edge2},
{name:"Bell note 1", type:"lin",  
minValue:0, maxValue:127, numberOfSteps:127, defaultValue:bell1},
{name:"Bell note 2", type:"lin",  
minValue:0, maxValue:127, numberOfSteps:127, defaultValue:bell2},
]

//
// Synchronizes the visible parameters with their internal counterparts.
//
function ParameterChanged(param, value) {
if (param == 0) { 
	minBowDist = value
   } else if (param == 1) { 
	bow1 = value
   } else if (param == 2) { 
	bow2 = value
   } else if (param == 3) { 
	edge1 = value
   } else if (param == 4) { 
	edge2 = value
   } else if (param == 5) { 
	bell1 = value
   } else if (param == 6) { 
	bell2 = value
}
}

//
// Returns the current time with millisecond precision. 
//
function getTimeMillis() {
return new Date().getTime()
}

//
// Called for every incoming MIDI event.
//
function HandleMIDI(e) {
if (e instanceof NoteOn) {
	if (e.pitch == bow1 || e.pitch == bow2) {
		// Bow was hit
		var now = getTimeMillis()
		if (lastBowOn > 0) {
			// Trace("Omitting duplicate bow hit")
			return
		} else if (now-lastEdgeOn < minBowDist) {
			lastBowOn = 0;
			// Trace("Omitting bow hit because edge hit occured shortly before")
			return
		}
		// Prepare for deferred bow hit execution
		lastBowOn = now
		lastBowPitch = e.pitch
		lastBowVelo = e.velocity
		return
	} else if (e.pitch == edge1 || e.pitch == edge2 || e.pitch == bell1 || e.pitch == bell2) {
		// Edge or bell were hit
		lastEdgeOn = new Date().getTime()
		lastBowOn = 0 // cancel any pending bow hit request
	}
} else if (e instanceof NoteOff) {
	if (e.pitch == bow1 || e.pitch == bow2) {
		// We omit all bow note off events here and execute them later after their note on counter parts
		return
	}
}
// pass through
e.send()
}

//
// Called every few milliseconds. Used to fire the deferred bow note(s).
//
function ProcessMIDI() {
var now = getTimeMillis()
if (lastBowOn > 0 && now-lastBowOn >= minBowDist) {
	lastBowOn = 0
	fireBow()
}
}

//
// Fires a bow on note, immediately followed by a bow off note.
//
function fireBow() {
var bow = new NoteOn
bow.pitch = lastBowPitch
bow.velocity = lastBowVelo
bow.send()
bow = new NoteOff
bow.pitch = lastBowPitch
bow.send()
}

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