I currently have code to play a chord. I play each note separately.
I have adapted my code so that I can supply a delay (in seconds). This should let me arpeggiate a chord:
// Major triad, arpeggiated
playNote(0, 0.0f);
playNote(4, 0.1f);
playNote(7, 0.2f);
The problem is all the notes play simultaneously!
Here is my code for playing a note:
struct PiSynthAudioSource : public AudioSource
:
void playNote(int n, float delay_s = 0.0f) {
MidiMessage m = MidiMessage::noteOn(1, 60 + n, .25f);
m.setTimeStamp(Time::getMillisecondCounterHiRes() * .001 + delay_s);
midiCollector.addMessageToQueue(m);
}
I have looked through the body of addMessageToQueue
and it looks as though my implementation should be correct. But all notes play simultaneously.
I wonder if maybe I should be spawning a thread for each note, but that starts to look like a lot of lines of code, much better if I can do it this way.
I’m looking for some kind of executeAfterDelay(0.5, []{ myFunc(); } )
function (if I have remembered my block syntax correctly) but I don’t think the framework has such function.
Can anyone suggest something?
π
PS I found Delayed function call?
PPS Complete synthplayer code is:
#ifndef SYNTH_H_INCLUDED
#define SYNTH_H_INCLUDED
#include "../JuceLibraryCode/JuceHeader.h"
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
SharedResourcePointer<AudioFormatManager> pFormatManager;
ScopedPointer<AudioSampleBuffer> UNUSED__bufferFromFile(File file)
{
if(pFormatManager->getNumKnownFormats() < 1)
pFormatManager->registerBasicFormats();
ScopedPointer<AudioFormatReader> reader = pFormatManager->createReaderFor(file);
jassert(reader);
ScopedPointer<AudioSampleBuffer> buffer = new AudioSampleBuffer(reader->numChannels, (int)reader->lengthInSamples);
reader->read(
(int* const*)&buffer // <-- void* no???
, reader->numChannels
, (int64)0 // startSampleInSource
, (int)reader->lengthInSamples
, false // fillLeftoverChannelsWithCopies
);
return buffer;
}
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
struct PiSynthAudioSource : public AudioSource
{
PiSynthAudioSource()
{
// Add some voices to our synth, to play the sounds..
for (int i = 16; --i >= 0;)
synth.addVoice(new SamplerVoice());
// ..and add a sound for them to play...
setUsingSampledSound();
}
void setUsingSampledSound()
{
WavAudioFormat wavFormat;
synth.clearSounds();
for (int i = 0; i < 12; i++)
{
// load from binary data!
const String filename = String("st_") + String(i) + String("_wav");
int size = 0;
const char* data = BinaryData::getNamedResource(filename.getCharPointer(), size);
auto memStream = new MemoryInputStream(data, size, false);
ScopedPointer<AudioFormatReader> audioReader = wavFormat.createReaderFor(memStream, true);
BigInteger midiNoteFlag;
midiNoteFlag.setRange(0, 128, false);
midiNoteFlag.setBit(60 + i); // MIDI C4 = 60
SamplerSound* pSound = new SamplerSound(
"Toneme_" + String(i),
*audioReader,
midiNoteFlag,
60 + i, // root midi note
0.0, // attack time
0.0, // release time
5.0 // maximum sample length
);
synth.addSound(pSound);
}
}
void prepareToPlay(int /*samplesPerBlockExpected*/, double sampleRate) final {
midiCollector.reset(sampleRate);
synth.setCurrentPlaybackSampleRate(sampleRate);
}
void releaseResources() override { }
void getNextAudioBlock(const AudioSourceChannelInfo& bufferToFill) final {
bufferToFill.clearActiveBufferRegion();
MidiBuffer incomingMidi;
midiCollector.removeNextBlockOfMessages(incomingMidi, bufferToFill.numSamples);
synth.renderNextBlock(*bufferToFill.buffer, incomingMidi, 0, bufferToFill.numSamples);
}
// the synth itself!
Synthesiser synth;
MidiMessageCollector midiCollector;
void playToneme(int n, float delay_s = 0.0f) {
MidiMessage m = MidiMessage::noteOn(1, 60 + n, .25f);
m.setTimeStamp(Time::getMillisecondCounterHiRes() * .001 + delay_s);
midiCollector.addMessageToQueue(m);
}
};
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
class PiSynthPlayer
{
private:
AudioDeviceManager& deviceManager;
PiSynthAudioSource synthAudioSource;
AudioSourcePlayer audioSourcePlayer;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PiSynthPlayer)
public:
void playToneme(int n, float delay_s = 0.0f) {
synthAudioSource.playToneme(n, delay_s);
}
PiSynthPlayer(AudioDeviceManager& outputDeviceManager)
: deviceManager(outputDeviceManager)
, synthAudioSource()
{
audioSourcePlayer.setSource(&synthAudioSource);
deviceManager.addAudioCallback(&audioSourcePlayer);
}
~PiSynthPlayer()
{
deviceManager.removeAudioCallback(&audioSourcePlayer);
audioSourcePlayer.setSource(nullptr);
}
};
#endif // SYNTH_H_INCLUDED