Midi Keys to Dynamic texture (Dt part done, what's the safest/sanest way to store array of keyboard notes)

Hello everyone,

I’m about a week into a learning Juce, and feeling more at home now.

I managed to successfully take an element (Dynamic texture part) from the OpenGL demo and got it to work inside a plugin! Yay I have moving/dynamic textures into a shader, awesome, and all by myself!

I spent last night till the more-than-early hours working on the next part which is filling this dynamic texture with midi note velocities, so an array of floats 127 elements big.

Everything compiles fine, then there’s behaviour I can’t quite track down, eg missed notes, midi notes not being sent out of the block to host. And I don’t know if I’m using the array correctly, maybe it needs to be a reference to an array that’s fixed in place in dynamic tex?

In my renderOpenGl loop I have this:

    dynamicTexture.applyTo(texture_01,processor.midiKeySender.keyNotes);
    texture_01.bind();
    shaderProgram->setUniform("texture01", 0);

midiKeySender is part of MidiMessageSender class, as I’m using the class for more than one job.

and this is my DynamicTexture class:

class DynamicTexture
{
    public:
    bool applyTo (OpenGLTexture& texture, std::array<float,127> keys) // add midi array 127 array of floats, map floats to velocity
    {
        
        Image image;
        // set to 127 feed midi values and velocities into 127 x 1 array
        int sizex = 127;
        int sizey = 1;

        if (! image.isValid())
        image = Image (Image::ARGB, sizex, sizey, true);
        
        {
            const MessageManagerLock mml (ThreadPoolJob::getCurrentThreadPoolJob());
            if (! mml.lockWasGained())
                return false;
            
            for (int i =0; i<sizex; i++)
            {
                float k = keys[i];
                Colour c = Colour(k , 1.0f  ,1.0f, 1.0f);
                image.setPixelAt(i, sizey, c);
            }
        }
        
        texture.loadImage(image);
        return true;
    }
    static Image resizeImageToPowerOfTwo (Image image)
    {
        if (! (isPowerOfTwo (image.getWidth()) && isPowerOfTwo (image.getHeight())))
            return image.rescaled (jmin (1024, nextPowerOfTwo (image.getWidth())),
                                   jmin (1024, nextPowerOfTwo (image.getHeight())));
        
        return image;
    }
};

I have a midiKeySender.process(midiMessages); inside the audio block, triggering if the midi note has changed.

and this is the responsible for handling the midi and putting into array named SetNoteArray:

#pragma once
#include "JuceHeader.h"
#include <array>

class MidiMessageSender
{
public:
    void process(MidiBuffer& midi)
    {
        midi.clear(); // remove incoming events
        
        int pos0, size0, pos1, size1;
        fifo.prepareToRead(SIZE, pos0, size0, pos1, size1);
        
        for (int i = 0; i < size0; ++i)
        {
            addNote(midi, notes[pos0 + i]); // Addnote has got an entire midi buffer as first input
            setNoteArray(midi, notes[pos0 + i]);
        }
        
        for (int i = 0; i < size1; ++i)
        {
            addNote(midi, notes[pos1 + i]);
            setNoteArray(midi, notes[pos0 + i]);
        }
        
        fifo.finishedRead(size0 + size1);
        // DBG(String::formatted("%i proceessMiditriggered=", 1)); // does dbg not working in private?
    }
    
    void sendNote(int pitch)
    {
        JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED; // this should only be called from one thread
        
        int pos0, size0, discard0, discard1;
        fifo.prepareToWrite(1, pos0, size0, discard0, discard1);
        
        if (size0 != 1)
        {
            jassertfalse; // full
            return;
        }
        
        notes[pos0] = pitch;
        
        fifo.finishedWrite(1);
    }
    
    void setNoteArray(MidiBuffer& midi, int notes)
    {
        MidiBuffer::Iterator it(midi);
        MidiMessage currentMessage;
        int samplePos;
        
        while (it.getNextEvent(currentMessage,samplePos))
        {
            if (currentMessage.isNoteOnOrOff())
                keyNotes[currentMessage.getNoteNumber()] = currentMessage.getFloatVelocity();
        }
    }
    std::array<float, 127> keyNotes;

private:
    void addNote(MidiBuffer& midi, int note)
    {
        midi.addEvent(MidiMessage::noteOn(1, note, 0.5f), 0); // inject them all at position 0 for now
    }
    
    void turnNoteOff(MidiBuffer& midi, int note)
    {
        midi.addEvent(MidiMessage::noteOff(1, note, 0.0f), 0); // inject them all at position 0 for now
    }
    
    constexpr static int SIZE = 16;
    AbstractFifo fifo{ SIZE };
    std::array<int, SIZE> notes;
    
};

I don’t know if this is the sanest way, it’s certainly not working as intended, could it be the for loop inside Dynamic texture that’s a bad idea? Dynamic Texture is getting called by OpenGL render loop, and if that’s called per frame I can imagine this is horrible practice, as it’s doing that whole for loop before continuing right?

Is it better to use a keyboard object and listener, this was the last thing I thought before handing in the towel.

The goal of this is to make a texture 0-127 of midi notes, filled with velocity, this texture is fed into the OpenGL shader so cool stuff can happen. I’ve made it initially so one note can trigger visuals, but I want chords now, and a convenient way for the shader to access them, which is why I’m sharing via a texture.

If anyone has any thoughts of helps/push in the right direction I’d be really appreciative.I feel like I almost get Juce, gimme three months and I reckon it will have really sunk in!