I done it! or I’m doing it in another window…
Yes, the synth/samplerVoice does do resampling
[code]void SamplerVoice::startNote (const int midiNoteNumber,
const float velocity,
SynthesiserSound* s,
const int /currentPitchWheelPosition/)
{
const SamplerSound* const sound = dynamic_cast <const SamplerSound*> (s);
jassert (sound != 0); // this object can only play SamplerSounds!
if (sound != 0)
{
const double targetFreq = MidiMessage::getMidiNoteInHertz (midiNoteNumber);
const double naturalFreq = MidiMessage::getMidiNoteInHertz (sound->midiRootNote);
pitchRatio = (targetFreq * sound->sourceSampleRate) / (naturalFreq * getSampleRate());
…
[/code]
and then pitchRatio is being referenced later on in the renderBlock function (method?)
[code]void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples)
{
const SamplerSound* const playingSound = (SamplerSound*) (SynthesiserSound*) getCurrentlyPlayingSound();
sourceSamplePosition += pitchRatio;
}
[/code]
but what is happening is that the pitchRatio is being set in startNote, and this ratio is not being altered until the next time startNote gets called.
So, what I have tried is altering the scope of targetFreq and naturalFreq
//in startNote()
/*
const double targetFreq = MidiMessage::getMidiNoteInHertz (midiNoteNumber);
const double naturalFreq = MidiMessage::getMidiNoteInHertz (sound->midiRootNote);
*/
targetFreq = MidiMessage::getMidiNoteInHertz (midiNoteNumber);
naturalFreq = MidiMessage::getMidiNoteInHertz (sound->midiRootNote);
//in juce_Sampler.h
private:
double targetFreq, naturalFreq; // I declared them here
so that I can access those variables in the renderNextBlock function…
const double newpitchRatio = (targetFreq * playingSound->sourceSampleRate) / (naturalFreq * getSampleRate()); //added this line, toward the end of the renderNextBlock function
//sourceSamplePosition += pitchRatio;
sourceSamplePosition += newpitchRatio;
and it works!
Now, I realise as I type this that ascertaining newPitchRatio in the renderNextBlock function may be a little expensive, cycle wise, but there is no equivalent to SynthesiserVoice::setCurrentPlaybackSampleRate available in the SamplerVoice class.
The more intelligent thing to do would probably be to add a method to alter the pitchRatio within SamplerVoice, but as it subclasses SynthesiserVoice I’m not quite sure how I would access it given that synth.getVoices() returns a SynthesiserVoice and not a SamplerVoice.
Or maybe it is and I have no idea what I am talking about, but I’m not particularly good at this whole poly inheritance subclassing thingy (you may recall my blatant abuse of TextButtons in my début Drum Machine?)
Other than this extra strain in the renderNextBlock method, I can’t see any real problem with this approach, but if alarm bells are going off on your end, do share!
(if none of that makes sense, I’m happy to post the modified classes for your entertainment)
edit: I’m playing with the tempo slider and occasionally (not too often, two pints and you may not notice) it doesn’t loop perfectly, and… this is off topic, but if I try to change the buffer size, it breaks at jassert (lowerLimit <= upperLimit) in juce_MathsFunctions. I dunno what that means exactly, but I have seen it before and not known then either.
more edit: the maths thing seems to pertain to AudioDeviceSelectorComponent: when I try to open the buffer size combo, it breaks. I am running my laptop with an external screen which is my primary, the laptop screen in the secondary screen. This problem only occurs when I try and open the combo box when it is present in the secondary screen, and I think the reason for this happening is that I have my primary monitor set lower than the secondary monitor (because that’s how it is in real life) and something about getting screen sizes is making it confused