Thread: MIDI Chord Recognition

  1. #1
    Registered User
    Join Date
    Jan 2010
    Posts
    19

    MIDI Chord Recognition

    Hello,

    I'm currently working on a program that recognizes chords by analyzing MIDI note input. The only way I can think of doing this is by creating a huge database of chords and what notes they are comprised of, on top of creating a database of midi notes and what alphabetical pitches they refer to (i.e. midi note 60 = C3).

    I googled for some resources but weren't able to find any.

    Could someone on this board tell me where I might be able to find information on how else this could be done?

    Any information would be appreciated. Thanks.

  2. #2
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Pretty much everything you need, Midi wise (and more) is on Geff Glatt's site... MIDI Technical Fanatic's Brainwashing Center

    First of all... are you getting your information from SMF (Standard Midi Format) files?

    If it's some other format, you will need to show us how it works before we can be a lot of help...
    Last edited by CommonTater; 10-26-2010 at 06:12 PM.

  3. #3
    Registered User
    Join Date
    Jan 2010
    Posts
    19
    Yes, I am in fact using PortSMF.

    CommonTater, thanks for helping me out the past few days. I'll take a more in depth look at the website.

  4. #4
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by baikal_m View Post
    Yes, I am in fact using PortSMF.

    CommonTater, thanks for helping me out the past few days. I'll take a more in depth look at the website.
    PortSMF? Do you mean capturing midi events from a port instead of a file?

    That changes things rather a lot... SMF files have the extension .mid or .midi ... A Midi port has a round 7 pin connector (similar to a keyboard connector). The distinction for your software is that the file has 16 channel compressed data in it... the port delivers 1 channel of uncompressed event data...

    Both are explained on the website, along with programming examples...
    I'll help where I can but it's been a while.
    Last edited by CommonTater; 10-26-2010 at 07:15 PM.

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    So, you have some array of notes which are all active simultaneously, say { Note1, Note2, Note3 }. Find the lowest valued note, and subtract it from the other notes. Then sort the resulting array. Now you've normalized everything to a base of zero, and you can recognize the chord by the distances between notes. After you've recognized the basic chord, add the original lowest valued note back to it to move it back to the proper pitch.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  6. #6
    Registered User
    Join Date
    Jan 2010
    Posts
    19
    Common Tater,
    I'm sorry, I misread your question. What I meant is that I am using the PortSMF library which is a part of PortMedia. It's a library for reading/writing MIDI files. Actually, getting the MIDI info part has been done but what I'm struggling with is the part where I sort these notes (since I am a novice programmer), find out what chord they are, and when this process is done I'll be writing another function that'll determine the interval between each note in the melody and the root of the chord that they play over.

    The MIDI files that I'm reading in are all formatted in a similar way. They all have four tracks: melody, harmony, bass, and drums. I'm writing this program to create a database of melody-harmony relationship.

    Additionally, my aim isn't to figure out exactly what chords are in a midi file. I just need to make sure the lowest note in a chord is in fact the root of the chord, since there might be inversions, etc. I thought that the best way to go about that is to figure out the chords since that would reveal the actual root of the chord.

    brewbuck,

    Great idea. That would make the chords much easier to handle. Thanks!

  7. #7
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Ok... now I understand the task a little better...

    There are some basics you can take from MIDI files...
    1) Way back when some very clever idiot undertook the decision to use tracks and ignore channels. Not helpful since MIDI is all about events on channels... The challenge is to sort the events per their respective channels, not tracks.

    2) One channel produces one instrument sound, so now you have a boundary for each chord. All notes in a valid chord must occur in the same channel.

    3) Every midi event has a time value, event code, channel, and event data. Since not all midi events produce sound you need to either ditch or ignore everything but Note-On and Note-Off events and then you can sort them by channels.

    4) Finding the lowest note in a chord is actually quite simple... they're in numerical order across a piano keyboard. Got 8 notes on? Just pick the lowest numerical valued note, which may or may not be the first one turned on... it's that "natural sound" thing again.

    On a couple of different notes (grin)...

    I didn't know about the PortSMF library... sorry if I misunderstood there. Sometimes you gotta tell me a couple of times to get it to sink in.

    I would suggest you make a little side trip and investigate C structs and arrays of structs for your song decoder. Believe me it's going to make the task ahead much simpler.

  8. #8
    Registered User
    Join Date
    Jan 2010
    Posts
    19
    Yes, I understand the lowest numerical valued note is the lowest pitch in a chord.

    The real problem that I'm facing is this:

    If I have these notes in an array: {43, 43, 48, 52}
    which would translate to: {G, G, C, E}

    I need to know the root of the chord but if I simply grab the lowest pitch I would be grabbing G, which is not the root of the chord. Since these three notes would make a C major chord I need to grab C. If I add 12 to 43 it would be 55, bring that to the end of the array and make it{48, 52, 55} and create a stack of thirds which would make it a root positioned chord. If I have more than three notes, I thought checking the differences between each note and if they aren't 4 or 3 (major or minor 3rd) I'd add 12 to the lower note and shuffle again and eventually they would become a stack of thirds.

    However, a problem with this is that there are some chords in some of the files with a 9th without a 7th, which would make this procedure impossible since a 9th would be a third above the 7th.

    So, my next thought was that if I figure out a chord recognition code (like in Logic Pro that tells you the chord of the midi notes being held down) then I would be able to find the root.

    I'm starting to feel this is a problem too difficult for me to tackle at my level of programming, but how could I ever learn anything if I didn't try something I don't know if I can do? Anyway, there might be a better/easier way to find just the root of the chord.

  9. #9
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by baikal_m View Post
    I'm starting to feel this is a problem too difficult for me to tackle at my level of programming, but how could I ever learn anything if I didn't try something I don't know if I can do? Anyway, there might be a better/easier way to find just the root of the chord.
    My musical knowledge is very limited. My MIDI knowledge is dominantly technical, from helping a friend build a homebrew sequencer... I'm very sure there is a mathematical way to discern the 3rds, 5ths and 7ths, but I have no idea what it might be... perhaps one of the others has some ideas...

    As for this being too difficult... naaaa, it's exactly what you need. Just think of all you will learn doing this...

    The bigger the challenge the sweeter the success.

  10. #10
    Registered User
    Join Date
    Mar 2009
    Posts
    344
    I'm definitely in the "a little knowledge is dangerous" camp, but see if this makes sense.

    Can you convert note numbers to frequencies and look at the ratios between them? You might need to do all permutations and some sort of best match.

    So in your example, you have 3 possible combinations.

    G, C, E
    C, E, G
    E, G, C

    Frequencies are relatively easy to find. It looks like midi notes start with C(-1) = index 0 = 8.175Hz. Since there are 12 notes per octave, and each octave doubles the frequency you get : 8.1758 * 2 ^ (note index / 12). These translate to frequencies :

    G (43) = 97.99887
    C (48) = 130.8128
    E (52) = 164.8138

    You can then take ratios using each of the notes as the root of the chord.

    G, C, E : 1.0, 1.33, 1.68
    C, E, G : 1.0, 1.26, 0.749
    E, G, C : 1.0, 0.595, 0.794

    Since you're working with frequencies, you can multiply or divide by 2 to put all the values between 1 and 2 (you're shifting the notes up or down an octave which doesn't change the chord). This just makes it easier to see the pattern.

    G, C, E : 1.0, 1.33, 1.68
    C, E, G : 1.0, 1.26, 1.50
    E, G, C : 1.0, 1.19, 1.59

    A major chord has a ratio of 4:5:6, or 1:1.25:1.5. There's nothing else which matches these patterns all that well so it's a major chord with C as the root.

    Implementation details :
    You'll probably want an array with the ratios for the types of chords you're looking for. For each of those, you can calculate a "distance" between the ratios you're looking at with the ideal ratio for that particular chord. Find the minimum distance and you've got a match. For example :

    Continuing from the example above. Pretend you're just searching for major and minor chords. The ideal values will look like this :

    maj : 1, 1.25, 1.5
    min : 1, 1.2, 1.5 (10:12:15 ratio)

    I'll use a simple sum of squares of distance - this will get rid of the sign when you subtract from the ideal value. It's a quick way to make a difference of -.2 be the same as 0.2 so that being wrong in one direction isn't canceled out by being just as wrong in the opposite direction on the next note.

    First checking against the ratio for major scales :
    G,C,E = (1-1) ^ 2 + (1.33 - 1.25)^2 + (1.68 - 1.5)^2 = .0402
    C,E,G = (1-1) ^ 2 + (1.26 - 1.25)^2 + (1.5-1.5)^2 = .0001
    E,G,C = (1-1) ^ 2 + (1.19 - 1.25)^2 + (1.59-1.5) ^ 2 = .011

    So there's a pretty good match with C,E,G as a C major scale. Note that it will never be exactly 0 since 12 notes per octave doesn't divide up the frequencies finely enough to get exact matches for the ideal ratios, so you're going to be looking for a best match, not a perfect one. That's good practice for real life.

    You can go through the math for the minor scales as well, but you'll find that none of the distances are nearly as close.

    Also note the ratio of the first note to itself is always 1 so you can eliminate that. You only have to add up the (squares of) the differences in the last two notes.

    Coming up with the ratios of notes in each chord is an exercise for the reader. I think you can go here Interval (music) - Wikipedia, the free encyclopedia, convert the ratios for each of the 12 semitones into a float value and use them. For example, a major chord is semitones 1, 4 and 8. 1 is just 1, 4 is 5:4 = 1.25 and 7 is 3:2 = 1.5. A minor chord is 1, 3, 8 (?) which is 1, 6:5 = 1.2 and 3:2 = 1.5. That's where my music theory runs out without more research.

    You'll need some way to account for cases where you only have 3 of the 4 notes, for example, for a chord but it's a good match otherwise.

    Sounds like an interesting project.
    Last edited by KCfromNC; 10-27-2010 at 02:51 PM.

  11. #11
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Given that note numbers correspond to frequencies (i.e. are in the same order) could not a similar algorythm be used directly on the note numbers themselves?

    The problem with using frequencies in MIDI systems is that the pitch wheel will alter the frequency, but not the note value. The typical pitch wheel will vary frequency up or down several whole notes from center.

  12. #12
    Registered User
    Join Date
    Mar 2009
    Posts
    344
    I guess you could, but you'd have to transform the ratios for the chords into something different.

    With frequencies, the ratios stay constant regardless of the octave. With note numbers, it changes since you're adding 12 to go up and octave instead of multiplying by two.

    So if you've got C (48), E(52), G(43+12=55), the ratio is 1:1.083:1.146. Move the exact same chord up an octave and it's C(60), E(64), G(67) = 1:1.067:1.117.

    And if you have a pitch wheel altering the frequency, just apply that as part of your number->frequency conversion?

  13. #13
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    The real problem is that musical nomenclature, as it stands, is an ambiguous representation; many scales overlap. The minor and major scales, for example, are both diatonic - the only way to distinguish them is to know apriori which note has been chosen as the root...and for that you'd have to ask the composer! Even worse, not all chords are played in "root mode" (whatever you call that); the root might appear somewhere in the middle of the chord, rather than at the bottom. The only real solution (if imperfect) might be to analyze the chord progressions of "typical" compositions so that you can at least infer what the most *likely* chord (at a given instant) might be. That's about the best you could do, methinks...
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Working with MIDI in C++
    By adamdavis in forum C++ Programming
    Replies: 2
    Last Post: 04-11-2010, 08:33 PM
  2. Replies: 1
    Last Post: 02-22-2010, 11:52 PM
  3. How to play midi music from resource without directX
    By alaphate in forum Windows Programming
    Replies: 0
    Last Post: 03-12-2009, 08:49 AM
  4. Intercept the MIDI Out
    By MattMik in forum C++ Programming
    Replies: 2
    Last Post: 10-18-2007, 02:05 AM
  5. speech/handwriting recognition for programming?
    By Sargnagel in forum Tech Board
    Replies: 7
    Last Post: 08-25-2003, 02:24 PM