Midi Delta Time/Samples


#1

Hello,

I have a process-loop and you will see the processNextMidiBuffer method, which handles the incoming midi signals. If there is a note on message, the method handleNoteOn will be called. What I want is the difference/delta in samples between the process-loop-start and the incoming midi-note-on signal. I hope, You understand what I mean (and sorry for my bad English).

void MultibandDelayAudioProcessor::handleNoteOn (MidiKeyboardState *source, int midiChannel, int midiNoteNumber, float velocity)
{
	delta = ...
}

void MultibandDelayAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
	_keyboardState->processNextMidiBuffer(midiMessages, 0, _bufferSize, false);
	
}

#2

Or how can I get the startpoint of a midi input? please helt. I don´t know how to handle it.


#3

The keyboard state object doesn’t know or care about the note offsets, and its callbacks should never need to know that kind of information! If your handleNoteOn method needs to know the time, then you’re putting your code in the wrong place!

All the code that needs to process the events based on their time should be called from your processBlock method, and should iterate the MidiBuffer. Have a look at the demo synthesiser for an example.


#4

ok thanks a lot. I found this example and it works fine except one thing. this is my code now

void MultibandDelayAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
	MidiMessage message (0xf4, 0.0);
	MidiBuffer::Iterator i (midiMessages);
	int sampleOffset;
	
	while (i.getNextEvent (message, sampleOffset))
	{
		if (message.isNoteOnOrOff ())
		{
			DBG("note offset: " + String(sampleOffset));
		}
	}
}

I set some midinotes in a sequencer and the value of sampleOffset is everytime “0”. Why?


#5

Well, that’s most likely because the sequencer is actually sending all the notes with a zero offset. Some hosts will do that.


#6

Ok, how can I get the exact sampleposition of a midi note or the offset for the main process loop, like:

// only an example.
offset = …

for (int i = 0; i < buffersize; i++)
if (i == offset)
osc.start ();

Please help. It is very frustrating. :frowning:


#7

Sorry, I don’t understand the question. You were doing it correctly before - if the host doesn’t send a timestamp, then there’s no way to magically find it out (?)


#8

Every process block wants two buffer (left, right) with sampledata-values, for example 512 samples. A sin generator for example looks like this:

void MultibandDelayAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
	float* samplesL = buffer.getSampleData (0);
	float* samplesR = buffer.getSampleData (1);
	_bufferSize = buffer.getNumSamples();

	for( int i = 0; i < _bufferSize; i++)
	{
		samplesL = sin(phase);
		samplesR = sin(phase);
		phase += phaseOffset;

		// stuff ...
	}

	// stuff ...
}

this code generates a unlimitted sinewave. to controll the sinewave with mid I have to build in the midi functions like:

void MultibandDelayAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
	// the necessary midi stuff...
	MidiMessage message (0xf4, 0.0);
	MidiBuffer::Iterator i (midiMessages);
	int sampleOffset;
	
	while (i.getNextEvent (message, sampleOffset))
	{
		// stuff....
	}

	float* samplesL = buffer.getSampleData (0);
	float* samplesR = buffer.getSampleData (1);
	_bufferSize = buffer.getNumSamples();

	for( int i = 0; i < _bufferSize; i++)
	{
		samplesL = sin(phase);
		samplesR = sin(phase);
		phase += phaseOffset;

		// stuff ...
	}

	// stuff ...
}

ok. the midi stuff is able to recognize incoming midi signals. For this example we don´t need polyphony. I only want to play or mute the sin with the keyboard. it has to be exact. i create an image to show what I mean with “exact”

You see, that the midinotes have an offset to the samplebuffer. the first note in the picture have for example an offset of 320 samples. the code to start the osc in the right position have to be like this:

void MultibandDelayAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
	// the necessary midi stuff...
	MidiMessage message (0xf4, 0.0);
	MidiBuffer::Iterator i (midiMessages);
	int sampleOffset;
	
	while (i.getNextEvent (message, sampleOffset))
	{
		offset = .....????
	}

	float* samplesL = buffer.getSampleData (0);
	float* samplesR = buffer.getSampleData (1);
	_bufferSize = buffer.getNumSamples();

	for( int i = 0; i < _bufferSize; i++)
	{
		if (i <= offset)
			continue;

		samplesL = sin(phase);
		samplesR = sin(phase);
		phase += phaseOffset;

		// stuff ...
	}

	// stuff ...
}

I don´t know if this is the way to handle it. I hope You understand what I mean and can help me.

Thanks and greetz from Germany


#9

offset is sampleOffset in your code


#10

Yes, but it is everytime “0” and that can not be true, because if I set for example 1/4 notes at 130 BPM, the times from the notes in samples are:
0, 20353, 40707,…

The buffersize length is still 512 samples
the first note has the offset 0 because 0 % 512 = 0;
the scond note has the offset 386 because 20353 % 512 = 386
the third note has the offset 259 because 40707 / 512 = 259

but when I test it, the offset is still “0”. Where is my mistake?


#11

Like I said, it’s probably the host’s mistake - some of them just get that wrong. Try another host before assuming it’s your own fault.


#12

Ok, i will try, but it is FL Studio. I can´t belive that FL Studio makes timing mistakes. Do You have any experience with FL Studio or this problem?


#13

DONE!

Fl is kidding me. :smiley: Why? The offset is everytime ‘0’ and that´s correct, because FL decreases the buffersize. When I set the buffersize to 512 samples in FL, then the buffersize isn´t 512 samples in the progressloop. The buffersize is variable and very small (values like 20, 22, 25,…). I rendered a generated noise as a wave file with 1/4 notes. the result is correct. the noise began at the correct sampleposition.

I also tested it in cubase. The buffersize is constant and I get now the sampleoffset. omg… :roll:

thanks a lot for Your help!