startNote wont trigger at all only render block
//==============================================================================
class MSamplerVoice final : public SynthesiserVoice
{
public:
explicit MSamplerVoice (std::shared_ptr<const MSamplerSound> sound)
: samplerSound (std::move (sound))
{
jassert (samplerSound != nullptr);
src_state_left = src_new(2, 1, &error);
src_state_right = src_new(2, 1, &error);
ratio = 1.0;
bufpos = 0;
for(int i = 0; i < 16; i++) {
bufl[i] = 0.0f;
bufr[i] = 0.0f;
}
}
~MSamplerVoice() override {
src_delete(src_state_left);
src_delete(src_state_right);
}
void pitchWheelMoved (int /*newValue*/) override {}
void controllerMoved (int /*controllerNumber*/, int /*newValue*/) override {}
bool canPlaySound (SynthesiserSound* sound) override
{
return dynamic_cast<MSamplerSound*> (sound) != nullptr;
}
bool isVoiceActive () const override {
return currentSamplePos < samplerSound->getSample()->getLength();
}
void startNote (int midiNoteNumber, float velocity, SynthesiserSound *sound, int currentPitchWheelPosition) override
{
level .setTargetValue (velocity);
frequency.setTargetValue (MidiMessage::getMidiNoteInHertz(midiNoteNumber));
auto points = samplerSound->getStartAndEndInSeconds();
sampleStart .setCurrentAndTargetValue (points.getStart() * samplerSound->getSample()->getSampleRate());
sampleEnd .setCurrentAndTargetValue (points.getStart() * samplerSound->getSample()->getSampleRate());
for (auto smoothed : { &level, &frequency, &sampleStart, &sampleEnd, &sampleTranspose })
smoothed->reset (getSampleRate(), 22.0/getSampleRate());
currentSamplePos = 0.0 + sampleStart.getCurrentValue();
src_reset(src_state_left);
src_reset(src_state_right);
src_data_left.end_of_input = 1;
src_data_right.end_of_input = 1;
ratio = juce::MidiMessage::getMidiNoteInHertz(48)/MidiMessage::getMidiNoteInHertz(midiNoteNumber);
src_data_left.src_ratio = ratio;
src_data_left.input_frames = samplerSound->getSample()->getLength();
src_data_right.src_ratio = ratio;
src_data_right.input_frames = samplerSound->getSample()->getLength();
}
void stopNote (float vel/*velocity*/, bool allowTailOff) override
{
ignoreUnused (allowTailOff);
// if (allowTailOff)
// {
// // start a tail-off by setting this flag. The render callback will pick up on
// // this and do a fade out, calling clearCurrentNote() when it's finished.
//
// if (approximatelyEqual (tailOff, 0.0)) // we only need to begin a tail-off if it's not already doing so - the
// tailOff = 1.0; // stopNote method could be called more than once.
// }
// else
// {
// // we're being told to stop playing immediately, so reset everything..
// clearCurrentNote();
// angleDelta = 0.0;
// }
clearCurrentNote();
}
void renderNextBlock (AudioBuffer<float>& outputBuffer,
int startSample,
int numSamples) override
{
render (outputBuffer, startSample, numSamples);
}
void renderNextBlock (AudioBuffer<double>& outputBuffer,
int startSample,
int numSamples) override
{
render (outputBuffer, startSample, numSamples);
}
double getCurrentSamplePosition() const
{
return currentSamplePos;
}
void setSampleTranspose(double newTranspose) {
sampleTranspose.setTargetValue(newTranspose);
}
// void getSampleTranspose(double newTranspose) {
// sampleTranspose.setValue(newTranspose);
// }
void prepareToPlay(double sampleRate, int spb, int outputChannels) {
setCurrentPlaybackSampleRate(sampleRate);
}
using SynthesiserVoice::renderNextBlock;
private:
template <typename Element>
void render (AudioBuffer<Element>& outputBuffer, int startSample, int numSamples)
{
jassert (samplerSound->getSample() != nullptr);
auto& data = samplerSound->getSample()->getBuffer();
auto len = samplerSound->getSample()->getLength();
auto inL = data.getReadPointer (0, currentSamplePos > len ? 0 : currentSamplePos);
auto inR = data.getNumChannels() > 1 ? data.getReadPointer (1, currentSamplePos > len ? 0 : currentSamplePos) : inL;
auto outL = outputBuffer.getWritePointer (0, startSample);
if (outL == nullptr)
return;
auto outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getWritePointer (1, startSample)
: nullptr;
DBG(getCurrentlyPlayingNote());
if(isVoiceActive()) {
while (numSamples > 0) {
int n = 8 - (bufpos & 7);
if(n > numSamples) {
n = numSamples;
}
int opp = (bufpos + 8 ) & 16;
float *pl = bufl + opp;
float *pr = bufr + opp;
memcpy(pl, outL, n*sizeof(float));
if(outR != nullptr) {
memcpy(pr, outR, n*sizeof(float));
}else{
memcpy(pr, outL, n*sizeof(float));
}
int bufnext = (bufpos + n) & 16;
if (0 == (bufnext & 7)) {
src_data_left.data_in = inL;
src_data_left.data_out = bufl;
src_data_left.output_frames = 8;
src_data_right.data_in = inR;
src_data_right.data_out = bufr;
src_data_right.output_frames = 8;
src_process(src_state_left, &src_data_left);
src_process(src_state_right, &src_data_right);
}
float *rl = bufl + bufpos;
float *rr = bufr + bufpos;
for(int i = 0; i < n ; i++) {
if(currentSamplePos >= samplerSound->getSample()->getLength() - 8) {
*outL += 0.0f;
*outR += 0.0f;
}else{
if(outR != nullptr) {
*outL += *rl;
*outR += *rr;
}else{
*outL += *rl+*rr;
}
}
currentSamplePos += 1/ratio;
outL++;
if(outR != nullptr) {
outR++;
}
rl++;
rr++;
}
bufpos = bufnext;
numSamples -= n;
}
} else{
while(numSamples > 0) {
*outL++ += 0.0;
if(outR != nullptr) {
*outR++ += 0.0;
}
numSamples--;
}
}
}
std::shared_ptr<const MSamplerSound> samplerSound;
SmoothedValue<double> level { 0 };
SmoothedValue<double> frequency { 0 };
SmoothedValue<double> sampleStart;
SmoothedValue<double> sampleEnd;
SmoothedValue<double> sampleTranspose;
double currentSamplePos { 0 };
double ratio{1.0};
float bufl[16];
float bufr[16];
int bufpos = 0;
int error = 0;
SRC_DATA src_data_left;
SRC_STATE * src_state_left;
SRC_DATA src_data_right;
SRC_STATE * src_state_right;
};
