Skip to main content
Topic: Turn grace notes into real ones. (Read 4338 times) previous topic - next topic

Turn grace notes into real ones.

This script turns grace notes into real ones and steals time from either the prior note or the following one.

There is no undo with this so either save before using or on a copy from another staff.
Code: [Select · Download]
/* Notes to Rests by Warren Porter "graceFix.js"
   After downloading this file, when setting it up in NWC User Tools create this command line:

   wscript "'Browse can insert the path for you' \graceFix.js" <PROMPT:Which?:=|Prev|Next>

   This converts grace notes to real ones while reducing the duration of the previous object.  First, copy an entire staff (which
   you will make visible and muted) to the clipboard, create a new staff (will eventually be hidden and played),
   then copy the clipboard to the new staff.  Run this command on that new staff.  Notes, chords, or rests which are followed
   by grace notes will be shortened by the (total) duration of the grace notes and the grace attribute will be removed.
   The original (and still on the displayed/muted staff) grace notes will now sound BEFORE the beat instead of ON the beat.
  
   Change:  You can take time from the note/chord AFTER the grace note(s) by chosing "Next"

 */
 //  Substitutions: Wscript.Arguments <-> parms
 //                 Item(n)            <-> [n]


var rc=0, errMsg="", Wscript_Arguments = new Array();
var NoteLengths = [ "Whole", "Half", "4th", "8th", "16th", "32nd", "64th", "128th", "256th", "512th", "1024th" ] ;
var SearchDur;


function getNoteLength(notelet) {  // Returns duration of note , whole = 768
//   var shell = new ActiveXObject("WScript.Shell");
parts = notelet.split(","), numParts=1;
var  noteLength= -1, searchstr="";
searchstr = parts[0].substr(0,3);
//shell.Popup(parts[0])
switch (searchstr) {
case "Who" : noteLength = 768; break;
case "Hal" : noteLength = 384; break;
case "4th" : noteLength = 192; break;
case "8th" : noteLength =  96; break;
case "16t" : noteLength =  48; break;
case "32n" : noteLength =  24; break;
case "64t" : noteLength =  12; break;
default:     noteLength =  -1;
}
  if (noteLength == -1)
    return -1;

  for (var i = 1; i < parts.length; i++) {
    if (parts[i].substr(0,9) == "DblDotted") {
  numParts=2;
  noteLength = noteLength * 7 / 4; }
else
      if (parts[i].substr(0,6) == "Dotted") {
  numParts=2;
    noteLength = noteLength * 3 / 2; }
  else
    if (parts[i].substr(0,7) == "Triplet") {
  numParts=2;
      noteLength = noteLength * 2 / 3; } }
  SearchDur = (numParts == 1)? parts[0]: parts[0] + "," + parts[1]
  return noteLength;
}

function doNext(clip) {
  var i, durTable = new Array(), newDur, binString="", saveDur, subDur=0, durSub = new Array(), saveOrig, newStrings = new Array();
  var lines = new Array(), result = new Array(), lastDur = 0, locDur=0, locGraceFst, locGraceLst, durGrace, sumGrace=0
  var saveBar="", locBar= -1, wholeRest=768;
  lines = clip.split("\n");

  for (i=0; i < lines.length; i++) {
      result=lines[i].match(/Dur:([^\|]*)/);
  if (sumGrace && (result == null)) {
  errMsg="Unattached Grace note";
  rc=1;
  return lines; }
  if (result == null)
  continue;  // No duration, didn't follow grace note.
  if (lines[i].indexOf("Grace") > 0) {  // Found a grace note/chord
durGrace = getNoteLength(result[1]);  // Find duration
sumGrace+= durGrace;   // Sum of grace notes so far
    lines[i]=lines[i].replace(",Grace","");  // Remove grace attribute
        continue;  }
  if (!sumGrace) // If has duration, is not grace, and doesn't follow grace
  continue;  // Ignore
  /*
  At this point something with a duration follows (a) Grace Note/Chord(s) and its duration must be reduced
  by sumGrace.
   */
    lastDur = getNoteLength(result[1]);
saveDur = SearchDur;
  newDur = (lastDur - sumGrace)
  if ((newDur % 3) != 0) {
    lines[i]+="\n|Text|Text:\"Can't do triplets.\"|Font:StaffItalic|Pos:10|Color:1"
            break; }
          newDur /= 3;
  if (newDur < 4) {
    errMsg="Note to convert isn't long enough, aborting.";
rc=1;
return lines;}
  binString=""
  for (var ii=0; ii < 9; ii++) {   //Convert to binary
    binString = (newDur % 2) + binString;
newDur = Math.floor(newDur/2); }
  durTable.length = 0, subDur=0;
  while (binString != "000000000") {
    for (ii=0; ii < 3; ii++)
  durSub[ii] = Number.POSITIVE_INFINITY;
    result = binString.match("111")
if (result != null)
  durSub[0] = result.index;
    result = binString.match("110")
if (result != null)
  durSub[1] = result.index;
    result = binString.match("10")
if (result != null)
  durSub[2] = result.index;
if (durSub[0] <= durSub[1] && durSub[0] <= durSub[2]) {
  durTable[subDur++] = NoteLengths[durSub[0]] + ",DblDotted";
  binString = binString.replace("111","000");
  continue;}
if (durSub[1] < durSub[0] && durSub[1] <= durSub[2]) {
  durTable[subDur++] = NoteLengths[durSub[1]] + ",Dotted";
  binString = binString.replace("11","00");
  continue;}
if (durSub[2] < durSub[0] && durSub[2] < durSub[1]) {
  durTable[subDur++] = NoteLengths[durSub[2]];
  binString = binString.replace("1","0");
  continue;}  }
// Code to manipulate durations goes here
saveOrig = lines[i];  // Save so can modify it several times if necess;
newStrings.length = 0;
for (ii = 0; ii < subDur;ii++) {
  newStrings[ii] = saveOrig.replace(saveDur,durTable[ii]);
      if (((subDur - 1) > ii) && (saveOrig.slice(0,6) != "|Rest|")) {
    newStrings[ii] = newStrings[ii].replace(/(\d),/g, "$1^,"); ;
    newStrings[ii] = newStrings[ii].replace(/$/, "^");
    newStrings[ii] = newStrings[ii].replace("^^", "^"); } }
lines[i] = newStrings.join("\r\n");
    sumGrace=0; } // So will not try to apply reductions again.

  return lines;
}

function doPrev(clip) {
  var i, durTable = new Array(), newDur, binString="", saveDur, subDur=0, durSub = new Array(), saveOrig, newStrings = new Array();
  var lines = new Array(), result = new Array(), lastDur = 0, locDur=0, locGraceFst, locGraceLst, durGrace, sumGrace=0
  var saveBar="", locBar= -1, wholeRest=768;
 // lines = clip.split("\r\n");

  lines = clip.split("\n");
  for (i=0; i < lines.length; i++) {
      if (lines[i].slice(0,4) == "|Bar")  {
saveBar = lines[i];
locBar=i;
continue;
  }
  if (lines[i].slice(0,8) == "|TimeSig") {
    result = lines[i].match(/re:(\d+)\/(\d+)/);
if (result != null)
  wholeRest = 768 * result[1] / result[2];
continue; }
      result=lines[i].match(/Dur:([^\|]*)/);
  if (result == null)
    continue;
      if (lines[i].indexOf("Grace") == -1) { // Found something with duration not a grace note
        lastDur = getNoteLength(result[1]);
saveDur = SearchDur;
locBar= -1;  // This measure didn't start with (a) grace(s) note/chord.
locDur = i;
        if (lines[i].slice(0,5) == "|Rest" && lastDur == 768)
  lastDur = wholeRest; }  // In case we need it.
  else  { // Found a grace note to convert
  locGraceFst=i;
  sumGrace=0;
  for (locGraceLst=i; locGraceLst < lines.length; locGraceLst++) {
    result=lines[locGraceLst].match(/Dur:([^\|]*)/);
var buggy = lines[locGraceLst].indexOf("Grace");
// if ((result == null) || (lines[locGraceLst].indexOf("Grace") > -1)) {// Doesn't have duration or not grace
//   break; }
    if (result == null)
  break;
if (buggy == -1)
  break;
    durGrace = getNoteLength(result[1]);
sumGrace+= durGrace;}
  locGraceLst--;
  if (locDur > 0)  {  //There was something with duration earlier so will have to reduce it.
  newDur = (lastDur - sumGrace)
  if ((newDur % 3) != 0) {
    lines[locGraceLst]+="\n|Text|Text:\"Can't do triplets.\"|Font:StaffItalic|Pos:10|Color:1"
            break; }
          newDur /= 3;
  if (newDur < 4) {
    errMsg="Note to convert isn't long enough, aborting.";
rc=1;
return lines;}
  binString=""
  for (var ii=0; ii < 9; ii++) {   //Convert to binary
    binString = (newDur % 2) + binString;
newDur = Math.floor(newDur/2); }
  durTable.length = 0, subDur=0;
  while (binString != "000000000") {
    for (ii=0; ii < 3; ii++)
  durSub[ii] = Number.POSITIVE_INFINITY;
    result = binString.match("111")
if (result != null)
  durSub[0] = result.index;
    result = binString.match("110")
if (result != null)
  durSub[1] = result.index;
    result = binString.match("10")
if (result != null)
  durSub[2] = result.index;
if (durSub[0] <= durSub[1] && durSub[0] <= durSub[2]) {
  durTable[subDur++] = NoteLengths[durSub[0]] + ",DblDotted";
  binString = binString.replace("111","000");
  continue;}
if (durSub[1] < durSub[0] && durSub[1] <= durSub[2]) {
  durTable[subDur++] = NoteLengths[durSub[1]] + ",Dotted";
  binString = binString.replace("11","00");
  continue;}
if (durSub[2] < durSub[0] && durSub[2] < durSub[1]) {
  durTable[subDur++] = NoteLengths[durSub[2]];
  binString = binString.replace("1","0");
  continue;}  }
// Code to manipulate durations goes here
saveOrig = lines[locDur];  // Save so can modify it several times if necess;
newStrings.length = 0;
for (ii = 0; ii < subDur;ii++) {
  newStrings[ii] = saveOrig.replace(saveDur,durTable[ii]);
      if (((subDur - 1) > ii) && (saveOrig.slice(0,6) != "|Rest|")) {
    newStrings[ii] = newStrings[ii].replace(/(\d),/g, "$1^,"); ;
    newStrings[ii] = newStrings[ii].replace(/$/, "^");
    newStrings[ii] = newStrings[ii].replace("^^", "^"); } }
lines[locDur] = newStrings.join("\r\n"); }
for (ii = locGraceFst; ii <= locGraceLst; ii++)
  lines[ii]=lines[ii].replace(",Grace","");
if (locBar > -1) {
      lines[locGraceLst]+= "\n" + saveBar; // Add barline after the grace notes
      lines[locBar] = "#"; }  // Turn original bar into a comment.
if (locDur == 0)
  lines[locGraceLst]+="\n|Bar\n|Text|Text:\"New bar added\"|Font:StaffItalic|Pos:8|Color:1";
i=locGraceLst; // So won't try to redo the same string of grace notes.
 }
  }  //End main processing loop
  return lines;
}

var myLines;
  if (WScript.Arguments.length != 1) {
    errMsg="NO Prompt read.";
rc=1; }
  else {
    if (WScript.Arguments.Item(0).slice(0,4) == "Prev")
  myLines=doPrev(WScript.StdIn.ReadAll()).join("\r\n");
else
  myLines=doNext(WScript.StdIn.ReadAll()).join("\r\n"); }

if (rc == 0)
  WScript.StdOut.Write(myLines);
else
  WScript.StdErr.Write(errMsg);
WScript.quit(rc);

Edit: Change documentation in first few lines of the script.
Since 1998

Re: Turn grace notes into real ones.

Reply #1
The following typo looks familiar to me:
Code: [Select · Download]
var NoteLengths = [ "Whole", "Half", "4th", "8th", "16th", "32nd", "64th", "128th", "256th", "512th", "1028th" ]
You probably want that to be "1024th" (although NWC doesn't support notes that short yet). Also, there should be a ";" at the end of the statement to be proper JavaScript.

Re: Turn grace notes into real ones.

Reply #2
You guys are amazing, haha!  This is so helpful!  ^_^