Inspired by Eric's Unjazzify tool and these threads -
https://forum.noteworthycomposer.com/?topic=2335.msg12893#msg12893
https://forum.noteworthycomposer.com/?topic=6032.0
https://forum.noteworthycomposer.com/?topic=5806
https://forum.noteworthycomposer.com/?topic=5590
I have written a tool to apply a variable amount of swing to tunes.
<?php
/*******************************************************************************
kbsc_Swing.php Version 1.00
This script creates a tempo staff
Copyright © 2009 by K.B.S. Creer.
All Rights Reserved
HISTORY:
================================================================================
[2009-02-11] Version 1.00: Initial release
*******************************************************************************/
require_once("lib/nwc2clips.inc");
function help_msg_and_exit()
{
echo 'Called as:
php\php.exe scripts\kbsc_Swing.php "/swing=<PROMPT:Swing as percentage:=*help>"
This User Tool creates a tempo staff to apply "swing" to a melody.
The amount of time applied to two notes adding up to one crotchet (quarter note) is split between the two notes according to a parameter specifying the percentage of the time to be applied to the first note.
The result is the same regardless of whether the notes are pair of quavers (eighth notes) or a dotted crotchet + a semi-quaver.
Triplets are left unchanged.
The tool works for tunes in 2/2, 4/4, 6/8, 9/8 and 12/8. In compound time, the process is applied to the first two quavers (eighth notes) of each set of three, the third remaining unchanged.
IMPORTANT - the process overwrites the melody. Create a copy of the melody in a new staff and apply the tool to that.' ;
exit(NWC2RC_REPORT) ;
}
function error_msg_and_exit_1($a)
{
echo "Error - $a. Number in range 5 to 95 required";
exit(NWC2RC_REPORT) ;
}
function error_msg_and_exit_2($a)
{
if ($a=="") {
echo "Error - Need a Time Signature. 2/2. 4/4, 6/8, 9/8 and 12/8 only";
} else {
echo "Error - Can't process Time Signature $a. - 2/2, 4/4, 6/8, 9/8 and 12/8 only";
}
exit(NWC2RC_REPORT) ;
}
define("QUARTER", 16);
define("EIGHTH", 8);
define("SIXTEENTH", 4);
$noteTypes = array ("Note", "Rest", "Chord", "RestChord"); //Items to process
$durArray = array ( "Whole" => 64, "Half" => 32, "4th" => 16, "8th" => 8, "16th" => 4, "32nd" => 2, "64th" => 1) ;
$durArray2 = array_flip ($durArray);
$partBarNotes = array ();
$tempo=120;
$beatLen=0;
$barDuration=0;
$beatsPerBar = 0;
$leadingNotes = TRUE;
$compound = FALSE;
$timeSig="";
function getDuration ($dur) {
//Given a Dur array, returns the duration of the note in sixteenth notes. e.g. crotchet (quarter note) = 16, dotted crotchet = 24
global $durArray;
$noteFactor=1;
$noteBase=1;
foreach ($dur as $key => $val) {
switch ($key) {
case "Triplet":
break;
case "Grace":
$noteBase=$durArray[$key];
break;
case "Dotted":
$noteFactor=3/2;
break;
case "DblDotted":
$noteFactor=7/4;
break;
case "Staccato":
break;
case "Tenuto":
break;
case "Accent":
break;
case "Slur":
break;
default:
$noteBase=$durArray[$key];
break;
}
}
$noteDuration=$noteBase*$noteFactor;
return $noteDuration;
}
function getBar (&$clipItems) {
/*******************************************************************************
Return an array of durations of notes from the current position up to the next bar line.
Quaver triplets are output as a single note with crotchet duration.
Notes longer than a crotchet are broken up as if they were built up of tied notes with maximum duration a crotchet.
Notes shorter than a quaver are combined into quavers
*******************************************************************************/
global $tempo, $beatLen, $barDuration, $beatsPerBar, $leadingNotes, $noteTypes;
$notesInBeat = array ();
$barDuration = 0;
$tripletDur = 0;
$item=current($clipItems);
$o = new NWC2ClipItem($item);
$oType = $o->GetObjType();
while ($item && $oType!="Bar") {
if ($oType=="Tempo") {
$tempo = $o->GetTaggedOpt("Tempo");
} elseif ($oType=="Ending") {
$leadingNotes = FALSE;
echo $item;
} elseif (in_array($oType, $noteTypes)) {
$opts = $o->GetOpts();
if (isset($opts["Dur"]["Triplet"])) {
$m=getDuration ($opts["Dur"]);
$tripletDur+=$m;
if ($opts["Dur"]["Triplet"]=="End") {
$tripletDur=$tripletDur * 2 / 3;
if ($tripletDur==$beatLen*2) { //crotchet triplet split into two crotchets
$notesInBeat[] = $beatLen;
$notesInBeat[] = $beatLen;
$barDuration+=$beatLen*2;
} else {
$notesInBeat[] = $tripletDur;
$barDuration+=$tripletDur;
}
$tripletDur = 0;
}
} else {
$duration=getDuration ($opts["Dur"]);
if ($duration<$beatLen/4) {
$littleNotesDur=$duration;
while ($littleNotesDur<$beatLen/2) {
$item=next($clipItems);
$o = new NWC2ClipItem($item);
$oType = $o->GetObjType();
if (in_array($oType, $noteTypes)) {
$opts = $o->GetOpts();
$duration=getDuration ($opts["Dur"]);
$littleNotesDur+=$duration;
}
$notesInBeat[] = $littleNotesDur;
$barDuration += $littleNotesDur;
}
} else {
while ($duration>$beatLen) {
$notesInBeat[] = $beatLen;
$barDuration += $beatLen;
$duration -= $beatLen;
}
$notesInBeat[] = $duration;
$barDuration += $duration;
}
}
}
$item=next($clipItems);
$o = new NWC2ClipItem($item);
$oType = $o->GetObjType();
}
return $notesInBeat;
}
function createMPC($pBN,$pc) {
global $tempo, $beatLen;
$MCPstr="|MPC|Controller:tempo|Style:Absolute|TimeRes:Sixteenth|SweepRes:1";
$offset = 0;
$Pt = 1;
$note = array_shift ($pBN);
if ($note>=QUARTER) {
$MCPstr.="|Pt$Pt:$offset,$tempo";
} else {
if ($note>0) {
$N=round(100 * $note * $tempo / (QUARTER * $pc));
$MCPstr.="|Pt$Pt:$offset,$N";
$Pt += 1;
$offset = $note / 4;
}
$pc = 100 - $pc;
$note = array_shift ($pBN);
if (isset($note)) {
if ($note>0) {
$N=round(100 * $note * $tempo / (QUARTER * $pc));
$MCPstr.="|Pt$Pt:$offset,$N";
$Pt += 1;
$offset = $note / 4;
}
$note = array_shift ($pBN);
if (isset($note)) {
$MCPstr.="|Pt$Pt:$offset,$tempo";
}
}
}
$MCPstr.="|Pos:-5|Wide:N|Justify:Left|Placement:BestFit|Color:0|Visibility:Default";
return $MCPstr;
}
function createRest($dur) {
global $durArray2;
if ($dur % 7) { //not divisible by 7 therefore not DblDotted
if ($dur % 3) { //not divisible by 3 therefore not Dotted
$durCode="";
} else { // Dotted
$durCode=",Dotted";
$dur=$dur * 2 / 3;
}
} else {
$durCode=",DblDotted";
$dur=$dur * 4 / 7;
}
$durCode=$durArray2[$dur] . $durCode;
$RestStr="|Rest|Dur:" . $durCode . "|Color:0|Visibility:Default";
return $RestStr;
}
function createBeat (&$barNotes, $partLength, $percentage) {
global $barDuration;
$partBarNotes = array ();
$partDur=0;
$j=0;
while ($partDur<$partLength && $j < 10) {
$noteDur=array_shift($barNotes);
$partBarNotes[] = $noteDur;
$partDur += $noteDur;
$j+=1;
}
$barDuration -= $partDur;
echo createMPC($partBarNotes, $percentage) . "\n";
echo createRest($partDur) . "\n";
}
//Get parameters
$clip = new NWC2Clip('php://stdin');
array_shift($argv) ; // get rid of the first arg (script name)
foreach ($argv as $arg) {
if ($arg == "help") help_msg_and_exit() ;
if (preg_match('/^(\d+)$/',$arg,$m)) {
$percentage = $m[1];
if ($percentage > 95 || $percentage < 5) {
error_msg_and_exit_1($percentage);
}
} else {
error_msg_and_exit_1($arg);
}
}
//Start of main processing
echo $clip->GetClipHeader()."\n";
//Read stuff before first note (clef, key, time sig etc.) and write it back to Noteworthy
$tempo=120;
$item=current($clip->Items);
$o = new NWC2ClipItem($item);
$oType = $o->GetObjType();
while ($item && !in_array($oType, $noteTypes)) {
if ($oType=="TimeSig") {
$timeSig = trim($o->GetTaggedOpt("Signature"));
if ($timeSig=="Common") {
$timeSig = "4/4";
} else {
if ($timeSig=="AllaBreve") {
$timeSig = "2/2";
}
}
if (preg_match('/^(\d+)\/(\d+)$/',$timeSig,$m)) {
$timeSigNum = $m[1];
$timeSigDen = $m[2];
$barLength=$timeSigNum * (64 / $timeSigDen);
}
}
if ($oType=="Tempo") {
$tempo = $o->GetTaggedOpt("Tempo");
}
echo $item;
$item=next($clip->Items);
$o = new NWC2ClipItem($item);
$oType = $o->GetObjType();
}
//Current Item is the first 'note' of the tune
if ($timeSig=="4/4" || $timeSig=="2/2") {
$beatsPerBar = 4;
$beatLen=16;
} elseif ($timeSig=="6/8") {
$beatsPerBar = 2;
$beatLen=24;
} elseif ($timeSig=="9/8") {
$beatsPerBar = 3;
$beatLen=24;
} elseif ($timeSig=="12/8") {
$beatsPerBar = 4;
$beatLen=24;
} else {
error_msg_and_exit_2($timeSig);
}
$barNotes=getBar($clip->Items);
$i=0;
while ($barDuration && $i < 100) {
if ($barDuration<$beatLen*$beatsPerBar) { //incomplete bar
if ($leadingNotes) {
if ($barDuration % $beatLen) { //the first note isn't on the beat
array_unshift($barNotes, 0);
if ($beatLen==24 && $barDuration % $beatLen==EIGHTH) {
array_unshift($barNotes, 0);
$PL=$barDuration % $beatLen;
}
createBeat ($barNotes, $barDuration % $beatLen, $percentage);
}
$k=0;
while ($barDuration && $k<10) {
createBeat ($barNotes, $beatLen, $percentage);
$k += 1;
}
$leadingNotes = FALSE;
} else {
$k=0;
while ($barDuration >= $beatLen && $k<10) {
createBeat ($barNotes, $beatLen, $percentage);
$k += 1;
}
if ($barDuration) {
createBeat ($barNotes, $barDuration, $percentage);
}
$leadingNotes = TRUE;
}
} else { //complete bar
$k=0;
while ($barDuration && $k<10) {
createBeat ($barNotes, $beatLen, $percentage);
$k += 1;
}
}
$item=current($clip->Items);
$o = new NWC2ClipItem($item);
$oType = $o->GetObjType();
while ($oType=="Bar") {
echo $item;
$item=next($clip->Items);
$o = new NWC2ClipItem($item);
$oType = $o->GetObjType();
}
$barNotes=getBar($clip->Items);
$i+=1;
}
echo NWC2_ENDCLIP."\n";
exit(NWC2RC_SUCCESS);
?>
Let me know what you think.
Bryan Creer