"; wc = window.open("","nocren","width=600,height=560,left=250,top=200") wc.document.write(html); wc.document.close(); } function genWorkEntry(parm) { var i; lastWork++; workTab[lastWork] = new Array(); workTab[lastWork][0] = parm; for (i = 1; i < 10; i++) workTab[lastWork][i] = -1; workTab[lastWork][10] = currentVoice * 5000 + lastWork; // Will sort on this field later } function fraction(num, denom) { return parseInt(num) / parseInt(denom); } function Mastersort(a,b) { return a[10] - b[10]; } function chordSort(a,b) { var anum, bnum, result; if (isNaN(a)) { result = a.match(/[#b-x]*(-*[\d+])/); anum = result[1]; } else { anum = a; } if (isNaN(b)) { result = b.match(/[#b-x]*(-*[\d+])/); bnum = result[1]; } else { bnum = b; } return anum - bnum; } function reduceIt(num,dum) { var lnum=parseInt(num),ldum=parseInt(dum), retstr=""; while((lnum%2 == 0) && (ldum%2 == 0)) { lnum/=2; ldum/=2;} if ((lnum%3 == 0) && (ldum%3 == 0)) { lnum/=3; ldum/=3; } retstr = lnum + " / " + ldum; return retstr; } function getTempoName(notelet) { var NoteLengths = [ [96,"Eighth"], [144,"Eighth Dotted"], [192,"--"], //Quarter note default [288,"Quarter Dotted"], [384,"Half"], [576,"Half Dotted"]] var min=0, max=NoteLengths.length - 1, mid; while (max >= min) { mid = Math.floor((max + min) / 2); if (notelet == NoteLengths[mid][0]) {return NoteLengths[mid][1];} if (notelet < NoteLengths[mid][0]) max = mid - 1; else min = mid + 1; } //End while loop alert("Couldn't find base note for tempo, assume quarter default"); return "--"; } function getNoteLength (notelet) { var NoteLengths = [ [8,"64th,Triplet"], [12,"64th"], [16,"32nd,Triplet"], [18,"64th,Dotted"], [21,"64th,DblDotted"],[24,"32nd"], [32,"16th,Triplet"], [36,"32nd,Dotted"], [42,"32nd,DblDotted"],[48,"16th"], [64,"8th,Triplet"], [72,"16th,Dotted"], [84,"16th,DblDotted"], [96,"8th"], [128,"4th,Triplet"], [144,"8th,Dotted"], [168,"8th,DblDotted"], [192,"4th"], [256,"Half,Triplet"], [288,"4th,Dotted"], [336,"4th,DblDotted"], [384,"Half"], [512,"Whole,Triplet"],[576,"Half,Dotted"], [672,"Half,DblDotted"], [768,"Whole"], [1152,"Whole,Dotted"], [1344,"Whole,DblDotted"] ] var min=0, max=NoteLengths.length - 1, mid; while (max >= min) { mid = Math.floor((max + min) / 2); if (notelet == NoteLengths[mid][0]) {return NoteLengths[mid][1];} if (notelet < NoteLengths[mid][0]) max = mid - 1; else min = mid + 1; } //End while loop return "Error in length"; } function findKey(token) { var result = new Array(); var keyTab = [ ["Ab",8],["A ",3],["A#",10],["Bb",10],["B ",5],["B#",0], ["Cb",5],["C ",0],["C#",7],["Db",7],["D ",2],["D#",9],["Eb",9],["E ",4],["E#",11], ["F ",11],["F#",6],["Gb",6],["G ",1],["G#",8] ]; //1-8 sharp keys, 6-11 flat keys, 6 = F# or Gb, 0 = C var key = "", i, ikey, iadj=0, dosharp; var Sharpline = "F#,C#,G#,D#,A#,E#,B#"; Flatline = "Bb,Eb,Ab,Db,Gb,Cb,Fb"; result= token.match(/([A-G][#b]?) *([A-Za-z]{0,3})/); if (result == null) { alert("Could not interpret key: "+ token + ", assuming C"); return "C"; } if (result.length > 1) {result[2] = result[2].toLowerCase();} if (result[1].length == 1 && result[1] == "C") {return "C";} key = result[1]; if (key.length == 1) {key += " ";} //Trailing space for search for (i = 0; i < keyTab.length; i++) { if (key == keyTab[i][0]) { ikey = keyTab[i][1]; break; } } if (ikey == keyTab.length) { errText+= "Did not recognize key: " + key + "\n"; return "C"; } if ((result[2].length == 1) && (result[2] == "m")) {iadj = 9;} else { if (result[2].length == 3) { switch (result[2]) { case "min" : iadj = 9; break case "aeo" : iadj = 9; break case "mix" : iadj = 11; break case "dor" : iadj = 10; break case "phr" : iadj = 8; break case "lyd" : iadj = 1; break case "loc" : iadj = 5; break case "maj" : iadj = 0; break case "ion" : iadj = 0; break default: {iadj = 0; errText += "Did not recognize mode: " + result[2] + "\n"; break;} } } } ikey += iadj; ikey = ikey%12; if (ikey == 0) { return "C"; } if (ikey > 0 && ikey < 5) {dosharp = 1;} else if (ikey > 7 && ikey < 12) {dosharp = 0;} else if (iadj == 0) { if (key.indexOf("b")> 0) {dosharp = 0;} else {dosharp = 1;} } else { if (confirm("Use Flat Key for " + result[0] + " ?") == true) {dosharp = 0;} else {dosharp = 1;}; } if (dosharp == 1) { var ilen = ikey * 3 - 1; return Sharpline.substr(0,ilen); } ilen = 35 - 3 * ikey; return Flatline.substr(0,ilen); } function checkDuration(num, aSlash, denom) { var lnum, ldenom, quo; if (num.length < 1) lnum = 1; else lnum = parseInt(num); if (aSlash.indexOf("/") < 0) return lnum * notelength; if (denom.length < 1) { ldenom = 1; if (aSlash.length >= 1) for (var i=0; i < aSlash.length; i++) ldenom *= 2; } else ldenom = parseInt(denom); quo = lnum * notelength / ldenom; if (quo < 8) { alert("note too short " + quo); quo = notelength; } if (Math.floor(quo) != quo) { errText += "This duration not allowed " + lnum + "/" + ldenom + "\n" alert("This duration not allowed " + lnum + "/" + ldenom); quo = notelength; } return quo; } function longRest(token) { var measCount = 0; if (token.length < 2) measCount = 1; else measCount= parseInt(token.substr(1)); genWorkEntry('Text|Text:"[' + measCount + ']"|Font:User1|Pos:-1|Wide:Y'); for (var i = 0; i < measCount; i++) { genWorkEntry("Rest|Dur:Whole|Visibility:Never"); if ((i + 1) < measCount) {genWorkEntry("Bar|Visibility:Never"); } } } function checkRest(token) { var result = new Array(); //Need local variable here var tfactor, tdur = "";; result = token.match(/[xz](\d*)(\/*)(\d*) ?/); tfactor = checkDuration(result[1], result[2], result[3]); if (tgroup > 0) { tfactor *= (tgrNum / tgrDum); tgroup--; } tdur = getNoteLength(tfactor); if (tdur.slice(0,3) == "Err") { tdur = getNoteLength(notelength); errText += "Rests of length " + reduceIt(tfactor, 768) + " not supported\n" ; } if (token.indexOf("x") > -1) tdur += "|Visibility:Never"; genWorkEntry("Rest|Dur:" + tdur); } function checkNotes(type1,token) { var noteString = "CDEFGABcdefgab", pos, beam=1, atie = 0; var result = new Array(); //Need local variable here var num, aslash, denom, tfactor; severeError=0; while (token.length > 0) { atie=0; result = token.match(anote); if (result == null) { genWorkEntry("Text|Text:\"" + token + "\"|Font:StaffBold|Pos:8|Wide:Y|Justify:Left|Placement:BestFit|Color:1|Visibility:Default"); token = ""; severeError = 1; return; } tfactor = checkDuration(result[5], result[6], result[7]); pos = noteString.indexOf(result[3]) - 6; //alert("result3: " + result[4]); for (var i =0; i 0) { tfactor *= (tgrNum / tgrDum); tgroup--; } genWorkEntry("NOTE"); workTab[lastWork][1] = tfactor workTab[lastWork][2] = pos workTab[lastWork][3] = ((graceOn)? 1 : 0) workTab[lastWork][4] = ((slurOn)? 1: 0) workTab[lastWork][5] = type1 workTab[lastWork][6] = atie workTab[lastWork][7] = beam workTab[lastWork][8] = 0 // Up or Down beams may go here workTab[lastWork][9] = ((result[1].length)? 1 : 0) //stacatto // workTab[lastWork][10] = currentVoice * 5000 + lastWork workTab[lastWork][11] = result[0] ; } token = token.substr(result[0].length); } } // 1 2 3 4 5 6 7 8 9 10 11 // NOTE, duration (in 768ths), acc-position, grace(0|1), slur(0,1), chord(0|1), tie(1,0), beam(0,1,2,4), Up|Down, stacatto, voice/line // 0 1 2 3 4 5 6 7 8 9 10 function startup() { document.nwcform.InputField.value=""; document.nwcform.OutputField.value=""; document.nwcform.DeBugging.checked=false document.nwcform.Sample.checked=false var dloc = document.location.toString(); if (dloc.slice(0,4) != "file") { document.nwcform.DeBugging.style.visibility = 'hidden'; } } function checkHead(atype,token) { var result = new Array(); // alert(atype + "<->" + token); switch (atype) { case 'A': //Lyricist lyricist = token; break; case 'C': //Composer author = token; break; case 'K': //Key key = token; if (doingHeader == 0) { genWorkEntry("Key|Signature:" + findKey(key)); } else { var asdf1 = findKey(key); tempstr = "Key|Signature:C" tempstr=tempstr.replace("C",asdf1); staffPlate[5] = tempstr; doingHeader=0; } break; case 'L': //Unit note length var anum, adenom; noteLengthStr = token; result = noteLengthStr.match(/ *(\d+) *\/ *(\d+) */); notelength = fraction(result[1],result[2]) * 768; break; case 'M': // Meter string meterStr = token; if (meterStr == "C|") meterStr = "AllaBreve"; if (meterStr == "C") meterStr = "Common"; if (doingHeader == 0) genWorkEntry("TimeSig|Signature:" + meterStr); else staffPlate[6] = "TimeSig|Signature:" + meterStr; break; case 'N': //Comments (notes) about the tune if (comments.length > 0) comments+= "\\r\\n"; comments += token; break; case 'P': //Text to be inserted genWorkEntry("Text|Text:\"" + token + "\"|Font:StaffBold|Pos:10"); break; case 'Q': //Tempo tempoStr = token; //alert(tempoStr); result = tempoStr.match(/ *(\d+) *\/ *(\d+) *= *(\d+) */); if (result != null) { var tnum = result[1]; var tdum = result[2]; var ttempo = result[3]; } else { result = tempoStr.match(/(\d+)/) if (result == null) { alert("Cannot interpret tempo"); break; } else ttempo = result[1]; } result = tempoStr.match(/"(.*)"/); if (result != null) tempoTxt = result[1]; //alert("Checking temp text " + tempoStr) //bugging var tnote = fraction(tnum,tdum) * 768; //alert(tnote); var tnotename = getTempoName(tnote); //alert(tnotename); tempoStr = "Tempo"; if (tnotename != "--") tempoStr += "|Base:" + tnotename; tempoStr += "|Tempo:" + ttempo; if (result != null) tempoStr += "|Text:\"" + tempoTxt + "\""; tempoStr += "|Pos:9"; genWorkEntry(tempoStr); break; case 'T': //Title title = token; if (title.indexOf('"') > -1) { //If any quotes in title result=title.match(/"([^"]*)"/) // ignore what is outside of them if (result != null) { title=result[1]; } else alert("Mismatched quotes in title"); } break; case 'V': //Voice ************* Code to be inserted*********** result = token.match(/ *([^ \\]+)/) if (voiceTab.length == 0) voiceTab[0] = result[1]; else { currentVoice = 0; while ((currentVoice < voiceTab.length) && (voiceTab[currentVoice] != result[1])) { currentVoice++;} if (voiceTab[currentVoice] != result[1]) { voiceTab[voiceTab.length] = result[1]; lyrics[currentVoice]=""; } } break; case 'X': //Refence number if (doingHeader == 0) { alert("More than one X: found, results may be unusable!!"); } break; //We don't do anything with it, but it has to be there. default: if (comments.length > 0) comments+= "\\r\\n"; comments += atype + ":" + token; break; } //End of case } //End checkHead function genNwc() { var OutputTab = new Array(); //Build nwctxt var errCnt=0; lines="", doingHeader=1, errText="", slurOn=0, bracketOn=0, graceOn=0, i, lyricRegExp=/\\r\\n ?w:(.*$)/; severeError=0, lastWork=-1, lyrics.length=0, lyrics[0]="", author="", comments="", title="", meterStr=""; workTab.length=0, chordArray.length=0, tgroup=0, notelength=96, lastfound=""; tempoTxt=""; currentVoice=0, voiceTab.length = 0, staffPlate.length=6; boilerPlate[1] = '|SongInfo|Title:"TITLE"|Author:"AUTHOR"|Lyricist:"LYRICIST"|Copyright1:""|Copyright2:""|Comments:"COMMENT"'; staffPlate[1] = 'StaffProperties|EndingBar:Section Close'; lines = document.nwcform.InputField.value; if (lines.length < 5) { alert("Empty input area, script aborted"); return 1; } lines = lines.replace(/%.*[\n\r]{1,2}/g,"\n"); // Removes all comments. lines = lines.replace(/ {2,}/g," "); // Two or more consecutive spaces replaced by one space lines = lines.replace(/\\ [\n\r]{1,2}/g,""); // Any backslash to and including newline is removed lines = lines.replace(/ *[\n\r]{1,2}/g,"\n"); // All spaces to end of line lines = lines.replace(/[\n\r]{1,2}/g,"\\r\\n"); // Replaces newline with string required for NWC lyrics lines = lines.replace(/\\\\/g,"\\") //Replaces two backslashes with one if necessary lines = "\\r\\n" + lines; //Start with newline character lines = lines.replace(/(\\r\\n){2,}/g,"\\r\\n"); document.nwcform.OutputField.value = lines; //For debugging only i=0; var rw = /\\r\\n ?w:/g while ((result = rw.exec(lines)) != null) { i++; } //Counts number of lyric lines if (i > 1) lyricRegExp=/\\r\\n ?w:([^\\]*)/ ; while (lines.length > 0) { //Main parsing loop var strLength, maxOffset = lines.length; while(lines.charCodeAt(0) == " ") // Remove extra spaces from leading character of code to be parsed {lines = lines.substr(1);} if (result = lines.match(lyricRegExp)) { // The w: will be the last thing if (result.index == 0) { lastfound = "lyrics" strLength = result[0].length; var nlyrics = result[1]; nlyrics = nlyrics.replace(/\'/g,"\\\'"); // Insert a slash before any quote in lyrics if (lyrics[currentVoice].length > 0) lyrics[currentVoice] += "\\r\\n"; lyrics[currentVoice] += nlyrics; lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/\\r\\n([A-Za-z]): ?([^\\]*)/))) { if (result.index == 0) { lastfound = "header"; strLength = result[0].length; checkHead(result[1],result[2]); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if (doingHeader) { doingHeader=0; } if ((result = lines.match(/"(_?)([^"]+)"/))) { //Found text if (result.index == 0) { lastfound = "text"; //alert("text: " + result[1]); strLength = result[0].length; var tempstr = "Text|Text:\"" + result[2] + "\"|Font:StaffItalic|Pos:"; tempstr += (result[1].length)? "-7": "9"; genWorkEntry(tempstr); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/\|\|/))) { //Found double bar line if (result.index == 0) { lastfound = "double bar"; strLength = result[0].length; genWorkEntry("Bar|Style:Double"); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/:\|(\d)/))) { //Found Repeat Close and Special ending if (result.index == 0) { lastfound = "repclose special"; strLength = result[0].length; genWorkEntry("Bar|Style:MasterRepeatClose"); genWorkEntry("Ending|Endings:" + result[1]); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/![^!\|\[\]]*!/))) { //Found ! delimited text will eventually process it here. if (result.index == 0) { lastfound = "!..!"; strLength = result[0].length; genWorkEntry("Text|Text:\"" + result[0] + "\"|Font:StaffBold|Pos:-8|Wide:Y|Justify:Left|Placement:BestFit|Color:3|Visibility:Default"); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/\| *!\\r/))) { //Found Barline systembreak if (result.index == 0) { lastfound = "bar sysbrk"; strLength = result[0].length; genWorkEntry("Bar|SysBreak:Y"); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/[\|\[]{1,2}(\d)/))) { //Found Barline,open bracket and Special ending if (result.index == 0) { lastfound = "bar and special"; strLength = result[0].length; genWorkEntry("Bar"); genWorkEntry("Ending|Endings:" + result[1]); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/:\|(\d)/))) { //Found Repeat Close and Special ending if (result.index == 0) { lastfound = "rep close and special"; strLength = result[0].length; genWorkEntry("Bar|Style:MasterRepeatClose"); genWorkEntry("Ending|Endings:" + result[1]); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/\[\||\|:/))) { //Repeat open [| or |: if (result.index == 0) { lastfound = "repeat open"; strLength = result[0].length; genWorkEntry("Bar|Style:MasterRepeatOpen"); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/\|\]|:\|[ !]*/))) { //Repeat close |] or :| if (result.index == 0) { lastfound = "repeat close"; strLength = result[0].length; genWorkEntry("Bar|Style:MasterRepeatClose"); if (result[0].indexOf("!") > 1) workTab[lastWork][0] += "|SysBreak:Y"; lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/\:\:/))) { //Repeat close, then repeat open :: if (result.index == 0) { lastfound = "rep close then open"; strLength = result[0].length; genWorkEntry("Bar|Style:MasterRepeatClose"); genWorkEntry("Bar|Style:MasterRepeatOpen"); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/([<>]{1,2})/))) { //Found 1 or 2 ">" or "<" if (result.index == 0) { lastfound = "timeshift"; strLength = result[0].length; genWorkEntry(result[0]); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/ *\) *\( */))) { //slur end & begin if (result.index == 0) { lastfound = "slurendbeg"; strLength = result[0].length; if (strLength > 2) if (workTab[lastWork][7] > -1) workTab[lastWork][7] = 0; // Found space in slur end/begin genWorkEntry(")("); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/ *\)( *)/))) { //slur end & maybe space if (result.index == 0) { lastfound = "slurend"; strLength = result[0].length; if (strLength > 1) if (workTab[lastWork][7] > -1) workTab[lastWork][7] = 0; // Found space after slur slurOn--; if (slurOn == 0) { workTab[lastWork][4] = 0; ; } lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/\((\d)/))) { //timing bracket (3 if (result.index == 0) { lastfound = "timebracket"; strLength = result[0].length; tgroup = parseInt(result[1]); if (tgroup == 2) {tgrNum = 3; tgrDum = 2} else if (tgroup == 3) {tgrNum = 2; tgrDum = 3} else { errText += "Can't handle (" + tgroup + "\n"; tgroup = 0; } lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/[\{\}\(\)\| ]/))) { //Ignore a space if found here if (result.index == 0) { lastfound = "onechar " + result[0]; strLength = result[0].length; var achar = result[0]; switch(achar) { case "{": graceOn = 1; break case "}": graceOn = 0; break case "(": slurOn++; break case ")": slurOn--; break case "|": genWorkEntry("Bar"); break; case " ": break; default: alert("Serious logic error checking : " + achar); break } lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/(\.?)\[([^\]]*)\](\d*)(\/*)(\d*)([- ]?)/))) { //Found Bracket enclosed code if (result.index == 0) { lastfound = "bracket enclosed"; strLength = result[0].length; token = result[1] + result[2]; if ((result1 = token.match(/([A-Za-z]):([^\\]*)/))) { checkHead(result1[1],result1[2]); // Code to generate posTab entries from imbedded header goes here } else { chordIndex = 0; chordArray.length = 0, errFlag=0; var spectoken = token; if ((spectoken.indexOf("(") > -1)) { spectoken = spectoken.replace(/\(/g,""); slurOn++; } if ((spectoken.indexOf(")") > -1)) { spectoken = spectoken.replace(/\)/g,""); slurOn--; } checkNotes(1,spectoken); // 1 indicates found notes will be in a chord if (severeError) { lines = lines.substr(strLength); continue; } workTab[lastWork][1] *= checkDuration(result[3],result[4],result[5]) / notelength; // Notelength already inserted for (var i =0; i 0) workTab[lastWork][9] = 1; } lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/Z(\d*) ?/))) { //Found a multi measure rest if (result.index == 0) { lastfound = "multirest"; strLength = result[0].length; longRest(result[0]); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/[zx](\d*)(\/*)(\d*) ?/))) { //Found a rest if (result.index == 0) { lastfound = "rest"; strLength = result[0].length; checkRest(result[0]); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(anote))) { //Found a note if (result.index == 0) { lastfound = "note"; strLength = result[0].length; checkNotes(0,result[0]); lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } if ((result = lines.match(/\\r\\n ?/))) { //Found end of line, ignore if (result.index == 0) { lastfound = "EOL"; strLength = result[0].length; lines = lines.substr(strLength); continue; } else maxOffset = (result.index < maxOffset)? result.index : maxOffset; } // If this point is reached, we found code we don't know what to do with if (errCnt++ < 3) { alert( lines + "\n" + "Unable to process: " + lines.substr(0,maxOffset) + " length: " + maxOffset + " last: " + lastfound);} if (errCnt == 3) {alert("Other errors will be summarized");} errText += "Unable to process: " + lines.substr(0,maxOffset) + " length: " + maxOffset + " last: " + lastfound + "\n"; genWorkEntry("Text|Text:\"" + lines.substr(0,maxOffset) + "\"|Font:StaffBold|Pos:-8|Wide:Y|Justify:Left|Placement:BestFit|Color:3|Visibility:Default"); lines = lines.substr(maxOffset); } //End main parsing loop // Applying tempo changes when >>, >, <, or << separates notes for (i = 0; i < workTab.length; i++) { switch (workTab[i][0]) { case ">>": workTab[i-1][1] *= 7/4; // Creates double dotted workTab[i+1][1] /= 4; // Adds two flags workTab[i][0] = "--"; break; case ">": workTab[i-1][1] *= 3/2; // Adds a dot workTab[i+1][1] /= 2; // Adds a flag workTab[i][0] = "--"; break; case "<<": workTab[i-1][1] /= 4; // Adds two flags workTab[i+1][1] *= 7/4; // Creates double dotted workTab[i][0] = "--"; break; case "<": workTab[i-1][1] /= 2; // Adds a flag workTab[i+1][1] *= 3/2; // Adds a dot workTab[i][0] = "--"; break; default: //A good place to check for non beamable notes if (workTab[i][1] > 168) {workTab[i][7] = -1;} break; } } // 1 2 3 4 5 6 7 8 9 10 // NOTE, duration (in 768ths), acc-position, grace(0|1), slur(0,1), chord(0|1), tie(1,0), beam(0,1,2,4), Up|Down, stacatto // 0 1 2 3 4 5 6 7 8 9 var unslurFlag = 1; var iprev, inext; for (i = workTab.length - 1; i > -1; i--) { //To remove slur attribute for last slur of any set, start from back if (workTab[i][0].slice(0,4) == "NOTE") { if (workTab[i][4] ==1 && unslurFlag == 1) { //Removed 3/20/11 workTab[i][4] = 0; unslurFlag = 0; } } else { if (workTab[i][0].slice(0,2) == ")(") { // Found slur close & slur open, prepare to reset if (slurOn == 1) {workTab[i][4] = 0;} unslurFlag = 1; workTab[i][0] = "--";} } //End else } //End slur fixup genWorkEntry("++"); //Artificial last record junk = 0; for (i = 0; (i+ 1) < workTab.length; i++) { //Processing beams, pass 1 if (workTab[i][0].slice(0,4) == "NOTE") { iprev = i - 1; if (iprev > -1) { while ((workTab[iprev][0].slice(0,2) == "--") || workTab[iprev][0].slice(0,2) == "Te") {iprev=(iprev)?(iprev - 1):(workTab.length -1) }} //Skip null or text entries else iprev=workTab.length -1; inext = parseInt(i) + 1; while ((workTab[inext][0].slice(0,2) == "--")|| (workTab[inext][0].slice(0,2) == "Te")){inext++;} // Can look at objects on either side of entry "i". if ((workTab[iprev][7] == -1) && (workTab[i][7] == 0)) {workTab[i][7] = -1} else if (((workTab[iprev][7] == -1) || (workTab[iprev][7] == 4)) && (workTab[i][7] == 1) && (workTab[inext][7] >= 0)) {workTab[i][7] = 2} else if ((workTab[iprev][7] == 0) && (workTab[i][7] == 1) && (workTab[inext][7] == -1)) {workTab[i][7] = -1} else if ((workTab[iprev][7] == 0) && (workTab[i][7] == 1) && ((workTab[inext][7] == 0) || (workTab[inext][7] == 1))) {workTab[i][7] = 2} else if ((workTab[iprev][7] == 1) || (workTab[iprev][7] == 2)) { if ((workTab[i][7] == 0) || ((workTab[i][7] == 1) && (workTab[inext][7] == -1))) {workTab[i][7] = 4;} } else if ((workTab[iprev][7] == -1) && (workTab[inext][7] == -1)) {workTab[i][7] = -1}; if (((workTab[iprev][7] == -1) || (workTab[iprev][7] == 4)) && (workTab[i][7] == 1) && (workTab[inext][7] == -1)) {workTab[i][7] = -1}; } // Beams, pass 1 } workTab.length--; //Remove artificial record for(i = 0; (i + 1) < workTab.length; i++) { if (workTab[i][7] == 2) { //Beam start var istart = i, sumOffset = 0, ilast; do { while (workTab[i][0].slice(0,2) == "--") {i++;}; var templine = "" + workTab[i][2]; workTab[i][2] = templine; result = workTab[i][2].match(/[#b-x]*(-*[\d+])/) var iOff1 = parseInt(result[1]); //Bottom or only note of chord/note sumOffset += iOff1; var lastComma = workTab[i][2].lastIndexOf(","); //Find top note of chord, or if it exists if (lastComma > 2) { var lastPosStr = workTab[i][2].slice(lastComma); result = lastPosStr.match(/[#b-x]*(-*[\d+])/) var iOff2 = parseInt(result[1]); sumOffset += iOff2; } else {sumOffset += iOff1;} //If no chord, count the note twice var ilast = i; } while (workTab[i++][7] != 4); i--; // Might cause a loop, be careful!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! var UpDnStr = (sumOffset < 0)? "Up" : "Down"; //Have determined stem direction for (itemp = istart; itemp <= ilast; itemp++) workTab[itemp][8] = UpDnStr; } //End if condition } //End beam loop // Clean up empty bars before or after a repeat sign for (i = 0; (i + 1) 3)) {repCheck++; } if ((workTab[i][0].search("RepeatClose") > 3)) {repCheck--;} } if ((repCheck > 0) || (repCheck < -1)) { errText += "Repeat open and close don't match\n"; } // If the last thing is an ordinary bar or double bar , remove it. i = workTab.length; while (workTab[i-1][0].slice(0,2) == "--") {i--; workTab.length--;} if (((workTab[i-1][0].length == 3) && (workTab[i-1][0].slice(0,3) == "Bar")) || (workTab[i-1][0].length == 16) && (workTab[i-1][0].slice(0,16) == "Bar|Style:Double")) workTab.length--; lines = ""; //To rebuild textarea // Used for live code if (document.nwcform.DeBugging.checked == false) { var tstring = "" + boilerPlate[1]; tstring = tstring.replace("TITLE",title); tstring = tstring.replace("AUTHOR",author); tstring = tstring.replace("LYRICIST",lyricist); tstring = tstring.replace("COMMENT",comments); boilerPlate[1] = tstring; // Ready to create NWCTXT area from workTab if (workTab[workTab.length - 1][0].slice(0,3) == "Bar") { //If piece ends in ANY type of barline tstring = "" + staffPlate[1]; tstring = tstring.replace("Section Close","Open (hidden)"); // don't use NWC's default staffPlate[1] = tstring; } for (var i = 0; i < boilerPlate.length; i++) { lines+=boilerPlate[i] + "\n"; } /////////////// Lines for new staff start here ///////////////////////// if (voiceTab.length > 0) { var SortFile = new Array(); SortFile.length = 0; for (i = 0; i < workTab.length; i++) SortFile[i] = workTab[i]; SortFile.sort(Mastersort); } currentVoice = 0; // Get ready for loop do { //Processes single staff (voice) in this loop if (voiceTab.length > 0) { var ii = 0; workTab.length = 0; for (i = 0; i < SortFile.length; i++) { if ( Math.floor(SortFile[i][10] / 5000) == currentVoice) workTab[ii++] = SortFile[i]; } } // If the last thing is an ordinary bar or double bar , remove it. i = workTab.length; if (i < 2) { alert ("wierd problem here"); return 1 } if (((workTab[i-1][0].length == 3) && (workTab[i-1][0].slice(0,3) == "Bar")) || (workTab[i-1][0].length == 16) && (workTab[i-1][0].slice(0,16) == "Bar|Style:Double")) workTab.length--; tstring = 'StaffProperties|Muted:N|Volume:127|StereoPan:64|Device:0|Channel:Z' asdf1 = currentVoice + 1; tstring=tstring.replace("Z",asdf1) staffPlate[2]=tstring; tstring = (voiceTab.length > 1)? 'AddStaff|Name:"Z"|Label:"Z"|Group:"Standard"': 'AddStaff|Name:"Z"|Group:"Standard"'; asdf1 = (voiceTab.length)?voiceTab[currentVoice] : "Staff" tstring=tstring.replace(/Z/g,asdf1) staffPlate[0]=tstring; for (i = 0; i < staffPlate.length; i++) { lines += "|" + staffPlate[i] + "\n" if ((i == 3) && (lyrics[currentVoice].length > 0)) { lines+= "|Lyrics|Placement:Bottom|Align:Standard Rules|Offset:0\n|Lyric1|Text:\"" + lyrics[currentVoice] + "\"\n";} } // End staffPlate insertion var tripcount=0; for (i = 0; i < workTab.length; i++) { // alert("i = " + i); if (workTab[i][0].slice(0,2) == "--") continue; if (workTab[i][0].slice(0,3) == "Bar") tripcount=0; if (workTab[i][0].slice(0,4) == "NOTE") { tstring = "|"; tstring += (workTab[i][5] == 1)? "Chord" : "Note"; tstring += "|Dur:"; var tdur = getNoteLength(workTab[i][1]); if (tdur.slice(0,3) == "Err") { var reducetxt = reduceIt(workTab[i][1],768) tdur = getNoteLength(notelength); //Substitute default length errText += "Notes of length " + reducetxt + " not supported\n" ; lines+= "|Text|Text:\"Length: " + reducetxt + " converted\"|Font:StaffBold|Pos:-8|Wide:Y|Justify:Left|Placement:BestFit|Color:3|Visibility:Default\n" } tstring += tdur; if (tdur.search("Trip") > 1) { if ((tripcount % 3) == 0) { //First triplet tstring += "=First"; } tripcount += parseInt(workTab[i][1]); if ((tripcount % 3) == 0) { //Last triplet tstring += "=End"; } } if (workTab[i][3]) tstring += ",Grace"; if (workTab[i][9]) tstring += ",Staccato"; if (workTab[i][4]) tstring += ",Slur"; tstring += "|Pos:" + workTab[i][2]; if ((workTab[i][7]) > 0) { tstring += "|Opts:Stem=" + workTab[i][8] + ",Beam"; if ((workTab[i][7]) == 2) { tstring += "=First"; } if ((workTab[i][7]) == 4) { tstring += "=End"; } } tstring += "\n"; lines += tstring; } else { lines += "|" + workTab[i][0] + "\n"; } } currentVoice++; } while (currentVoice < voiceTab.length); // End staff (voice) loop ////////////////// End of insertion for one staff ////////////////////////////////////// lines += "!NoteWorthyComposer-End\n"; } //End of live code section else { // Start debugging only section for (i = 0 ; i < workTab.length; i++) { lines += i + " " ; for (j =0; j < workTab[i].length; j++) {lines += workTab[i][j] + " "; } if ((i+1) < workTab.length) lines += "\n"; } } // 1 2 3 4 5 6 7 8 9 10 // NOTE, duration (in 768ths), acc-position, grace(0|1), slur(0,1), chord(0|1), tie(1,0), beam(0,1,2,4), Up|Down, stacatto // 0 1 2 3 4 5 6 7 8 9 if (errText.length) {alert(errText);} document.nwcform.OutputField.value = lines; if (document.nwcform.DeBugging.checked == false) {document.nwcform.OutputField.select();} //Pre selected for Cntl/C // */ } //End of function
Convert ABC Notation to NoteWorthy Composer text
Please check several useful links near the bottom.
Sample Data
Paste abc text into the area on the left.

Copy the above to your clipboard and save it as a file ending in .nwctxt where it can be imported into NoteWorthy Composer or NoteWorthy Viewer.  For more information on NWC or to purchase it, click noteworthysoftware.com.
For a free viewer that can read nwctxt files, look at this link.
A good source for abc tunes compiled by John Chambers: trillian.mit.edu/~jc/music/abc.
A desktop shortcut can avoid the need to copy the output to a NWCTXT file is here. After Cntl/C, clicking the shortcut will start the Viewer or Composer with your converted file.
To convert a staff of NWC to ABC, check out this user tool.   The boxmark2 font used to create multi measure rests is available from Scriptorium.
Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License 2011 by Warren Porter