Hi there, I am trying to get a reliable timing for plugins to come. So I created a timekeeper class t that counts sample blocks and calculates note values in samples and such so other classes can use it.
In the class MidiProcessor, I then use these values and loop over the current block to create the actual events with the corresponding sample number.
Ich checked this a couple of times also debugged the values (sample position, numblocks, samples since start, abd it all looks good and evenb corresponds with my daws samples (at least the debugged values)
Still it sounds just a bit off from time to time, especially with a click. Also when I create notes in the editor of the daw its absolutely perfect and does not sound off.
Can someone look and see if I am doing something wrong or if the concept / approach is wrong? (And maybe tell why and what would be right)
I do not feel like Studio one is changing buffer sizes (aso dbged them out) and also my code should handle that.
Many thanks in advance…
In the processor:
playHead = this->getPlayHead();
playHead->getCurrentPosition(positionInfo);
bpm = positionInfo.bpm;
timeKeeper.setBpm(bpm);
timeKeeper.calculateNoteValues();
midiProcessor.processMidi(midiMessages, timeKeeper);
if (positionInfo.isPlaying)
{
timeKeeper.keepTime(buffer.getNumSamples());
}
else
{
timeKeeper.resetTransport();
}
Timekeeper:
void TimeKeeper::keepTime(int samples)
{
numSamples = samples;
tkTransport.tkBar = floor(tkSamplesPassed / tkSamplesPerBar) + 1;
tkTransport.tkQuarter = floor(tkSamplesPassed / tkSamplesPerQuarterNote) + 1 - 4 * (tkTransport.tkBar - 1);
tkTransport.tkEighth = floor(tkSamplesPassed / tkSamplesPerEighthNote) + 1 - 8 * (tkTransport.tkBar - 1);
tkTransport.tkSixteenth = floor(tkSamplesPassed / tkSamplesPerSixteenthNote) + 1 - 16 * (tkTransport.tkBar - 1);
tkTransport.tkThirtySecondth= floor(tkSamplesPassed / tkSamplesPerThirtySecondthNote) + 1 - 32 * (tkTransport.tkBar - 1);
tkTransport.tkSixtyfourth= floor(tkSamplesPassed / tkSamplesPerSixtyFourthNote) + 1 - 64 * (tkTransport.tkBar - 1);
tkSamplesPassed += numSamples;
tkIsPlaying = true;
tkHasStopped = false;
}
void TimeKeeper::resetTransport()
{
tkTransport.tkBar = 1;
tkTransport.tkQuarter = 1;
tkTransport.tkEighth = 1;
tkTransport.tkSixteenth = 1;
tkTransport.tkThirtySecondth = 1;
tkTransport.tkSixtyfourth = 1;
tkSamplesPassed = 0;
tkIsPlaying = false;
tkHasStopped = true;
}
bool TimeKeeper::isPlaying()
{
return tkIsPlaying;
}
bool TimeKeeper::hasStopped()
{
return tkHasStopped;
}
MidiProcessor:
//MidiBuffer::Iterator it(midiMessages); dont need that right now
MidiMessage currentMessage;
int samplePos;
int numSamples = timeKeeper.numSamples;
long samplesperQuarterNote = timeKeeper.tkSamplesPerQuarterNote;
long samplesPassed = timeKeeper.tkSamplesPassed;
long noteDuration = samplesperQuarterNote * 0.1f;
uint8 volume = 80;
if (timeKeeper.tkIsPlaying)
{
for (int i = 0; i < numSamples; i++)
{
if (!noteOn)
{
if ((((samplesPassed + i) % samplesperQuarterNote) == 0))
{
auto message = MidiMessage::noteOn(1, 44, volume);
midiMessages.addEvent(message, i);
noteOnSample = samplesPassed + i;
noteOn = true;
}
} else
{
if ((noteOnSample + noteDuration) == (samplesPassed + i))
{
auto message = MidiMessage::noteOff(1, 44, volume);
midiMessages.addEvent(message, i);
noteOn = false;
noteOnSample = 0;
}
}
}
}
if (timeKeeper.hasStopped())
{
auto message = MidiMessage::allNotesOff(1);
midiMessages.addEvent(message, numSamples - 1);
}
}
private:
};