Determining Chords vs Lyrics (1 Viewer)

JonXL

Member
Local time
Today, 06:00
Joined
Jul 9, 2021
Messages
70
I'm working on a script that will clean up and transpose chord/lyric sheets. Here's a couple examples of what I mean - the chords are the letters atop the lyrics.

Code:
G
All of my love all of my kissing

You don't know what you've been a missing   
C                               G
Oh boy  when you're with me  oh boy                         
                        D7                 G
The world will see that you were meant for me


All of my life I've been a waiting

Tonight there'll be no hesitating   
C                               G
Oh boy  when you're with me  oh boy                         
                        D7                 G
The world will see that you were meant for me


Code:
Em       G
Today is gonna be the day
              D                  A7sus4
That they're gonna throw it back to you
Em          G
By now you should've somehow
    D                A7sus4
Realised what you gotta do
Em                   G
I don't believe that anybody
 D           A7sus4              Em G  D  A7sus4
Feels the way I do about you now

The basic form is that the script runs through the range line by line (as split into an array on each new line) and then within the chord line breaks it down into each chord which can then be separately cleaned up/transposed and put back into the string to update the original line ultimately to be written back to the range...

Everything is working well with one exception: I cannot figure out a reliable way to distinguish a line of chords from a line of lyrics.

If I can place the chord line in a specific place (eg, every other line), there is little issue identifying the chord line. But that's not how the real world works - often there are double-enters between groupings of verses, or chords-only/lyrics-only lines, etc. So... how to 'spot' when running through the lines which line has chords vs lyrics... ?

I've thought of maybe trying to identify if there are any real words in a line and thus excluding it - but that would fail on things like A or Am. While I could maybe accommodate that, I'd still have the issue of figuring out if a word is a real word (can I look in the Word dictionary?). Outside that, I can't think of a decent way to do this. I get this is kind of more of a business logic question than one basically on the scripting, but I'm hoping that the group here will be able to spot some additional business logic possibilities given the technology that I've missed.

Any help appreciated! :)
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 19:00
Joined
May 7, 2009
Messages
16,775
maybe put in a Dictionary Collection all chords:

Dim colChords As Object
set colChords = Createobject("Scripting.Dictionary")
'add all chords
colChords.Add Item:="C", Key:="C"
colChords.Add Item:="Cm", Key:="Cm"
colChords.Add Item:="Cm7", Key:="Cm7"
'etc

'now after Splitting your line, test it if it is in the Chord collection:
var = Split(theLine)
for each v In var
'check if it is a chord
If colChords.Exists(v & "")
' it is a chord
else
'lyric
end if
next


''''''''''''''''
you can even create a UDF and pass a Text to it:

public function IsChord(Byval strText As String) As Boolean
Static colChords As Object
If colChord Is Nothing Then
'build the dictionary here
set colChords = Createobject("Scripting.Dictionary")
'add all chords
colChords.Add Item:="C", Key:="C"
colChords.Add Item:="Cm", Key:="Cm"
colChords.Add Item:="Cm7", Key:="Cm7"
'etc
'etc
End If
IsChord = (colChords.Exists(strText))
end function
 

JonXL

Member
Local time
Today, 06:00
Joined
Jul 9, 2021
Messages
70
maybe put in a Dictionary Collection all chords:

Dim colChords As Object
set colChords = Createobject("Scripting.Dictionary")
'add all chords
colChords.Add Item:="C", Key:="C"
colChords.Add Item:="Cm", Key:="Cm"
colChords.Add Item:="Cm7", Key:="Cm7"
'etc

'now after Splitting your line, test it if it is in the Chord collection:
var = Split(theLine)
for each v In var
'check if it is a chord
If colChords.Exists(v & "")
' it is a chord
else
'lyric
end if
next

I'd go this route but it will get confused by things like the word A and chord A.
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 19:00
Joined
May 7, 2009
Messages
16,775
hhmm, when you split you can get the Ubound of the array, right?
i think only chord "A" is the problem?
so initially test the whole line and count how many is the chords:

dim iCount As Integer, iTextCount
dim i As Integer
var = split(theLine)
iTextCount = Ubound(var)
iCount = 0
For i = 0 to iTextCount
iCount = iCount + Abs(colChords.Exists(var(i)))
Next
'iCount > iTextCount , means this line is Chord line
If iCount > iTextCount then
'Chords
'do a second loop here, no need to test colChord.Exists, since we already did it ahead.
Else
'Lyrics
End If
 
Last edited:

theDBguy

I’m here to help
Staff member
Local time
Today, 04:00
Joined
Oct 29, 2018
Messages
19,134
When I look at the sample lyrics, would it be safe to assume that a chord line would have a lot of spaces between each chord as compared to only a single space between lyric words? Just thinking out loud...
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Today, 06:00
Joined
Feb 28, 2001
Messages
23,117
I think I'm with theDBguy here. Don't focus on chords. You should be able to find lines of text that are CLEARLY lyrics. A dictionary approach probably wouldn't work well to identify chords. But there is another question here. What is the source of these lines of lyrics and chords? Frequently, the best solution for a nasty problem is to label the nasty items so that you can go back later to identify them. If, during data import, you can put a prefix on any chorded lines using a character totally unlikely to be used in lyrics, the problem becomes a lot easier.
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 19:00
Joined
May 7, 2009
Messages
16,775
I think I'm with theDBguy here. Don't focus on chords
unlikely but probably, there is one line and 1 word and 1 chord, is it a chord or lyric?

Code:
Am
Hello

G     F                 A
Is it me you're looking for?
 

Gasman

Enthusiastic Amateur
Local time
Today, 12:00
Joined
Sep 21, 2011
Messages
10,838
Chords are of a max length?
Would need a combination of tests I would expect

Otherwise Em would be found in 'See Emily Play' ?
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 19:00
Joined
May 7, 2009
Messages
16,775
Otherwise Em would be found in 'See Emily Play' ?
im not using Instr(), so it will only be found in the Chords when using dictionary( dictObj.Exists(Key)).
only "A" can be lyric or chord.
on my last, example:

Code:
Am
Hello

G     F                 A
Is it me you're looking for?

the first line: "Am", will be chord
when you Split it:
Ubound(var) = 0
"Am" in dictionary so 1 i added to iCount
then, iCount > Ubound(var)
therfore it is chord.

next line..."Hello"
not in dictionary, so iCount = 0
iCount > Ubound will be False, therefore not a chord

third line: G F A
all in dictionary, the Ubound() = 2, iCount = 3
iCount > Ubound, therefore a chord

fourth line,
"Is it me you're looking for?"
Ubound = 5
icount = 0, not a Chord.

'''''''''''
will only work if the chords are Separated by a space char.
 

JonXL

Member
Local time
Today, 06:00
Joined
Jul 9, 2021
Messages
70
Wow... this got a lot of input. :)

Thank you all for the input. My current setup is already using a dictionary with the chords as keys and an array for the item (so if you are moving a G up two semitones, you will find the new chord with dctKeyList("G")(2):

Code:
'set up dictionary
    Set dctKeyList = New Scripting.Dictionary
   
    With dctKeyList
        .RemoveAll
        .Add "A_", Array("A_", "A", "B_", "B", "C", "D_", "D", "E_", "E", "F", "F#", "G", "A_")
        .Add "A", Array("A", "B_", "B", "C", "D_", "D", "E_", "E", "F", "F#", "G", "A_", "A")
        .Add "A#", Array("A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#")
        .Add "B_", Array("B_", "B", "C", "D_", "D", "E_", "E", "F", "F#", "G", "A_", "A", "B_")
        .Add "B", Array("B", "C", "D_", "D", "E_", "E", "F", "F#", "G", "A_", "A", "B_", "B")
        .Add "C", Array("C", "D_", "D", "E_", "E", "F", "F#", "G", "A_", "A", "B_", "B", "C")
        .Add "C#", Array("C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#")
        .Add "D_", Array("D_", "D", "E_", "E", "F", "F#", "G", "A_", "A", "B_", "B", "C", "D_")
        .Add "D", Array("D", "E_", "E", "F", "F#", "G", "A_", "A", "B_", "B", "C", "D_", "D")
        .Add "D#", Array("D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#")
        .Add "E_", Array("E_", "E", "F", "F#", "G", "A_", "A", "B_", "B", "C", "D_", "D", "E_")
        .Add "E", Array("E", "F", "F#", "G", "A_", "A", "B_", "B", "C", "D_", "D", "E_", "E")
        .Add "F", Array("F", "F#", "G", "A_", "A", "B_", "B", "C", "D_", "D", "E_", "E", "F")
        .Add "F#", Array("F#", "G", "A_", "A", "B_", "B", "C", "D_", "D", "E_", "E", "F", "F#")
        .Add "G_", Array("G_", "G", "A_", "A", "B_", "B", "C", "D_", "D", "E_", "E", "F", "G_")
        .Add "G", Array("G", "A_", "A", "B_", "B", "C", "D_", "D", "E_", "E", "F", "F#", "G")
        .Add "G#", Array("G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#")
    End With

As it sits now, I have my code set to just skip over anything that isn't valid in the keylist (I don't know why I called it key instead of chord...). For minors, etc., those are pulled out separately in each chunk (chunks are separated by spaces); so for an Em7, there will be the root variable of value "E", the full chunk of "Em7" and the 'extra' of "m7". It is the root that is checked against the keylist. Again, when the root isn't found, it just passes over that but this only makes sense because I know where the chord lines are (every other). If I am trying to figure out where the chord lines are, I think based on @arnelgp's suggestion, I can use the 'check if it's in list' logic to figure out whether I am on a chord line or a lyric line. I believe the full 'business logic' will be something like this...

  1. Collect all 'roots' for a given line into an array/dictionary/etc. (the 'root' is the portion of the chunk - character groupings separated by spaces - starting at the beginning of the chunk up until a letter that is either an S/s, m/M or numeric). In the sentence "Is it me you're looking for", "Is", "it", etc. will be roots; in "Am" the root will be "A"; in "I am here", "I", "a" and "here" will be roots.
  2. Check the root against the list of chords; if any are not chords, it is a lyric line - skip over it.
  3. If ALL ARE chords, what are they?
  4. If AT LEAST ONE is not "am" or "ab", it is certainly a chords line - process it
  5. If they are all one of "am" "ab", ... (here I am debating either a) popup notifying the user of an uncertain line and let them choose how to proceed probably with an option to interpret all other lines matching that pattern with whatever chord/lyric choice the user makes or b) using common-sense English interpretation that the words "am" and "ab(s)" don't really appear by themselves in any given phrases and so must be chords if they are the only things on the line - this has the risk that if the rows are broken up weird, we could have a sentence of "I am here" in three lines where the "am" is considered a chord - I don't know how likely that is....)
Curious - 5.a or .b, which do you all think is most reasonable here? I can't say I've ever seen a song that would fail a 5.b test, but I don't like to say never. On the other hand, it is quite common for "A" to appear as the only chord on a line - it's a common chord - and so I could end up being endlessly prompted to confirm lines are chords just to avoid the one instance out of 100 million where "A" might actually be a lyric all on its own line.

ABE: Could probably add some additional logic to really make sure, like if "Am" and "Ab" are on the line together and the only thing, it's almost certainly not a string of English words but rather chords - again, though, that's not too common in chords either, so it might not help distinguish in this case if I go the 5.a route and I am just trying to cut back the number of times I'd get a popup...

Thanks again!
Jon
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Today, 06:00
Joined
Feb 28, 2001
Messages
23,117
Chords are of a max length?

Yes, but nonetheless can be quite long. For example, these are all legit chord designations: G#maj7b5 or Bbdim7 or F#69

In the end analysis, if you have no anchor that tells you what the line IS then you are going to have to find a way to TELL the program. If you cannot rely on strict alternation between a "chord line" vs. a "lyric line" then you are going to have major headaches, minor indigestion, diminished sanity, and dominant confusion. (The musicians among you will recognize what I did there.)

Then, of course, when I played with a small rock-and-blues combo, our favorite ending chord was "F demolished."
 

GPGeorge

Grover Park George
Local time
Today, 04:00
Joined
Nov 25, 2004
Messages
764
Yes, but nonetheless can be quite long. For example, these are all legit chord designations: G#maj7b5 or Bbdim7 or F#69

In the end analysis, if you have no anchor that tells you what the line IS then you are going to have to find a way to TELL the program. If you cannot rely on strict alternation between a "chord line" vs. a "lyric line" then you are going to have major headaches, minor indigestion, diminished sanity, and dominant confusion. (The musicians among you will recognize what I did there.)

Then, of course, when I played with a small rock-and-blues combo, our favorite ending chord was "F demolished."
Causing treble again I see.
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Today, 06:00
Joined
Feb 28, 2001
Messages
23,117
Of course, George. My favorite chord is discord.
 

Users who are viewing this thread

Top Bottom