Midi controllers are not implemented in SamplerVoice


Specifically pitchWheelMoved and controllerMoved are empty functions. I didn’t notice before because I was using my own PanningSamplerVoice class. However this required changing some SamplerVoice private access members to protected access.

I got tired of making the modification for every new release of Juce so I decided to try to forgo the mods and use Midi controllers to change the volume and pan and found it doesn’t work because SamplerVoice::controllerMoved is an empty function (so is pitchWheelMoved, but my app is a drum machine, so I don’t use it).

SamplerVoice uses velocity to do volume changes, setting its members lgain and rgain to a normalized midi velocity (float(velocity)/127). However, this is not the proper way to do it. Velocity is how hard you play a note–it can be loud or soft depending on what your amp setting is. Gain should be mapped to Midi controller 7 – it’s purpose is to emulate the volume knob on an amp.

Implementing the functions would be easy: add a switch statement with cases for the gain and pan midi controller ids and use the passed in values to maintain the relation: lgain = pan*gain; rgain = (1-pan)*gain where lgain, and rgain are (private) members of SamplerVoice and pan and gain have values in between 0 and 1.

Another possibility is to make SamplerVoice::lgain and rgain protected variables instead of private so we can directly manipulate gain and pan. This is essentially the mod I make every time I download a new Juce.


My pan calculations were incorrect: they assumed a normalized pan, that is, pan is in [0, 1], and they swapped left and right. All my pan controls run from [-1, 1]. Here is the correct calculation:

void PanningSamplerVoice::updateGainAndPan() { // first normalize pan float normalizedPan = (pan + 1)*0.5f; // simple linear pan rgain = normalizedPan*gain; lgain = (1-normalizedPan)*gain; }[/code]


Yes, fair point. That sampler code is only supposed to be very basic though - if you’re writing your own sampler that needs extra functionality, I’d probably recommend just writing your own synthesiser class entirely, rather than deriving from this one.