I am having problems trying to send MIDI messages from my iPhone to my Macbook, no messages are registered in MIDI monitor. This is using the MIDIKeyboardComponent. I have enabled background audio in the projucer and xcode and am connecting my phone using a lightning cable. With other free midi keyboard apps a signal is received in midi monitor.
/*
==============================================================================
This file was auto-generated!
==============================================================================
*/
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
//==============================================================================
/*
This component lives inside our window, and this is where you should put all
your controls and content.
*/
class MainContentComponent : public Component,
private MidiKeyboardStateListener
{
public:
//==============================================================================
MainContentComponent()
: keyboardComponent (keyboardState, MidiKeyboardComponent::horizontalKeyboard), startTime (Time::getMillisecondCounterHiRes() * 0.001)
{
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));
StringArray str = MidiOutput::getDevices();
Array<MidiDeviceInfo> array = MidiOutput::getAvailableDevices();
for (MidiDeviceInfo a : array) {
std::cout << a.name << "\n";
}
midiDevice = MidiOutput::createNewDevice("Iphone out");
midiDevice->startBackgroundThread();
// device = MidiOutput::openDevice("IDAM MIDI Host");
//device
setSize (800, 300);
}
~MainContentComponent() override
{
keyboardState.removeListener (this);
}
void paint (Graphics&) override {}
void resized() override
{
//auto halfWidth = getWidth() / 2;
auto area = getLocalBounds();
keyboardComponent.setBounds (area.removeFromTop (180).reduced(4));
midiMessagesBox.setBounds(20, 300, getWidth() - 20, getHeight() - 100);
//midiMessagesBox.setBounds (getLocalBounds().withWidth (halfWidth).withX (halfWidth).reduced (101));
}
private:
static String 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 setNoteNumber (int noteNumber)
{
auto message = MidiMessage::noteOn (1, noteNumber, (uint8) 100);
message.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001 - startTime);
addMessageToBuffer (message);
auto messageOff = MidiMessage::noteOff (message.getChannel(), message.getNoteNumber());
messageOff.setTimeStamp (message.getTimeStamp() + 0.1);
addMessageToBuffer (messageOff);
}
void logMessage (const String& m)
{
midiMessagesBox.moveCaretToEnd();
midiMessagesBox.insertTextAtCaret (m + newLine);
}
void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message)
{
const ScopedValueSetter<bool> scopedInputFlag (isAddingFromMidiInput, true);
keyboardState.processNextMidiEvent (message);
postMessageToList (message, source->getName());
}
void handleNoteOn (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity) override
{
if (! isAddingFromMidiInput)
{
auto m = MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity);
m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
postMessageToList (m, "On-Screen Keyboard");
}
midiDevice->sendMessageNow(MidiMessage::noteOn(midiChannel, midiNoteNumber, velocity));
}
void handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float /*velocity*/) override
{
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 (MainContentComponent* 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<MainContentComponent> owner;
MidiMessage message;
String source;
};
void postMessageToList (const MidiMessage& message, const String& source)
{
(new IncomingMessageCallback (this, message, source))->post();
}
void 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);
}
void addMessageToBuffer (const MidiMessage& message)
{
auto timestamp = message.getTimeStamp();
auto sampleNumber = (int) (timestamp * sampleRate);
midiBuffer.addEvent (message, sampleNumber);
}
//==============================================================================
MidiKeyboardState keyboardState;
MidiKeyboardComponent keyboardComponent;
bool isAddingFromMidiInput = false;
TextEditor midiMessagesBox;
int midiChannel = 1;
double startTime;
MidiBuffer midiBuffer; // [1]
std::unique_ptr<MidiOutput> midiDevice;
double sampleRate = 44100.0; // [2]
int previousSampleNumber = 0; // [3]
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};