| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2017 - ROLI Ltd.
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    By using JUCE, you agree to the terms of both the JUCE 5 End-User License
 -    Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
 -    27th April 2017).
 - 
 -    End User License Agreement: www.juce.com/juce-5-licence
 -    Privacy Policy: www.juce.com/juce-5-privacy-policy
 - 
 -    Or: You may also use this code under the terms of the GPL v3 (see
 -    www.gnu.org/licenses).
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - #include "../JuceDemoHeader.h"
 - 
 - /** Simple list box that just displays a StringArray. */
 - class MidiLogListBoxModel   : public ListBoxModel
 - {
 - public:
 -     MidiLogListBoxModel (const Array<MidiMessage>& list)
 -         : midiMessageList (list)
 -     {
 -     }
 - 
 -     int getNumRows() override    { return midiMessageList.size(); }
 - 
 -     void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected) override
 -     {
 -         if (rowIsSelected)
 -             g.fillAll (Colours::blue.withAlpha (0.2f));
 - 
 -         if (isPositiveAndBelow (row, midiMessageList.size()))
 -         {
 -             g.setColour (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::defaultText,
 -                                                  Colours::black));
 - 
 -             const MidiMessage& message = midiMessageList.getReference (row);
 -             double time = message.getTimeStamp();
 - 
 -             g.drawText (String::formatted ("%02d:%02d:%02d",
 -                                            ((int) (time / 3600.0)) % 24,
 -                                            ((int) (time / 60.0)) % 60,
 -                                            ((int) time) % 60)
 -                             + "  -  " + message.getDescription(),
 -                         Rectangle<int> (width, height).reduced (4, 0),
 -                         Justification::centredLeft, true);
 -         }
 -     }
 - 
 - private:
 -     const Array<MidiMessage>& midiMessageList;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiLogListBoxModel)
 - };
 - 
 - //==============================================================================
 - class MidiDemo  : public Component,
 -                   private MidiInputCallback,
 -                   private MidiKeyboardStateListener,
 -                   private AsyncUpdater
 - {
 - public:
 -     MidiDemo()
 -         : deviceManager (MainAppWindow::getSharedAudioDeviceManager()),
 -           keyboardComponent (keyboardState, MidiKeyboardComponent::horizontalKeyboard),
 -           midiLogListBoxModel (midiMessageList)
 -     {
 -         setOpaque (true);
 - 
 -         // MIDI Inputs
 -         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 (int i = 0; i < midiInputs.size(); ++i)
 -         {
 -             if (deviceManager.isMidiInputEnabled (midiInputs[i]))
 -             {
 -                 setMidiInput (i);
 -                 break;
 -             }
 -         }
 - 
 -         // if no enabled devices were found just use the first one in the list
 -         if (midiInputList.getSelectedId() == 0)
 -             setMidiInput (0);
 - 
 - 
 -         // MIDI Outputs
 -         addAndMakeVisible (midiOutputListLabel);
 -         midiOutputListLabel.setText ("MIDI Output:", dontSendNotification);
 -         midiOutputListLabel.attachToComponent (&midiOutputList, true);
 - 
 -         addAndMakeVisible (midiOutputList);
 -         midiOutputList.setTextWhenNoChoicesAvailable ("No MIDI Output Enabled");
 -         midiOutputList.addItemList (MidiOutput::getDevices(), 1);
 -         midiOutputList.onChange = [this] { setMidiOutput (midiOutputList.getSelectedItemIndex()); };
 - 
 -         addAndMakeVisible (keyboardComponent);
 -         keyboardState.addListener (this);
 - 
 -         addAndMakeVisible (messageListBox);
 -         messageListBox.setModel (&midiLogListBoxModel);
 -     }
 - 
 -     ~MidiDemo()
 -     {
 -         keyboardState.removeListener (this);
 -         deviceManager.removeMidiInputCallback (MidiInput::getDevices()[midiInputList.getSelectedItemIndex()], this);
 -     }
 - 
 -     void paint (Graphics& g) override
 -     {
 -         g.fillAll (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground));
 -     }
 - 
 -     void resized() override
 -     {
 -         auto area = getLocalBounds();
 -         midiInputList.setBounds (area.removeFromTop (36).removeFromRight (getWidth() - 150).reduced (8));
 -         midiOutputList.setBounds (area.removeFromTop (36).removeFromRight (getWidth() - 150).reduced (8));
 -         keyboardComponent.setBounds (area.removeFromTop (80).reduced(8));
 -         messageListBox.setBounds (area.reduced (8));
 -     }
 - 
 - private:
 -     AudioDeviceManager& deviceManager;
 -     ComboBox midiInputList, midiOutputList;
 -     Label midiInputListLabel, midiOutputListLabel;
 -     int lastInputIndex = 0;
 -     bool isAddingFromMidiInput = false;
 - 
 -     MidiKeyboardState keyboardState;
 -     MidiKeyboardComponent keyboardComponent;
 - 
 -     ListBox messageListBox;
 -     Array<MidiMessage> midiMessageList;
 -     MidiLogListBoxModel midiLogListBoxModel;
 -     ScopedPointer<MidiOutput> currentMidiOutput;
 - 
 -     //==============================================================================
 -     /** Starts listening to a MIDI input device, enabling it if necessary. */
 -     void 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 setMidiOutput (int index)
 -     {
 -         currentMidiOutput.reset();
 - 
 -         if (MidiOutput::getDevices() [index].isNotEmpty())
 -         {
 -             currentMidiOutput = MidiOutput::openDevice (index);
 -             jassert (currentMidiOutput);
 -         }
 -     }
 - 
 -     // These methods handle callbacks from the midi device + on-screen keyboard..
 -     void handleIncomingMidiMessage (MidiInput*, const MidiMessage& message) override
 -     {
 -         const ScopedValueSetter<bool> scopedInputFlag (isAddingFromMidiInput, true);
 -         keyboardState.processNextMidiEvent (message);
 -         postMessageToList (message);
 -     }
 - 
 -     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);
 -         }
 -     }
 - 
 -     void handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity) override
 -     {
 -         if (! isAddingFromMidiInput)
 -         {
 -             auto m = MidiMessage::noteOff (midiChannel, midiNoteNumber, velocity);
 -             m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
 -             postMessageToList (m);
 -         }
 -     }
 - 
 -     // This is used to dispach an incoming message to the message thread
 -     struct IncomingMessageCallback   : public CallbackMessage
 -     {
 -         IncomingMessageCallback (MidiDemo* d, const MidiMessage& m)
 -             : demo (d), message (m) {}
 - 
 -         void messageCallback() override
 -         {
 -             if (demo != nullptr)
 -                 demo->addMessageToList (message);
 -         }
 - 
 -         Component::SafePointer<MidiDemo> demo;
 -         MidiMessage message;
 -     };
 - 
 -     void postMessageToList (const MidiMessage& message)
 -     {
 -         if (currentMidiOutput != nullptr)
 -             currentMidiOutput->sendMessageNow (message);
 - 
 -         (new IncomingMessageCallback (this, message))->post();
 -     }
 - 
 -     void addMessageToList (const MidiMessage& message)
 -     {
 -         midiMessageList.add (message);
 -         triggerAsyncUpdate();
 -     }
 - 
 -     void handleAsyncUpdate() override
 -     {
 -         messageListBox.updateContent();
 -         messageListBox.scrollToEnsureRowIsOnscreen (midiMessageList.size() - 1);
 -         messageListBox.repaint();
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiDemo)
 - };
 - 
 - 
 - // This static object will register this demo type in a global list of demos..
 - static JuceDemoType<MidiDemo> demo ("32 Audio: MIDI i/o");
 
 
  |