Hello, so I am trying to make it so that my synthesizer can handle external midi inputs, and so far i’ve been following the juce website tutorial on “handling midi inputs”, Ive made a new class with a header& cpp for the midi keyboard and input alone and this is what it looks like:
Header
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
//==============================================================================
/*
*/
class Midi : public Component,
private MidiInputCallback,
private MidiKeyboardStateListener,
private ComboBox::Listener
{
public:
Midi();
~Midi();
void paint (Graphics&) override;
void resized() override;
void setMidiInput(int index);
void handleIncomingMidiMessage(MidiInput* source, const MidiMessage& message)override;
void handleNoteOn(MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity)override;
void handleNoteOff(MidiKeyboardState*, int midiChannel, int midiNoteNumber);
void postMessageToList (const MidiMessage& message, const String& source);
void addMessageToList (const MidiMessage& message, const String& source);
void logMessage (const String& m);
String getMidiMessageDescription (const MidiMessage& m);
void comboBoxChanged(ComboBox*) override;
private:
AudioDeviceManager deviceManager;
ComboBox midiInputList;
Label midiInputListLabel;
int lastInputIndex = 0;
bool isAddingFromMidiInput = false;
MidiKeyboardState keyboardState;
MidiKeyboardComponent keyboardComponent;
TextEditor midiMessagesBox;
double startTime;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Midi)
};
cpp
#include "../JuceLibraryCode/JuceHeader.h"
#include "Midi.h"
//==============================================================================
Midi::Midi() : keyboardComponent (keyboardState, MidiKeyboardComponent::horizontalKeyboard),
startTime (Time::getMillisecondCounterHiRes() * 0.001)
{
addAndMakeVisible (midiInputListLabel);
midiInputListLabel.setText ("MIDI Input:", dontSendNotification);
midiInputListLabel.attachToComponent (&midiInputList, true);
addAndMakeVisible (midiInputList);
midiInputList.setTextWhenNoChoicesAvailable ("No MIDI Inputs Enabled");
auto midiInputs = MidiInput::getDevices();
midiInputList.addItemList (midiInputs, 1);
midiInputList.onChange = [this] { setMidiInput (midiInputList.getSelectedItemIndex()); };
// find the first enabled device and use that by default
for (auto midiInput : midiInputs)
{
if (deviceManager.isMidiInputEnabled (midiInput))
{
setMidiInput (midiInputs.indexOf (midiInput));
break;
}
}
// if no enabled devices were found just use the first one in the list
if (midiInputList.getSelectedId() == 0)
setMidiInput (0);
addAndMakeVisible (keyboardComponent);
keyboardState.addListener (this);
addAndMakeVisible (midiMessagesBox);
midiMessagesBox.setMultiLine (true);
midiMessagesBox.setReturnKeyStartsNewLine (true);
midiMessagesBox.setReadOnly (true);
midiMessagesBox.setScrollbarsShown (true);
midiMessagesBox.setCaretVisible (false);
midiMessagesBox.setPopupMenuEnabled (true);
midiMessagesBox.setColour (TextEditor::backgroundColourId, Colour (0x32ffffff));
midiMessagesBox.setColour (TextEditor::outlineColourId, Colour (0x1c000000));
midiMessagesBox.setColour (TextEditor::shadowColourId, Colour (0x16000000));
}
Midi::~Midi()
{
}
void Midi::paint (Graphics& g)
{
}
void Midi::resized()
{
auto area = getLocalBounds();
midiInputList .setBounds (area.removeFromTop (36).removeFromRight (getWidth() - 150).reduced (8));
keyboardComponent.setBounds (area.removeFromTop (80).reduced(8));
midiMessagesBox .setBounds (area.reduced (8));
}
void Midi::setMidiInput (int index)
{
auto list = MidiInput::getDevices();
deviceManager.removeMidiInputCallback (list[lastInputIndex], this);
auto newInput = list[index];
if (! deviceManager.isMidiInputEnabled (newInput))
deviceManager.setMidiInputEnabled (newInput, true);
deviceManager.addMidiInputCallback (newInput, this);
midiInputList.setSelectedId (index + 1, dontSendNotification);
lastInputIndex = index;
}
void Midi::handleIncomingMidiMessage(MidiInput* source, const MidiMessage& message)
{
const ScopedValueSetter<bool> scopedInputFlag (isAddingFromMidiInput, true);
keyboardState.processNextMidiEvent (message);
postMessageToList (message, source->getName());
}
void Midi::handleNoteOn(MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity)
{
if (! isAddingFromMidiInput)
{
auto m = MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity);
m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
postMessageToList (m, "On-Screen Keyboard");
}
}
void Midi::handleNoteOff(MidiKeyboardState*, int midiChannel, int midiNoteNumber)
{
if (! isAddingFromMidiInput)
{
auto m = MidiMessage::noteOff (midiChannel, midiNoteNumber);
m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
postMessageToList (m, "On-Screen Keyboard");
}
}
class IncomingMessageCallback : public CallbackMessage
{
public:
IncomingMessageCallback (Midi* o, const MidiMessage& m, const String& s)
: owner (o), message (m), source (s)
{}
void messageCallback() override
{
if (owner != nullptr)
owner->addMessageToList (message, source);
}
Component::SafePointer<Midi> owner;
MidiMessage message;
String source;
};
void Midi::postMessageToList (const MidiMessage& message, const String& source)
{
(new IncomingMessageCallback (this, message, source))->post();
}
void Midi::addMessageToList (const MidiMessage& message, const String& source)
{
auto time = message.getTimeStamp() - startTime;
auto hours = ((int) (time / 3600.0)) % 24;
auto minutes = ((int) (time / 60.0)) % 60;
auto seconds = ((int) time) % 60;
auto millis = ((int) (time * 1000.0)) % 1000;
auto timecode = String::formatted ("%02d:%02d:%02d.%03d",
hours,
minutes,
seconds,
millis);
auto description = getMidiMessageDescription (message);
String midiMessageString (timecode + " - " + description + " (" + source + ")"); // [7]
logMessage (midiMessageString);
}
String Midi::getMidiMessageDescription (const MidiMessage& m)
{
if (m.isNoteOn()) return "Note on " + MidiMessage::getMidiNoteName (m.getNoteNumber(), true, true, 3);
if (m.isNoteOff()) return "Note off " + MidiMessage::getMidiNoteName (m.getNoteNumber(), true, true, 3);
if (m.isProgramChange()) return "Program change " + String (m.getProgramChangeNumber());
if (m.isPitchWheel()) return "Pitch wheel " + String (m.getPitchWheelValue());
if (m.isAftertouch()) return "After touch " + MidiMessage::getMidiNoteName (m.getNoteNumber(), true, true, 3) + ": " + String (m.getAfterTouchValue());
if (m.isChannelPressure()) return "Channel pressure " + String (m.getChannelPressureValue());
if (m.isAllNotesOff()) return "All notes off";
if (m.isAllSoundOff()) return "All sound off";
if (m.isMetaEvent()) return "Meta event";
if (m.isController())
{
String name (MidiMessage::getControllerName (m.getControllerNumber()));
if (name.isEmpty())
name = "[" + String (m.getControllerNumber()) + "]";
return "Controller " + name + ": " + String (m.getControllerValue());
}
return String::toHexString (m.getRawData(), m.getRawDataSize());
}
void Midi::logMessage (const String& m)
{
midiMessagesBox.moveCaretToEnd();
midiMessagesBox.insertTextAtCaret (m + newLine);
}
void Midi::comboBoxChanged(ComboBox* box)
{
}
I wish to pass this class as an object in my pluginEditor.h, however I always recieve an error “Field type ‘Midi’ is an abstract class”, I tried researching the bug, and adding all the functions required from each class, but still do not know why i get this error.
pluginEditor
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"
#include "OscillatorEditor.h"
#include "Midi.h"
//==============================================================================
/**
*/
class SharodVstAudioProcessorEditor:
public AudioProcessorEditor,
public Slider::Listener
{
public:
SharodVstAudioProcessorEditor (SharodVstAudioProcessor&);
~SharodVstAudioProcessorEditor();
//==============================================================================
void paint (Graphics&) override;
void resized() override;
void sliderValueChanged(Slider* slider) override;
private:
// This reference is provided as a quick way for your editor to
// access the processor object that created it.
SharodVstAudioProcessor& processor;
Midi midiGUI;
public:
(SharodVstAudioProcessorEditor)
};
Thanks for the help in advance.