How to add multiple SamplerSound's for a single note and discriminate by velocity?

If you hit the same problem - here is what I came up with.

Sampler : Synthesiser.

// Sampler.h

#ifndef SAMPLER_H_INCLUDED
#define SAMPLER_H_INCLUDED

#include "../JuceLibraryCode/JuceHeader.h"

class Sampler : public Synthesiser
{
public:
    void noteOn (
        const int midiChannel,
        const int midiNoteNumber,
        const float velocity
    ) override;
};

#endif  // SAMPLER_H_INCLUDED

Implementation.

// Sampler.cpp

#include "Sampler.h"
#include "SamplerSoundLayer.h"

void Sampler::noteOn (const int midiChannel,
                          const int midiNoteNumber,
                          const float velocity)
{
    const ScopedLock sl (lock);

    for (int i = sounds.size(); --i >= 0;)
    {
        SynthesiserSound* const soundSource = sounds.getUnchecked(i);
        SamplerSoundLayer* const sound = static_cast<SamplerSoundLayer* const> ( soundSource );

        if ( sound->appliesTo ( midiNoteNumber, velocity )
             && sound->appliesToChannel ( midiChannel ) )
        {
            // If hitting a note that's still ringing, stop it first (it could be
            // still playing because of the sustain or sostenuto pedal).
            for ( int j = voices.size(); --j >= 0; )
            {
                SynthesiserVoice* const voice = voices.getUnchecked (j);
                if ( voice->getCurrentlyPlayingNote() == midiNoteNumber
                     && voice->isPlayingChannel ( midiChannel ) )
                    stopVoice ( voice, 1.0f, true );
            }
            startVoice ( findFreeVoice ( sound, midiChannel, midiNoteNumber, isNoteStealingEnabled() ),
                        sound, midiChannel, midiNoteNumber, velocity );
        }
    }
}

SamplerSoundLayer : SamplerSound.

// SamplerSoundLayer.h

#ifndef SAMPLERSOUNDLAYER_H_INCLUDED
#define SAMPLERSOUNDLAYER_H_INCLUDED

#include "../JuceLibraryCode/JuceHeader.h"

class SamplerSoundLayer : public SamplerSound
{
public:
    SamplerSoundLayer (
        const String& name,
        AudioFormatReader& source,
        const BigInteger& midiNotes,
        int midiNoteForNormalPitch,
        Range<float> velocityRange,
        double attackTimeSecs,
        double releaseTimeSecs,
        double maxSampleLengthSeconds
    );
    ~SamplerSoundLayer();
    bool appliesTo( int midiNoteNumber, float velocity );
private:
    Range<float> velocity;
};

#endif  // SAMPLERSOUNDLAYER_H_INCLUDED

Implementation.

// SamplerSoundLayer.cpp

#include "SamplerSoundLayer.h"

SamplerSoundLayer::SamplerSoundLayer (const String& soundName,
                            AudioFormatReader& source,
                            const BigInteger& notes,
                            const int midiNoteForNormalPitch,
                            Range<float> velocityRange,
                            const double attackTimeSecs,
                            const double releaseTimeSecs,
                            const double maxSampleLengthSeconds)
    :   SamplerSound(
            soundName,
            source,
            notes,
            midiNoteForNormalPitch,
            attackTimeSecs,
            releaseTimeSecs,
            maxSampleLengthSeconds
        ),
        velocity( velocityRange )
{
}

SamplerSoundLayer::~SamplerSoundLayer()
{
}

bool SamplerSoundLayer::appliesTo( int midiNoteNumber, float velocity )
{
    bool appliesToMidiNote = appliesToNote( midiNoteNumber );
    bool isInVelocityRange = this->velocity.contains( velocity );

    return appliesToMidiNote && isInVelocityRange;
}

 

Cheers,

Nikolay Tsenkov

6 Likes