Swing (1/1) *Bryan Creer*: Inspired by Eric's Unjazzify tool and these threads - https://www.noteworthysoftware.com/forum/?topic=2335.msg12893#msg12893 https://www.noteworthysoftware.com/forum/?topic=6032.0 https://www.noteworthysoftware.com/forum/?topic=5806 https://www.noteworthysoftware.com/forum/?topic=5590 I have written a tool to apply a variable amount of swing to tunes. Code: [Select · Download] " 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; $notesInBeat[] = $tripletDur; $barDuration+=$tripletDur; $tripletDur = 0; } } else { $duration=getDuration ($opts["Dur"]); $beatRemainder = $beatLen - $barDuration%$beatLen; //count from current position to end of beat if ($duration<=$beatLen/4 and $beatRemainder = 0) { // combine short notes into a beat only at start of beat $littleNotesDur=$duration; while ($littleNotesDur<$beatLen/2) { $item=next($clipItems); $o = new NWC2ClipItem($item); $oType = $o->GetObjType(); if (in_array($oType, $noteTypes)) { $opts = $o->GetOpts(); $m=getDuration ($opts["Dur"]); $littleNotesDur+=$m; } $notesInBeat[] = $littleNotesDur; $barDuration += $littleNotesDur; } } else { while ((($barDuration%$beatLen)+$duration)>$beatLen) { // split a longer than beat note to complete beat $notesInBeat[] = $beatRemainder; $barDuration += $beatRemainder; $duration -= $beatRemainder; } $notesInBeat[] = $duration; $barDuration += $duration; } } } $item=next($clipItems); $o = new NWC2ClipItem($item); $oType = $o->GetObjType(); } $collect = 0; $notesInBar2 = array(); foreach ($notesInBeat as $duration) { // consolidate shorter notes into quarter beats (e.g. 1/16s) if ($duration+$collect <= $beatLen/4 && array_sum($notesInBar2)%($beatLen/4) == 0) { $collect += $duration; } else { if ($collect > 0) { $notesInBar2 [] = $collect; } $collect = $duration; } } if ($collect > 0) { $notesInBar2 [] = $collect; } // *** //print_r ($notesInBar2); reset ($notesInBar2); // *** $collect = 0; $notesInBar3 = array(); foreach ($notesInBar2 as $duration) { // consolidate paired quarter beats into half beats (e.g. 1/8s) if ($duration == $beatLen/4 && $duration+$collect <= $beatLen/2 && array_sum($notesInBar3)%($beatLen/2) == 0) { $collect += $duration; } else { if ($collect > 0) { $notesInBar3 [] = $collect; } $collect = $duration; } } if ($collect > 0) { $notesInBar3 [] = $collect; } // *** //print_r ($notesInBar3); reset ($notesInBar3); // *** return $notesInBar3; } 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) { $note2 = current ($pBN); if ($note==$beatLen/4 && $note2==$beatLen/4*3) { $pc = 100 - $pc; } $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<20) { createBeat ($barNotes, $beatLen, $percentage); $k += 1; } $leadingNotes = FALSE; } else { $k=0; while ($barDuration >= $beatLen && $k<20) { createBeat ($barNotes, $beatLen, $percentage); $k += 1; } if ($barDuration) { createBeat ($barNotes, $barDuration, $percentage); } $leadingNotes = TRUE; } } else { //complete bar $k=0; while ($barDuration && $k<20) { 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 *Lawrie Pardy*: G'day Brian, haven't had a good look at it yet, but here's useful command line for it: tool name: Swing It - kbsc command: php\php.exe Scripts\kbsc_Swing.php Or if you'd like to copy and past to the NWC2usertiils.ini file: Swing It - kbsc='php\php.exe Scripts\kbsc_Swing.php ' Navigation [0] Message Index