Pauses between samples with AudioTransportSource

Each note has a set of samples, and as long as the key is pressed, the samples must be played randomly one after the other without stopping. That is, it looks like a cycle of several samples.

AudioTransportSource* playingSample;
bool playingSampleExist = false;
// Check if the sample is over:
if (playingSample->isPlaying() == false 
                || playingSample->getCurrentPosition() >= playingSample->getLengthInSeconds() 
                || playingSample->hasStreamFinished())
// Randomly pick a new sample and play it:
void NewProjectAudioProcessor::PlaySample(int noteNumber)
    int countOfNoteSamples = notesAndSamples.getReference(noteNumber).size();

    if (countOfNoteSamples > 0)
        int randomSampleNumber = Random::getSystemRandom().nextInt(countOfNoteSamples);
        playingSample = notesAndSamples.getReference(noteNumber).getReference(randomSampleNumber);
        playingSampleExist = true;

// Selected sample plays:
void NewProjectAudioProcessor::GetNextAudioBlockForPlayingSamples(AudioBuffer<float>& buffer)

Unfortunately, I get small pauses between samples:

I debugged processBlock and got some interesting results:

// Plays the end of the first sample
playingSample->isPlaying(): true
playingSample->getCurrentPosition(): 0.0914966
playingSample->getLengthInSeconds(): 0.1
playingSample seconds left: 0.0085034

// First sample ended and silence lasted 0.00165533 seconds
playingSample->isPlaying(): false
playingSample->getCurrentPosition(): 0.101655
playingSample->getLengthInSeconds(): 0.1
playingSample seconds left: -0.00165533

// Second sample started playing
playingSample->isPlaying(): true
playingSample->getCurrentPosition(): 0.0102268
playingSample->getLengthInSeconds(): 0.1
playingSample seconds left: 0.0897732

I think the sample ends before the new cycle of processBlock has time to start. How to make a note play without pauses?

The TransportAudioSource pulls from an AudioFormatReaderSource. Maybe you even have some buffering going on (you should!). So that takes some time to rewind which could be the one block silence. When I implemented such a loop I added a spare Buffered AudioFormatReaderSource on standby that would kick in when the end was reached and the exhausted source can be rewound while the spare is polaying. However I still added a crossfade just in case.

Please tell me more, I have no idea what you are talking about. How can i have two AudioFormatReaderSource for one AudioTransportSource at once?

Well you cannot, but like I keep saying I wouldn’t use AudioTransportSource at all. You cannot start a note accurately to a sample, which is a requirement for a virtual instrument.
AudioTransportSource is if you create a player with a GUI controlled start/stop button. Because there you need the asynchronous action. But it is not suited for anything else.

What then do you propose? I tried Synthesiser, but it is too multifunctional, has its own logic for handling midi messages, sources, and so on, I will have to completely rewrite it. I just need to load the sound file into some object, store those objects into an array, and start playing any of them aloud with something like play() and stop(). If it doesn’t work perfectly with AudioTransportSource then what solution can you suggest?

And what is suitable for a virtual instrument?

I am afraid it’s the juce::Synthesizer class and juce::SynthesizerVoice.

The reason is, the plugin processing is continuously running. There is no start here and end there you could implement, all is happening at the same time and in blocks. So you need some kind of context when you enter for the next block.
The synthesizer classes take care of this context. You are free to implement it yourself, but you will likely end up with something similar. And my advice if you want to write your own, still try to understand how they did it, so you avoid mistakes others already made and corrected.

Have a look into the tutorial: Building a MIDI Synthesizer
or watch the youtube tutorials from theaudioprogrammer: