Transpose a MIDI Note using MidiMessageCollector?

Hi,

Nobody has successfully answered my post here:

http://www.rawmaterialsoftware.com/viewtopic.php?f=8&t=9683

So, I wondered if I’m way off track and thought I’d try to use a MidiMessageCollector to transpose the MIDI by 5 semitones. Here is the code I tried, for more detail see the aforementioned post:

[code] const int notenum = midi_message.getNoteNumber();

        const uint8 velocity = midi_message.getVelocity();
        
        const int channel = midi_message.getChannel();
        
                    
        //Transposing by 5 semitones:
        
        int oldNote = notenum;
        
        int newNote = notenum+5;
        
        //_newNoteNumber = newNote;
        
        MidiMessageCollector* collect = new MidiMessageCollector();
                                
        juce::MidiMessage noteOff(juce::MidiMessage::noteOff(channel, oldNote));
        juce::MidiMessage noteOn(juce::MidiMessage::noteOn(channel, newNote, velocity));
            
        
        collect->removeNextBlockOfMessages(output, buffer.getNumSamples());
        
        collect->addMessageToQueue (noteOff);
        collect->addMessageToQueue(noteOn);

[/code]

I thought this would ‘kill’ the old note and replace it with the transposed note. It doesn’t work. Which approach should I use for transposition/ why doesn’t this code work? How do I ‘add’ the queue to midimessages or does this happen automatically?

I’d appreciate any helpful answer. Apologies for my NOOBish questions.

Trying to kill a note and adding a new one sounds like a bad idea. A note off is just a note message with velocity 0, and adding note offs like that would also kill any playing notes that were transposed to that same pitch.

I have no experience with this either but I think what you want to do is something like:

  • create a MidiBuffer
  • iterate over the input buffer. For example look at MidiOutput cpp file

[code]MidiBuffer::Iterator i (buffer);

const uint8* data;
int len, time;

while (i.getNextEvent (data, len, time))
{

}[/code]
  • use this data to create MidiMessage instances.
  • use isNoteOn() / isNoteOff() to find the messages which represent midi note on/off, leaving others in tact
  • if note message, use getNoteNumber() and setNoteNumber() to read and transpose the pitches
  • add the messages to your buffer, if messages are not note on/off add them to your buffer unaltered
  • copy the buffer to the input buffer, overwriting all data.

You probably have to do something with timestamps as well to make sure that you add all the messages to the new buffer with the same timestamp as they were existing in your original buffer.

Hi 0x80,

Thanks very much. The first constructive comment! I’ll give that a try later.

Cheers,

Dave

For future reference for anybody who may struggle while testing an Audio Unit with transposition, the problem was not my code but the AU format. The following code easily changes a note when using a VST in a host but the Audio Unit doesn’t work as it cannot send MIDI to the host.

[code]void ZS1AudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
MidiBuffer output;

MidiBuffer::Iterator mid_buffer_iter(midiMessages);
MidiMessage m(0xf0);
int sample;
while(mid_buffer_iter.getNextEvent(m,sample))
{

		if (m.isNoteOn()) {

				const int ch = m.getChannel();
                          
                //Pre Transpose:
                _lastNoteNumber = m.getNoteNumber();
            
                //Add 5 semitones:
                const int tnote = m.getNoteNumber() + 5;
            
                //Display new transposed note:
                _tNote = tnote;
                            
				const uint8 v = m.getVelocity();
            
                output.addEvent(MidiMessage::noteOn(ch,tnote,v),sample);

        }
            
		else if (m.isNoteOff()) {

            
            const int ch = m.getChannel();

            
            //Add 5 semitones:
            const int tnote = m.getNoteNumber() + 5;
            const uint8 v = m.getVelocity();
            
            output.addEvent(MidiMessage::noteOff(ch,tnote,v),sample);

            
		}

}
midiMessages.clear();
midiMessages = output;
   

MidiBuffer finaloutput;

MidiBuffer::Iterator mid_buffer_iter2(midiMessages);
MidiMessage m2(0xf0);
int sample2;
while(mid_buffer_iter2.getNextEvent(m2,sample2))
{
    //Confirm the note got transposed, it did:
    _finalNoteNumber = m2.getNoteNumber();
}

}[/code]