14 Replies Latest reply: Aug 17, 2010 4:29 PM by captfoss RSS

    How can I measure the frequency(or pitch or note) of a midi file?

    843802
      Hi guys, i am new to this forum and a relatively new java programmer. So please, bear with me, if sometimes I ask or tell somethings that are completely nonsense.

      I need to create a program with basic karaoke functions plus the song's pitch can change depending on the pitch of the singer. So far, i've already created the karaoke with basic functions, such as play, pause, stop, etc. (it plays midi files). It can now also measure the pitch of the singer using a mic in real time.

      my problem, now is that, i'm having a hard time figuring out how to measure the pitch, or even just the notes, of the midi file. So that i can properly align the pitch of the song to the singer's voice.

      can you guys help me with it? thanks a lot in advance.
        • 1. Re: How can I measure the frequency(or pitch or note) of a midi file?
          843802
          How are you related to the instigator of this thread [http://forums.sun.com/thread.jspa?threadID=5447343&tstart=0|http://forums.sun.com/thread.jspa?threadID=5447343&tstart=0] ?
          • 2. Re: How can I measure the frequency(or pitch or note) of a midi file?
            843802
            im not, in any way, related to that thread. why did you ask?
            • 3. Re: How can I measure the frequency(or pitch or note) of a midi file?
              843802
              isji wrote:
              im not, in any way, related to that thread. why did you ask?
              He was 'Simm isj' and you are '*isj* i' so I was curious. Seemed a bit of a coincidence.
              • 4. Re: How can I measure the frequency(or pitch or note) of a midi file?
                843802
                oh i see you, our names and posts, are somewhat related. no wonder you get curious. But, i dont really know him/her at all.

                by the way, do you have any idea how can i measure the notes, of a midi file?
                • 5. Re: How can I measure the frequency(or pitch or note) of a midi file?
                  843802
                  isji wrote:
                  by the way, do you have any idea how can i measure the notes, of a midi file?
                  I know little about midi but your thread made me curious since I thought that the whole point of midi was that it consisted of tokens each of which uniquely defines a note and instrument and duration. The thread title implies I have a misunderstanding so I shall follow this thread in the hope of getting a better understanding.
                  • 6. Re: How can I measure the frequency(or pitch or note) of a midi file?
                    843802
                    sabre150 wrote:
                    isji wrote:
                    by the way, do you have any idea how can i measure the notes, of a midi file?
                    I know little about midi but your thread made me curious since I thought that the whole point of midi was that it consisted of tokens each of which uniquely defines a note and instrument and duration. The thread title implies I have a misunderstanding so I shall follow this thread in the hope of getting a better understanding.
                    well, that is also what i know. A midi file is basically a tokens(or channels) of instruments(with its particular note in a particular time - or tick) that is put together to form a music.

                    i am having a hard time, getting the note on a particular token and time.
                    • 7. Re: How can I measure the frequency(or pitch or note) of a midi file?
                      captfoss
                      sabre150 wrote:
                      I thought that the whole point of midi was that it consisted of tokens each of which uniquely defines a note and instrument and duration.
                      Actually, MIDI files are actually based on states, and the files consist of a series of commands... you sort of think a MIDI file would be a series of things like "Play middle C for 4 counts as a harpsicord", but, it doesn't actually work anything like that.

                      And if you think about it, it makes sense... one of the major purposes of MIDI is to capture & digitize a live performance on a piano... and in that context, the control scheme makes sense.

                      To change instruments, you issue a command to change the instrument state...and you play as that instrument until another change instrument command comes down.

                      To play a note, you generate a NOTE_ON event that contains the key pressed & the velocity with which it was pressed...and the note sounds until a NOTE_OFF event is generated... that seems a weird way to do it, except in the context of recording a piano being played live...

                      So MIDI is a giant state-machine, and a MIDI file is essentially an event log that can be replayed... completely different paradigm than sampled music or the way you think of a MIDI file (especially if you've ever used a staff-based MIDI composer program)
                      • 8. Re: How can I measure the frequency(or pitch or note) of a midi file?
                        843802
                        captfoss wrote:
                        but, it doesn't actually work anything like that.
                        As I said, I know little about Midi - it turns out I know less than I thought.
                        • 9. Re: How can I measure the frequency(or pitch or note) of a midi file?
                          captfoss
                          isji wrote:
                          my problem, now is that, i'm having a hard time figuring out how to measure the pitch, or even just the notes, of the midi file. So that i can properly align the pitch of the song to the singer's voice.
                          You'd need a method to intercept the MIDI events as they're being rendered... once you have the MIDI events, it's easy to get the notes...

                          Assuming you have the MidiMessage object associated with the event being played, you'd simply need to do:
                          byte[] data = midiMessage.getMessage();
                          And that will give you a byte array...
                          int note, velocity;
                          if (data[0] == ShortMessage.NOTE_ON) {
                              note = data[1];
                              velocity = data[2];
                          }
                          And for the note values, they go from 0-127, where 60 is "middle C" (which is 261.6Hz).

                          You could convert the "note" to a frequency using a lookup table using values from the internet.
                          • 10. Re: How can I measure the frequency(or pitch or note) of a midi file?
                            843802
                            thanks captfoss, you made me realize a lot of things.
                            captfoss wrote:

                            You'd need a method to intercept the MIDI events as they're being rendered... once you have the MIDI events, it's easy to get the notes...
                            how can i intercept the MIDI events?

                            Assuming you have the MidiMessage object associated with the event being played, you'd simply need to do:
                            and how can i associate MidiMessage with the event?

                            sorry, if im asking easy questions. but i tried study midi event and midimessage and im still getting confused.
                            • 11. Re: How can I measure the frequency(or pitch or note) of a midi file?
                              captfoss
                              isji wrote:
                              how can i intercept the MIDI events?
                              You can do it the way the following example does it:
                              [http://www.jsresources.org/examples/MidiPlayer.html]

                              Look through the code for the way the "DumpReceiver" is handled. You're essentially wanting to do the same thing, except for the writing to the console part.
                              and how can i associate MidiMessage with the event?
                              I'm guessing you don't speak English as a first language... The association between the MidiMessage and the MidiEvent is inheriant, as a MidiEvent contains a MidiMessage.
                              MidiMessage message = event.getMessage();
                              • 12. Re: How can I measure the frequency(or pitch or note) of a midi file?
                                843802
                                     
                                import java.awt.event.ActionEvent;  
                                import java.awt.event.ActionListener;  
                                import java.io.File;  
                                import java.io.IOException;  
                                import javax.sound.midi.*;  
                                import javax.swing.*;  
                                import javax.swing.event.ChangeEvent;  
                                import javax.swing.event.ChangeListener;  
                                  
                                public class SoundPlayer extends JComponent {  
                                  boolean midi; // Are we playing a midi file or a sampled one?  
                                  
                                  Sequence sequence; // The contents of a MIDI file  
                                  Sequencer sequencer; // We play MIDI Sequences with a Sequencer  
                                  boolean playing = false; // whether the sound is current playing  
                                  
                                  // Length and position of the sound are measured in milliseconds for  
                                  // sampled sounds and MIDI "ticks" for MIDI sounds  
                                  int audioLength; // Length of the sound.  
                                  int audioPosition = 0; // Current position within the sound  
                                  
                                  // The following fields are for the GUI  
                                  JButton play; // The Play/Stop button  
                                  JSlider progress; // Shows and sets current position in sound  
                                  JLabel time; // Displays audioPosition as a number  
                                  Timer timer; // Updates slider every 100 milliseconds  
                                  
                                  // The main method just creates an SoundPlayer in a Frame and displays it  
                                  public static void main(String[] args) throws IOException, MidiUnavailableException, InvalidMidiDataException {  
                                    SoundPlayer player;  
                                  
                                    File file = new File("C:\\Users\\sj\\Documents\\All Out of Love.mid"); // This is the file we'll be playing  
                                    // Determine whether it is midi or sampled audio  
                                    boolean ismidi;  
                                    try {  
                                      // We discard the return value of this method; we just need to know  
                                      // whether it returns successfully or throws an exception  
                                      MidiSystem.getMidiFileFormat(file);  
                                      ismidi = true;  
                                    } catch (InvalidMidiDataException e) {  
                                      ismidi = false;  
                                    }  
                                  
                                    // Create a SoundPlayer object to play the sound.  
                                    player = new SoundPlayer(file, ismidi);  
                                  
                                    // Put it in a window and play it  
                                    JFrame f = new JFrame("SoundPlayer");  
                                    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
                                    f.getContentPane().add(player, "Center");  
                                    f.pack();  
                                    f.setVisible(true);  
                                  }  
                                  
                                  // Create an SoundPlayer component for the specified file.  
                                  public SoundPlayer(File f, boolean isMidi) throws IOException, MidiUnavailableException, InvalidMidiDataException {  
                                    if (isMidi) { // The file is a MIDI file  
                                      midi = true;  
                                      // First, get a Sequencer to play sequences of MIDI events  
                                      // That is, to send events to a Synthesizer at the right time.  
                                      sequencer = MidiSystem.getSequencer(); // Used to play sequences  
                                      sequencer.open(); // Turn it on.  
                                  
                                      // Get a Synthesizer for the Sequencer to send notes to  
                                      Synthesizer synth = MidiSystem.getSynthesizer();  
                                      synth.open(); // acquire whatever resources it needs  
                                  
                                      // The Sequencer obtained above may be connected to a Synthesizer  
                                      // by default, or it may not. Therefore, we explicitly connect it.  
                                      Transmitter transmitter = sequencer.getTransmitter();  
                                      Receiver receiver = synth.getReceiver();  
                                      transmitter.setReceiver(receiver);  
                                  
                                      // Read the sequence from the file and tell the sequencer about it  
                                      sequence = MidiSystem.getSequence(f);  
                                      sequencer.setSequence(sequence);  
                                      audioLength = (int) sequence.getTickLength(); // Get sequence length  
                                    }   
                                  
                                    // Now create the basic GUI  
                                    play = new JButton("Play"); // Play/stop button  
                                    progress = new JSlider(0, audioLength, 0); // Shows position in sound  
                                    time = new JLabel("0"); // Shows position as a #  
                                  
                                    // When clicked, start or stop playing the sound  
                                    play.addActionListener(new ActionListener() {  
                                      public void actionPerformed(ActionEvent e) {  
                                        if (playing)  
                                          stop();  
                                        else  
                                          play();  
                                      }  
                                    });  
                                  
                                    // Whenever the slider value changes, first update the time label.  
                                    // Next, if we're not already at the new position, skip to it.  
                                    progress.addChangeListener(new ChangeListener() {  
                                      public void stateChanged(ChangeEvent e) {  
                                        int value = progress.getValue();  
                                        // Update the time label  
                                        if (midi)  
                                          time.setText(value + "");         
                                        // If we're not already there, skip there.  
                                        if (value != audioPosition)  
                                          skip(value);  
                                      }  
                                    });  
                                  
                                    // This timer calls the tick() method 10 times a second to keep  
                                    // our slider in sync with the music.  
                                    timer = new javax.swing.Timer(100, new ActionListener() {  
                                      public void actionPerformed(ActionEvent e) {  
                                        tick();  
                                      }  
                                    });  
                                  
                                    // put those controls in a row  
                                    Box row = Box.createHorizontalBox();  
                                    row.add(play);  
                                    row.add(progress);  
                                    row.add(time);  
                                  
                                    // And add them to this component.  
                                    setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));  
                                    this.add(row);  
                                  
                                    // Now add additional controls based on the type of the sound  
                                  
                                  }  
                                  
                                  /** Start playing the sound at the current position */  
                                  public void play() {  
                                    if (midi)  
                                      sequencer.start();  
                                  
                                    timer.start();  
                                    play.setText("Stop");  
                                    playing = true;  
                                  }  
                                  
                                  /** Stop playing the sound, but retain the current position */  
                                  public void stop() {  
                                    timer.stop();  
                                    if (midi)  
                                      sequencer.stop();  
                                  
                                    play.setText("Play");  
                                    playing = false;  
                                  }  
                                  
                                  /** Stop playing the sound and reset the position to 0 */  
                                  public void reset() {  
                                    stop();  
                                    if (midi)  
                                      sequencer.setTickPosition(0);  
                                  
                                    audioPosition = 0;  
                                    progress.setValue(0);  
                                  }  
                                  
                                  /** Skip to the specified position */  
                                  public void skip(int position) { // Called when user drags the slider  
                                    if (position < 0 || position > audioLength)  
                                      return;  
                                    audioPosition = position;  
                                    if (midi)  
                                      sequencer.setTickPosition(position);  
                                  
                                    progress.setValue(position); // in case skip() is called from outside  
                                  }  
                                  
                                  /** Return the length of the sound in ms or ticks */  
                                  public int getLength() {  
                                    return audioLength;  
                                  }  
                                  
                                  // An internal method that updates the progress bar.  
                                  // The Timer object calls it 10 times a second.  
                                  // If the sound has finished, it resets to the beginning  
                                  void tick() {  
                                    if (midi && sequencer.isRunning()) {  
                                      audioPosition = (int) sequencer.getTickPosition();  
                                      progress.setValue(audioPosition);  
                                    }  else  
                                      reset();  
                                  }  
                                  
                                }
                                This is the Midi Player that i've been working with. Can you guys help me?
                                • 13. Re: How can I measure the frequency(or pitch or note) of a midi file?
                                  843802
                                  Hi Captfloss,

                                  I'am really sorry if i asked terrible questions.
                                  • 14. Re: How can I measure the frequency(or pitch or note) of a midi file?
                                    captfoss
                                    isji wrote:
                                    Hi Captfloss,

                                    I'am really sorry if i asked terrible questions.
                                    Not sure what exactly you want help with at this point, I've answered all of your questions...