' MakeChord-AdditiveAccidental-LP.vbs - Proof of concept - Lawrie Pardy.
' Version 1.1
' With updates from "addOctave.vbs" and correspondence courtesy of RickG
' Usage: run the script with 0 or more space delimited arguments. Each argument is an interval to create a chord.
' I.E. to create a triad, your arguments are "3 5" - no quotes, to create an octave use "8" or leave blank,
' to create a first inversion triad try "-4 3", a second inversion triad try "-6 -4". A 9th? try "3 5 7 9"
' You can specify an "additive accidental" too. I.E. b3 will add a flat to the any accidental on the original note when it
' creates the 3rd. A b-4 would make the created chord member a b 4th down.
' So in the b3 case a B would have a Db added to it, a Bb would have a Dbb added to it. Naturals will be natural no matter what!
' There is also a limit - if the original note is bb or X then it doesn't matter what you add (excepting a natural) the bb or X
' is the limit that can be achieved.
' BTW, we aren't worried about order here either... Any set of intervals in any order should work OK
'
' Lots of comments included to prove to myself I have some idea of what I think I'm doing
'
Option Explicit ' Require explicit declaration of variables
Dim lin, objArgs, args, i, j, k, n, na, a1, pos1, posadd, acc, acc1, acc2, accC, accadd, test ' Create initial variables
' Assign a number to add to the Pos of the original note to define the position of the new chordmember
' Default is octave (add 7) but could be a 3rd (add 2) etc. - you choose from the command line
' At the moment the script assumes that any accidentals on the original note will be required for the new chordmember too
' unless overridden on the command line.
' If you want to change this, be my guest.
' Read any arguments from the command line
Set objArgs = WScript.Arguments
If objArgs.Count <> 0 Then ' make sure we actually have at least one argument
If LCase(objArgs.Item(0)) = "help" Then
Dim hlp(4) ' Create an array to hold the help text
hlp(0) = "Space delimited numbers specify the required intervals."
hlp(1) = "They may be negative or unsigned (positive)."
hlp(2) = "and may include v (double flat), b (flat), n (natural), # (sharp) or x (double sharp)."
hlp(3) = "E.G. 3 5 would give a normal triad, -4 3 would give a 1st inversion triad."
hlp(4) = "These accidentals are additive to any accidental on the starting note"
MsgBox Join(hlp, vbLf), 0 , "Help - Optional arguments:": WScript.Quit ' Quit if the help text is displayed.
End If
End If
If objArgs.Count = 0 Then args = 1 Else args = objArgs.count
Redim posadd(args), accadd(args)
For k = 0 to objArgs.Count - 1 ' Start the loop - Choose the array element to test
If objArgs.Item(k) <> "" Then ' make sure we actually have at least one argument
n = aPos(objArgs.Item(k)) ' call aPos to create an array we can test
accadd(k + 1) = "" ' Make sure the acc. to be added starts off blank
accadd(k + 1) = AccToNum(n(0)) ' Assign a number to accadd to represent the accidental
posadd(k + 1) = n(1) - 1 ' Assume we have a positive interval so subtract 1 from it: 3 becomes 2
If Instr(n(1),"-0") Then ' But if we have a negative zero interval add nuthin, but gotta catch it
posadd(k + 1) = n(1)
Else If n(1) = 0 Then ' Or if we have a zero interval add nuthin, but still gotta catch it
posadd(k + 1) = n(1)
Else If Instr(n(1), "-") Then ' And if we have a negative interval then add 1 to it: -5 becomes -4
posadd(k + 1) = n(1) + 1
End If
End If
End If
End If
Next ' Loop the loop 'till done.
If posadd(1) = "" then posadd(1) = 7 ' If we don't have any arguments, assume that an octave chord is required
Do Until WScript.StdIn.AtEndOfStream ' Read the clip - line by line
lin = WScript.StdIn.ReadLine
a1 = Split(lin & "|", "|"): i = 0 'Create an array called "a1" from the line (lin)
If a1(1) = "RestChord" Then ' Check to see if we have a "restchord"
If Instr(a1(5), ",") = 0 Then i = 5 ' If so we need to work with a diferent part of a1
ElseIf a1(1) = "Note" Then ' If we don't have a rest chord make sure we have a note
a1(1) = "Chord": i = 3 ' If so, we change it to a chord
End If
If i Then ' If i is not 0 get ready to call the "aPos" function
n = aPos(Split(a1(i), ":")(1)) ' Populate n from a1(3) or a1(5) with the result of aPos, splitting it at the ":"
pos1 = n(1) ' assign original pos to variable for later use
acc1 = n(0) ' assign original acc to variable for later use
For j = 1 to args ' loop for the number of args (intervals) on the command line
n(1) = pos1 + CInt(posadd(j)) ' add each interval
n(0) = aAcc(acc1, accadd(j)) ' call aAcc and pass the original notes' acc and the new acc.
test = n(0) = "n" AND accadd(j) = 0 ' Check to see if both the source note AND the arg. have no acc
If test Then n(0) = "" ' If so, then override the nat. that would otherwise be assigned.
if objArgs.Count = 0 then n(0) = acc1 ' If we don't specifyanything on the command line then use the source notes acc
If accadd(j) = "0" then n(0) = "n" ' If we specify a natural on the command line then override the calculated acc
a1(i) = a1(i) + "," & Join(n, "") ' repolulate a1(i) with the updated chord members
next ' loop de loop
lin = Join(a1, "|") ' Finally recreate the line from the updated array
End If
WScript.StdOut.WriteLine lin ' Write the line out ready for the next one
Loop ' loop de outer loop
Function aPos(s) ' NotePitchPos to array
Dim test: test = Split("nb#xv ? oxXz ^") ' Create an array to test against
Dim r(3), c, i1 ' retval, char, index
r(1) = s: c = Left(s, 1) ' is it an accidental?
For Each i1 In Array(0, 3, 2)
If InStr(test(i1), c) Then r(i1) = c
r(1) = Replace(r(1), r(i1), "", 1, 1)
c = Right(r(1), 1) ' tie?, hed?
Next: aPos = r ' Array(acc, pos, hed, tie)
End Function
Function aAcc(char, i2) ' inc, dec accidental ' Calculate new accidental
Dim j1: j1 = AccToNum(char) + i2 ' Assign a number to j1 to represent the accidental and add new acc to it
If j1 < -2 Then j1 = -2 Else If j1 > 2 Then j1 = 2 ' limit j1 to the range bb to x (double sharp)
aAcc = Mid("vbn#x", j1 + 3, 1) ' and convert acc back to a symbol
End Function
Function AccToNum(char) ' Assign a number to represent the accidental -2 = bb to 2 = x
if char <> "" Then AccToNum = InStr("vbn#x", char) - 3
End Function ' null returned if char not found
' eof MakeChord-AdditiveAccidental-LP.vbs - Proof of concept